Merge 'v2.0.0-alpha3' into master

This commit is contained in:
Fernandez Ludovic 2019-03-29 15:38:45 +01:00
commit 7baa752a9d
78 changed files with 2711 additions and 1355 deletions

View file

@ -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?
<!-- <!--

View file

@ -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?
<!-- <!--

View file

@ -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}

View file

@ -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
View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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+.

View file

@ -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).

View file

@ -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:

View file

@ -145,7 +145,7 @@ Do not hesitate to complete it.
| [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.

View file

@ -9,23 +9,29 @@ 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"
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: addprefix
spec:
addprefix:
prefix: /bar
```
```toml tab="File"
# Prefixing with /foo
[http.middlewares] [http.middlewares]
[http.middlewares.add-foo.AddPrefix] [http.middlewares.add-foo.AddPrefix]
prefix = "/foo" prefix = "/foo"
``` ```
??? example "Docker -- Prefixing with /bar"
```yaml
a-container:
image: a-container-image
labels:
- "traefik.http.middlewares.add-bar.addprefix.prefix=/bar"
```
## Configuration Options ## Configuration Options
### prefix ### prefix

View file

@ -9,24 +9,20 @@ 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"
# Declaring the user list
[http.middlewares] [http.middlewares]
[http.middlewares.test-auth.basicauth] [http.middlewares.test-auth.basicauth]
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"] "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
### General ### General

View file

@ -13,23 +13,19 @@ 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"
# Sets the maximum request body to 2Mb
[http.middlewares] [http.middlewares]
[http.middlewares.2Mb-limit.buffering] [http.middlewares.2Mb-limit.buffering]
maxRequestBodyBytes = 250000 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
### maxRequestBodyBytes ### maxRequestBodyBytes

View file

@ -23,24 +23,19 @@ 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"
# Latency Check
[http.middlewares] [http.middlewares]
[http.middlewares.latency-check.circuitbreaker] [http.middlewares.latency-check.circuitbreaker]
expression = "LatencyAtQuantileMS(50.0) > 100" 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
There are three possible states for your circuit breaker: There are three possible states for your circuit breaker:

View file

@ -9,22 +9,18 @@ The Compress middleware enables the gzip compression.
## Configuration Examples ## Configuration Examples
??? example "File -- enable gzip compression" ```yaml tab="Docker"
# Enable gzip compression
```toml
[http.middlewares]
[http.middlewares.test-compress.Compress]
```
??? example "Docker -- enable gzip compression"
```yml
a-container:
image: a-container-image
labels: labels:
- "traefik.http.middlewares.test-compress.compress=true", - "traefik.http.middlewares.test-compress.compress=true",
``` ```
```toml tab="File"
# Enable gzip compression
[http.middlewares]
[http.middlewares.test-compress.Compress]
```
## Notes ## Notes
Responses are compressed when: Responses are compressed when:

View file

@ -9,23 +9,18 @@ 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"
```toml
[http.middlewares]
[http.middlewares.test-auth.digestauth]
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: labels:
- "traefik.http.middlewares.declared-users-only.digestauth.usersFile=path-to-file.ext", - "traefik.http.middlewares.declared-users-only.digestauth.usersFile=path-to-file.ext",
``` ```
```toml tab="File"
[http.middlewares]
[http.middlewares.test-auth.digestauth]
users = ["test:traefik:a2688e031edb4be6a3797f3882655c05",
"test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]
```
!!! tip !!! tip
Use `htdigest` to generate passwords. Use `htdigest` to generate passwords.

View file

@ -12,9 +12,16 @@ 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"
# Custom Error Page for 5XX
[http.routers] [http.routers]
[http.routers.router1] [http.routers.router1]
Service = "my-service" Service = "my-service"
@ -30,18 +37,6 @@ The ErrorPage middleware returns a custom page in lieu of the default, according
# ... 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"
```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 !!! note
In this example, the error page URL is based on the status code (`query=/{status}.html)`. In this example, the error page URL is based on the status code (`query=/{status}.html)`.

View file

@ -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,9 +11,8 @@ 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
```toml
[http.middlewares] [http.middlewares]
[http.middlewares.test-auth.forwardauth] [http.middlewares.test-auth.forwardauth]
address = "https://authserver.com/auth" address = "https://authserver.com/auth"
@ -27,11 +26,8 @@ Otherwise, the response from the authentication server is returned.
key = "path/to/foo.key" key = "path/to/foo.key"
``` ```
??? example "Docker -- Forward authentication to authserver.com" ```yaml tab="Docker"
# Forward authentication to authserver.com
```yml
a-container:
image: a-container-image
labels: labels:
- "traefik.http.middlewares.test-auth.ForwardAuth.Address=https://authserver.com/auth" - "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.AuthResponseHeaders=X-Auth-User, X-Secret"
@ -41,7 +37,6 @@ Otherwise, the response from the authentication server is returned.
- "traefik.http.middlewares.test-auth.ForwardAuth.TLS.InsecureSkipVerify=true" - "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.TLS.Key=path/to/foo.key"
- "traefik.http.middlewares.test-auth.ForwardAuth.TrustForwardHeader=true" - "traefik.http.middlewares.test-auth.ForwardAuth.TrustForwardHeader=true"
``` ```
## Configuration Options ## Configuration Options

View file

@ -13,9 +13,15 @@ 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]
@ -24,16 +30,6 @@ Add the `X-Script-Name` header to the proxied request and the `X-Custom-Response
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
`X-Script-Name` header added to the proxied request, the `X-Custom-Request-Header` header removed from the request, and the `X-Custom-Response-Header` header removed from the response. `X-Script-Name` header added to the proxied request, the `X-Custom-Request-Header` header removed from the request, and the `X-Custom-Response-Header` header removed from the response.

View file

@ -9,23 +9,19 @@ 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"
# Accepts request from defined IP
[http.middlewares] [http.middlewares]
[http.middlewares.test-ipwhitelist.ipWhiteList] [http.middlewares.test-ipwhitelist.ipWhiteList]
sourceRange = ["127.0.0.1/32", "192.168.1.7"] 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
### sourceRange ### sourceRange

View file

@ -9,23 +9,19 @@ 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"
# Limiting to 10 simultaneous connections
[http.middlewares] [http.middlewares]
[http.middlewares.test-maxconn.maxconn] [http.middlewares.test-maxconn.maxconn]
amount = 10 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
### amount ### amount

View file

@ -13,9 +13,54 @@ 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"
# As a Kubernetes Traefik IngressRoute
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: Middleware
metadata:
name: stripprefix
spec:
stripprefix:
prefixes:
- /stripit
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingressroute.crd
spec:
# more fields...
routes:
# more fields...
middleware:
- name: stripprefix
```
```toml tab="File"
# As Toml Configuration File
[providers] [providers]
[providers.file] [providers.file]
@ -23,7 +68,7 @@ Pieces of middleware can be combined in chains to fit every scenario.
[http.routers.router1] [http.routers.router1]
Service = "myService" Service = "myService"
Middlewares = ["foo-add-prefix"] Middlewares = ["foo-add-prefix"]
Rule = "Host: example.com" Rule = "Host(`example.com`)"
[http.middlewares] [http.middlewares]
[http.middlewares.foo-add-prefix.AddPrefix] [http.middlewares.foo-add-prefix.AddPrefix]
@ -38,16 +83,6 @@ Pieces of middleware can be combined in chains to fit every scenario.
Weight = 1 Weight = 1
``` ```
??? example "As a Docker Label"
```yaml
# A container that exposes a simple API
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",
```
## Advanced Configuration ## Advanced Configuration
When you declare a middleware, it lives in its `provider` namespace. When you declare a middleware, it lives in its `provider` namespace.

View file

@ -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"
# Pass the escaped pem in the `X-Forwarded-Tls-Client-Cert` header.
labels:
- "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]
[http.middlewares.test-passtlsclientcert.passtlsclientcert] [http.middlewares.test-passtlsclientcert.passtlsclientcert]
pem = true pem = true
``` ```
??? example "Docker -- Pass the escaped pem in the `X-Forwarded-Tls-Client-Cert` header" ??? example "Pass the escaped pem in the `X-Forwarded-Tls-Client-Cert` header"
```yml ```yaml tab="Docker"
a-container: # Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header
image: a-container-image
labels: labels:
- "traefik.http.middlewares.Middleware11.passtlsclientcert.pem=true" - "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 "File -- Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header" ```toml tab="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

View file

@ -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!}

View file

@ -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"
@ -46,7 +26,7 @@ Checking the Health of Your Traefik Instances
``` ```
| 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

View 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

View 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

View file

@ -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

View file

@ -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

View 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.

View file

@ -0,0 +1,6 @@
# Traefik & Kubernetes
Kubernetes Ingress.
{: .subtitle }
TODO

View file

@ -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.
@ -26,11 +27,11 @@ 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"

View 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
```

View file

@ -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]

View file

@ -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"
``` ```
@ -249,7 +249,7 @@ 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"

View file

@ -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

View 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

View 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

View 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

View 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: ""

View 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.

View 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

View file

@ -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'

View file

@ -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
View 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"]

View file

@ -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

View file

@ -15,4 +15,3 @@ spec:
services: services:
- name: whoami - name: whoami
port: 80 port: 80

View file

@ -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, Watch: true,
Filename: "myfilename",
Constraints: nil,
Trace: true,
DebugLogGeneratedTemplate: 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",

View file

@ -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

View file

@ -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)

View file

@ -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)
}) })

View file

@ -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)
}

View file

@ -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 {

View 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
}

View file

@ -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

View file

@ -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.

View file

@ -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"`
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 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
}

View file

@ -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
}, },

View 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:

View file

@ -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

View file

@ -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"},

View file

@ -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"`
} }

View file

@ -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

View file

@ -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",

View file

@ -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,
}, },

View file

@ -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

View file

@ -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)
} }
} }

View file

@ -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

View file

@ -1,5 +0,0 @@
#!/usr/bin/env bash
set -e
./script/crossbinary-default
./script/crossbinary-others

View file

@ -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

View file

@ -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"

View file

@ -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 -

View 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
# #

View file

@ -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;
}
}