Merge 'v2.0.0-alpha3' into master
This commit is contained in:
commit
7baa752a9d
78 changed files with 2711 additions and 1355 deletions
11
.github/ISSUE_TEMPLATE.md
vendored
11
.github/ISSUE_TEMPLATE.md
vendored
|
@ -16,6 +16,17 @@ For end-user related support questions, please refer to one of the following:
|
||||||
If you intend to ask a support question: DO NOT FILE AN ISSUE.
|
If you intend to ask a support question: DO NOT FILE AN ISSUE.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
### Did you try using a 1.7.x configuration for the version 2.0?
|
||||||
|
|
||||||
|
- [ ] Yes
|
||||||
|
- [ ] No
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
If you just checked the "Yes" box, be aware that this is probably not a bug. The configurations between 1.X and 2.X are NOT compatible. Please have a look here https://docs.traefik.io/v2.0/getting-started/configuration-overview/.
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
### What did you do?
|
### What did you do?
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|
11
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
11
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
|
@ -20,6 +20,17 @@ For end-user related support questions, please refer to one of the following:
|
||||||
|
|
||||||
Bug
|
Bug
|
||||||
|
|
||||||
|
### Did you try using a 1.7.x configuration for the version 2.0?
|
||||||
|
|
||||||
|
- [ ] Yes
|
||||||
|
- [ ] No
|
||||||
|
|
||||||
|
<!--
|
||||||
|
|
||||||
|
If you just checked the "Yes" box, be aware that this is probably not a bug. The configurations between 1.X and 2.X are NOT compatible. Please have a look here https://docs.traefik.io/v2.0/getting-started/configuration-overview/.
|
||||||
|
|
||||||
|
-->
|
||||||
|
|
||||||
### What did you do?
|
### What did you do?
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|
|
@ -24,7 +24,7 @@ before_deploy:
|
||||||
sudo -E apt-get -yq update;
|
sudo -E apt-get -yq update;
|
||||||
sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install docker-ce=${DOCKER_VERSION}*;
|
sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install docker-ce=${DOCKER_VERSION}*;
|
||||||
docker version;
|
docker version;
|
||||||
make image;
|
make build-image;
|
||||||
if [ "$TRAVIS_TAG" ]; then
|
if [ "$TRAVIS_TAG" ]; then
|
||||||
make release-packages;
|
make release-packages;
|
||||||
fi;
|
fi;
|
||||||
|
@ -38,6 +38,7 @@ deploy:
|
||||||
file: dist/traefik*
|
file: dist/traefik*
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
file_glob: true
|
file_glob: true
|
||||||
|
draft: true
|
||||||
on:
|
on:
|
||||||
repo: containous/traefik
|
repo: containous/traefik
|
||||||
tags: true
|
tags: true
|
||||||
|
@ -47,11 +48,6 @@ deploy:
|
||||||
on:
|
on:
|
||||||
repo: containous/traefik
|
repo: containous/traefik
|
||||||
tags: true
|
tags: true
|
||||||
- provider: script
|
|
||||||
script: sh script/deploy-docker.sh
|
|
||||||
skip_cleanup: true
|
|
||||||
on:
|
|
||||||
repo: containous/traefik
|
|
||||||
- provider: pages
|
- provider: pages
|
||||||
edge: false
|
edge: false
|
||||||
github_token: ${GITHUB_TOKEN}
|
github_token: ${GITHUB_TOKEN}
|
||||||
|
|
35
CHANGELOG.md
35
CHANGELOG.md
|
@ -1,5 +1,40 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
## [v2.0.0-alpha3](https://github.com/containous/traefik/tree/v2.0.0-alpha3) (2019-03-29)
|
||||||
|
[All Commits](https://github.com/containous/traefik/compare/v2.0.0-alpha2...v2.0.0-alpha3)
|
||||||
|
|
||||||
|
**Enhancements:**
|
||||||
|
- **[acme,k8s,k8s/crd]** Document the TLS with ACME case ([#4654](https://github.com/containous/traefik/pull/4654) by [mpl](https://github.com/mpl))
|
||||||
|
- **[docker,tcp]** Add support for TCP labels in Docker provider ([#4621](https://github.com/containous/traefik/pull/4621) by [juliens](https://github.com/juliens))
|
||||||
|
- **[provider]** Remove BaseProvider ([#4661](https://github.com/containous/traefik/pull/4661) by [ldez](https://github.com/ldez))
|
||||||
|
|
||||||
|
**Bug fixes:**
|
||||||
|
- **[server]** Fix panic while server shutdown ([#4644](https://github.com/containous/traefik/pull/4644) by [juliens](https://github.com/juliens))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
- **[acme,k8s,k8s/crd]** Full ACME+CRD example ([#4652](https://github.com/containous/traefik/pull/4652) by [mpl](https://github.com/mpl))
|
||||||
|
- **[acme]** Enhance manual dnsChallenge documentation ([#4636](https://github.com/containous/traefik/pull/4636) by [ntaranov](https://github.com/ntaranov))
|
||||||
|
- **[docker]** Fix Getting started ([#4646](https://github.com/containous/traefik/pull/4646) by [mmatur](https://github.com/mmatur))
|
||||||
|
- **[docker]** docker-compose examples ([#4642](https://github.com/containous/traefik/pull/4642) by [karnthis](https://github.com/karnthis))
|
||||||
|
- **[middleware]** Fix typo in forwardAuth middleware documentation ([#4638](https://github.com/containous/traefik/pull/4638) by [AkeemMcLennon](https://github.com/AkeemMcLennon))
|
||||||
|
- **[middleware]** Enhance middleware examples. ([#4680](https://github.com/containous/traefik/pull/4680) by [ldez](https://github.com/ldez))
|
||||||
|
- Fix typos in docs ([#4662](https://github.com/containous/traefik/pull/4662) by [SeMeKh](https://github.com/SeMeKh))
|
||||||
|
- Remove old links in readme ([#4651](https://github.com/containous/traefik/pull/4651) by [ldez](https://github.com/ldez))
|
||||||
|
- Fix some minors errors on the documentation ([#4664](https://github.com/containous/traefik/pull/4664) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||||
|
- Fix dead maintainers link on the README.md ([#4639](https://github.com/containous/traefik/pull/4639) by [benjaminch](https://github.com/benjaminch))
|
||||||
|
- Update traefik.sample.toml ([#4657](https://github.com/containous/traefik/pull/4657) by [ldez](https://github.com/ldez))
|
||||||
|
|
||||||
|
## [v2.0.0-alpha2](https://github.com/containous/traefik/tree/v2.0.0-alpha2) (2019-03-19)
|
||||||
|
[All Commits](https://github.com/containous/traefik/compare/v2.0.0-alpha1...v2.0.0-alpha2)
|
||||||
|
|
||||||
|
**Bug fixes:**
|
||||||
|
- **[k8s,k8s/crd]** Fix log messages about label selector ([#4629](https://github.com/containous/traefik/pull/4629) by [mpl](https://github.com/mpl))
|
||||||
|
- **[server]** Fix problem in aggregator provider ([#4625](https://github.com/containous/traefik/pull/4625) by [juliens](https://github.com/juliens))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
- **[k8s,k8s/crd]** doc: kubernetes CRD provider ([#4620](https://github.com/containous/traefik/pull/4620) by [mpl](https://github.com/mpl))
|
||||||
|
- **[webui]** change docs and adjust dashboard for v2 alpha ([#4632](https://github.com/containous/traefik/pull/4632) by [SantoDE](https://github.com/SantoDE))
|
||||||
|
|
||||||
## [v2.0.0-alpha1](https://github.com/containous/traefik/tree/v2.0.0-alpha1) (2019-03-18)
|
## [v2.0.0-alpha1](https://github.com/containous/traefik/tree/v2.0.0-alpha1) (2019-03-18)
|
||||||
[All Commits](https://github.com/containous/traefik/compare/v1.7.0-rc1...v2.0.0-alpha1)
|
[All Commits](https://github.com/containous/traefik/compare/v1.7.0-rc1...v2.0.0-alpha1)
|
||||||
|
|
||||||
|
|
176
Makefile
176
Makefile
|
@ -1,4 +1,22 @@
|
||||||
.PHONY: all docs docs-serve clear-static
|
.PHONY: all docs docs-serve
|
||||||
|
|
||||||
|
SRCS = $(shell git ls-files '*.go' | grep -v '^vendor/')
|
||||||
|
|
||||||
|
TAG_NAME := $(shell git tag -l --contains HEAD)
|
||||||
|
SHA := $(shell git rev-parse HEAD)
|
||||||
|
VERSION_GIT := $(if $(TAG_NAME),$(TAG_NAME),$(SHA))
|
||||||
|
VERSION := $(if $(VERSION),$(VERSION),$(VERSION_GIT))
|
||||||
|
|
||||||
|
BIND_DIR := "dist"
|
||||||
|
|
||||||
|
GIT_BRANCH := $(subst heads/,,$(shell git rev-parse --abbrev-ref HEAD 2>/dev/null))
|
||||||
|
TRAEFIK_DEV_IMAGE := traefik-dev$(if $(GIT_BRANCH),:$(subst /,-,$(GIT_BRANCH)))
|
||||||
|
|
||||||
|
REPONAME := $(shell echo $(REPO) | tr '[:upper:]' '[:lower:]')
|
||||||
|
TRAEFIK_IMAGE := $(if $(REPONAME),$(REPONAME),"containous/traefik")
|
||||||
|
|
||||||
|
INTEGRATION_OPTS := $(if $(MAKE_DOCKER_HOST),-e "DOCKER_HOST=$(MAKE_DOCKER_HOST)", -e "TEST_CONTAINER=1" -v "/var/run/docker.sock:/var/run/docker.sock")
|
||||||
|
DOCKER_BUILD_ARGS := $(if $(DOCKER_VERSION), "--build-arg=DOCKER_VERSION=$(DOCKER_VERSION)",)
|
||||||
|
|
||||||
TRAEFIK_ENVS := \
|
TRAEFIK_ENVS := \
|
||||||
-e OS_ARCH_ARG \
|
-e OS_ARCH_ARG \
|
||||||
|
@ -11,93 +29,33 @@ TRAEFIK_ENVS := \
|
||||||
-e CI \
|
-e CI \
|
||||||
-e CONTAINER=DOCKER # Indicator for integration tests that we are running inside a container.
|
-e CONTAINER=DOCKER # Indicator for integration tests that we are running inside a container.
|
||||||
|
|
||||||
SRCS = $(shell git ls-files '*.go' | grep -v '^vendor/')
|
|
||||||
|
|
||||||
TAG_NAME := $(shell git tag -l --contains HEAD)
|
|
||||||
SHA := $(shell git rev-parse HEAD)
|
|
||||||
VERSION_GIT := $(if $(TAG_NAME),$(TAG_NAME),$(SHA))
|
|
||||||
VERSION := $(if $(VERSION),$(VERSION),$(VERSION_GIT))
|
|
||||||
|
|
||||||
BIND_DIR := "dist"
|
|
||||||
TRAEFIK_MOUNT := -v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/containous/traefik/$(BIND_DIR)"
|
TRAEFIK_MOUNT := -v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/containous/traefik/$(BIND_DIR)"
|
||||||
|
|
||||||
GIT_BRANCH := $(subst heads/,,$(shell git rev-parse --abbrev-ref HEAD 2>/dev/null))
|
|
||||||
TRAEFIK_DEV_IMAGE := traefik-dev$(if $(GIT_BRANCH),:$(subst /,-,$(GIT_BRANCH)))
|
|
||||||
REPONAME := $(shell echo $(REPO) | tr '[:upper:]' '[:lower:]')
|
|
||||||
TRAEFIK_IMAGE := $(if $(REPONAME),$(REPONAME),"containous/traefik")
|
|
||||||
INTEGRATION_OPTS := $(if $(MAKE_DOCKER_HOST),-e "DOCKER_HOST=$(MAKE_DOCKER_HOST)", -e "TEST_CONTAINER=1" -v "/var/run/docker.sock:/var/run/docker.sock")
|
|
||||||
|
|
||||||
DOCKER_BUILD_ARGS := $(if $(DOCKER_VERSION), "--build-arg=DOCKER_VERSION=$(DOCKER_VERSION)",)
|
|
||||||
DOCKER_RUN_OPTS := $(TRAEFIK_ENVS) $(TRAEFIK_MOUNT) "$(TRAEFIK_DEV_IMAGE)"
|
DOCKER_RUN_OPTS := $(TRAEFIK_ENVS) $(TRAEFIK_MOUNT) "$(TRAEFIK_DEV_IMAGE)"
|
||||||
DOCKER_RUN_TRAEFIK := docker run $(INTEGRATION_OPTS) -it $(DOCKER_RUN_OPTS)
|
DOCKER_RUN_TRAEFIK := docker run $(INTEGRATION_OPTS) -it $(DOCKER_RUN_OPTS)
|
||||||
DOCKER_RUN_TRAEFIK_NOTTY := docker run $(INTEGRATION_OPTS) -i $(DOCKER_RUN_OPTS)
|
DOCKER_RUN_TRAEFIK_NOTTY := docker run $(INTEGRATION_OPTS) -i $(DOCKER_RUN_OPTS)
|
||||||
|
|
||||||
print-%: ; @echo $*=$($*)
|
PRE_TARGET ?= build-dev-image
|
||||||
|
|
||||||
default: binary
|
default: binary
|
||||||
|
|
||||||
all: generate-webui build ## validate all checks, build linux binary, run all tests\ncross non-linux binaries
|
## Build Dev Docker image
|
||||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh
|
build-dev-image: dist
|
||||||
|
|
||||||
binary: generate-webui build ## build the linux binary
|
|
||||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate binary
|
|
||||||
|
|
||||||
crossbinary-default: generate-webui build
|
|
||||||
$(DOCKER_RUN_TRAEFIK_NOTTY) ./script/make.sh generate crossbinary-default
|
|
||||||
|
|
||||||
crossbinary-default-parallel:
|
|
||||||
$(MAKE) generate-webui
|
|
||||||
$(MAKE) build crossbinary-default
|
|
||||||
|
|
||||||
test: build ## run the unit and integration tests
|
|
||||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate test-unit binary test-integration
|
|
||||||
|
|
||||||
test-unit: build ## run the unit tests
|
|
||||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate test-unit
|
|
||||||
|
|
||||||
test-integration: build ## run the integration tests
|
|
||||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate binary test-integration
|
|
||||||
TEST_HOST=1 ./script/make.sh test-integration
|
|
||||||
|
|
||||||
validate: build ## validate code, vendor
|
|
||||||
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate validate-lint validate-misspell validate-vendor
|
|
||||||
|
|
||||||
build: dist
|
|
||||||
docker build $(DOCKER_BUILD_ARGS) -t "$(TRAEFIK_DEV_IMAGE)" -f build.Dockerfile .
|
docker build $(DOCKER_BUILD_ARGS) -t "$(TRAEFIK_DEV_IMAGE)" -f build.Dockerfile .
|
||||||
|
|
||||||
build-no-cache: dist
|
## Build Dev Docker image without cache
|
||||||
|
build-dev-image-no-cache: dist
|
||||||
docker build --no-cache -t "$(TRAEFIK_DEV_IMAGE)" -f build.Dockerfile .
|
docker build --no-cache -t "$(TRAEFIK_DEV_IMAGE)" -f build.Dockerfile .
|
||||||
|
|
||||||
shell: build ## start a shell inside the build env
|
## Create the "dist" directory
|
||||||
$(DOCKER_RUN_TRAEFIK) /bin/bash
|
|
||||||
|
|
||||||
image-dirty: binary ## build a docker traefik image
|
|
||||||
docker build -t $(TRAEFIK_IMAGE) .
|
|
||||||
|
|
||||||
image: clear-static binary ## clean up static directory and build a docker traefik image
|
|
||||||
docker build -t $(TRAEFIK_IMAGE) .
|
|
||||||
|
|
||||||
docs:
|
|
||||||
make -C ./docs docs
|
|
||||||
|
|
||||||
docs-serve:
|
|
||||||
make -C ./docs docs-serve
|
|
||||||
|
|
||||||
dist:
|
dist:
|
||||||
mkdir dist
|
mkdir dist
|
||||||
|
|
||||||
run-dev:
|
## Build WebUI Docker image
|
||||||
go generate
|
build-webui-image:
|
||||||
go build ./cmd/traefik
|
|
||||||
./traefik
|
|
||||||
|
|
||||||
clear-static:
|
|
||||||
rm -rf static
|
|
||||||
|
|
||||||
build-webui:
|
|
||||||
docker build -t traefik-webui -f webui/Dockerfile webui
|
docker build -t traefik-webui -f webui/Dockerfile webui
|
||||||
|
|
||||||
generate-webui: build-webui
|
## Generate WebUI
|
||||||
|
generate-webui: build-webui-image
|
||||||
if [ ! -d "static" ]; then \
|
if [ ! -d "static" ]; then \
|
||||||
mkdir -p static; \
|
mkdir -p static; \
|
||||||
docker run --rm -v "$$PWD/static":'/src/static' traefik-webui npm run build; \
|
docker run --rm -v "$$PWD/static":'/src/static' traefik-webui npm run build; \
|
||||||
|
@ -105,29 +63,76 @@ generate-webui: build-webui
|
||||||
echo 'For more informations show `webui/readme.md`' > $$PWD/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md; \
|
echo 'For more informations show `webui/readme.md`' > $$PWD/static/DONT-EDIT-FILES-IN-THIS-DIRECTORY.md; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
generate-crd:
|
## Build the linux binary
|
||||||
./script/update-generated-crd-code.sh
|
binary: generate-webui $(PRE_TARGET)
|
||||||
|
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK)) ./script/make.sh generate binary
|
||||||
|
|
||||||
lint:
|
## Build the binary for the standard plaforms (linux, darwin, windows)
|
||||||
script/validate-lint
|
crossbinary-default: generate-webui build-dev-image
|
||||||
|
$(DOCKER_RUN_TRAEFIK_NOTTY) ./script/make.sh generate crossbinary-default
|
||||||
|
|
||||||
fmt:
|
## Build the binary for the standard plaforms (linux, darwin, windows) in parallel
|
||||||
gofmt -s -l -w $(SRCS)
|
crossbinary-default-parallel:
|
||||||
|
$(MAKE) generate-webui
|
||||||
|
$(MAKE) build-dev-image crossbinary-default
|
||||||
|
|
||||||
|
## Run the unit and integration tests
|
||||||
|
test: build-dev-image
|
||||||
|
$(DOCKER_RUN_TRAEFIK) ./script/make.sh generate test-unit binary test-integration
|
||||||
|
|
||||||
|
## Run the unit tests
|
||||||
|
test-unit: $(PRE_TARGET)
|
||||||
|
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK)) ./script/make.sh generate test-unit
|
||||||
|
|
||||||
|
## Pull all images for integration tests
|
||||||
pull-images:
|
pull-images:
|
||||||
grep --no-filename -E '^\s+image:' ./integration/resources/compose/*.yml | awk '{print $$2}' | sort | uniq | xargs -P 6 -n 1 docker pull
|
grep --no-filename -E '^\s+image:' ./integration/resources/compose/*.yml | awk '{print $$2}' | sort | uniq | xargs -P 6 -n 1 docker pull
|
||||||
|
|
||||||
|
## Run the integration tests
|
||||||
|
test-integration: $(PRE_TARGET)
|
||||||
|
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK),TEST_CONTAINER=1) ./script/make.sh generate binary test-integration
|
||||||
|
TEST_HOST=1 ./script/make.sh test-integration
|
||||||
|
|
||||||
|
## Validate code, vendor
|
||||||
|
validate: $(PRE_TARGET)
|
||||||
|
$(if $(PRE_TARGET),$(DOCKER_RUN_TRAEFIK)) ./script/make.sh generate validate-lint validate-misspell validate-vendor
|
||||||
|
|
||||||
|
## Clean up static directory and build a Docker Traefik image
|
||||||
|
build-image: binary
|
||||||
|
rm -rf static
|
||||||
|
docker build -t $(TRAEFIK_IMAGE) .
|
||||||
|
|
||||||
|
## Build a Docker Traefik image
|
||||||
|
build-image-dirty: binary
|
||||||
|
docker build -t $(TRAEFIK_IMAGE) .
|
||||||
|
|
||||||
|
## Start a shell inside the build env
|
||||||
|
shell: build-dev-image
|
||||||
|
$(DOCKER_RUN_TRAEFIK) /bin/bash
|
||||||
|
|
||||||
|
## Build documentation site
|
||||||
|
docs:
|
||||||
|
make -C ./docs docs
|
||||||
|
|
||||||
|
## Serve the documentation site localy
|
||||||
|
docs-serve:
|
||||||
|
make -C ./docs docs-serve
|
||||||
|
|
||||||
|
## Generate CRD clientset
|
||||||
|
generate-crd:
|
||||||
|
./script/update-generated-crd-code.sh
|
||||||
|
|
||||||
|
## Download dependencies
|
||||||
dep-ensure:
|
dep-ensure:
|
||||||
dep ensure -v
|
dep ensure -v
|
||||||
./script/prune-dep.sh
|
./script/prune-dep.sh
|
||||||
|
|
||||||
|
## Clean vendor directory
|
||||||
dep-prune:
|
dep-prune:
|
||||||
./script/prune-dep.sh
|
./script/prune-dep.sh
|
||||||
|
|
||||||
help: ## this help
|
## Create packages for the release
|
||||||
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {sub("\\\\n",sprintf("\n%22c"," "), $$2);printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
release-packages: generate-webui build-dev-image
|
||||||
|
|
||||||
release-packages: generate-webui build
|
|
||||||
rm -rf dist
|
rm -rf dist
|
||||||
$(DOCKER_RUN_TRAEFIK_NOTTY) goreleaser release --skip-publish
|
$(DOCKER_RUN_TRAEFIK_NOTTY) goreleaser release --skip-publish
|
||||||
$(DOCKER_RUN_TRAEFIK_NOTTY) tar cfz dist/traefik-${VERSION}.src.tar.gz \
|
$(DOCKER_RUN_TRAEFIK_NOTTY) tar cfz dist/traefik-${VERSION}.src.tar.gz \
|
||||||
|
@ -138,3 +143,12 @@ release-packages: generate-webui build
|
||||||
--exclude .github \
|
--exclude .github \
|
||||||
--exclude dist .
|
--exclude dist .
|
||||||
$(DOCKER_RUN_TRAEFIK_NOTTY) chown -R $(shell id -u):$(shell id -g) dist/
|
$(DOCKER_RUN_TRAEFIK_NOTTY) chown -R $(shell id -u):$(shell id -g) dist/
|
||||||
|
|
||||||
|
## Format the Code
|
||||||
|
fmt:
|
||||||
|
gofmt -s -l -w $(SRCS)
|
||||||
|
|
||||||
|
run-dev:
|
||||||
|
go generate
|
||||||
|
go build ./cmd/traefik
|
||||||
|
./traefik
|
||||||
|
|
|
@ -33,7 +33,7 @@ Pointing Traefik at your orchestrator should be the _only_ configuration step yo
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
:construction: As stated in the [1.7 release note](https://blog.containo.us/traefik-1-7-yet-another-slice-of-awesomeness-2a9c99737889#782d), a significant update is in progress on the [master](https://github.com/containous/traefik/tree/master) branch. This branch will remain in constant evolution and prone to change with little notice, so use it for test purposes only.
|
:warning: Please be aware that the old configurations for Traefik v1.X are NOT compatible with the v2.X config as of now. If you're testing out v2, please ensure you are using a [v2 configuration](https://docs.traefik.io/v2.0/).
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
|
@ -86,10 +86,6 @@ _(But if you'd rather configure some of your routes manually, Traefik supports t
|
||||||
|
|
||||||
To get your hands on Traefik, you can use the [5-Minute Quickstart](http://docs.traefik.io/#the-traefik-quickstart-using-docker) in our documentation (you will need Docker).
|
To get your hands on Traefik, you can use the [5-Minute Quickstart](http://docs.traefik.io/#the-traefik-quickstart-using-docker) in our documentation (you will need Docker).
|
||||||
|
|
||||||
Alternatively, if you don't want to install anything on your computer, you can try Traefik online in this great [Katacoda tutorial](https://www.katacoda.com/courses/traefik/deploy-load-balancer) that shows how to load balance requests between multiple Docker containers.
|
|
||||||
|
|
||||||
If you are looking for a more comprehensive and real use-case example, you can also check [Play-With-Docker](http://training.play-with-docker.com/traefik-load-balancing/) to see how to load balance between multiple nodes.
|
|
||||||
|
|
||||||
## Web UI
|
## Web UI
|
||||||
|
|
||||||
You can access the simple HTML frontend of Traefik.
|
You can access the simple HTML frontend of Traefik.
|
||||||
|
@ -144,7 +140,7 @@ You will learn fundamental Traefik features and see some demos with Kubernetes.
|
||||||
|
|
||||||
## Maintainers
|
## Maintainers
|
||||||
|
|
||||||
[Information about process and maintainers](MAINTAINER.md)
|
[Information about process and maintainers](docs/content/contributing/maintainers.md)
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|
|
@ -171,7 +171,6 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
|
||||||
|
|
||||||
// default Kubernetes
|
// default Kubernetes
|
||||||
var defaultKubernetes ingress.Provider
|
var defaultKubernetes ingress.Provider
|
||||||
defaultKubernetes.Watch = true
|
|
||||||
|
|
||||||
defaultProviders := static.Providers{
|
defaultProviders := static.Providers{
|
||||||
File: &defaultFile,
|
File: &defaultFile,
|
||||||
|
|
|
@ -43,6 +43,19 @@ $ ls dist/
|
||||||
traefik*
|
traefik*
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The following targets can be executed outside Docker (we don't recommend that):
|
||||||
|
|
||||||
|
- `test-unit`
|
||||||
|
- `test-integration`
|
||||||
|
- `validate`
|
||||||
|
- `binary` (the webUI is still generated by using Docker)
|
||||||
|
|
||||||
|
ex:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PRE_TARGET= make test-unit
|
||||||
|
```
|
||||||
|
|
||||||
### Method 2: Using `go`
|
### Method 2: Using `go`
|
||||||
|
|
||||||
You need `go` v1.9+.
|
You need `go` v1.9+.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Configuration Overview
|
# Configuration Introduction
|
||||||
|
|
||||||
How the Magic Happens
|
How the Magic Happens
|
||||||
{: .subtitle }
|
{: .subtitle }
|
||||||
|
@ -15,6 +15,10 @@ Elements in the _static configuration_ set up connections to [providers](../../p
|
||||||
The _dynamic configuration_ contains everything that defines how the requests are handled by your system.
|
The _dynamic configuration_ contains everything that defines how the requests are handled by your system.
|
||||||
This configuration can change and is seamlessly hot-reloaded, without any request interuption or connection loss.
|
This configuration can change and is seamlessly hot-reloaded, without any request interuption or connection loss.
|
||||||
|
|
||||||
|
!!! warning "Incompatible Configuration"
|
||||||
|
Please be aware that the old configurations for Traefik v1.X are NOT compatible with the v2.X config as of now.
|
||||||
|
If you're testing out v2, please ensure you are using a v2 configuration.
|
||||||
|
|
||||||
## The Dynamic Configuration
|
## The Dynamic Configuration
|
||||||
|
|
||||||
Traefik gets its _dynamic configuration_ from [providers](../providers/overview.md): wether an orchestrator, a service registry, or a plain old configuration file. Since this configuration is specific to your infrastructure choices, we invite you to refer to the [dedicated section of this documentation](../providers/overview.md).
|
Traefik gets its _dynamic configuration_ from [providers](../providers/overview.md): wether an orchestrator, a service registry, or a plain old configuration file. Since this configuration is specific to your infrastructure choices, we invite you to refer to the [dedicated section of this documentation](../providers/overview.md).
|
||||||
|
|
|
@ -5,9 +5,6 @@ A Simple Use Case Using Docker
|
||||||
|
|
||||||
![quickstart-diagram](../assets/img/quickstart-diagram.png)
|
![quickstart-diagram](../assets/img/quickstart-diagram.png)
|
||||||
|
|
||||||
!!! tip
|
|
||||||
To save some time, you can clone [Traefik's repository](https://github.com/containous/traefik).
|
|
||||||
|
|
||||||
## Launch Traefik With the Docker Provider
|
## Launch Traefik With the Docker Provider
|
||||||
|
|
||||||
Create a `docker-compose.yml` file where you will define a `reverse-proxy` service that uses the official Traefik image:
|
Create a `docker-compose.yml` file where you will define a `reverse-proxy` service that uses the official Traefik image:
|
||||||
|
@ -17,8 +14,8 @@ version: '3'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
reverse-proxy:
|
reverse-proxy:
|
||||||
image: traefik # The official Traefik docker image
|
image: traefik:v2.0 # The official v2.0 Traefik docker image
|
||||||
command: --api --docker # Enables the web UI and tells Traefik to listen to docker
|
command: --api --providers.docker # Enables the web UI and tells Traefik to listen to docker
|
||||||
ports:
|
ports:
|
||||||
- "80:80" # The HTTP port
|
- "80:80" # The HTTP port
|
||||||
- "8080:8080" # The Web UI (enabled by --api)
|
- "8080:8080" # The Web UI (enabled by --api)
|
||||||
|
@ -34,7 +31,7 @@ Start your `reverse-proxy` with the following command:
|
||||||
docker-compose up -d reverse-proxy
|
docker-compose up -d reverse-proxy
|
||||||
```
|
```
|
||||||
|
|
||||||
You can open a browser and go to [http://localhost:8080](http://localhost:8080) to see Traefik's dashboard (we'll go back there once we have launched a service in step 2).
|
You can open a browser and go to [http://localhost:8080/api/rawdata](http://localhost:8080/api/rawdata) to see Traefik's API rawdata (we'll go back there once we have launched a service in step 2).
|
||||||
|
|
||||||
## Traefik Detects New Services and Creates the Route for You
|
## Traefik Detects New Services and Creates the Route for You
|
||||||
|
|
||||||
|
@ -47,7 +44,7 @@ Edit your `docker-compose.yml` file and add the following at the end of your fil
|
||||||
whoami:
|
whoami:
|
||||||
image: containous/whoami # A container that exposes an API to show its IP address
|
image: containous/whoami # A container that exposes an API to show its IP address
|
||||||
labels:
|
labels:
|
||||||
- "traefik.router.rule=Host:whoami.docker.localhost"
|
- "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
|
||||||
```
|
```
|
||||||
|
|
||||||
The above defines `whoami`: a simple web service that outputs information about the machine it is deployed on (its IP address, host, and so on).
|
The above defines `whoami`: a simple web service that outputs information about the machine it is deployed on (its IP address, host, and so on).
|
||||||
|
@ -58,7 +55,7 @@ Start the `whoami` service with the following command:
|
||||||
docker-compose up -d whoami
|
docker-compose up -d whoami
|
||||||
```
|
```
|
||||||
|
|
||||||
Go back to your browser ([http://localhost:8080](http://localhost:8080)) and see that Traefik has automatically detected the new container and updated its own configuration.
|
Go back to your browser ([http://localhost:8080/api/rawdata](http://localhost:8080/api/rawdata)) and see that Traefik has automatically detected the new container and updated its own configuration.
|
||||||
|
|
||||||
When Traefik detects new services, it creates the corresponding routes so you can call them ... _let's see!_ (Here, we're using curl)
|
When Traefik detects new services, it creates the corresponding routes so you can call them ... _let's see!_ (Here, we're using curl)
|
||||||
|
|
||||||
|
@ -82,7 +79,7 @@ Run more instances of your `whoami` service with the following command:
|
||||||
docker-compose up -d --scale whoami=2
|
docker-compose up -d --scale whoami=2
|
||||||
```
|
```
|
||||||
|
|
||||||
Go back to your browser ([http://localhost:8080](http://localhost:8080)) and see that Traefik has automatically detected the new instance of the container.
|
Go back to your browser ([http://localhost:8080/api/rawdata](http://localhost:8080/api/rawdata)) and see that Traefik has automatically detected the new instance of the container.
|
||||||
|
|
||||||
Finally, see that Traefik load-balances between the two instances of your services by running twice the following command:
|
Finally, see that Traefik load-balances between the two instances of your services by running twice the following command:
|
||||||
|
|
||||||
|
|
|
@ -137,15 +137,15 @@ Do not hesitate to complete it.
|
||||||
| [Gandi v5](http://doc.livedns.gandi.net) | `gandiv5` | `GANDIV5_API_KEY` | YES |
|
| [Gandi v5](http://doc.livedns.gandi.net) | `gandiv5` | `GANDIV5_API_KEY` | YES |
|
||||||
| [Glesys](https://glesys.com/) | `glesys` | `GLESYS_API_USER`, `GLESYS_API_KEY`, `GLESYS_DOMAIN` | Not tested yet |
|
| [Glesys](https://glesys.com/) | `glesys` | `GLESYS_API_USER`, `GLESYS_API_KEY`, `GLESYS_DOMAIN` | Not tested yet |
|
||||||
| [GoDaddy](https://godaddy.com/domains) | `godaddy` | `GODADDY_API_KEY`, `GODADDY_API_SECRET` | Not tested yet |
|
| [GoDaddy](https://godaddy.com/domains) | `godaddy` | `GODADDY_API_KEY`, `GODADDY_API_SECRET` | Not tested yet |
|
||||||
| [Google Cloud DNS](https://cloud.google.com/dns/docs/) | `gcloud` | `GCE_PROJECT`, Application Default Credentials [^2] [^3], [`GCE_SERVICE_ACCOUNT_FILE`] | YES |
|
| [Google Cloud DNS](https://cloud.google.com/dns/docs/) | `gcloud` | `GCE_PROJECT`, Application Default Credentials [^2] [^3], [`GCE_SERVICE_ACCOUNT_FILE`] | YES |
|
||||||
| [hosting.de](https://www.hosting.de) | `hostingde` | `HOSTINGDE_API_KEY`, `HOSTINGDE_ZONE_NAME` | Not tested yet |
|
| [hosting.de](https://www.hosting.de) | `hostingde` | `HOSTINGDE_API_KEY`, `HOSTINGDE_ZONE_NAME` | Not tested yet |
|
||||||
| HTTP request | `httpreq` | `HTTPREQ_ENDPOINT`, `HTTPREQ_MODE`, `HTTPREQ_USERNAME`, `HTTPREQ_PASSWORD` [^1] | YES |
|
| HTTP request | `httpreq` | `HTTPREQ_ENDPOINT`, `HTTPREQ_MODE`, `HTTPREQ_USERNAME`, `HTTPREQ_PASSWORD` [^1] | YES |
|
||||||
| [IIJ](https://www.iij.ad.jp/) | `iij` | `IIJ_API_ACCESS_KEY`, `IIJ_API_SECRET_KEY`, `IIJ_DO_SERVICE_CODE` | Not tested yet |
|
| [IIJ](https://www.iij.ad.jp/) | `iij` | `IIJ_API_ACCESS_KEY`, `IIJ_API_SECRET_KEY`, `IIJ_DO_SERVICE_CODE` | Not tested yet |
|
||||||
| [INWX](https://www.inwx.de/en) | `inwx` | `INWX_USERNAME`, `INWX_PASSWORD` | YES |
|
| [INWX](https://www.inwx.de/en) | `inwx` | `INWX_USERNAME`, `INWX_PASSWORD` | YES |
|
||||||
| [Lightsail](https://aws.amazon.com/lightsail/) | `lightsail` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `DNS_ZONE` | Not tested yet |
|
| [Lightsail](https://aws.amazon.com/lightsail/) | `lightsail` | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `DNS_ZONE` | Not tested yet |
|
||||||
| [Linode](https://www.linode.com) | `linode` | `LINODE_API_KEY` | Not tested yet |
|
| [Linode](https://www.linode.com) | `linode` | `LINODE_API_KEY` | Not tested yet |
|
||||||
| [Linode v4](https://www.linode.com) | `linodev4` | `LINODE_TOKEN` | Not tested yet |
|
| [Linode v4](https://www.linode.com) | `linodev4` | `LINODE_TOKEN` | Not tested yet |
|
||||||
| manual | - | none, but you need to run Traefik interactively, turn on `acmeLogging` to see instructions and press <kbd>Enter</kbd>. | YES |
|
| manual | - | none, but you need to run Traefik interactively [^4], turn on `acmeLogging` to see instructions and press <kbd>Enter</kbd>. | YES |
|
||||||
| [MyDNS.jp](https://www.mydns.jp/) | `mydnsjp` | `MYDNSJP_MASTER_ID`, `MYDNSJP_PASSWORD` | YES |
|
| [MyDNS.jp](https://www.mydns.jp/) | `mydnsjp` | `MYDNSJP_MASTER_ID`, `MYDNSJP_PASSWORD` | YES |
|
||||||
| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` | YES |
|
| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` | YES |
|
||||||
| [name.com](https://www.name.com/) | `namedotcom` | `NAMECOM_USERNAME`, `NAMECOM_API_TOKEN`, `NAMECOM_SERVER` | Not tested yet |
|
| [name.com](https://www.name.com/) | `namedotcom` | `NAMECOM_USERNAME`, `NAMECOM_API_TOKEN`, `NAMECOM_SERVER` | Not tested yet |
|
||||||
|
@ -172,6 +172,7 @@ Do not hesitate to complete it.
|
||||||
[^1]: more information about the HTTP message format can be found [here](https://go-acme.github.io/lego/dns/httpreq/)
|
[^1]: more information about the HTTP message format can be found [here](https://go-acme.github.io/lego/dns/httpreq/)
|
||||||
[^2]: [providing_credentials_to_your_application](https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application)
|
[^2]: [providing_credentials_to_your_application](https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application)
|
||||||
[^3]: [google/default.go](https://github.com/golang/oauth2/blob/36a7019397c4c86cf59eeab3bc0d188bac444277/google/default.go#L61-L76)
|
[^3]: [google/default.go](https://github.com/golang/oauth2/blob/36a7019397c4c86cf59eeab3bc0d188bac444277/google/default.go#L61-L76)
|
||||||
|
[^4]: `docker stack` remark: there is no way to support terminal attached to container when deploying with `docker stack`, so you might need to run container with `docker run -it` to generate certificates using `manual` provider.
|
||||||
|
|
||||||
!!! note "`delayBeforeCheck`"
|
!!! note "`delayBeforeCheck`"
|
||||||
By default, the `provider` verifies the TXT record _before_ letting ACME verify.
|
By default, the `provider` verifies the TXT record _before_ letting ACME verify.
|
||||||
|
|
|
@ -19,7 +19,7 @@ TLS is enabled at the [router](../routing/routers/index.md) level, but some opti
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[tlsOptions]
|
[tlsOptions]
|
||||||
[tlsOptions.default]
|
[tlsOptions.default]
|
||||||
minVersion = "VersionTLS12"
|
minVersion = "VersionTLS12"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -9,22 +9,28 @@ The AddPrefix middleware updates the URL Path of the request before forwarding i
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "File -- Prefixing with /foo"
|
```yaml tab="Docker"
|
||||||
|
# Prefixing with /foo
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.add-bar.addprefix.prefix=/foo"
|
||||||
|
```
|
||||||
|
|
||||||
```toml
|
```yaml tab="Kubernetes"
|
||||||
[http.middlewares]
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
[http.middlewares.add-foo.AddPrefix]
|
kind: Middleware
|
||||||
prefix = "/foo"
|
metadata:
|
||||||
```
|
name: addprefix
|
||||||
|
spec:
|
||||||
|
addprefix:
|
||||||
|
prefix: /bar
|
||||||
|
```
|
||||||
|
|
||||||
??? example "Docker -- Prefixing with /bar"
|
```toml tab="File"
|
||||||
|
# Prefixing with /foo
|
||||||
```yaml
|
[http.middlewares]
|
||||||
a-container:
|
[http.middlewares.add-foo.AddPrefix]
|
||||||
image: a-container-image
|
prefix = "/foo"
|
||||||
labels:
|
```
|
||||||
- "traefik.http.middlewares.add-bar.addprefix.prefix=/bar"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
||||||
|
|
|
@ -9,23 +9,19 @@ The BasicAuth middleware is a quick way to restrict access to your services to k
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "File -- Declaring the user list"
|
```yaml tab="Docker"
|
||||||
|
# Declaring the user list
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.declared-users-only.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||||
|
```
|
||||||
|
|
||||||
```toml
|
```toml tab="File"
|
||||||
[http.middlewares]
|
# Declaring the user list
|
||||||
[http.middlewares.test-auth.basicauth]
|
[http.middlewares]
|
||||||
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
[http.middlewares.test-auth.basicauth]
|
||||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
|
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||||
```
|
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
|
||||||
|
```
|
||||||
??? example "Docker -- Using an external file for the authorized users"
|
|
||||||
|
|
||||||
```yml
|
|
||||||
a-container:
|
|
||||||
image: a-container-image
|
|
||||||
labels:
|
|
||||||
- "traefik.http.middlewares.declared-users-only.basicauth.usersFile=path-to-file.ext",
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
||||||
|
|
|
@ -13,22 +13,18 @@ This can help services deal with large data (multipart/form-data for example), a
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "File -- Sets the maximum request body to 2Mb"
|
```yaml tab="Docker"
|
||||||
|
# Sets the maximum request body to 2Mb
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.2Mb-memory.buffering.maxRequestBodyBytes=250000",
|
||||||
|
```
|
||||||
|
|
||||||
```toml
|
```toml tab="File"
|
||||||
[http.middlewares]
|
# Sets the maximum request body to 2Mb
|
||||||
[http.middlewares.2Mb-limit.buffering]
|
[http.middlewares]
|
||||||
maxRequestBodyBytes = 250000
|
[http.middlewares.2Mb-limit.buffering]
|
||||||
```
|
maxRequestBodyBytes = 250000
|
||||||
|
```
|
||||||
??? example "Docker -- Buffers 1Mb of the request in memory, then writes to disk"
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
a-container:
|
|
||||||
image: a-container-image
|
|
||||||
labels:
|
|
||||||
- "traefik.http.middlewares.1Mb-memory.buffering.memRequestBodyBytes=125000",
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
||||||
|
|
|
@ -23,23 +23,18 @@ To assess if your system is healthy, the circuit breaker constantly monitors the
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "Latency Check -- Using Toml"
|
```yaml tab="Docker"
|
||||||
|
# Latency Check
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.latency-check.circuitbreaker.expression=LatencyAtQuantileMS(50.0) > 100"
|
||||||
|
```
|
||||||
|
|
||||||
```toml
|
```toml tab="File"
|
||||||
[http.middlewares]
|
# Latency Check
|
||||||
[http.middlewares.latency-check.circuitbreaker]
|
[http.middlewares]
|
||||||
expression = "LatencyAtQuantileMS(50.0) > 100"
|
[http.middlewares.latency-check.circuitbreaker]
|
||||||
```
|
expression = "LatencyAtQuantileMS(50.0) > 100"
|
||||||
|
```
|
||||||
??? example "Latency Check -- Using Docker Labels"
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# in a docker compose file
|
|
||||||
container-definition:
|
|
||||||
image: image-name
|
|
||||||
labels:
|
|
||||||
- "traefik.http.middlewares.latency-check.circuitbreaker.expression=LatencyAtQuantileMS(50.0) > 100"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Possible States
|
## Possible States
|
||||||
|
|
||||||
|
|
|
@ -9,21 +9,17 @@ The Compress middleware enables the gzip compression.
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "File -- enable gzip compression"
|
```yaml tab="Docker"
|
||||||
|
# Enable gzip compression
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.test-compress.compress=true",
|
||||||
|
```
|
||||||
|
|
||||||
```toml
|
```toml tab="File"
|
||||||
[http.middlewares]
|
# Enable gzip compression
|
||||||
[http.middlewares.test-compress.Compress]
|
[http.middlewares]
|
||||||
```
|
[http.middlewares.test-compress.Compress]
|
||||||
|
```
|
||||||
??? example "Docker -- enable gzip compression"
|
|
||||||
|
|
||||||
```yml
|
|
||||||
a-container:
|
|
||||||
image: a-container-image
|
|
||||||
labels:
|
|
||||||
- "traefik.http.middlewares.test-compress.compress=true",
|
|
||||||
```
|
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
|
|
|
@ -9,22 +9,17 @@ The DigestAuth middleware is a quick way to restrict access to your services to
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "File -- Declaring the user list"
|
```yaml tab="Docker"
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.declared-users-only.digestauth.usersFile=path-to-file.ext",
|
||||||
|
```
|
||||||
|
|
||||||
```toml
|
```toml tab="File"
|
||||||
[http.middlewares]
|
[http.middlewares]
|
||||||
[http.middlewares.test-auth.digestauth]
|
[http.middlewares.test-auth.digestauth]
|
||||||
users = ["test:traefik:a2688e031edb4be6a3797f3882655c05", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]
|
users = ["test:traefik:a2688e031edb4be6a3797f3882655c05",
|
||||||
```
|
"test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]
|
||||||
|
```
|
||||||
??? example "Docker -- Using an external file for the authorized users"
|
|
||||||
|
|
||||||
```yml
|
|
||||||
a-container:
|
|
||||||
image: a-container-image
|
|
||||||
labels:
|
|
||||||
- "traefik.http.middlewares.declared-users-only.digestauth.usersFile=path-to-file.ext",
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! tip
|
!!! tip
|
||||||
|
|
||||||
|
|
|
@ -12,38 +12,33 @@ The ErrorPage middleware returns a custom page in lieu of the default, according
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "File -- Custom Error Page for 5XX"
|
```yaml tab="Docker"
|
||||||
|
# Dynamic Custom Error Page for 5XX Status Code
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.test-errorpage.errors.status=500-599",
|
||||||
|
- "traefik.http.middlewares.test-errorpage.errors.service=serviceError",
|
||||||
|
- "traefik.http.middlewares.test-errorpage.errors.query=/{status}.html",
|
||||||
|
```
|
||||||
|
|
||||||
```toml
|
```toml tab="File"
|
||||||
[http.routers]
|
# Custom Error Page for 5XX
|
||||||
[http.routers.router1]
|
[http.routers]
|
||||||
Service = "my-service"
|
[http.routers.router1]
|
||||||
Rule = Host(`my-domain`)
|
Service = "my-service"
|
||||||
|
Rule = Host(`my-domain`)
|
||||||
|
|
||||||
[http.middlewares]
|
[http.middlewares]
|
||||||
[http.middlewares.5XX-errors.Errors]
|
[http.middlewares.5XX-errors.Errors]
|
||||||
status = ["500-599"]
|
status = ["500-599"]
|
||||||
service = "error-handler-service"
|
service = "error-handler-service"
|
||||||
query = "/error.html"
|
query = "/error.html"
|
||||||
|
|
||||||
[http.services]
|
[http.services]
|
||||||
# ... definition of error-handler-service and my-service
|
# ... definition of error-handler-service and my-service
|
||||||
```
|
```
|
||||||
|
|
||||||
??? example "Docker -- Dynamic Custom Error Page for 5XX Status Code"
|
!!! note
|
||||||
|
In this example, the error page URL is based on the status code (`query=/{status}.html)`.
|
||||||
```yaml
|
|
||||||
a-container:
|
|
||||||
image: a-container-image
|
|
||||||
labels:
|
|
||||||
- "traefik.http.middlewares.test-errorpage.errors.status=500-599",
|
|
||||||
- "traefik.http.middlewares.test-errorpage.errors.service=serviceError",
|
|
||||||
- "traefik.http.middlewares.test-errorpage.errors.query=/{status}.html",
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! note
|
|
||||||
In this example, the error page URL is based on the status code (`query=/{status}.html)`.
|
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# ForwardAuth
|
# ForwardAuth
|
||||||
|
|
||||||
Using an External Service to Ccheck for Credentials
|
Using an External Service to Check for Credentials
|
||||||
{: .subtitle }
|
{: .subtitle }
|
||||||
|
|
||||||
![AuthForward](../assets/img/middleware/authforward.png)
|
![AuthForward](../assets/img/middleware/authforward.png)
|
||||||
|
@ -11,38 +11,33 @@ Otherwise, the response from the authentication server is returned.
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "File -- Forward authentication to authserver.com"
|
```toml tab="File"
|
||||||
|
# Forward authentication to authserver.com
|
||||||
|
[http.middlewares]
|
||||||
|
[http.middlewares.test-auth.forwardauth]
|
||||||
|
address = "https://authserver.com/auth"
|
||||||
|
trustForwardHeader = true
|
||||||
|
authResponseHeaders = ["X-Auth-User", "X-Secret"]
|
||||||
|
|
||||||
```toml
|
[http.middlewares.test-auth.forwardauth.tls]
|
||||||
[http.middlewares]
|
ca = "path/to/local.crt"
|
||||||
[http.middlewares.test-auth.forwardauth]
|
caOptional = true
|
||||||
address = "https://authserver.com/auth"
|
cert = "path/to/foo.cert"
|
||||||
trustForwardHeader = true
|
key = "path/to/foo.key"
|
||||||
authResponseHeaders = ["X-Auth-User", "X-Secret"]
|
```
|
||||||
|
|
||||||
[http.middlewares.test-auth.forwardauth.tls]
|
```yaml tab="Docker"
|
||||||
ca = "path/to/local.crt"
|
# Forward authentication to authserver.com
|
||||||
caOptional = true
|
labels:
|
||||||
cert = "path/to/foo.cert"
|
- "traefik.http.middlewares.test-auth.ForwardAuth.Address=https://authserver.com/auth"
|
||||||
key = "path/to/foo.key"
|
- "traefik.http.middlewares.test-auth.ForwardAuth.AuthResponseHeaders=X-Auth-User, X-Secret"
|
||||||
```
|
- "traefik.http.middlewares.test-auth.ForwardAuth.TLS.CA=path/to/local.crt"
|
||||||
|
- "traefik.http.middlewares.test-auth.ForwardAuth.TLS.CAOptional=true"
|
||||||
??? example "Docker -- Forward authentication to authserver.com"
|
- "traefik.http.middlewares.test-auth.ForwardAuth.TLS.Cert=path/to/foo.cert"
|
||||||
|
- "traefik.http.middlewares.test-auth.ForwardAuth.TLS.InsecureSkipVerify=true"
|
||||||
```yml
|
- "traefik.http.middlewares.test-auth.ForwardAuth.TLS.Key=path/to/foo.key"
|
||||||
a-container:
|
- "traefik.http.middlewares.test-auth.ForwardAuth.TrustForwardHeader=true"
|
||||||
image: a-container-image
|
```
|
||||||
labels:
|
|
||||||
- "traefik.http.middlewares.test-auth.ForwardAuth.Address=https://authserver.com/auth"
|
|
||||||
- "traefik.http.middlewares.test-auth.ForwardAuth.AuthResponseHeaders=X-Auth-User, X-Secret"
|
|
||||||
- "traefik.http.middlewares.test-auth.ForwardAuth.TLS.CA=path/to/local.crt"
|
|
||||||
- "traefik.http.middlewares.test-auth.ForwardAuth.TLS.CAOptional=true"
|
|
||||||
- "traefik.http.middlewares.test-auth.ForwardAuth.TLS.Cert=path/to/foo.cert"
|
|
||||||
- "traefik.http.middlewares.test-auth.ForwardAuth.TLS.InsecureSkipVerify=true"
|
|
||||||
- "traefik.http.middlewares.test-auth.ForwardAuth.TLS.Key=path/to/foo.key"
|
|
||||||
- "traefik.http.middlewares.test-auth.ForwardAuth.TrustForwardHeader=true"
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
||||||
|
|
|
@ -13,26 +13,22 @@ The Headers middleware can manage the requests/responses headers.
|
||||||
|
|
||||||
Add the `X-Script-Name` header to the proxied request and the `X-Custom-Response-Header` to the response
|
Add the `X-Script-Name` header to the proxied request and the `X-Custom-Response-Header` to the response
|
||||||
|
|
||||||
??? example "File"
|
```yaml tab="Docker"
|
||||||
|
a-container:
|
||||||
|
image: a-container-image
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.testHeader.Headers.CustomRequestHeaders.X-Script-Name=test",
|
||||||
|
- "traefik.http.middlewares.testHeader.Headers.CustomResponseHeaders.X-Custom-Response-Header=True",
|
||||||
|
```
|
||||||
|
|
||||||
```toml
|
```toml tab="File"
|
||||||
[http.middlewares]
|
[http.middlewares]
|
||||||
[http.middlewares.testHeader.headers]
|
[http.middlewares.testHeader.headers]
|
||||||
[http.middlewares.testHeader.headers.CustomRequestHeaders]
|
[http.middlewares.testHeader.headers.CustomRequestHeaders]
|
||||||
X-Script-Name = "test"
|
X-Script-Name = "test"
|
||||||
[http.middlewares.testHeader.headers.CustomResponseHeaders]
|
[http.middlewares.testHeader.headers.CustomResponseHeaders]
|
||||||
X-Custom-Response-Header = "True"
|
X-Custom-Response-Header = "True"
|
||||||
```
|
```
|
||||||
|
|
||||||
??? example "Docker"
|
|
||||||
|
|
||||||
```yml
|
|
||||||
a-container:
|
|
||||||
image: a-container-image
|
|
||||||
labels:
|
|
||||||
- "traefik.http.middlewares.testHeader.Headers.CustomRequestHeaders.X-Script-Name=test",
|
|
||||||
- "traefik.http.middlewares.testHeader.Headers.CustomResponseHeaders.X-Custom-Response-Header=True",
|
|
||||||
```
|
|
||||||
|
|
||||||
### Adding and Removing Headers
|
### Adding and Removing Headers
|
||||||
|
|
||||||
|
|
|
@ -9,22 +9,18 @@ IPWhitelist accepts / refuses requests based on the client IP.
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "File -- Accepts request from defined IP"
|
```yaml tab="Docker"
|
||||||
|
# Accepts request from defined IP
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.Middleware9.IPWhiteList.SourceRange=127.0.0.1/32, 192.168.1.7"
|
||||||
|
```
|
||||||
|
|
||||||
```toml
|
```toml tab="File"
|
||||||
[http.middlewares]
|
# Accepts request from defined IP
|
||||||
[http.middlewares.test-ipwhitelist.ipWhiteList]
|
[http.middlewares]
|
||||||
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
|
[http.middlewares.test-ipwhitelist.ipWhiteList]
|
||||||
```
|
sourceRange = ["127.0.0.1/32", "192.168.1.7"]
|
||||||
|
```
|
||||||
??? example "Docker -- Accepts request from defined IP"
|
|
||||||
|
|
||||||
```yml
|
|
||||||
a-container:
|
|
||||||
image: a-container-image
|
|
||||||
labels:
|
|
||||||
- "traefik.http.middlewares.Middleware9.IPWhiteList.SourceRange=127.0.0.1/32, 192.168.1.7"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
||||||
|
|
|
@ -9,22 +9,18 @@ To proactively prevent services from being overwhelmed with high load, a maximum
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "File -- Limiting to 10 simultaneous connections"
|
```yaml tab="Docker"
|
||||||
|
# Limiting to 10 simultaneous connections
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.test-maxconn.maxconn.amount=10"
|
||||||
|
```
|
||||||
|
|
||||||
```toml
|
```toml tab="File"
|
||||||
[http.middlewares]
|
# Limiting to 10 simultaneous connections
|
||||||
[http.middlewares.test-maxconn.maxconn]
|
[http.middlewares]
|
||||||
amount = 10
|
[http.middlewares.test-maxconn.maxconn]
|
||||||
```
|
amount = 10
|
||||||
|
```
|
||||||
??? example "Docker -- Limiting to 10 simultaneous connections"
|
|
||||||
|
|
||||||
```yml
|
|
||||||
a-container:
|
|
||||||
image: a-container-image
|
|
||||||
labels:
|
|
||||||
- "traefik.http.middlewares.test-maxconn.maxconn.amount=10"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
||||||
|
|
|
@ -13,40 +13,75 @@ Pieces of middleware can be combined in chains to fit every scenario.
|
||||||
|
|
||||||
## Configuration Example
|
## Configuration Example
|
||||||
|
|
||||||
??? example "As Toml Configuration File"
|
```yaml tab="Docker"
|
||||||
|
# As a Docker Label
|
||||||
|
whoami:
|
||||||
|
image: containous/whoami # A container that exposes an API to show its IP address
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.foo-add-prefix.addprefix.prefix=/foo",
|
||||||
|
```
|
||||||
|
|
||||||
```toml
|
```yaml tab="Kubernetes"
|
||||||
[providers]
|
# As a Kubernetes Traefik IngressRoute
|
||||||
[providers.file]
|
apiVersion: apiextensions.k8s.io/v1beta1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: middlewares.traefik.containo.us
|
||||||
|
spec:
|
||||||
|
group: traefik.containo.us
|
||||||
|
version: v1alpha1
|
||||||
|
names:
|
||||||
|
kind: Middleware
|
||||||
|
plural: middlewares
|
||||||
|
singular: middleware
|
||||||
|
scope: Namespaced
|
||||||
|
|
||||||
[http.routers]
|
---
|
||||||
[http.routers.router1]
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
Service = "myService"
|
kind: Middleware
|
||||||
Middlewares = ["foo-add-prefix"]
|
metadata:
|
||||||
Rule = "Host: example.com"
|
name: stripprefix
|
||||||
|
spec:
|
||||||
|
stripprefix:
|
||||||
|
prefixes:
|
||||||
|
- /stripit
|
||||||
|
|
||||||
[http.middlewares]
|
---
|
||||||
[http.middlewares.foo-add-prefix.AddPrefix]
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
prefix = "/foo"
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: ingressroute.crd
|
||||||
|
spec:
|
||||||
|
# more fields...
|
||||||
|
routes:
|
||||||
|
# more fields...
|
||||||
|
middleware:
|
||||||
|
- name: stripprefix
|
||||||
|
```
|
||||||
|
|
||||||
[http.services]
|
```toml tab="File"
|
||||||
[http.services.service1]
|
# As Toml Configuration File
|
||||||
[http.services.service1.LoadBalancer]
|
[providers]
|
||||||
|
[providers.file]
|
||||||
|
|
||||||
[[http.services.service1.LoadBalancer.Servers]]
|
[http.routers]
|
||||||
URL = "http://127.0.0.1:80"
|
[http.routers.router1]
|
||||||
Weight = 1
|
Service = "myService"
|
||||||
```
|
Middlewares = ["foo-add-prefix"]
|
||||||
|
Rule = "Host(`example.com`)"
|
||||||
|
|
||||||
??? example "As a Docker Label"
|
[http.middlewares]
|
||||||
|
[http.middlewares.foo-add-prefix.AddPrefix]
|
||||||
|
prefix = "/foo"
|
||||||
|
|
||||||
```yaml
|
[http.services]
|
||||||
# A container that exposes a simple API
|
[http.services.service1]
|
||||||
whoami:
|
[http.services.service1.LoadBalancer]
|
||||||
image: containous/whoami # A container that exposes an API to show its IP address
|
|
||||||
labels:
|
[[http.services.service1.LoadBalancer.Servers]]
|
||||||
- "traefik.http.middlewares.foo-add-prefix.addprefix.prefix=/foo",
|
URL = "http://127.0.0.1:80"
|
||||||
```
|
Weight = 1
|
||||||
|
```
|
||||||
|
|
||||||
## Advanced Configuration
|
## Advanced Configuration
|
||||||
|
|
||||||
|
|
|
@ -9,26 +9,47 @@ PassTLSClientCert adds in header the selected data from the passed client tls ce
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "File -- Pass the escaped pem in the `X-Forwarded-Tls-Client-Cert` header"
|
Pass the escaped pem in the `X-Forwarded-Tls-Client-Cert` header.
|
||||||
|
|
||||||
```toml
|
```yaml tab="Docker"
|
||||||
[http.middlewares]
|
# Pass the escaped pem in the `X-Forwarded-Tls-Client-Cert` header.
|
||||||
[http.middlewares.test-passtlsclientcert.passtlsclientcert]
|
labels:
|
||||||
pem = true
|
- "traefik.http.middlewares.Middleware11.passtlsclientcert.pem=true"
|
||||||
|
```
|
||||||
|
|
||||||
|
```toml tab="File"
|
||||||
|
# Pass the escaped pem in the `X-Forwarded-Tls-Client-Cert` header.
|
||||||
|
[http.middlewares]
|
||||||
|
[http.middlewares.test-passtlsclientcert.passtlsclientcert]
|
||||||
|
pem = true
|
||||||
|
```
|
||||||
|
|
||||||
|
??? example "Pass the escaped pem in the `X-Forwarded-Tls-Client-Cert` header"
|
||||||
|
|
||||||
|
```yaml tab="Docker"
|
||||||
|
# Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header
|
||||||
|
labels:
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notafter=true"
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notbefore=true"
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.sans=true"
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.commonname=true"
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.country=true"
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.domaincomponent=true"
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.locality=true"
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organization=true"
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.province=true"
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.serialnumber=true"
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.commonname=true"
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.country=true"
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.domaincomponent=true"
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.locality=true"
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.organization=true"
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.province=true"
|
||||||
|
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.serialnumber=true"
|
||||||
```
|
```
|
||||||
|
|
||||||
??? example "Docker -- Pass the escaped pem in the `X-Forwarded-Tls-Client-Cert` header"
|
```toml tab="File"
|
||||||
|
# Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header
|
||||||
```yml
|
|
||||||
a-container:
|
|
||||||
image: a-container-image
|
|
||||||
labels:
|
|
||||||
- "traefik.http.middlewares.Middleware11.passtlsclientcert.pem=true"
|
|
||||||
```
|
|
||||||
|
|
||||||
??? example "File -- Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header"
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[http.middlewares]
|
[http.middlewares]
|
||||||
[http.middlewares.test-passtlsclientcert.passtlsclientcert]
|
[http.middlewares.test-passtlsclientcert.passtlsclientcert]
|
||||||
[http.middlewares.test-passtlsclientcert.passtlsclientcert.info]
|
[http.middlewares.test-passtlsclientcert.passtlsclientcert.info]
|
||||||
|
@ -53,31 +74,6 @@ PassTLSClientCert adds in header the selected data from the passed client tls ce
|
||||||
domainComponent = true
|
domainComponent = true
|
||||||
```
|
```
|
||||||
|
|
||||||
??? example "Docker -- Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header"
|
|
||||||
|
|
||||||
```yml
|
|
||||||
a-container:
|
|
||||||
image: a-container-image
|
|
||||||
labels:
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notafter=true"
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notbefore=true"
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.sans=true"
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.commonname=true"
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.country=true"
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.domaincomponent=true"
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.locality=true"
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organization=true"
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.province=true"
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.serialnumber=true"
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.commonname=true"
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.country=true"
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.domaincomponent=true"
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.locality=true"
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.organization=true"
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.province=true"
|
|
||||||
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.serialnumber=true"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
||||||
### General
|
### General
|
||||||
|
|
|
@ -13,31 +13,31 @@ The RateLimit middleware ensures that services will receive a _fair_ number of r
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[http.middlewares]
|
[http.middlewares]
|
||||||
[http.middlewares.fair-ratelimit.ratelimit]
|
[http.middlewares.fair-ratelimit.ratelimit]
|
||||||
extractorfunc = "client.ip"
|
extractorfunc = "client.ip"
|
||||||
|
|
||||||
[http.middlewares.fair-ratelimit.ratelimit.rateset1]
|
[http.middlewares.fair-ratelimit.ratelimit.rateset1]
|
||||||
period = "10s"
|
period = "10s"
|
||||||
average = 100
|
average = 100
|
||||||
burst = 200
|
burst = 200
|
||||||
```
|
```
|
||||||
|
|
||||||
??? example "Combine multiple limits"
|
??? example "Combine multiple limits"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[http.middlewares]
|
[http.middlewares]
|
||||||
[http.middlewares.fair-ratelimit.ratelimit]
|
[http.middlewares.fair-ratelimit.ratelimit]
|
||||||
extractorfunc = "client.ip"
|
extractorfunc = "client.ip"
|
||||||
|
|
||||||
[http.middlewares.fair-ratelimit.ratelimit.rateset1]
|
[http.middlewares.fair-ratelimit.ratelimit.rateset1]
|
||||||
period = "10s"
|
period = "10s"
|
||||||
average = 100
|
average = 100
|
||||||
burst = 200
|
burst = 200
|
||||||
|
|
||||||
[http.middlewares.fair-ratelimit.ratelimit.rateset2]
|
[http.middlewares.fair-ratelimit.ratelimit.rateset2]
|
||||||
period = "3s"
|
period = "3s"
|
||||||
average = 5
|
average = 5
|
||||||
burst = 10
|
burst = 10
|
||||||
```
|
```
|
||||||
|
|
||||||
Here, an average of 5 requests every 3 seconds is allowed and an average of 100 requests every 10 seconds. These can "burst" up to 10 and 200 in each period, respectively.
|
Here, an average of 5 requests every 3 seconds is allowed and an average of 100 requests every 10 seconds. These can "burst" up to 10 and 200 in each period, respectively.
|
||||||
|
|
|
@ -5,6 +5,10 @@ See What's Going On
|
||||||
|
|
||||||
The dashboard is the central place that shows you the current active routes handled by Traefik.
|
The dashboard is the central place that shows you the current active routes handled by Traefik.
|
||||||
|
|
||||||
|
!!! warning "Dashboard WIP"
|
||||||
|
Currently, the dashboard is in a Work In Progress State while being reconstructed for v2.
|
||||||
|
Therefore, the dashboard is currently not working.
|
||||||
|
|
||||||
<figure>
|
<figure>
|
||||||
<img src="../../assets/img/dashboard-main.png" alt="Dashboard - Providers" />
|
<img src="../../assets/img/dashboard-main.png" alt="Dashboard - Providers" />
|
||||||
<figcaption>The dashboard in action with Traefik listening to 3 different providers</figcaption>
|
<figcaption>The dashboard in action with Traefik listening to 3 different providers</figcaption>
|
||||||
|
@ -27,10 +31,10 @@ To enable the dashboard, you need to enable Traefik's API.
|
||||||
|
|
||||||
??? example "Using the Command Line"
|
??? example "Using the Command Line"
|
||||||
|
|
||||||
Option | Values | Default Value
|
| Option | Values | Default Value |
|
||||||
-- | -- | --:
|
| --------------- | --------------- | --------------------: |
|
||||||
--api | \[true\|false\] | false
|
| --api | \[true\|false\] | false |
|
||||||
--api.dashboard | \[true\|false\] | true when api is true
|
| --api.dashboard | \[true\|false\] | true when api is true |
|
||||||
|
|
||||||
{!more-on-command-line.md!}
|
{!more-on-command-line.md!}
|
||||||
|
|
||||||
|
@ -50,10 +54,10 @@ To enable the dashboard, you need to enable Traefik's API.
|
||||||
|
|
||||||
??? example "Using a Key/Value Store"
|
??? example "Using a Key/Value Store"
|
||||||
|
|
||||||
Key | Values | Default Value
|
| Key | Values | Default Value |
|
||||||
-- | -- | --:
|
| ------------- | --------------- | --------------------: |
|
||||||
api | \[true\|false\] | false
|
| api | \[true\|false\] | false |
|
||||||
api.dashboard | \[true\|false\] | true when api is true
|
| api.dashboard | \[true\|false\] | true when api is true |
|
||||||
|
|
||||||
{!more-on-key-value-store.md!}
|
{!more-on-key-value-store.md!}
|
||||||
|
|
||||||
|
|
|
@ -5,30 +5,10 @@ Checking the Health of Your Traefik Instances
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "Enabling /ping on the http EntryPoint"
|
??? example "Enabling /ping"
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[entrypoints]
|
|
||||||
[entrypoints.web]
|
|
||||||
address = ":80"
|
|
||||||
|
|
||||||
[ping]
|
[ping]
|
||||||
entryPoint = "http"
|
|
||||||
```
|
|
||||||
|
|
||||||
??? example "Enabling /ping on the https EntryPoint"
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[entrypoints]
|
|
||||||
[entrypoints.web]
|
|
||||||
address = ":80"
|
|
||||||
|
|
||||||
[entrypoints.web-secure]
|
|
||||||
address = ":443"
|
|
||||||
[entrypoints.web-secure.tls]
|
|
||||||
|
|
||||||
[ping]
|
|
||||||
entryPoint = "https"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
??? example "Enabling /ping on a dedicated EntryPoint"
|
??? example "Enabling /ping on a dedicated EntryPoint"
|
||||||
|
@ -45,8 +25,8 @@ Checking the Health of Your Traefik Instances
|
||||||
entryPoint = "ping"
|
entryPoint = "ping"
|
||||||
```
|
```
|
||||||
|
|
||||||
| Path | Method | Description |
|
| Path | Method | Description |
|
||||||
|---------|---------------|----------------------------------------------------------------------------------------------------|
|
|---------|---------------|-----------------------------------------------------------------------------------------------------|
|
||||||
| `/ping` | `GET`, `HEAD` | A simple endpoint to check for Traefik process liveness. Return a code `200` with the content: `OK` |
|
| `/ping` | `GET`, `HEAD` | A simple endpoint to check for Traefik process liveness. Return a code `200` with the content: `OK` |
|
||||||
|
|
||||||
## Configuration Options
|
## Configuration Options
|
||||||
|
|
13
docs/content/providers/crd_ingress_route.yml
Normal file
13
docs/content/providers/crd_ingress_route.yml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
apiVersion: apiextensions.k8s.io/v1beta1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: ingressroutes.traefik.containo.us
|
||||||
|
|
||||||
|
spec:
|
||||||
|
group: traefik.containo.us
|
||||||
|
version: v1alpha1
|
||||||
|
names:
|
||||||
|
kind: IngressRoute
|
||||||
|
plural: ingressroutes
|
||||||
|
singular: ingressroute
|
||||||
|
scope: Namespaced
|
13
docs/content/providers/crd_middlewares.yml
Normal file
13
docs/content/providers/crd_middlewares.yml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
apiVersion: apiextensions.k8s.io/v1beta1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: middlewares.traefik.containo.us
|
||||||
|
|
||||||
|
spec:
|
||||||
|
group: traefik.containo.us
|
||||||
|
version: v1alpha1
|
||||||
|
names:
|
||||||
|
kind: Middleware
|
||||||
|
plural: middlewares
|
||||||
|
singular: middleware
|
||||||
|
scope: Namespaced
|
|
@ -17,7 +17,7 @@ Attach labels to your containers and let Traefik do the rest!
|
||||||
Enabling the docker provider
|
Enabling the docker provider
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[docker]
|
[providers.docker]
|
||||||
endpoint = "unix:///var/run/docker.sock"
|
endpoint = "unix:///var/run/docker.sock"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ Attach labels to your containers and let Traefik do the rest!
|
||||||
my-container:
|
my-container:
|
||||||
# ...
|
# ...
|
||||||
labels:
|
labels:
|
||||||
- traefik.http.services.my-container.rule=Host(my-domain)
|
- traefik.http.routers.my-container.rule=Host(`my-domain`)
|
||||||
```
|
```
|
||||||
|
|
||||||
??? example "Configuring Docker Swarm & Deploying / Exposing Services"
|
??? example "Configuring Docker Swarm & Deploying / Exposing Services"
|
||||||
|
@ -53,7 +53,7 @@ Attach labels to your containers and let Traefik do the rest!
|
||||||
my-container:
|
my-container:
|
||||||
deploy:
|
deploy:
|
||||||
labels:
|
labels:
|
||||||
- traefik.http.services.my-container.rule=Host(my-domain)
|
- traefik.http.routers.my-container.rule=Host(`my-domain`)
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! important "Labels in Docker Swarm Mode"
|
!!! important "Labels in Docker Swarm Mode"
|
||||||
|
@ -124,7 +124,7 @@ Traefik requires access to the docker socket to get its dynamic configuration.
|
||||||
services:
|
services:
|
||||||
|
|
||||||
traefik:
|
traefik:
|
||||||
image: traefik
|
image: traefik:v2.0 # The official v2.0 Traefik docker image
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "80:80"
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -228,6 +228,27 @@ You can declare pieces of middleware using labels starting with `traefik.http.mi
|
||||||
|
|
||||||
If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared.
|
If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared.
|
||||||
|
|
||||||
|
### TCP
|
||||||
|
|
||||||
|
You can declare TCP Routers and/or Services using labels.
|
||||||
|
|
||||||
|
??? example "Declaring TCP Routers and Services"
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
my-container:
|
||||||
|
# ...
|
||||||
|
labels:
|
||||||
|
- traefik.tcp.routers.my-router.rule="HostSNI(`my-host.com`)"
|
||||||
|
- traefik.tcp.routers.my-router.rule.tls="true"
|
||||||
|
- traefik.tcp.services.my-service.loadbalancer.server.port="4123"
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! warning "TCP and HTTP"
|
||||||
|
|
||||||
|
If you declare a TCP Router/Service, it will prevent Traefik from automatically create an HTTP Router/Service (like it does by default if no TCP Router/Service is defined).
|
||||||
|
You can declare both a TCP Router/Service and an HTTP Router/Service for the same container (but you have to do so manually).
|
||||||
|
|
||||||
### Specific Options
|
### Specific Options
|
||||||
|
|
||||||
#### traefik.enable
|
#### traefik.enable
|
||||||
|
|
|
@ -22,7 +22,7 @@ You can write these configuration elements:
|
||||||
|
|
||||||
``` toml
|
``` toml
|
||||||
# Enabling the file provider
|
# Enabling the file provider
|
||||||
[providers.files]
|
[providers.file]
|
||||||
|
|
||||||
[http]
|
[http]
|
||||||
# Add the router
|
# Add the router
|
||||||
|
|
128
docs/content/providers/kubernetes-crd.md
Normal file
128
docs/content/providers/kubernetes-crd.md
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
# Traefik & Kubernetes
|
||||||
|
|
||||||
|
The Kubernetes Ingress Controller, The Custom Resource Way.
|
||||||
|
{: .subtitle }
|
||||||
|
|
||||||
|
<!--
|
||||||
|
TODO (Link "Kubernetes Ingress controller" to ./kubernetes-ingress.md)
|
||||||
|
-->
|
||||||
|
|
||||||
|
The Traefik Kubernetes provider used to be a Kubernetes Ingress controller in the strict sense of the term; that is to say,
|
||||||
|
it would manage access to a cluster services by supporting the [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) specification.
|
||||||
|
|
||||||
|
However, as the community expressed the need to benefit from Traefik features without resorting to (lots of) annotations,
|
||||||
|
we ended up writing a [Custom Resource Definition](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) (alias CRD in the following) for an IngressRoute type, defined below, in order to provide a better way to configure access to a Kubernetes cluster.
|
||||||
|
|
||||||
|
## Traefik IngressRoute definition
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
--8<-- "content/providers/crd_ingress_route.yml"
|
||||||
|
```
|
||||||
|
|
||||||
|
That `IngressRoute` kind can then be used to define an `IngressRoute` object, such as:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: ingressroutefoo.crd
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entrypoints:
|
||||||
|
- web
|
||||||
|
routes:
|
||||||
|
# Match is the rule corresponding to an underlying router.
|
||||||
|
# Later on, match could be the simple form of a path prefix, e.g. just "/bar",
|
||||||
|
# but for now we only support a traefik style matching rule.
|
||||||
|
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||||
|
# kind could eventually be one of "Rule", "Path", "Host", "Method", "Header",
|
||||||
|
# "Parameter", etc, to support simpler forms of rule matching, but for now we
|
||||||
|
# only support "Rule".
|
||||||
|
kind: Rule
|
||||||
|
# Priority disambiguates rules of the same length, for route matching.
|
||||||
|
priority: 12
|
||||||
|
services:
|
||||||
|
- name: whoami
|
||||||
|
port: 80
|
||||||
|
```
|
||||||
|
|
||||||
|
## Middleware
|
||||||
|
|
||||||
|
Additionally, to allow for the use of middlewares in an `IngressRoute`, we defined the CRD below for the `Middleware` kind.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
--8<-- "content/providers/crd_middlewares.yml"
|
||||||
|
```
|
||||||
|
|
||||||
|
Once the `Middleware` kind has been registered with the Kubernetes cluster, it can then be used in `IngressRoute` definitions, such as:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: stripprefix
|
||||||
|
|
||||||
|
spec:
|
||||||
|
stripprefix:
|
||||||
|
prefixes:
|
||||||
|
- /stripit
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: ingressroutebar.crd
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entrypoints:
|
||||||
|
- web
|
||||||
|
routes:
|
||||||
|
- match: Host(`bar.com`) && PathPrefix(`/stripit`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: whoami
|
||||||
|
port: 80
|
||||||
|
middlewares:
|
||||||
|
- name: stripprefix
|
||||||
|
```
|
||||||
|
|
||||||
|
## TLS
|
||||||
|
|
||||||
|
To allow for TLS, we made use of the `Secret` kind, as it was already defined, and it can be directly used in an `IngressRoute`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: supersecret
|
||||||
|
|
||||||
|
data:
|
||||||
|
tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=
|
||||||
|
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: ingressroutetls.crd
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- web
|
||||||
|
routes:
|
||||||
|
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: whoami
|
||||||
|
port: 443
|
||||||
|
tls:
|
||||||
|
secretName: supersecret
|
||||||
|
```
|
||||||
|
|
||||||
|
## Full reference example
|
||||||
|
|
||||||
|
[Traefik IngressRoute Reference](../reference/providers/kubernetescrd.md).
|
||||||
|
|
||||||
|
## Further
|
||||||
|
|
||||||
|
Also see the [full example](../user-guides/crd-acme/index.md) with Let's Encrypt.
|
6
docs/content/providers/kubernetes-ingress.md
Normal file
6
docs/content/providers/kubernetes-ingress.md
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# Traefik & Kubernetes
|
||||||
|
|
||||||
|
Kubernetes Ingress.
|
||||||
|
{: .subtitle }
|
||||||
|
|
||||||
|
TODO
|
|
@ -8,7 +8,8 @@ Traefik's Many Friends
|
||||||
Configuration discovery in Traefik is achieved through _Providers_.
|
Configuration discovery in Traefik is achieved through _Providers_.
|
||||||
|
|
||||||
The _providers_ are existing infrastructure components, whether orchestrators, container engines, cloud providers, or key-value stores.
|
The _providers_ are existing infrastructure components, whether orchestrators, container engines, cloud providers, or key-value stores.
|
||||||
The idea is that Traefik will query the providers' API in order to find relevant information about routing, and each time Traefik detects a change, it dynamically updates the routes.
|
The idea is that Traefik will query the providers' API in order to find relevant information about routing,
|
||||||
|
and each time Traefik detects a change, it dynamically updates the routes.
|
||||||
|
|
||||||
Deploy and forget is Traefik's credo.
|
Deploy and forget is Traefik's credo.
|
||||||
|
|
||||||
|
@ -25,12 +26,12 @@ Even if each provider is different, we can categorize them in four groups:
|
||||||
|
|
||||||
Below is the list of the currently supported providers in Traefik.
|
Below is the list of the currently supported providers in Traefik.
|
||||||
|
|
||||||
| Provider | Type | Configuration Type |
|
| Provider | Type | Configuration Type |
|
||||||
|-----------------------------|--------------|--------------------|
|
|---------------------------------|--------------|--------------------|
|
||||||
| [Docker](./docker.md) | Orchestrator | Label |
|
| [Docker](./docker.md) | Orchestrator | Label |
|
||||||
| [File](./file.md) | Orchestrator | Custom Annotation |
|
| [File](./file.md) | Orchestrator | Custom Annotation |
|
||||||
| Kubernetes (not documented) | Orchestrator | Custom Annotation |
|
| [Kubernetes](kubernetes-crd.md) | Orchestrator | Custom Resource |
|
||||||
| Marathon (not documented) | Orchestrator | Label |
|
| Marathon (not yet documented) | Orchestrator | Label |
|
||||||
|
|
||||||
!!! note "More Providers"
|
!!! note "More Providers"
|
||||||
|
|
||||||
|
@ -38,7 +39,8 @@ Below is the list of the currently supported providers in Traefik.
|
||||||
|
|
||||||
## Constraints Configuration
|
## Constraints Configuration
|
||||||
|
|
||||||
If you want to limit the scope of Traefik service discovery, you can set constraints. Doing so, Traefik will create routes for containers that match these constraints only.
|
If you want to limit the scope of Traefik service discovery, you can set constraints.
|
||||||
|
Doing so, Traefik will create routes for containers that match these constraints only.
|
||||||
|
|
||||||
??? example "Containers with the api Tag"
|
??? example "Containers with the api Tag"
|
||||||
|
|
||||||
|
|
81
docs/content/reference/providers/kubernetescrd.md
Normal file
81
docs/content/reference/providers/kubernetescrd.md
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
# Kubernetes -- Reference
|
||||||
|
|
||||||
|
## Kubernetes
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
################################################################
|
||||||
|
# Kubernetes Provider
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
apiVersion: apiextensions.k8s.io/v1beta1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: ingressroutes.traefik.containo.us
|
||||||
|
|
||||||
|
spec:
|
||||||
|
group: traefik.containo.us
|
||||||
|
version: v1alpha1
|
||||||
|
names:
|
||||||
|
kind: IngressRoute
|
||||||
|
plural: ingressroutes
|
||||||
|
singular: ingressroute
|
||||||
|
scope: Namespaced
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1beta1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: middlewares.traefik.containo.us
|
||||||
|
spec:
|
||||||
|
group: traefik.containo.us
|
||||||
|
version: v1alpha1
|
||||||
|
names:
|
||||||
|
kind: Middleware
|
||||||
|
plural: middlewares
|
||||||
|
singular: middleware
|
||||||
|
scope: Namespaced
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: ingressroute.crd
|
||||||
|
spec:
|
||||||
|
entrypoints:
|
||||||
|
- web
|
||||||
|
- web-secure
|
||||||
|
routes:
|
||||||
|
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||||
|
kind: Rule
|
||||||
|
priority: 12
|
||||||
|
# defining several services is possible and allowed, but for now the servers of
|
||||||
|
# all the services (for a given route) get merged altogether under the same
|
||||||
|
# load-balancing strategy.
|
||||||
|
services:
|
||||||
|
- name: s1
|
||||||
|
port: 80
|
||||||
|
healthcheck:
|
||||||
|
path: /health
|
||||||
|
host: baz.com
|
||||||
|
intervalseconds: 7
|
||||||
|
timeoutseconds: 60
|
||||||
|
# strategy defines the load balancing strategy between the servers. It defaults
|
||||||
|
# to Round Robin, and for now only Round Robin is supported anyway.
|
||||||
|
strategy: RoundRobin
|
||||||
|
- name: s2
|
||||||
|
port: 433
|
||||||
|
healthcheck:
|
||||||
|
path: /health
|
||||||
|
host: baz.com
|
||||||
|
intervalseconds: 7
|
||||||
|
timeoutseconds: 60
|
||||||
|
- match: PathPrefix(`/misc`)
|
||||||
|
services:
|
||||||
|
- name: s3
|
||||||
|
port: 80
|
||||||
|
middleware:
|
||||||
|
- name: stripprefix
|
||||||
|
- name: addprefix
|
||||||
|
tls:
|
||||||
|
secretName: supersecret
|
||||||
|
```
|
|
@ -1,6 +1,6 @@
|
||||||
# EntryPoints
|
# EntryPoints
|
||||||
|
|
||||||
Opening Connections for Incomming Requests
|
Opening Connections for Incoming Requests
|
||||||
{: .subtitle }
|
{: .subtitle }
|
||||||
|
|
||||||
![EntryPoints](../assets/img/entrypoints.png)
|
![EntryPoints](../assets/img/entrypoints.png)
|
||||||
|
@ -29,11 +29,6 @@ They define the port which will receive the requests (whether HTTP or TCP).
|
||||||
|
|
||||||
[entrypoints.web-secure]
|
[entrypoints.web-secure]
|
||||||
address = ":443"
|
address = ":443"
|
||||||
|
|
||||||
[entrypoints.web-secure.tls]
|
|
||||||
[[entrypoints.web-secure.tls.certificates]]
|
|
||||||
certFile = "tests/traefik.crt"
|
|
||||||
keyFile = "tests/traefik.key"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- Two entrypoints are defined: one called `web`, and the other called `web-secure`.
|
- Two entrypoints are defined: one called `web`, and the other called `web-secure`.
|
||||||
|
@ -51,7 +46,7 @@ Entrypoints are part of the [static configuration](../getting-started/configurat
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
--entryPoints='Name:http Address::80'
|
--entryPoints='Name:http Address::80'
|
||||||
--entryPoints='Name:https Address::443 TLS'
|
--entryPoints='Name:https Address::443'
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
|
@ -64,7 +59,7 @@ Entrypoints are part of the [static configuration](../getting-started/configurat
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
traefik:
|
traefik:
|
||||||
image: traefik
|
image: traefik:v2.0 # The official v2.0 Traefik docker image
|
||||||
command:
|
command:
|
||||||
- --defaultentrypoints=powpow
|
- --defaultentrypoints=powpow
|
||||||
- "--entryPoints=Name:powpow Address::42 Compress:true"
|
- "--entryPoints=Name:powpow Address::42 Compress:true"
|
||||||
|
@ -74,7 +69,7 @@ Entrypoints are part of the [static configuration](../getting-started/configurat
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
traefik:
|
traefik:
|
||||||
image: traefik
|
image: traefik:v2.0 # The official v2.0 Traefik docker image
|
||||||
command: --defaultentrypoints=powpow --entryPoints='Name:powpow Address::42 Compress:true'
|
command: --defaultentrypoints=powpow --entryPoints='Name:powpow Address::42 Compress:true'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -97,7 +92,7 @@ Traefik supports [ProxyProtocol](https://www.haproxy.org/download/1.8/doc/proxy-
|
||||||
|
|
||||||
??? example "Insecure Mode -- Testing Environnement Only"
|
??? example "Insecure Mode -- Testing Environnement Only"
|
||||||
|
|
||||||
In a test environments, you can configure Traefik to trust every incomming connection. Doing so, every remote client address will be replaced (`trustedIPs` won't have any effect)
|
In a test environments, you can configure Traefik to trust every incoming connection. Doing so, every remote client address will be replaced (`trustedIPs` won't have any effect)
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[entrypoints]
|
[entrypoints]
|
||||||
|
|
|
@ -15,7 +15,7 @@ In the process, routers may use pieces of [middleware](../../middlewares/overvie
|
||||||
```toml
|
```toml
|
||||||
[http.routers]
|
[http.routers]
|
||||||
[http.routers.my-router]
|
[http.routers.my-router]
|
||||||
rule = "Path(/foo)"
|
rule = "Path(`/foo`)"
|
||||||
service = "service-foo"
|
service = "service-foo"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ In the process, routers may use pieces of [middleware](../../middlewares/overvie
|
||||||
```toml
|
```toml
|
||||||
[http.routers]
|
[http.routers]
|
||||||
[http.routers.my-router]
|
[http.routers.my-router]
|
||||||
rule = "Path(/foo)"
|
rule = "Path(`/foo`)"
|
||||||
middlewares = ["authentication"] # declared elsewhere
|
middlewares = ["authentication"] # declared elsewhere
|
||||||
service = "service-foo"
|
service = "service-foo"
|
||||||
```
|
```
|
||||||
|
@ -67,7 +67,7 @@ If you want to limit the router scope to a set of entrypoint, set the entrypoint
|
||||||
[http.routers]
|
[http.routers]
|
||||||
[http.routers.Router-1]
|
[http.routers.Router-1]
|
||||||
# By default, routers listen to every entrypoints
|
# By default, routers listen to every entrypoints
|
||||||
rule = "Host(traefik.io)"
|
rule = "Host(`traefik.io`)"
|
||||||
service = "service-1"
|
service = "service-1"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ If you want to limit the router scope to a set of entrypoint, set the entrypoint
|
||||||
[http.routers]
|
[http.routers]
|
||||||
[http.routers.Router-1]
|
[http.routers.Router-1]
|
||||||
entryPoints = ["web-secure", "other"] # won't listen to entrypoint web
|
entryPoints = ["web-secure", "other"] # won't listen to entrypoint web
|
||||||
rule = "Host(traefik.io)"
|
rule = "Host(`traefik.io`)"
|
||||||
service = "service-1"
|
service = "service-1"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -248,9 +248,9 @@ If you want to limit the router scope to a set of entrypoints, set the entrypoin
|
||||||
|
|
||||||
### Rule
|
### Rule
|
||||||
|
|
||||||
| Rule | Description |
|
| Rule | Description |
|
||||||
|--------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
|
|------------------------------|-------------------------------------------------------------------------|
|
||||||
| ``HostSNI(`domain-1`, ...)`` | Check if the Server Name Indication corresponds to the given `domains`. |
|
| ``HostSNI(`domain-1`, ...)`` | Check if the Server Name Indication corresponds to the given `domains`. |
|
||||||
|
|
||||||
!!! important "HostSNI & TLS"
|
!!! important "HostSNI & TLS"
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,7 @@ The `weight` option defines the weight of the server for the load balancing algo
|
||||||
[http.services.my-service.LoadBalancer]
|
[http.services.my-service.LoadBalancer]
|
||||||
[[http.services.my-service.LoadBalancer.servers]]
|
[[http.services.my-service.LoadBalancer.servers]]
|
||||||
url = "http://private-ip-server-1/"
|
url = "http://private-ip-server-1/"
|
||||||
|
weight = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Load-balancing
|
#### Load-balancing
|
||||||
|
@ -97,8 +98,10 @@ Various methods of load balancing are supported:
|
||||||
method = "drr"
|
method = "drr"
|
||||||
[[http.services.my-service.LoadBalancer.servers]]
|
[[http.services.my-service.LoadBalancer.servers]]
|
||||||
url = "http://private-ip-server-1/"
|
url = "http://private-ip-server-1/"
|
||||||
|
weight = 1
|
||||||
[[http.services.my-service.LoadBalancer.servers]]
|
[[http.services.my-service.LoadBalancer.servers]]
|
||||||
url = "http://private-ip-server-1/"
|
url = "http://private-ip-server-1/"
|
||||||
|
weight = 1
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Sticky sessions
|
#### Sticky sessions
|
||||||
|
|
91
docs/content/user-guides/crd-acme/01-crd.yml
Normal file
91
docs/content/user-guides/crd-acme/01-crd.yml
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
apiVersion: apiextensions.k8s.io/v1beta1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: ingressroutes.traefik.containo.us
|
||||||
|
|
||||||
|
spec:
|
||||||
|
group: traefik.containo.us
|
||||||
|
version: v1alpha1
|
||||||
|
names:
|
||||||
|
kind: IngressRoute
|
||||||
|
plural: ingressroutes
|
||||||
|
singular: ingressroute
|
||||||
|
scope: Namespaced
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: apiextensions.k8s.io/v1beta1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
name: middlewares.traefik.containo.us
|
||||||
|
|
||||||
|
spec:
|
||||||
|
group: traefik.containo.us
|
||||||
|
version: v1alpha1
|
||||||
|
names:
|
||||||
|
kind: Middleware
|
||||||
|
plural: middlewares
|
||||||
|
singular: middleware
|
||||||
|
scope: Namespaced
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: ClusterRole
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
metadata:
|
||||||
|
name: traefik-ingress-controller
|
||||||
|
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- services
|
||||||
|
- endpoints
|
||||||
|
- secrets
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- extensions
|
||||||
|
resources:
|
||||||
|
- ingresses
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- extensions
|
||||||
|
resources:
|
||||||
|
- ingresses/status
|
||||||
|
verbs:
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- traefik.containo.us
|
||||||
|
resources:
|
||||||
|
- middlewares
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- traefik.containo.us
|
||||||
|
resources:
|
||||||
|
- ingressroutes
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: ClusterRoleBinding
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
metadata:
|
||||||
|
name: traefik-ingress-controller
|
||||||
|
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: ClusterRole
|
||||||
|
name: traefik-ingress-controller
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: traefik-ingress-controller
|
||||||
|
namespace: default
|
32
docs/content/user-guides/crd-acme/02-services.yml
Normal file
32
docs/content/user-guides/crd-acme/02-services.yml
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: traefik
|
||||||
|
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
name: web
|
||||||
|
port: 8000
|
||||||
|
- protocol: TCP
|
||||||
|
name: admin
|
||||||
|
port: 8080
|
||||||
|
- protocol: TCP
|
||||||
|
name: websecure
|
||||||
|
port: 4443
|
||||||
|
selector:
|
||||||
|
app: traefik
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: whoami
|
||||||
|
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
name: web
|
||||||
|
port: 80
|
||||||
|
selector:
|
||||||
|
app: whoami
|
79
docs/content/user-guides/crd-acme/03-deployments.yml
Normal file
79
docs/content/user-guides/crd-acme/03-deployments.yml
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
namespace: default
|
||||||
|
name: traefik-ingress-controller
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: Deployment
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
metadata:
|
||||||
|
namespace: default
|
||||||
|
name: traefik
|
||||||
|
labels:
|
||||||
|
app: traefik
|
||||||
|
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: traefik
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: traefik
|
||||||
|
spec:
|
||||||
|
serviceAccountName: traefik-ingress-controller
|
||||||
|
containers:
|
||||||
|
- name: traefik
|
||||||
|
image: traefik:v2.0
|
||||||
|
args:
|
||||||
|
- --api
|
||||||
|
- --accesslog
|
||||||
|
- --entrypoints=Name:web Address::8000
|
||||||
|
- --entrypoints=Name:websecure Address::4443
|
||||||
|
- --providers.kubernetescrd
|
||||||
|
- --providers.kubernetescrd.trace
|
||||||
|
- --acme
|
||||||
|
- --acme.acmelogging
|
||||||
|
- --acme.tlschallenge
|
||||||
|
- --acme.onhostrule
|
||||||
|
- --acme.email=foo@you.com
|
||||||
|
- --acme.entrypoint=websecure
|
||||||
|
- --acme.storage=acme.json
|
||||||
|
# Please note that this is the staging Let's Encrypt server.
|
||||||
|
# Once you get things working, you should remove that whole line altogether.
|
||||||
|
- --acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
|
||||||
|
ports:
|
||||||
|
- name: web
|
||||||
|
containerPort: 8000
|
||||||
|
- name: websecure
|
||||||
|
containerPort: 4443
|
||||||
|
- name: admin
|
||||||
|
containerPort: 8080
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: Deployment
|
||||||
|
apiVersion: extensions/v1beta1
|
||||||
|
metadata:
|
||||||
|
namespace: default
|
||||||
|
name: whoami
|
||||||
|
labels:
|
||||||
|
app: whoami
|
||||||
|
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: whoami
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: whoami
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: whoami
|
||||||
|
image: containous/whoami
|
||||||
|
ports:
|
||||||
|
- name: web
|
||||||
|
containerPort: 80
|
30
docs/content/user-guides/crd-acme/04-ingressroutes.yml
Normal file
30
docs/content/user-guides/crd-acme/04-ingressroutes.yml
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: simpleingressroute
|
||||||
|
spec:
|
||||||
|
entrypoints:
|
||||||
|
- web
|
||||||
|
routes:
|
||||||
|
- match: Host(`your.domain.com`) && PathPrefix(`/notls`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: whoami
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: ingressroutetls
|
||||||
|
spec:
|
||||||
|
entrypoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`your.domain.com`) && PathPrefix(`/tls`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: whoami
|
||||||
|
port: 80
|
||||||
|
tls:
|
||||||
|
secretName: ""
|
100
docs/content/user-guides/crd-acme/index.md
Normal file
100
docs/content/user-guides/crd-acme/index.md
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
# Traefik & CRD & Let's Encrypt
|
||||||
|
|
||||||
|
Traefik with an IngressRoute Custom Resource Definition for Kubernetes, and TLS Through Let's Encrypt.
|
||||||
|
{: .subtitle }
|
||||||
|
|
||||||
|
This document is intended to be a fully working example demonstrating how to set up Traefik in [Kubernetes](https://kubernetes.io),
|
||||||
|
with the dynamic configuration coming from the [IngressRoute Custom Resource](../../providers/kubernetes-crd.md),
|
||||||
|
and TLS setup with [Let's Encrypt](https://letsencrypt.org).
|
||||||
|
However, for the sake of simplicity, we're using [k3s](https://github.com/rancher/k3s) docker image for the Kubernetes cluster setup.
|
||||||
|
|
||||||
|
Please note that for this setup, given that we're going to use ACME's TLS-ALPN-01 challenge, the host you'll be running it on must be able to receive connections from the outside on port 443.
|
||||||
|
And of course its internet facing IP address must match the domain name you intend to use.
|
||||||
|
|
||||||
|
In the following, the Kubernetes resources defined in YAML configuration files can be applied to the setup in two different ways:
|
||||||
|
|
||||||
|
- the first, and usual way, is simply with the `kubectl apply` command.
|
||||||
|
- the second, which can be used for this tutorial, is to directly place the files in the directory used by the k3s docker image for such inputs (`/var/lib/rancher/k3s/server/manifests`).
|
||||||
|
|
||||||
|
## k3s Docker-compose Configuration ##
|
||||||
|
|
||||||
|
Our starting point is the docker-compose configuration file, to start the k3s cluster.
|
||||||
|
You can start it with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose -f k3s.yml up
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
--8<-- "content/user-guides/crd-acme/k3s.yml"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cluster Resources ##
|
||||||
|
|
||||||
|
Let's now have a look (in the order they should be applied, if using `kubectl apply`) at all the required resources for the full setup.
|
||||||
|
|
||||||
|
### IngressRoute Definition ###
|
||||||
|
|
||||||
|
First, the definition of the `IngressRoute` and the `Middleware` kinds.
|
||||||
|
Also note the RBAC authorization resources; they'll be referenced through the `serviceAccountName` of the deployment, later on.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
--8<-- "content/user-guides/crd-acme/01-crd.yml"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Services ###
|
||||||
|
|
||||||
|
Then, the services. One for Traefik itself, and one for the app it routes for, i.e. in this case our demo HTTP server: [whoami](https://github.com/containous/whoami).
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
--8<-- "content/user-guides/crd-acme/02-services.yml"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deployments ###
|
||||||
|
|
||||||
|
Next, the deployments, i.e. the actual pods behind the services.
|
||||||
|
Again, one pod for Traefik, and one for the whoami app.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
--8<-- "content/user-guides/crd-acme/03-deployments.yml"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Port Forwarding ###
|
||||||
|
|
||||||
|
Now, as an exception to what we said above, please note that you should not let the ingressRoute resources below be applied automatically to your cluster.
|
||||||
|
The reason is, as soon as the ACME provider of Traefik detects we have TLS routers, it will try to generate the certificates for the corresponding domains.
|
||||||
|
And this will not work, because as it is, our Traefik pod is not reachable from the outside, which will make the ACME TLS challenge fail.
|
||||||
|
Therefore, for the whole thing to work, we must delay applying the ingressRoute resources until we have port-forwarding set up properly, which is the next step.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl port-forward --address 0.0.0.0 service/traefik 8000:8000 8080:8080 443:4443 -n default
|
||||||
|
```
|
||||||
|
|
||||||
|
Also, and this is out of the scope if this guide, please note that because of the privileged ports limitation on Linux, the above command might fail to listen on port 443.
|
||||||
|
In which case you can use tricks such as elevating caps of `kubectl` with `setcaps`, or using `authbind`, or setting up a NAT between your host and the WAN.
|
||||||
|
Look it up.
|
||||||
|
|
||||||
|
### Traefik Routers ###
|
||||||
|
|
||||||
|
We can now finally apply the actual ingressRoutes, with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl apply -f 04-ingressroutes.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
--8<-- "content/user-guides/crd-acme/04-ingressroutes.yml"
|
||||||
|
```
|
||||||
|
|
||||||
|
Give it a few seconds for the ACME TLS challenge to complete, and you should then be able to access your whoami pod (routed through Traefik), from the outside.
|
||||||
|
Both with or (just for fun, do not do that in production) without TLS:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl [-k] https://your.domain.com/tls
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl [-k] http://your.domain.com:8000/notls
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that you'll have to use `-k` as long as you're using the staging server of Let's Encrypt, since it is not in the root DNS servers.
|
30
docs/content/user-guides/crd-acme/k3s.yml
Normal file
30
docs/content/user-guides/crd-acme/k3s.yml
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
server:
|
||||||
|
image: rancher/k3s:v0.2.0
|
||||||
|
command: server --disable-agent --no-deploy traefik
|
||||||
|
environment:
|
||||||
|
- K3S_CLUSTER_SECRET=somethingtotallyrandom
|
||||||
|
- K3S_KUBECONFIG_OUTPUT=/output/kubeconfig.yaml
|
||||||
|
- K3S_KUBECONFIG_MODE=666
|
||||||
|
volumes:
|
||||||
|
# k3s will generate a kubeconfig.yaml in this directory. This volume is mounted
|
||||||
|
# on your host, so you can then 'export KUBECONFIG=/somewhere/on/your/host/out/kubeconfig.yaml',
|
||||||
|
# in order for your kubectl commands to work.
|
||||||
|
- /somewhere/on/your/host/out:/output
|
||||||
|
# This directory is where you put all the (yaml) configuration files of
|
||||||
|
# the Kubernetes resources.
|
||||||
|
- /somewhere/on/your/host/in:/var/lib/rancher/k3s/server/manifests
|
||||||
|
ports:
|
||||||
|
- 6443:6443
|
||||||
|
|
||||||
|
node:
|
||||||
|
image: rancher/k3s:v0.2.0
|
||||||
|
privileged: true
|
||||||
|
links:
|
||||||
|
- server
|
||||||
|
environment:
|
||||||
|
- K3S_URL=https://server:6443
|
||||||
|
- K3S_CLUSTER_SECRET=somethingtotallyrandom
|
||||||
|
volumes:
|
||||||
|
# this is where you would place a alternative traefik image (saved as a .tar file with
|
||||||
|
# 'docker save'), if you want to use it, instead of the traefik:v2.0 image.
|
||||||
|
- /sowewhere/on/your/host/custom-image:/var/lib/rancher/k3s/agent/images
|
|
@ -66,19 +66,22 @@ markdown_extensions:
|
||||||
|
|
||||||
# Page tree
|
# Page tree
|
||||||
nav:
|
nav:
|
||||||
|
- '': 'providers/kubernetes-ingress.md'
|
||||||
- '': 'reference/acme.md'
|
- '': 'reference/acme.md'
|
||||||
- '': 'reference/providers/docker.md'
|
- '': 'reference/providers/docker.md'
|
||||||
- '': 'reference/providers/file.md'
|
- '': 'reference/providers/file.md'
|
||||||
|
- '': 'reference/providers/kubernetescrd.md'
|
||||||
- '': 'reference/entrypoints.md'
|
- '': 'reference/entrypoints.md'
|
||||||
- 'Welcome': 'index.md'
|
- 'Welcome': 'index.md'
|
||||||
- 'Getting Started':
|
- 'Getting Started':
|
||||||
- 'Concepts' : 'getting-started/concepts.md'
|
- 'Concepts' : 'getting-started/concepts.md'
|
||||||
- 'Quick Start': 'getting-started/quick-start.md'
|
- 'Quick Start': 'getting-started/quick-start.md'
|
||||||
- 'Configuration Overview': 'getting-started/configuration-overview.md'
|
- 'Configuration Introduction': 'getting-started/configuration-overview.md'
|
||||||
- 'Configuration Discovery':
|
- 'Configuration Discovery':
|
||||||
- 'Overview': 'providers/overview.md'
|
- 'Overview': 'providers/overview.md'
|
||||||
- 'Docker': 'providers/docker.md'
|
- 'Docker': 'providers/docker.md'
|
||||||
- 'File': 'providers/file.md'
|
- 'File': 'providers/file.md'
|
||||||
|
- 'Kubernetes IngressRoute': 'providers/kubernetes-crd.md'
|
||||||
- 'Routing & Load Balancing':
|
- 'Routing & Load Balancing':
|
||||||
- 'Overview': 'routing/overview.md'
|
- 'Overview': 'routing/overview.md'
|
||||||
- 'Entrypoints': 'routing/entrypoints.md'
|
- 'Entrypoints': 'routing/entrypoints.md'
|
||||||
|
@ -119,6 +122,8 @@ nav:
|
||||||
- 'Logs': 'observability/logs.md'
|
- 'Logs': 'observability/logs.md'
|
||||||
- 'Access Logs': 'observability/access-logs.md'
|
- 'Access Logs': 'observability/access-logs.md'
|
||||||
- 'Tracing': 'observability/tracing.md'
|
- 'Tracing': 'observability/tracing.md'
|
||||||
|
- 'User Guides':
|
||||||
|
- 'Kubernetes and Let''s Encrypt': 'user-guides/crd-acme/index.md'
|
||||||
- 'Contributing':
|
- 'Contributing':
|
||||||
- 'Thank You!': 'contributing/thank-you.md'
|
- 'Thank You!': 'contributing/thank-you.md'
|
||||||
- 'Submitting Issues': 'contributing/submitting-issues.md'
|
- 'Submitting Issues': 'contributing/submitting-issues.md'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
mkdocs==1.0.4
|
mkdocs==1.0.4
|
||||||
pymdown-extensions==6.0
|
pymdown-extensions==6.0
|
||||||
mkdocs-bootswatch==1.0
|
mkdocs-bootswatch==1.0
|
||||||
mkdocs-material==3.3.0
|
mkdocs-material==4.0.2
|
||||||
markdown-include==0.5.1
|
markdown-include==0.5.1
|
||||||
|
|
42
exp.Dockerfile
Normal file
42
exp.Dockerfile
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
# WEBUI
|
||||||
|
FROM node:8.15.0 as webui
|
||||||
|
|
||||||
|
ENV WEBUI_DIR /src/webui
|
||||||
|
RUN mkdir -p $WEBUI_DIR
|
||||||
|
|
||||||
|
COPY ./webui/ $WEBUI_DIR/
|
||||||
|
|
||||||
|
WORKDIR $WEBUI_DIR
|
||||||
|
RUN yarn install
|
||||||
|
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# BUILD
|
||||||
|
FROM golang:1.12-alpine as gobuild
|
||||||
|
|
||||||
|
RUN apk --update upgrade \
|
||||||
|
&& apk --no-cache --no-progress add git mercurial bash gcc musl-dev curl tar \
|
||||||
|
&& rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
|
RUN mkdir -p /usr/local/bin \
|
||||||
|
&& curl -fsSL -o /usr/local/bin/go-bindata https://github.com/containous/go-bindata/releases/download/v1.0.0/go-bindata \
|
||||||
|
&& chmod +x /usr/local/bin/go-bindata
|
||||||
|
|
||||||
|
WORKDIR /go/src/github.com/containous/traefik
|
||||||
|
COPY . /go/src/github.com/containous/traefik
|
||||||
|
|
||||||
|
RUN rm -rf /go/src/github.com/containous/traefik/static/
|
||||||
|
COPY --from=webui /src/static/ /go/src/github.com/containous/traefik/static/
|
||||||
|
|
||||||
|
RUN ./script/make.sh generate binary
|
||||||
|
|
||||||
|
## IMAGE
|
||||||
|
FROM scratch
|
||||||
|
|
||||||
|
COPY script/ca-certificates.crt /etc/ssl/certs/
|
||||||
|
COPY --from=gobuild /go/src/github.com/containous/traefik/dist/traefik /
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
VOLUME ["/tmp"]
|
||||||
|
|
||||||
|
ENTRYPOINT ["/traefik"]
|
|
@ -144,6 +144,43 @@ func (s *DockerSuite) TestDefaultDockerContainers(c *check.C) {
|
||||||
c.Assert(version["Version"], checker.Equals, "swarm/1.0.0")
|
c.Assert(version["Version"], checker.Equals, "swarm/1.0.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestDockerContainersWithTCPLabels(c *check.C) {
|
||||||
|
tempObjects := struct {
|
||||||
|
DockerHost string
|
||||||
|
DefaultRule string
|
||||||
|
}{
|
||||||
|
DockerHost: s.getDockerHost(),
|
||||||
|
DefaultRule: "Host(`{{ normalize .Name }}.docker.localhost`)",
|
||||||
|
}
|
||||||
|
|
||||||
|
file := s.adaptFile(c, "fixtures/docker/simple.toml", tempObjects)
|
||||||
|
defer os.Remove(file)
|
||||||
|
|
||||||
|
// Start a container with some labels
|
||||||
|
labels := map[string]string{
|
||||||
|
"traefik.tcp.Routers.Super.Rule": "HostSNI(`my.super.host`)",
|
||||||
|
"traefik.tcp.Routers.Super.tls": "true",
|
||||||
|
"traefik.tcp.Services.Super.Loadbalancer.server.port": "8080",
|
||||||
|
}
|
||||||
|
|
||||||
|
s.startContainerWithLabels(c, "containous/whoamitcp", labels, "-name", "my.super.host")
|
||||||
|
|
||||||
|
// Start traefik
|
||||||
|
cmd, display := s.traefikCmd(withConfigFile(file))
|
||||||
|
defer display(c)
|
||||||
|
err := cmd.Start()
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
defer cmd.Process.Kill()
|
||||||
|
|
||||||
|
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 500*time.Millisecond, try.StatusCodeIs(http.StatusOK), try.BodyContains("HostSNI(`my.super.host`)"))
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
who, err := guessWho("127.0.0.1:8000", "my.super.host", true)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
c.Assert(who, checker.Contains, "my.super.host")
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DockerSuite) TestDockerContainersWithLabels(c *check.C) {
|
func (s *DockerSuite) TestDockerContainersWithLabels(c *check.C) {
|
||||||
tempObjects := struct {
|
tempObjects := struct {
|
||||||
DockerHost string
|
DockerHost string
|
||||||
|
|
|
@ -15,4 +15,3 @@ spec:
|
||||||
services:
|
services:
|
||||||
- name: whoami
|
- name: whoami
|
||||||
port: 80
|
port: 80
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDo_globalConfiguration(t *testing.T) {
|
func TestDo_globalConfiguration(t *testing.T) {
|
||||||
|
|
||||||
config := &static.Configuration{}
|
config := &static.Configuration{}
|
||||||
|
|
||||||
sendAnonymousUsage := true
|
sendAnonymousUsage := true
|
||||||
|
@ -148,9 +147,15 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Providers.File = &file.Provider{
|
config.Providers.File = &file.Provider{
|
||||||
BaseProvider: provider.BaseProvider{
|
Directory: "file Directory",
|
||||||
Watch: true,
|
Watch: true,
|
||||||
Filename: "file Filename",
|
Filename: "file Filename",
|
||||||
|
DebugLogGeneratedTemplate: true,
|
||||||
|
TraefikFile: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Providers.Docker = &docker.Provider{
|
||||||
|
Constrainer: provider.Constrainer{
|
||||||
Constraints: types.Constraints{
|
Constraints: types.Constraints{
|
||||||
{
|
{
|
||||||
Key: "file Constraints Key 1",
|
Key: "file Constraints Key 1",
|
||||||
|
@ -163,20 +168,8 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
MustMatch: true,
|
MustMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
|
||||||
Directory: "file Directory",
|
|
||||||
}
|
|
||||||
|
|
||||||
config.Providers.Docker = &docker.Provider{
|
|
||||||
BaseProvider: provider.BaseProvider{
|
|
||||||
Watch: true,
|
|
||||||
Filename: "myfilename",
|
|
||||||
Constraints: nil,
|
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
},
|
||||||
|
Watch: true,
|
||||||
Endpoint: "MyEndPoint",
|
Endpoint: "MyEndPoint",
|
||||||
DefaultRule: "PathPrefix(`/`)",
|
DefaultRule: "PathPrefix(`/`)",
|
||||||
TLS: &types.ClientTLS{
|
TLS: &types.ClientTLS{
|
||||||
|
@ -194,24 +187,6 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Providers.Kubernetes = &ingress.Provider{
|
config.Providers.Kubernetes = &ingress.Provider{
|
||||||
BaseProvider: provider.BaseProvider{
|
|
||||||
Watch: true,
|
|
||||||
Filename: "myFileName",
|
|
||||||
Constraints: types.Constraints{
|
|
||||||
{
|
|
||||||
Key: "k8s Constraints Key 1",
|
|
||||||
Regex: "k8s Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "k8s Constraints Key 1",
|
|
||||||
Regex: "k8s Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
|
||||||
Endpoint: "MyEndpoint",
|
Endpoint: "MyEndpoint",
|
||||||
Token: "MyToken",
|
Token: "MyToken",
|
||||||
CertAuthFilePath: "MyCertAuthPath",
|
CertAuthFilePath: "MyCertAuthPath",
|
||||||
|
@ -222,24 +197,6 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
config.Providers.KubernetesCRD = &crd.Provider{
|
config.Providers.KubernetesCRD = &crd.Provider{
|
||||||
BaseProvider: provider.BaseProvider{
|
|
||||||
Watch: true,
|
|
||||||
Filename: "myFileName",
|
|
||||||
Constraints: types.Constraints{
|
|
||||||
{
|
|
||||||
Key: "k8s Constraints Key 1",
|
|
||||||
Regex: "k8s Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: "k8s Constraints Key 1",
|
|
||||||
Regex: "k8s Constraints Regex 2",
|
|
||||||
MustMatch: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Trace: true,
|
|
||||||
DebugLogGeneratedTemplate: true,
|
|
||||||
},
|
|
||||||
Endpoint: "MyEndpoint",
|
Endpoint: "MyEndpoint",
|
||||||
Token: "MyToken",
|
Token: "MyToken",
|
||||||
CertAuthFilePath: "MyCertAuthPath",
|
CertAuthFilePath: "MyCertAuthPath",
|
||||||
|
|
|
@ -53,6 +53,23 @@ type TCPLoadBalancerService struct {
|
||||||
Method string `json:"method,omitempty" toml:",omitempty"`
|
Method string `json:"method,omitempty" toml:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mergeable tells if the given service is mergeable.
|
||||||
|
func (l *TCPLoadBalancerService) Mergeable(loadBalancer *TCPLoadBalancerService) bool {
|
||||||
|
savedServers := l.Servers
|
||||||
|
defer func() {
|
||||||
|
l.Servers = savedServers
|
||||||
|
}()
|
||||||
|
l.Servers = nil
|
||||||
|
|
||||||
|
savedServersLB := loadBalancer.Servers
|
||||||
|
defer func() {
|
||||||
|
loadBalancer.Servers = savedServersLB
|
||||||
|
}()
|
||||||
|
loadBalancer.Servers = nil
|
||||||
|
|
||||||
|
return reflect.DeepEqual(l, loadBalancer)
|
||||||
|
}
|
||||||
|
|
||||||
// Mergeable tells if the given service is mergeable.
|
// Mergeable tells if the given service is mergeable.
|
||||||
func (l *LoadBalancerService) Mergeable(loadBalancer *LoadBalancerService) bool {
|
func (l *LoadBalancerService) Mergeable(loadBalancer *LoadBalancerService) bool {
|
||||||
savedServers := l.Servers
|
savedServers := l.Servers
|
||||||
|
@ -70,6 +87,11 @@ func (l *LoadBalancerService) Mergeable(loadBalancer *LoadBalancerService) bool
|
||||||
return reflect.DeepEqual(l, loadBalancer)
|
return reflect.DeepEqual(l, loadBalancer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetDefaults Default values for a LoadBalancerService.
|
||||||
|
func (l *TCPLoadBalancerService) SetDefaults() {
|
||||||
|
l.Method = "wrr"
|
||||||
|
}
|
||||||
|
|
||||||
// SetDefaults Default values for a LoadBalancerService.
|
// SetDefaults Default values for a LoadBalancerService.
|
||||||
func (l *LoadBalancerService) SetDefaults() {
|
func (l *LoadBalancerService) SetDefaults() {
|
||||||
l.PassHostHeader = true
|
l.PassHostHeader = true
|
||||||
|
@ -97,9 +119,15 @@ type Server struct {
|
||||||
// TCPServer holds a TCP Server configuration
|
// TCPServer holds a TCP Server configuration
|
||||||
type TCPServer struct {
|
type TCPServer struct {
|
||||||
Address string `json:"address" label:"-"`
|
Address string `json:"address" label:"-"`
|
||||||
|
Port string `toml:"-" json:"-"`
|
||||||
Weight int `json:"weight"`
|
Weight int `json:"weight"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetDefaults Default values for a Server.
|
||||||
|
func (s *TCPServer) SetDefaults() {
|
||||||
|
s.Weight = 1
|
||||||
|
}
|
||||||
|
|
||||||
// SetDefaults Default values for a Server.
|
// SetDefaults Default values for a Server.
|
||||||
func (s *Server) SetDefaults() {
|
func (s *Server) SetDefaults() {
|
||||||
s.Weight = 1
|
s.Weight = 1
|
||||||
|
|
|
@ -383,6 +383,9 @@ func (p *Provider) watchNewDomains(ctx context.Context) {
|
||||||
case config := <-p.configFromListenerChan:
|
case config := <-p.configFromListenerChan:
|
||||||
if config.TCP != nil {
|
if config.TCP != nil {
|
||||||
for routerName, route := range config.TCP.Routers {
|
for routerName, route := range config.TCP.Routers {
|
||||||
|
if route.TLS == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
ctxRouter := log.With(ctx, log.Str(log.RouterName, routerName), log.Str(log.Rule, route.Rule))
|
ctxRouter := log.With(ctx, log.Str(log.RouterName, routerName), log.Str(log.Rule, route.Rule))
|
||||||
|
|
||||||
domains, err := rules.ParseHostSNI(route.Rule)
|
domains, err := rules.ParseHostSNI(route.Rule)
|
||||||
|
@ -395,6 +398,9 @@ func (p *Provider) watchNewDomains(ctx context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for routerName, route := range config.HTTP.Routers {
|
for routerName, route := range config.HTTP.Routers {
|
||||||
|
if route.TLS == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
ctxRouter := log.With(ctx, log.Str(log.RouterName, routerName), log.Str(log.Rule, route.Rule))
|
ctxRouter := log.With(ctx, log.Str(log.RouterName, routerName), log.Str(log.Rule, route.Rule))
|
||||||
|
|
||||||
domains, err := rules.ParseDomains(route.Rule)
|
domains, err := rules.ParseDomains(route.Rule)
|
||||||
|
|
|
@ -82,6 +82,7 @@ func (p ProviderAggregator) Provide(configurationChan chan<- config.Message, poo
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, prd := range p.providers {
|
for _, prd := range p.providers {
|
||||||
|
prd := prd
|
||||||
safe.Go(func() {
|
safe.Go(func() {
|
||||||
launchProvider(configurationChan, pool, prd)
|
launchProvider(configurationChan, pool, prd)
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,105 +0,0 @@
|
||||||
package provider
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
|
||||||
"github.com/Masterminds/sprig"
|
|
||||||
"github.com/containous/traefik/pkg/config"
|
|
||||||
"github.com/containous/traefik/pkg/log"
|
|
||||||
"github.com/containous/traefik/pkg/tls"
|
|
||||||
"github.com/containous/traefik/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// BaseProvider should be inherited by providers.
|
|
||||||
type BaseProvider struct {
|
|
||||||
Watch bool `description:"Watch provider" export:"true"`
|
|
||||||
Filename string `description:"Override default configuration template. For advanced users :)" export:"true"`
|
|
||||||
Constraints types.Constraints `description:"Filter services by constraint, matching with Traefik tags." export:"true"`
|
|
||||||
Trace bool `description:"Display additional provider logs (if available)." export:"true"`
|
|
||||||
DebugLogGeneratedTemplate bool `description:"Enable debug logging of generated configuration template." export:"true"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Init for compatibility reason the BaseProvider implements an empty Init.
|
|
||||||
func (p *BaseProvider) Init() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatchConstraints must match with EVERY single constraint
|
|
||||||
// returns first constraint that do not match or nil.
|
|
||||||
func (p *BaseProvider) MatchConstraints(tags []string) (bool, *types.Constraint) {
|
|
||||||
// if there is no tags and no constraints, filtering is disabled
|
|
||||||
if len(tags) == 0 && len(p.Constraints) == 0 {
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, constraint := range p.Constraints {
|
|
||||||
// xor: if ok and constraint.MustMatch are equal, then no tag is currently matching with the constraint
|
|
||||||
if ok := constraint.MatchConstraintWithAtLeastOneTag(tags); ok != constraint.MustMatch {
|
|
||||||
return false, constraint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no constraint or every constraints matching
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateConfiguration creates a provider configuration from content using templating.
|
|
||||||
func (p *BaseProvider) CreateConfiguration(tmplContent string, funcMap template.FuncMap, templateObjects interface{}) (*config.Configuration, error) {
|
|
||||||
var defaultFuncMap = sprig.TxtFuncMap()
|
|
||||||
// tolower is deprecated in favor of sprig's lower function
|
|
||||||
defaultFuncMap["tolower"] = strings.ToLower
|
|
||||||
defaultFuncMap["normalize"] = Normalize
|
|
||||||
defaultFuncMap["split"] = split
|
|
||||||
for funcID, funcElement := range funcMap {
|
|
||||||
defaultFuncMap[funcID] = funcElement
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpl := template.New(p.Filename).Funcs(defaultFuncMap)
|
|
||||||
|
|
||||||
_, err := tmpl.Parse(tmplContent)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var buffer bytes.Buffer
|
|
||||||
err = tmpl.Execute(&buffer, templateObjects)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var renderedTemplate = buffer.String()
|
|
||||||
if p.DebugLogGeneratedTemplate {
|
|
||||||
log.Debugf("Template content: %s", tmplContent)
|
|
||||||
log.Debugf("Rendering results: %s", renderedTemplate)
|
|
||||||
}
|
|
||||||
return p.DecodeConfiguration(renderedTemplate)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DecodeConfiguration Decodes a *types.Configuration from a content.
|
|
||||||
func (p *BaseProvider) DecodeConfiguration(content string) (*config.Configuration, error) {
|
|
||||||
configuration := &config.Configuration{
|
|
||||||
HTTP: &config.HTTPConfiguration{
|
|
||||||
Routers: make(map[string]*config.Router),
|
|
||||||
Middlewares: make(map[string]*config.Middleware),
|
|
||||||
Services: make(map[string]*config.Service),
|
|
||||||
},
|
|
||||||
TCP: &config.TCPConfiguration{
|
|
||||||
Routers: make(map[string]*config.TCPRouter),
|
|
||||||
Services: make(map[string]*config.TCPService),
|
|
||||||
},
|
|
||||||
TLS: make([]*tls.Configuration, 0),
|
|
||||||
TLSStores: make(map[string]tls.Store),
|
|
||||||
TLSOptions: make(map[string]tls.TLS),
|
|
||||||
}
|
|
||||||
if _, err := toml.Decode(content, configuration); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return configuration, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func split(sep, s string) []string {
|
|
||||||
return strings.Split(s, sep)
|
|
||||||
}
|
|
|
@ -36,6 +36,12 @@ func Merge(ctx context.Context, configurations map[string]*config.Configuration)
|
||||||
routersToDelete := map[string]struct{}{}
|
routersToDelete := map[string]struct{}{}
|
||||||
routers := map[string][]string{}
|
routers := map[string][]string{}
|
||||||
|
|
||||||
|
servicesTCPToDelete := map[string]struct{}{}
|
||||||
|
servicesTCP := map[string][]string{}
|
||||||
|
|
||||||
|
routersTCPToDelete := map[string]struct{}{}
|
||||||
|
routersTCP := map[string][]string{}
|
||||||
|
|
||||||
middlewaresToDelete := map[string]struct{}{}
|
middlewaresToDelete := map[string]struct{}{}
|
||||||
middlewares := map[string][]string{}
|
middlewares := map[string][]string{}
|
||||||
|
|
||||||
|
@ -61,6 +67,20 @@ func Merge(ctx context.Context, configurations map[string]*config.Configuration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for serviceName, service := range conf.TCP.Services {
|
||||||
|
servicesTCP[serviceName] = append(servicesTCP[serviceName], root)
|
||||||
|
if !AddServiceTCP(configuration.TCP, serviceName, service) {
|
||||||
|
servicesTCPToDelete[serviceName] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for routerName, router := range conf.TCP.Routers {
|
||||||
|
routersTCP[routerName] = append(routersTCP[routerName], root)
|
||||||
|
if !AddRouterTCP(configuration.TCP, routerName, router) {
|
||||||
|
routersTCPToDelete[routerName] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for middlewareName, middleware := range conf.HTTP.Middlewares {
|
for middlewareName, middleware := range conf.HTTP.Middlewares {
|
||||||
middlewares[middlewareName] = append(middlewares[middlewareName], root)
|
middlewares[middlewareName] = append(middlewares[middlewareName], root)
|
||||||
if !AddMiddleware(configuration.HTTP, middlewareName, middleware) {
|
if !AddMiddleware(configuration.HTTP, middlewareName, middleware) {
|
||||||
|
@ -81,6 +101,18 @@ func Merge(ctx context.Context, configurations map[string]*config.Configuration)
|
||||||
delete(configuration.HTTP.Routers, routerName)
|
delete(configuration.HTTP.Routers, routerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for serviceName := range servicesTCPToDelete {
|
||||||
|
logger.WithField(log.ServiceName, serviceName).
|
||||||
|
Errorf("Service TCP defined multiple times with different configurations in %v", servicesTCP[serviceName])
|
||||||
|
delete(configuration.TCP.Services, serviceName)
|
||||||
|
}
|
||||||
|
|
||||||
|
for routerName := range routersTCPToDelete {
|
||||||
|
logger.WithField(log.RouterName, routerName).
|
||||||
|
Errorf("Router TCP defined multiple times with different configurations in %v", routersTCP[routerName])
|
||||||
|
delete(configuration.TCP.Routers, routerName)
|
||||||
|
}
|
||||||
|
|
||||||
for middlewareName := range middlewaresToDelete {
|
for middlewareName := range middlewaresToDelete {
|
||||||
logger.WithField(log.MiddlewareName, middlewareName).
|
logger.WithField(log.MiddlewareName, middlewareName).
|
||||||
Errorf("Middleware defined multiple times with different configurations in %v", middlewares[middlewareName])
|
Errorf("Middleware defined multiple times with different configurations in %v", middlewares[middlewareName])
|
||||||
|
@ -90,6 +122,31 @@ func Merge(ctx context.Context, configurations map[string]*config.Configuration)
|
||||||
return configuration
|
return configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddServiceTCP Adds a service to a configurations.
|
||||||
|
func AddServiceTCP(configuration *config.TCPConfiguration, serviceName string, service *config.TCPService) bool {
|
||||||
|
if _, ok := configuration.Services[serviceName]; !ok {
|
||||||
|
configuration.Services[serviceName] = service
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !configuration.Services[serviceName].LoadBalancer.Mergeable(service.LoadBalancer) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
configuration.Services[serviceName].LoadBalancer.Servers = append(configuration.Services[serviceName].LoadBalancer.Servers, service.LoadBalancer.Servers...)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddRouterTCP Adds a router to a configurations.
|
||||||
|
func AddRouterTCP(configuration *config.TCPConfiguration, routerName string, router *config.TCPRouter) bool {
|
||||||
|
if _, ok := configuration.Routers[routerName]; !ok {
|
||||||
|
configuration.Routers[routerName] = router
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return reflect.DeepEqual(configuration.Routers[routerName], router)
|
||||||
|
}
|
||||||
|
|
||||||
// AddService Adds a service to a configurations.
|
// AddService Adds a service to a configurations.
|
||||||
func AddService(configuration *config.HTTPConfiguration, serviceName string, service *config.Service) bool {
|
func AddService(configuration *config.HTTPConfiguration, serviceName string, service *config.Service) bool {
|
||||||
if _, ok := configuration.Services[serviceName]; !ok {
|
if _, ok := configuration.Services[serviceName]; !ok {
|
||||||
|
@ -137,10 +194,33 @@ func MakeDefaultRuleTemplate(defaultRule string, funcMap template.FuncMap) (*tem
|
||||||
return template.New("defaultRule").Funcs(defaultFuncMap).Parse(defaultRule)
|
return template.New("defaultRule").Funcs(defaultFuncMap).Parse(defaultRule)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BuildTCPRouterConfiguration Builds a router configuration.
|
||||||
|
func BuildTCPRouterConfiguration(ctx context.Context, configuration *config.TCPConfiguration) {
|
||||||
|
for routerName, router := range configuration.Routers {
|
||||||
|
loggerRouter := log.FromContext(ctx).WithField(log.RouterName, routerName)
|
||||||
|
if len(router.Rule) == 0 {
|
||||||
|
delete(configuration.Routers, routerName)
|
||||||
|
loggerRouter.Errorf("Empty rule")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(router.Service) == 0 {
|
||||||
|
if len(configuration.Services) > 1 {
|
||||||
|
delete(configuration.Routers, routerName)
|
||||||
|
loggerRouter.
|
||||||
|
Error("Could not define the service name for the router: too many services")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for serviceName := range configuration.Services {
|
||||||
|
router.Service = serviceName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// BuildRouterConfiguration Builds a router configuration.
|
// BuildRouterConfiguration Builds a router configuration.
|
||||||
func BuildRouterConfiguration(ctx context.Context, configuration *config.HTTPConfiguration, defaultRouterName string, defaultRuleTpl *template.Template, model interface{}) {
|
func BuildRouterConfiguration(ctx context.Context, configuration *config.HTTPConfiguration, defaultRouterName string, defaultRuleTpl *template.Template, model interface{}) {
|
||||||
logger := log.FromContext(ctx)
|
|
||||||
|
|
||||||
if len(configuration.Routers) == 0 {
|
if len(configuration.Routers) == 0 {
|
||||||
if len(configuration.Services) > 1 {
|
if len(configuration.Services) > 1 {
|
||||||
log.FromContext(ctx).Info("Could not create a router for the container: too many services")
|
log.FromContext(ctx).Info("Could not create a router for the container: too many services")
|
||||||
|
@ -151,7 +231,7 @@ func BuildRouterConfiguration(ctx context.Context, configuration *config.HTTPCon
|
||||||
}
|
}
|
||||||
|
|
||||||
for routerName, router := range configuration.Routers {
|
for routerName, router := range configuration.Routers {
|
||||||
loggerRouter := logger.WithField(log.RouterName, routerName)
|
loggerRouter := log.FromContext(ctx).WithField(log.RouterName, routerName)
|
||||||
if len(router.Rule) == 0 {
|
if len(router.Rule) == 0 {
|
||||||
writer := &bytes.Buffer{}
|
writer := &bytes.Buffer{}
|
||||||
if err := defaultRuleTpl.Execute(writer, model); err != nil {
|
if err := defaultRuleTpl.Execute(writer, model); err != nil {
|
||||||
|
|
27
pkg/provider/constrainer.go
Normal file
27
pkg/provider/constrainer.go
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package provider
|
||||||
|
|
||||||
|
import "github.com/containous/traefik/pkg/types"
|
||||||
|
|
||||||
|
// Constrainer Filter services by constraint, matching with Traefik tags.
|
||||||
|
type Constrainer struct {
|
||||||
|
Constraints types.Constraints `description:"Filter services by constraint, matching with Traefik tags." export:"true"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// MatchConstraints must match with EVERY single constraint
|
||||||
|
// returns first constraint that do not match or nil.
|
||||||
|
func (c *Constrainer) MatchConstraints(tags []string) (bool, *types.Constraint) {
|
||||||
|
// if there is no tags and no constraints, filtering is disabled
|
||||||
|
if len(tags) == 0 && len(c.Constraints) == 0 {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, constraint := range c.Constraints {
|
||||||
|
// xor: if ok and constraint.MustMatch are equal, then no tag is currently matching with the constraint
|
||||||
|
if ok := constraint.MatchConstraintWithAtLeastOneTag(tags); ok != constraint.MustMatch {
|
||||||
|
return false, constraint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no constraint or every constraints matching
|
||||||
|
return true, nil
|
||||||
|
}
|
|
@ -33,6 +33,21 @@ func (p *Provider) buildConfiguration(ctx context.Context, containersInspected [
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(confFromLabel.TCP.Routers) > 0 || len(confFromLabel.TCP.Services) > 0 {
|
||||||
|
err := p.buildTCPServiceConfiguration(ctxContainer, container, confFromLabel.TCP)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
provider.BuildTCPRouterConfiguration(ctxContainer, confFromLabel.TCP)
|
||||||
|
if len(confFromLabel.HTTP.Routers) == 0 &&
|
||||||
|
len(confFromLabel.HTTP.Middlewares) == 0 &&
|
||||||
|
len(confFromLabel.HTTP.Services) == 0 {
|
||||||
|
configurations[containerName] = confFromLabel
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = p.buildServiceConfiguration(ctxContainer, container, confFromLabel.HTTP)
|
err = p.buildServiceConfiguration(ctxContainer, container, confFromLabel.HTTP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
|
@ -57,6 +72,28 @@ func (p *Provider) buildConfiguration(ctx context.Context, containersInspected [
|
||||||
return provider.Merge(ctx, configurations)
|
return provider.Merge(ctx, configurations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Provider) buildTCPServiceConfiguration(ctx context.Context, container dockerData, configuration *config.TCPConfiguration) error {
|
||||||
|
serviceName := getServiceName(container)
|
||||||
|
|
||||||
|
if len(configuration.Services) == 0 {
|
||||||
|
configuration.Services = make(map[string]*config.TCPService)
|
||||||
|
lb := &config.TCPLoadBalancerService{}
|
||||||
|
lb.SetDefaults()
|
||||||
|
configuration.Services[serviceName] = &config.TCPService{
|
||||||
|
LoadBalancer: lb,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, service := range configuration.Services {
|
||||||
|
err := p.addServerTCP(ctx, container, service.LoadBalancer)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Provider) buildServiceConfiguration(ctx context.Context, container dockerData, configuration *config.HTTPConfiguration) error {
|
func (p *Provider) buildServiceConfiguration(ctx context.Context, container dockerData, configuration *config.HTTPConfiguration) error {
|
||||||
serviceName := getServiceName(container)
|
serviceName := getServiceName(container)
|
||||||
|
|
||||||
|
@ -102,6 +139,36 @@ func (p *Provider) keepContainer(ctx context.Context, container dockerData) bool
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Provider) addServerTCP(ctx context.Context, container dockerData, loadBalancer *config.TCPLoadBalancerService) error {
|
||||||
|
serverPort := ""
|
||||||
|
if loadBalancer != nil && len(loadBalancer.Servers) > 0 {
|
||||||
|
serverPort = loadBalancer.Servers[0].Port
|
||||||
|
}
|
||||||
|
ip, port, err := p.getIPPort(ctx, container, serverPort)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(loadBalancer.Servers) == 0 {
|
||||||
|
server := config.TCPServer{}
|
||||||
|
server.SetDefaults()
|
||||||
|
|
||||||
|
loadBalancer.Servers = []config.TCPServer{server}
|
||||||
|
}
|
||||||
|
|
||||||
|
if serverPort != "" {
|
||||||
|
port = serverPort
|
||||||
|
loadBalancer.Servers[0].Port = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
if port == "" {
|
||||||
|
return errors.New("port is missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
loadBalancer.Servers[0].Address = net.JoinHostPort(ip, port)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Provider) addServer(ctx context.Context, container dockerData, loadBalancer *config.LoadBalancerService) error {
|
func (p *Provider) addServer(ctx context.Context, container dockerData, loadBalancer *config.LoadBalancerService) error {
|
||||||
serverPort := getLBServerPort(loadBalancer)
|
serverPort := getLBServerPort(loadBalancer)
|
||||||
ip, port, err := p.getIPPort(ctx, container, serverPort)
|
ip, port, err := p.getIPPort(ctx, container, serverPort)
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -41,7 +41,8 @@ var _ provider.Provider = (*Provider)(nil)
|
||||||
|
|
||||||
// Provider holds configurations of the provider.
|
// Provider holds configurations of the provider.
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
provider.BaseProvider `mapstructure:",squash" export:"true"`
|
provider.Constrainer `mapstructure:",squash" export:"true"`
|
||||||
|
Watch bool `description:"Watch provider" export:"true"`
|
||||||
Endpoint string `description:"Docker server endpoint. Can be a tcp or a unix socket endpoint"`
|
Endpoint string `description:"Docker server endpoint. Can be a tcp or a unix socket endpoint"`
|
||||||
DefaultRule string `description:"Default rule"`
|
DefaultRule string `description:"Default rule"`
|
||||||
TLS *types.ClientTLS `description:"Enable Docker TLS support" export:"true"`
|
TLS *types.ClientTLS `description:"Enable Docker TLS support" export:"true"`
|
||||||
|
@ -61,7 +62,7 @@ func (p *Provider) Init() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
p.defaultRuleTpl = defaultRuleTpl
|
p.defaultRuleTpl = defaultRuleTpl
|
||||||
return p.BaseProvider.Init()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// dockerData holds the need data to the provider.
|
// dockerData holds the need data to the provider.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package file
|
package file
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -10,6 +11,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/BurntSushi/toml"
|
||||||
|
"github.com/Masterminds/sprig"
|
||||||
"github.com/containous/traefik/pkg/config"
|
"github.com/containous/traefik/pkg/config"
|
||||||
"github.com/containous/traefik/pkg/log"
|
"github.com/containous/traefik/pkg/log"
|
||||||
"github.com/containous/traefik/pkg/provider"
|
"github.com/containous/traefik/pkg/provider"
|
||||||
|
@ -25,14 +28,16 @@ var _ provider.Provider = (*Provider)(nil)
|
||||||
|
|
||||||
// Provider holds configurations of the provider.
|
// Provider holds configurations of the provider.
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
provider.BaseProvider `mapstructure:",squash" export:"true"`
|
Directory string `description:"Load configuration from one or more .toml files in a directory" export:"true"`
|
||||||
Directory string `description:"Load configuration from one or more .toml files in a directory" export:"true"`
|
Watch bool `description:"Watch provider" export:"true"`
|
||||||
TraefikFile string
|
Filename string `description:"Override default configuration template. For advanced users :)" export:"true"`
|
||||||
|
DebugLogGeneratedTemplate bool `description:"Enable debug logging of generated configuration template." export:"true"`
|
||||||
|
TraefikFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init the provider
|
// Init the provider
|
||||||
func (p *Provider) Init() error {
|
func (p *Provider) Init() error {
|
||||||
return p.BaseProvider.Init()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide allows the file provider to provide configurations to traefik
|
// Provide allows the file provider to provide configurations to traefik
|
||||||
|
@ -305,3 +310,55 @@ func (p *Provider) loadFileConfigFromDirectory(ctx context.Context, directory st
|
||||||
}
|
}
|
||||||
return configuration, nil
|
return configuration, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateConfiguration creates a provider configuration from content using templating.
|
||||||
|
func (p *Provider) CreateConfiguration(tmplContent string, funcMap template.FuncMap, templateObjects interface{}) (*config.Configuration, error) {
|
||||||
|
var defaultFuncMap = sprig.TxtFuncMap()
|
||||||
|
defaultFuncMap["normalize"] = provider.Normalize
|
||||||
|
defaultFuncMap["split"] = strings.Split
|
||||||
|
for funcID, funcElement := range funcMap {
|
||||||
|
defaultFuncMap[funcID] = funcElement
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl := template.New(p.Filename).Funcs(defaultFuncMap)
|
||||||
|
|
||||||
|
_, err := tmpl.Parse(tmplContent)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
err = tmpl.Execute(&buffer, templateObjects)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var renderedTemplate = buffer.String()
|
||||||
|
if p.DebugLogGeneratedTemplate {
|
||||||
|
log.Debugf("Template content: %s", tmplContent)
|
||||||
|
log.Debugf("Rendering results: %s", renderedTemplate)
|
||||||
|
}
|
||||||
|
return p.DecodeConfiguration(renderedTemplate)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeConfiguration Decodes a *types.Configuration from a content.
|
||||||
|
func (p *Provider) DecodeConfiguration(content string) (*config.Configuration, error) {
|
||||||
|
configuration := &config.Configuration{
|
||||||
|
HTTP: &config.HTTPConfiguration{
|
||||||
|
Routers: make(map[string]*config.Router),
|
||||||
|
Middlewares: make(map[string]*config.Middleware),
|
||||||
|
Services: make(map[string]*config.Service),
|
||||||
|
},
|
||||||
|
TCP: &config.TCPConfiguration{
|
||||||
|
Routers: make(map[string]*config.TCPRouter),
|
||||||
|
Services: make(map[string]*config.TCPService),
|
||||||
|
},
|
||||||
|
TLS: make([]*tls.Configuration, 0),
|
||||||
|
TLSStores: make(map[string]tls.Store),
|
||||||
|
TLSOptions: make(map[string]tls.TLS),
|
||||||
|
}
|
||||||
|
if _, err := toml.Decode(content, configuration); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return configuration, nil
|
||||||
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ type clientWrapper struct {
|
||||||
factoriesCrd map[string]externalversions.SharedInformerFactory
|
factoriesCrd map[string]externalversions.SharedInformerFactory
|
||||||
factoriesKube map[string]informers.SharedInformerFactory
|
factoriesKube map[string]informers.SharedInformerFactory
|
||||||
|
|
||||||
ingressLabelSelector labels.Selector
|
labelSelector labels.Selector
|
||||||
|
|
||||||
isNamespaceAll bool
|
isNamespaceAll bool
|
||||||
watchedNamespaces k8s.Namespaces
|
watchedNamespaces k8s.Namespaces
|
||||||
|
@ -202,7 +202,7 @@ func (c *clientWrapper) GetIngressRoutes() []*v1alpha1.IngressRoute {
|
||||||
var result []*v1alpha1.IngressRoute
|
var result []*v1alpha1.IngressRoute
|
||||||
|
|
||||||
for ns, factory := range c.factoriesCrd {
|
for ns, factory := range c.factoriesCrd {
|
||||||
ings, err := factory.Traefik().V1alpha1().IngressRoutes().Lister().List(c.ingressLabelSelector)
|
ings, err := factory.Traefik().V1alpha1().IngressRoutes().Lister().List(c.labelSelector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err)
|
log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err)
|
||||||
}
|
}
|
||||||
|
@ -216,7 +216,7 @@ func (c *clientWrapper) GetMiddlewares() []*v1alpha1.Middleware {
|
||||||
var result []*v1alpha1.Middleware
|
var result []*v1alpha1.Middleware
|
||||||
|
|
||||||
for ns, factory := range c.factoriesCrd {
|
for ns, factory := range c.factoriesCrd {
|
||||||
ings, err := factory.Traefik().V1alpha1().Middlewares().Lister().List(c.ingressLabelSelector)
|
ings, err := factory.Traefik().V1alpha1().Middlewares().Lister().List(c.labelSelector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err)
|
log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err)
|
||||||
}
|
}
|
||||||
|
@ -230,7 +230,7 @@ func (c *clientWrapper) GetMiddlewares() []*v1alpha1.Middleware {
|
||||||
func (c *clientWrapper) GetIngresses() []*extensionsv1beta1.Ingress {
|
func (c *clientWrapper) GetIngresses() []*extensionsv1beta1.Ingress {
|
||||||
var result []*extensionsv1beta1.Ingress
|
var result []*extensionsv1beta1.Ingress
|
||||||
for ns, factory := range c.factoriesKube {
|
for ns, factory := range c.factoriesKube {
|
||||||
ings, err := factory.Extensions().V1beta1().Ingresses().Lister().List(c.ingressLabelSelector)
|
ings, err := factory.Extensions().V1beta1().Ingresses().Lister().List(c.labelSelector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err)
|
log.Errorf("Failed to list ingresses in namespace %s: %s", ns, err)
|
||||||
}
|
}
|
||||||
|
@ -320,7 +320,7 @@ func (c *clientWrapper) newResourceEventHandler(events chan<- interface{}) cache
|
||||||
// Ignore Ingresses that do not match our custom label selector.
|
// Ignore Ingresses that do not match our custom label selector.
|
||||||
if ing, ok := obj.(*extensionsv1beta1.Ingress); ok {
|
if ing, ok := obj.(*extensionsv1beta1.Ingress); ok {
|
||||||
lbls := labels.Set(ing.GetLabels())
|
lbls := labels.Set(ing.GetLabels())
|
||||||
return c.ingressLabelSelector.Matches(lbls)
|
return c.labelSelector.Matches(lbls)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
|
20
pkg/provider/kubernetes/crd/fixtures/with_tls_acme.yml
Normal file
20
pkg/provider/kubernetes/crd/fixtures/with_tls_acme.yml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
apiVersion: traefik.containo.us/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: test.crd
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- web
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: Host(`foo.com`) && PathPrefix(`/bar`)
|
||||||
|
kind: Rule
|
||||||
|
priority: 12
|
||||||
|
services:
|
||||||
|
- name: whoami
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
tls:
|
||||||
|
secretName:
|
|
@ -16,7 +16,6 @@ import (
|
||||||
"github.com/containous/traefik/pkg/config"
|
"github.com/containous/traefik/pkg/config"
|
||||||
"github.com/containous/traefik/pkg/job"
|
"github.com/containous/traefik/pkg/job"
|
||||||
"github.com/containous/traefik/pkg/log"
|
"github.com/containous/traefik/pkg/log"
|
||||||
"github.com/containous/traefik/pkg/provider"
|
|
||||||
"github.com/containous/traefik/pkg/provider/kubernetes/crd/traefik/v1alpha1"
|
"github.com/containous/traefik/pkg/provider/kubernetes/crd/traefik/v1alpha1"
|
||||||
"github.com/containous/traefik/pkg/provider/kubernetes/k8s"
|
"github.com/containous/traefik/pkg/provider/kubernetes/k8s"
|
||||||
"github.com/containous/traefik/pkg/safe"
|
"github.com/containous/traefik/pkg/safe"
|
||||||
|
@ -33,23 +32,22 @@ const (
|
||||||
|
|
||||||
// Provider holds configurations of the provider.
|
// Provider holds configurations of the provider.
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
provider.BaseProvider `mapstructure:",squash" export:"true"`
|
|
||||||
Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)"`
|
Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)"`
|
||||||
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)"`
|
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)"`
|
||||||
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)"`
|
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)"`
|
||||||
DisablePassHostHeaders bool `description:"Kubernetes disable PassHost Headers" export:"true"`
|
DisablePassHostHeaders bool `description:"Kubernetes disable PassHost Headers" export:"true"`
|
||||||
Namespaces k8s.Namespaces `description:"Kubernetes namespaces" export:"true"`
|
Namespaces k8s.Namespaces `description:"Kubernetes namespaces" export:"true"`
|
||||||
LabelSelector string `description:"Kubernetes Ingress label selector to use" export:"true"`
|
LabelSelector string `description:"Kubernetes label selector to use" export:"true"`
|
||||||
IngressClass string `description:"Value of kubernetes.io/ingress.class annotation to watch for" export:"true"`
|
IngressClass string `description:"Value of kubernetes.io/ingress.class annotation to watch for" export:"true"`
|
||||||
lastConfiguration safe.Safe
|
lastConfiguration safe.Safe
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Provider) newK8sClient(ctx context.Context, ingressLabelSelector string) (*clientWrapper, error) {
|
func (p *Provider) newK8sClient(ctx context.Context, labelSelector string) (*clientWrapper, error) {
|
||||||
ingLabelSel, err := labels.Parse(ingressLabelSelector)
|
labelSel, err := labels.Parse(labelSelector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("invalid ingress label selector: %q", ingressLabelSelector)
|
return nil, fmt.Errorf("invalid label selector: %q", labelSelector)
|
||||||
}
|
}
|
||||||
log.FromContext(ctx).Infof("ingress label selector is: %q", ingLabelSel)
|
log.FromContext(ctx).Infof("label selector is: %q", labelSel)
|
||||||
|
|
||||||
withEndpoint := ""
|
withEndpoint := ""
|
||||||
if p.Endpoint != "" {
|
if p.Endpoint != "" {
|
||||||
|
@ -70,7 +68,7 @@ func (p *Provider) newK8sClient(ctx context.Context, ingressLabelSelector string
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
client.ingressLabelSelector = ingLabelSel
|
client.labelSelector = labelSel
|
||||||
}
|
}
|
||||||
|
|
||||||
return client, err
|
return client, err
|
||||||
|
@ -78,7 +76,7 @@ func (p *Provider) newK8sClient(ctx context.Context, ingressLabelSelector string
|
||||||
|
|
||||||
// Init the provider.
|
// Init the provider.
|
||||||
func (p *Provider) Init() error {
|
func (p *Provider) Init() error {
|
||||||
return p.BaseProvider.Init()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide allows the k8s provider to provide configurations to traefik
|
// Provide allows the k8s provider to provide configurations to traefik
|
||||||
|
@ -95,7 +93,7 @@ func (p *Provider) Provide(configurationChan chan<- config.Message, pool *safe.P
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Debugf("Using Ingress label selector: %q", p.LabelSelector)
|
logger.Debugf("Using label selector: %q", p.LabelSelector)
|
||||||
k8sClient, err := p.newK8sClient(ctxLog, p.LabelSelector)
|
k8sClient, err := p.newK8sClient(ctxLog, p.LabelSelector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -310,6 +310,43 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "TLS with ACME",
|
||||||
|
paths: []string{"services.yml", "with_tls_acme.yml"},
|
||||||
|
expected: &config.Configuration{
|
||||||
|
TCP: &config.TCPConfiguration{},
|
||||||
|
HTTP: &config.HTTPConfiguration{
|
||||||
|
Routers: map[string]*config.Router{
|
||||||
|
"default/test.crd-6b204d94623b3df4370c": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "default/test.crd-6b204d94623b3df4370c",
|
||||||
|
Rule: "Host(`foo.com`) && PathPrefix(`/bar`)",
|
||||||
|
Priority: 12,
|
||||||
|
TLS: &config.RouterTLSConfig{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: map[string]*config.Middleware{},
|
||||||
|
Services: map[string]*config.Service{
|
||||||
|
"default/test.crd-6b204d94623b3df4370c": {
|
||||||
|
LoadBalancer: &config.LoadBalancerService{
|
||||||
|
Servers: []config.Server{
|
||||||
|
{
|
||||||
|
URL: "http://10.10.0.1:80",
|
||||||
|
Weight: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
URL: "http://10.10.0.2:80",
|
||||||
|
Weight: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Method: "wrr",
|
||||||
|
PassHostHeader: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "Simple Ingress Route, defaulting to https for servers",
|
desc: "Simple Ingress Route, defaulting to https for servers",
|
||||||
paths: []string{"services.yml", "with_https_default.yml"},
|
paths: []string{"services.yml", "with_https_default.yml"},
|
||||||
|
|
|
@ -20,8 +20,11 @@ type Route struct {
|
||||||
Middlewares []MiddlewareRef `json:"middlewares"`
|
Middlewares []MiddlewareRef `json:"middlewares"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TLS contains the TLS certificates configuration of the routes.
|
// TLS contains the TLS certificates configuration of the routes. To enable
|
||||||
|
// Let's Encrypt, set a SecretName with an empty value.
|
||||||
type TLS struct {
|
type TLS struct {
|
||||||
|
// SecretName is the name of the referenced Kubernetes Secret to specify the
|
||||||
|
// certificate details.
|
||||||
SecretName string `json:"secretName"`
|
SecretName string `json:"secretName"`
|
||||||
// TODO MinimumProtocolVersion string `json:"minimumProtocolVersion,omitempty"`
|
// TODO MinimumProtocolVersion string `json:"minimumProtocolVersion,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@ import (
|
||||||
"github.com/containous/traefik/pkg/config"
|
"github.com/containous/traefik/pkg/config"
|
||||||
"github.com/containous/traefik/pkg/job"
|
"github.com/containous/traefik/pkg/job"
|
||||||
"github.com/containous/traefik/pkg/log"
|
"github.com/containous/traefik/pkg/log"
|
||||||
"github.com/containous/traefik/pkg/provider"
|
|
||||||
"github.com/containous/traefik/pkg/provider/kubernetes/k8s"
|
"github.com/containous/traefik/pkg/provider/kubernetes/k8s"
|
||||||
"github.com/containous/traefik/pkg/safe"
|
"github.com/containous/traefik/pkg/safe"
|
||||||
"github.com/containous/traefik/pkg/tls"
|
"github.com/containous/traefik/pkg/tls"
|
||||||
|
@ -34,7 +33,6 @@ const (
|
||||||
|
|
||||||
// Provider holds configurations of the provider.
|
// Provider holds configurations of the provider.
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
provider.BaseProvider `mapstructure:",squash" export:"true"`
|
|
||||||
Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)"`
|
Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)"`
|
||||||
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)"`
|
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)"`
|
||||||
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)"`
|
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)"`
|
||||||
|
@ -90,7 +88,7 @@ func (p *Provider) newK8sClient(ctx context.Context, ingressLabelSelector string
|
||||||
|
|
||||||
// Init the provider.
|
// Init the provider.
|
||||||
func (p *Provider) Init() error {
|
func (p *Provider) Init() error {
|
||||||
return p.BaseProvider.Init()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide allows the k8s provider to provide configurations to traefik
|
// Provide allows the k8s provider to provide configurations to traefik
|
||||||
|
|
|
@ -115,6 +115,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
||||||
"traefik.http.routers.Router0.middlewares": "foobar, fiibar",
|
"traefik.http.routers.Router0.middlewares": "foobar, fiibar",
|
||||||
"traefik.http.routers.Router0.priority": "42",
|
"traefik.http.routers.Router0.priority": "42",
|
||||||
"traefik.http.routers.Router0.rule": "foobar",
|
"traefik.http.routers.Router0.rule": "foobar",
|
||||||
|
"traefik.http.routers.Router0.tls": "true",
|
||||||
"traefik.http.routers.Router0.service": "foobar",
|
"traefik.http.routers.Router0.service": "foobar",
|
||||||
"traefik.http.routers.Router1.entrypoints": "foobar, fiibar",
|
"traefik.http.routers.Router1.entrypoints": "foobar, fiibar",
|
||||||
"traefik.http.routers.Router1.middlewares": "foobar, fiibar",
|
"traefik.http.routers.Router1.middlewares": "foobar, fiibar",
|
||||||
|
@ -171,6 +172,7 @@ func TestDecodeConfiguration(t *testing.T) {
|
||||||
Service: "foobar",
|
Service: "foobar",
|
||||||
Rule: "foobar",
|
Rule: "foobar",
|
||||||
Priority: 42,
|
Priority: 42,
|
||||||
|
TLS: &config.RouterTLSConfig{},
|
||||||
},
|
},
|
||||||
"Router1": {
|
"Router1": {
|
||||||
EntryPoints: []string{
|
EntryPoints: []string{
|
||||||
|
@ -504,6 +506,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||||
Service: "foobar",
|
Service: "foobar",
|
||||||
Rule: "foobar",
|
Rule: "foobar",
|
||||||
Priority: 42,
|
Priority: 42,
|
||||||
|
TLS: &config.RouterTLSConfig{},
|
||||||
},
|
},
|
||||||
"Router1": {
|
"Router1": {
|
||||||
EntryPoints: []string{
|
EntryPoints: []string{
|
||||||
|
@ -925,6 +928,7 @@ func TestEncodeConfiguration(t *testing.T) {
|
||||||
"traefik.HTTP.Routers.Router0.Priority": "42",
|
"traefik.HTTP.Routers.Router0.Priority": "42",
|
||||||
"traefik.HTTP.Routers.Router0.Rule": "foobar",
|
"traefik.HTTP.Routers.Router0.Rule": "foobar",
|
||||||
"traefik.HTTP.Routers.Router0.Service": "foobar",
|
"traefik.HTTP.Routers.Router0.Service": "foobar",
|
||||||
|
"traefik.HTTP.Routers.Router0.TLS": "true",
|
||||||
"traefik.HTTP.Routers.Router1.EntryPoints": "foobar, fiibar",
|
"traefik.HTTP.Routers.Router1.EntryPoints": "foobar, fiibar",
|
||||||
"traefik.HTTP.Routers.Router1.Middlewares": "foobar, fiibar",
|
"traefik.HTTP.Routers.Router1.Middlewares": "foobar, fiibar",
|
||||||
"traefik.HTTP.Routers.Router1.Priority": "42",
|
"traefik.HTTP.Routers.Router1.Priority": "42",
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containous/traefik/pkg/provider"
|
|
||||||
"github.com/gambol99/go-marathon"
|
"github.com/gambol99/go-marathon"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -24,7 +23,6 @@ func TestGetConfiguration(t *testing.T) {
|
||||||
Labels: &map[string]string{},
|
Labels: &map[string]string{},
|
||||||
},
|
},
|
||||||
p: Provider{
|
p: Provider{
|
||||||
BaseProvider: provider.BaseProvider{},
|
|
||||||
ExposedByDefault: false,
|
ExposedByDefault: false,
|
||||||
FilterMarathonConstraints: false,
|
FilterMarathonConstraints: false,
|
||||||
},
|
},
|
||||||
|
@ -45,7 +43,6 @@ func TestGetConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
p: Provider{
|
p: Provider{
|
||||||
BaseProvider: provider.BaseProvider{},
|
|
||||||
ExposedByDefault: false,
|
ExposedByDefault: false,
|
||||||
FilterMarathonConstraints: false,
|
FilterMarathonConstraints: false,
|
||||||
},
|
},
|
||||||
|
@ -66,7 +63,6 @@ func TestGetConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
p: Provider{
|
p: Provider{
|
||||||
BaseProvider: provider.BaseProvider{},
|
|
||||||
ExposedByDefault: false,
|
ExposedByDefault: false,
|
||||||
FilterMarathonConstraints: false,
|
FilterMarathonConstraints: false,
|
||||||
},
|
},
|
||||||
|
@ -87,7 +83,6 @@ func TestGetConfiguration(t *testing.T) {
|
||||||
Labels: &map[string]string{},
|
Labels: &map[string]string{},
|
||||||
},
|
},
|
||||||
p: Provider{
|
p: Provider{
|
||||||
BaseProvider: provider.BaseProvider{},
|
|
||||||
ExposedByDefault: false,
|
ExposedByDefault: false,
|
||||||
FilterMarathonConstraints: true,
|
FilterMarathonConstraints: true,
|
||||||
},
|
},
|
||||||
|
@ -108,7 +103,6 @@ func TestGetConfiguration(t *testing.T) {
|
||||||
Labels: &map[string]string{},
|
Labels: &map[string]string{},
|
||||||
},
|
},
|
||||||
p: Provider{
|
p: Provider{
|
||||||
BaseProvider: provider.BaseProvider{},
|
|
||||||
ExposedByDefault: true,
|
ExposedByDefault: true,
|
||||||
FilterMarathonConstraints: false,
|
FilterMarathonConstraints: false,
|
||||||
},
|
},
|
||||||
|
@ -129,7 +123,6 @@ func TestGetConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
p: Provider{
|
p: Provider{
|
||||||
BaseProvider: provider.BaseProvider{},
|
|
||||||
ExposedByDefault: true,
|
ExposedByDefault: true,
|
||||||
FilterMarathonConstraints: false,
|
FilterMarathonConstraints: false,
|
||||||
},
|
},
|
||||||
|
@ -150,7 +143,6 @@ func TestGetConfiguration(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
p: Provider{
|
p: Provider{
|
||||||
BaseProvider: provider.BaseProvider{},
|
|
||||||
ExposedByDefault: true,
|
ExposedByDefault: true,
|
||||||
FilterMarathonConstraints: false,
|
FilterMarathonConstraints: false,
|
||||||
},
|
},
|
||||||
|
|
|
@ -46,7 +46,9 @@ var _ provider.Provider = (*Provider)(nil)
|
||||||
|
|
||||||
// Provider holds configuration of the provider.
|
// Provider holds configuration of the provider.
|
||||||
type Provider struct {
|
type Provider struct {
|
||||||
provider.BaseProvider
|
provider.Constrainer `mapstructure:",squash" export:"true"`
|
||||||
|
Trace bool `description:"Display additional provider logs." export:"true"`
|
||||||
|
Watch bool `description:"Watch provider" export:"true"`
|
||||||
Endpoint string `description:"Marathon server endpoint. You can also specify multiple endpoint for Marathon" export:"true"`
|
Endpoint string `description:"Marathon server endpoint. You can also specify multiple endpoint for Marathon" export:"true"`
|
||||||
DefaultRule string `description:"Default rule"`
|
DefaultRule string `description:"Default rule"`
|
||||||
ExposedByDefault bool `description:"Expose Marathon apps by default" export:"true"`
|
ExposedByDefault bool `description:"Expose Marathon apps by default" export:"true"`
|
||||||
|
@ -89,7 +91,7 @@ func (p *Provider) Init() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
p.defaultRuleTpl = defaultRuleTpl
|
p.defaultRuleTpl = defaultRuleTpl
|
||||||
return p.BaseProvider.Init()
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide allows the marathon provider to provide configurations to traefik
|
// Provide allows the marathon provider to provide configurations to traefik
|
||||||
|
|
|
@ -312,11 +312,13 @@ func (c *connectionTracker) Shutdown(ctx context.Context) error {
|
||||||
|
|
||||||
// Close close all the connections in the tracked connections list
|
// Close close all the connections in the tracked connections list
|
||||||
func (c *connectionTracker) Close() {
|
func (c *connectionTracker) Close() {
|
||||||
|
c.lock.Lock()
|
||||||
|
defer c.lock.Unlock()
|
||||||
for conn := range c.conns {
|
for conn := range c.conns {
|
||||||
if err := conn.Close(); err != nil {
|
if err := conn.Close(); err != nil {
|
||||||
log.WithoutContext().Errorf("Error while closing connection: %v", err)
|
log.WithoutContext().Errorf("Error while closing connection: %v", err)
|
||||||
}
|
}
|
||||||
c.RemoveConnection(conn)
|
delete(c.conns, conn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,9 @@ if [ -z "${VALIDATE_UPSTREAM:-}" ]; then
|
||||||
# are running more than one validate bundlescript
|
# are running more than one validate bundlescript
|
||||||
|
|
||||||
VALIDATE_REPO='https://github.com/containous/traefik.git'
|
VALIDATE_REPO='https://github.com/containous/traefik.git'
|
||||||
|
## FIXME wrong assumption
|
||||||
VALIDATE_BRANCH='master'
|
VALIDATE_BRANCH='master'
|
||||||
|
|
||||||
# Should not be needed for now O:)
|
|
||||||
# if [ "$TRAVIS" = 'true' -a "$TRAVIS_PULL_REQUEST" != 'false' ]; then
|
|
||||||
# VALIDATE_REPO="https://github.com/${TRAVIS_REPO_SLUG}.git"
|
|
||||||
# VALIDATE_BRANCH="${TRAVIS_BRANCH}"
|
|
||||||
# fi
|
|
||||||
|
|
||||||
VALIDATE_HEAD="$(git rev-parse --verify HEAD)"
|
VALIDATE_HEAD="$(git rev-parse --verify HEAD)"
|
||||||
|
|
||||||
git fetch -q "$VALIDATE_REPO" "refs/heads/$VALIDATE_BRANCH"
|
git fetch -q "$VALIDATE_REPO" "refs/heads/$VALIDATE_BRANCH"
|
||||||
|
@ -26,9 +21,4 @@ if [ -z "${VALIDATE_UPSTREAM:-}" ]; then
|
||||||
git diff "$VALIDATE_COMMIT_DIFF" "$@"
|
git diff "$VALIDATE_COMMIT_DIFF" "$@"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
validate_log() {
|
|
||||||
if [ "$VALIDATE_UPSTREAM" != "$VALIDATE_HEAD" ]; then
|
|
||||||
git log "$VALIDATE_COMMIT_LOG" "$@"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
./script/crossbinary-default
|
|
||||||
./script/crossbinary-others
|
|
|
@ -1,74 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if ! test -e autogen/genstatic/gen.go; then
|
|
||||||
echo >&2 'error: generate must be run before crossbinary'
|
|
||||||
false
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$VERSION" ]; then
|
|
||||||
VERSION=$(git rev-parse HEAD)
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$CODENAME" ]; then
|
|
||||||
CODENAME=cheddar
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$DATE" ]; then
|
|
||||||
DATE=$(date -u '+%Y-%m-%d_%I:%M:%S%p')
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Building ${VERSION} ${CODENAME} ${DATE}"
|
|
||||||
|
|
||||||
GIT_REPO_URL='github.com/containous/traefik/pkg/version'
|
|
||||||
GO_BUILD_CMD="go build -ldflags"
|
|
||||||
GO_BUILD_OPT="-s -w -X ${GIT_REPO_URL}.Version=${VERSION} -X ${GIT_REPO_URL}.Codename=${CODENAME} -X ${GIT_REPO_URL}.BuildDate=${DATE}"
|
|
||||||
|
|
||||||
# Build arm binaries
|
|
||||||
OS_PLATFORM_ARG=(linux windows darwin)
|
|
||||||
OS_ARCH_ARG=(386)
|
|
||||||
for OS in ${OS_PLATFORM_ARG[@]}; do
|
|
||||||
BIN_EXT=''
|
|
||||||
if [ "$OS" == "windows" ]; then
|
|
||||||
BIN_EXT='.exe'
|
|
||||||
fi
|
|
||||||
for ARCH in ${OS_ARCH_ARG[@]}; do
|
|
||||||
echo "Building binary for ${OS}/${ARCH}..."
|
|
||||||
GOARCH=${ARCH} GOOS=${OS} CGO_ENABLED=0 ${GO_BUILD_CMD} "${GO_BUILD_OPT}" -o "dist/traefik_${OS}-${ARCH}${BIN_EXT}" ./cmd/traefik/
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
# Build Bsd binaries
|
|
||||||
OS_PLATFORM_ARG=(freebsd openbsd)
|
|
||||||
OS_ARCH_ARG=(386 amd64)
|
|
||||||
for OS in ${OS_PLATFORM_ARG[@]}; do
|
|
||||||
for ARCH in ${OS_ARCH_ARG[@]}; do
|
|
||||||
# Get rid of existing binaries
|
|
||||||
rm -f dist/traefik_${OS}-${ARCH}
|
|
||||||
echo "Building binary for $OS/$ARCH..."
|
|
||||||
GOARCH=${ARCH} GOOS=${OS} CGO_ENABLED=0 ${GO_BUILD_CMD} "$GO_BUILD_OPT" -o "dist/traefik_$OS-$ARCH" ./cmd/traefik/
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
# Build arm binaries
|
|
||||||
OS_PLATFORM_ARG=(linux)
|
|
||||||
OS_ARCH_ARG=(arm)
|
|
||||||
ARM_ARG=(6)
|
|
||||||
for OS in ${OS_PLATFORM_ARG[@]}; do
|
|
||||||
for ARCH in ${OS_ARCH_ARG[@]}; do
|
|
||||||
for ARM in ${ARM_ARG[@]}; do
|
|
||||||
echo "Building binary for $OS/${ARCH}32v${ARM}..."
|
|
||||||
GOARCH=${ARCH} GOOS=${OS} GOARM=${ARM} CGO_ENABLED=0 ${GO_BUILD_CMD} "$GO_BUILD_OPT" -o "dist/traefik_$OS-${ARCH}" ./cmd/traefik/
|
|
||||||
done
|
|
||||||
done
|
|
||||||
done
|
|
||||||
|
|
||||||
# Build ppc64le binaries
|
|
||||||
OS_PLATFORM_ARG=(linux)
|
|
||||||
OS_ARCH_ARG=(ppc64le)
|
|
||||||
for OS in ${OS_PLATFORM_ARG[@]}; do
|
|
||||||
for ARCH in ${OS_ARCH_ARG[@]}; do
|
|
||||||
echo "Building binary for ${OS}/${ARCH}..."
|
|
||||||
GOARCH=${ARCH} GOOS=${OS} CGO_ENABLED=0 ${GO_BUILD_CMD} "${GO_BUILD_OPT}" -o "dist/traefik_${OS}-${ARCH}" ./cmd/traefik/
|
|
||||||
done
|
|
||||||
done
|
|
|
@ -1,19 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [ -n "$TRAVIS_COMMIT" ]; then
|
|
||||||
echo "Deploying PR..."
|
|
||||||
else
|
|
||||||
echo "Skipping deploy PR"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# create docker image containous/traefik
|
|
||||||
echo "Updating docker containous/traefik image..."
|
|
||||||
docker login -u $DOCKER_USER -p $DOCKER_PASS
|
|
||||||
docker tag containous/traefik containous/traefik:${TRAVIS_COMMIT}
|
|
||||||
docker push containous/traefik:${TRAVIS_COMMIT}
|
|
||||||
docker tag containous/traefik containous/traefik:experimental
|
|
||||||
docker push containous/traefik:experimental
|
|
||||||
|
|
||||||
echo "Deployed"
|
|
|
@ -22,7 +22,7 @@ ssh-add ~/.ssh/traefiker_rsa
|
||||||
echo "Updating traefik-library-imag repo..."
|
echo "Updating traefik-library-imag repo..."
|
||||||
git clone git@github.com:containous/traefik-library-image.git
|
git clone git@github.com:containous/traefik-library-image.git
|
||||||
cd traefik-library-image
|
cd traefik-library-image
|
||||||
./update.sh $VERSION
|
./updatev2.sh $VERSION
|
||||||
git add -A
|
git add -A
|
||||||
echo $VERSION | git commit --file -
|
echo $VERSION | git commit --file -
|
||||||
echo $VERSION | git tag -a $VERSION --file -
|
echo $VERSION | git tag -a $VERSION --file -
|
||||||
|
|
|
@ -1,20 +1,9 @@
|
||||||
################################################################
|
################################################################
|
||||||
# Global configuration
|
# Global configuration
|
||||||
################################################################
|
################################################################
|
||||||
|
[global]
|
||||||
# Enable debug mode
|
checkNewVersion = true
|
||||||
#
|
sendAnonymousUsage = true
|
||||||
# Optional
|
|
||||||
# Default: false
|
|
||||||
#
|
|
||||||
# debug = true
|
|
||||||
|
|
||||||
# Log level
|
|
||||||
#
|
|
||||||
# Optional
|
|
||||||
# Default: "ERROR"
|
|
||||||
#
|
|
||||||
# logLevel = "DEBUG"
|
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
# Entrypoints configuration
|
# Entrypoints configuration
|
||||||
|
@ -37,7 +26,14 @@
|
||||||
#
|
#
|
||||||
# Optional
|
# Optional
|
||||||
#
|
#
|
||||||
# [traefikLog]
|
[log]
|
||||||
|
|
||||||
|
# Log level
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
# Default: "ERROR"
|
||||||
|
#
|
||||||
|
# logLevel = "DEBUG"
|
||||||
|
|
||||||
# Sets the filepath for the traefik log. If not specified, stdout will be used.
|
# Sets the filepath for the traefik log. If not specified, stdout will be used.
|
||||||
# Intermediate directories are created if necessary.
|
# Intermediate directories are created if necessary.
|
||||||
|
@ -121,7 +117,7 @@
|
||||||
################################################################
|
################################################################
|
||||||
|
|
||||||
# Enable Docker configuration backend
|
# Enable Docker configuration backend
|
||||||
[docker]
|
[providers.docker]
|
||||||
|
|
||||||
# Docker server endpoint. Can be a tcp or a unix socket endpoint.
|
# Docker server endpoint. Can be a tcp or a unix socket endpoint.
|
||||||
#
|
#
|
||||||
|
@ -130,13 +126,12 @@
|
||||||
#
|
#
|
||||||
# endpoint = "tcp://10.10.10.10:2375"
|
# endpoint = "tcp://10.10.10.10:2375"
|
||||||
|
|
||||||
# Default domain used.
|
# Default host rule.
|
||||||
# Can be overridden by setting the "traefik.domain" label on a container.
|
|
||||||
#
|
#
|
||||||
# Optional
|
# Optional
|
||||||
# Default: ""
|
# Default: ""
|
||||||
#
|
#
|
||||||
# domain = "docker.localhost"
|
# DefaultRule = "Host(`{{ normalize .Name }}.docker.localhost`)"
|
||||||
|
|
||||||
# Expose containers by default in traefik
|
# Expose containers by default in traefik
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component, Inject } from '@angular/core';
|
||||||
|
import { DOCUMENT } from '@angular/common';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
|
@ -6,9 +7,30 @@ import { Component } from '@angular/core';
|
||||||
<main class="wip">
|
<main class="wip">
|
||||||
<img src="./assets/images/traefik.logo.svg" alt="logo" />
|
<img src="./assets/images/traefik.logo.svg" alt="logo" />
|
||||||
<header>
|
<header>
|
||||||
<h1 class="title">Work in progress...</h1>
|
<h1 class="title">
|
||||||
|
<i class="fa fa-exclamation-triangle"></i>
|
||||||
|
Work in progress...
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
In the meantime, you can review your current configuration by using
|
||||||
|
the
|
||||||
|
<a href="{{ href }}/api/rawdata">{{ href }}/api/rawdata</a> endpoint
|
||||||
|
<br /><br />
|
||||||
|
Also, please keep your <i class="fa fa-eye"></i> on our
|
||||||
|
<a href="https://docs.traefik.io/v2.0/operations/dashboard/"
|
||||||
|
>documentation</a
|
||||||
|
>
|
||||||
|
to stay informed
|
||||||
|
</p>
|
||||||
|
<p></p>
|
||||||
</header>
|
</header>
|
||||||
</main>
|
</main>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
export class AppComponent {}
|
export class AppComponent {
|
||||||
|
public href: string;
|
||||||
|
|
||||||
|
constructor(@Inject(DOCUMENT) private document: Document) {
|
||||||
|
this.href = this.document.location.origin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue