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