From 82308c9a53c16e5010588e6ba4583f40760f200b Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Mon, 18 Mar 2019 17:20:42 +0100 Subject: [PATCH 01/27] chore: release draft mode. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 391ca7f58..2e29cc9b1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,6 +38,7 @@ deploy: file: dist/traefik* skip_cleanup: true file_glob: true + draft: true on: repo: containous/traefik tags: true From 076d6abfe4dd2dcdfa0a1babb273aa5fbfc3edcf Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Tue, 19 Mar 2019 09:04:04 +0100 Subject: [PATCH 02/27] Change deploy script. --- script/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/deploy.sh b/script/deploy.sh index 8504e4ffb..6f67e99a6 100755 --- a/script/deploy.sh +++ b/script/deploy.sh @@ -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 - From cb417b80772a15563f9ea7eb858d4f2d3ed31fce Mon Sep 17 00:00:00 2001 From: Julien Salleyron Date: Tue, 19 Mar 2019 10:04:04 +0100 Subject: [PATCH 03/27] Fix problem in aggregator provider --- pkg/provider/aggregator/aggregator.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/provider/aggregator/aggregator.go b/pkg/provider/aggregator/aggregator.go index dea68443a..faf814ebc 100644 --- a/pkg/provider/aggregator/aggregator.go +++ b/pkg/provider/aggregator/aggregator.go @@ -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) }) From 4c3cf87f62758de44d14cc4ec19584157223508d Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Tue, 19 Mar 2019 11:50:03 +0100 Subject: [PATCH 04/27] New build system for experimental Docker image. --- .travis.yml | 5 ----- exp.Dockerfile | 41 +++++++++++++++++++++++++++++++++++++++++ script/deploy-docker.sh | 19 ------------------- 3 files changed, 41 insertions(+), 24 deletions(-) create mode 100644 exp.Dockerfile delete mode 100644 script/deploy-docker.sh diff --git a/.travis.yml b/.travis.yml index 2e29cc9b1..71a2d457d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,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} diff --git a/exp.Dockerfile b/exp.Dockerfile new file mode 100644 index 000000000..189afff3f --- /dev/null +++ b/exp.Dockerfile @@ -0,0 +1,41 @@ +# 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 + +COPY --from=webui /src/static/ /go/src/github.com/containous/traefik/static/ + +RUN ./script/make.sh 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"] diff --git a/script/deploy-docker.sh b/script/deploy-docker.sh deleted file mode 100644 index d73a95faa..000000000 --- a/script/deploy-docker.sh +++ /dev/null @@ -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" From f346251719afd90c14871a2b2e43a285b046240a Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Tue, 19 Mar 2019 12:24:04 +0100 Subject: [PATCH 05/27] Fix new build system for experimental Docker image. --- exp.Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exp.Dockerfile b/exp.Dockerfile index 189afff3f..ab5d81b2f 100644 --- a/exp.Dockerfile +++ b/exp.Dockerfile @@ -25,9 +25,10 @@ RUN mkdir -p /usr/local/bin \ 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 binary +RUN ./script/make.sh generate binary ## IMAGE FROM scratch From c4b7e8f288e0c81bcb9e10a3256a8f87943caadb Mon Sep 17 00:00:00 2001 From: mpl Date: Tue, 19 Mar 2019 16:44:06 +0100 Subject: [PATCH 06/27] doc: kubernetes CRD provider Co-authored-by: Jean-Baptiste Doumenjou --- docs/content/middlewares/addprefix.md | 12 ++ docs/content/middlewares/overview.md | 39 ++++++ docs/content/providers/crd_ingress_route.yml | 13 ++ docs/content/providers/crd_middlewares.yml | 13 ++ docs/content/providers/kubernetes-crd.md | 122 ++++++++++++++++++ docs/content/providers/kubernetes-ingress.md | 6 + docs/content/providers/overview.md | 18 +-- .../reference/providers/kubernetescrd.md | 81 ++++++++++++ docs/mkdocs.yml | 3 + 9 files changed, 299 insertions(+), 8 deletions(-) create mode 100644 docs/content/providers/crd_ingress_route.yml create mode 100644 docs/content/providers/crd_middlewares.yml create mode 100644 docs/content/providers/kubernetes-crd.md create mode 100644 docs/content/providers/kubernetes-ingress.md create mode 100644 docs/content/reference/providers/kubernetescrd.md diff --git a/docs/content/middlewares/addprefix.md b/docs/content/middlewares/addprefix.md index 9c2644518..ac9ba6538 100644 --- a/docs/content/middlewares/addprefix.md +++ b/docs/content/middlewares/addprefix.md @@ -26,6 +26,18 @@ The AddPrefix middleware updates the URL Path of the request before forwarding i - "traefik.http.middlewares.add-bar.addprefix.prefix=/bar" ``` +??? example "Kubernetes -- Prefixing with /bar" + + ```yaml + apiVersion: traefik.containo.us/v1alpha1 + kind: Middleware + metadata: + name: addprefix + spec: + addprefix: + prefix: /bar + ``` + ## Configuration Options ### prefix diff --git a/docs/content/middlewares/overview.md b/docs/content/middlewares/overview.md index 91324af11..21bc5015f 100644 --- a/docs/content/middlewares/overview.md +++ b/docs/content/middlewares/overview.md @@ -48,6 +48,45 @@ Pieces of middleware can be combined in chains to fit every scenario. - "traefik.http.middlewares.foo-add-prefix.addprefix.prefix=/foo", ``` +??? example "As a Kubernetes Traefik IngressRoute" + + ```yaml + apiVersion: apiextensions.k8s.io/v1beta1 + kind: CustomResourceDefinition + metadata: + name: middlewares.traefik.containo.us + spec: + group: traefik.containo.us + version: v1alpha1 + names: + kind: Middleware + plural: middlewares + singular: middleware + scope: Namespaced + + --- + apiVersion: traefik.containo.us/v1alpha1 + kind: Middleware + metadata: + name: stripprefix + spec: + stripprefix: + prefixes: + - /stripit + + --- + apiVersion: traefik.containo.us/v1alpha1 + kind: IngressRoute + metadata: + name: ingressroute.crd + spec: + # more fields... + routes: + # more fields... + middleware: + - name: stripprefix + ``` + ## Advanced Configuration When you declare a middleware, it lives in its `provider` namespace. diff --git a/docs/content/providers/crd_ingress_route.yml b/docs/content/providers/crd_ingress_route.yml new file mode 100644 index 000000000..0bcfd3568 --- /dev/null +++ b/docs/content/providers/crd_ingress_route.yml @@ -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 diff --git a/docs/content/providers/crd_middlewares.yml b/docs/content/providers/crd_middlewares.yml new file mode 100644 index 000000000..d1ae35f79 --- /dev/null +++ b/docs/content/providers/crd_middlewares.yml @@ -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 diff --git a/docs/content/providers/kubernetes-crd.md b/docs/content/providers/kubernetes-crd.md new file mode 100644 index 000000000..44bb2fe79 --- /dev/null +++ b/docs/content/providers/kubernetes-crd.md @@ -0,0 +1,122 @@ +# Traefik & Kubernetes + +The Kubernetes Ingress Controller, The Custom Resource Way. +{: .subtitle } + +[comment]: # (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). diff --git a/docs/content/providers/kubernetes-ingress.md b/docs/content/providers/kubernetes-ingress.md new file mode 100644 index 000000000..c08f63810 --- /dev/null +++ b/docs/content/providers/kubernetes-ingress.md @@ -0,0 +1,6 @@ +# Traefik & Kubernetes + +Kubernetes Ingress. +{: .subtitle } + +TODO diff --git a/docs/content/providers/overview.md b/docs/content/providers/overview.md index f0f65c1f8..305f31565 100644 --- a/docs/content/providers/overview.md +++ b/docs/content/providers/overview.md @@ -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" diff --git a/docs/content/reference/providers/kubernetescrd.md b/docs/content/reference/providers/kubernetescrd.md new file mode 100644 index 000000000..b9fedf5af --- /dev/null +++ b/docs/content/reference/providers/kubernetescrd.md @@ -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 +``` \ No newline at end of file diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index a1e9f2064..32724e1d5 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -66,9 +66,11 @@ 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': @@ -79,6 +81,7 @@ nav: - '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' From f99a473436bd00ebe20699e928a070e79f792eb8 Mon Sep 17 00:00:00 2001 From: mpl Date: Tue, 19 Mar 2019 17:30:04 +0100 Subject: [PATCH 07/27] Fix log msgs about label selector --- pkg/provider/kubernetes/crd/client.go | 10 +++++----- pkg/provider/kubernetes/crd/kubernetes.go | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pkg/provider/kubernetes/crd/client.go b/pkg/provider/kubernetes/crd/client.go index e17566841..948453189 100644 --- a/pkg/provider/kubernetes/crd/client.go +++ b/pkg/provider/kubernetes/crd/client.go @@ -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 }, diff --git a/pkg/provider/kubernetes/crd/kubernetes.go b/pkg/provider/kubernetes/crd/kubernetes.go index 8d8b50c92..d46861a50 100644 --- a/pkg/provider/kubernetes/crd/kubernetes.go +++ b/pkg/provider/kubernetes/crd/kubernetes.go @@ -39,17 +39,17 @@ type Provider struct { 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 +70,7 @@ func (p *Provider) newK8sClient(ctx context.Context, ingressLabelSelector string } if err == nil { - client.ingressLabelSelector = ingLabelSel + client.labelSelector = labelSel } return client, err @@ -95,7 +95,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 From e7033071b923fdbf8c3c2145a3816443b5c676b5 Mon Sep 17 00:00:00 2001 From: Manuel Zapf Date: Tue, 19 Mar 2019 17:54:10 +0100 Subject: [PATCH 08/27] change docs and adjust dashboard for v2 alpha Co-authored-by: Jean-Baptiste Doumenjou --- docs/content/getting-started/quick-start.md | 6 ++--- docs/content/operations/dashboard.md | 20 +++++++++------ webui/src/app/app.component.ts | 28 ++++++++++++++++++--- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/docs/content/getting-started/quick-start.md b/docs/content/getting-started/quick-start.md index 762c64d21..b43eef89c 100644 --- a/docs/content/getting-started/quick-start.md +++ b/docs/content/getting-started/quick-start.md @@ -34,7 +34,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 @@ -58,7 +58,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 +82,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: diff --git a/docs/content/operations/dashboard.md b/docs/content/operations/dashboard.md index 9e20e6777..7a21fca66 100644 --- a/docs/content/operations/dashboard.md +++ b/docs/content/operations/dashboard.md @@ -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. +??? note "Dashboard WIP" + Currently, the dashboard is in a Work In Progress State while being reconstructed for v2. + Therefore, the dashboard is currently not working. +
Dashboard - Providers
The dashboard in action with Traefik listening to 3 different providers
@@ -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!} diff --git a/webui/src/app/app.component.ts b/webui/src/app/app.component.ts index 4218b7340..abed5b68c 100644 --- a/webui/src/app/app.component.ts +++ b/webui/src/app/app.component.ts @@ -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';
logo
-

Work in progress...

+

+ + Work in progress... +

+

+ In the meantime, you can review your current configuration by using + the + {{ href }}/api/rawdata endpoint +

+ Also, please keep your on our + documentation + to stay informed +

+

` }) -export class AppComponent {} +export class AppComponent { + public href: string; + + constructor(@Inject(DOCUMENT) private document: Document) { + this.href = this.document.location.origin; + } +} From 8a86777db86809cd134b2919f78c855f0352e820 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Tue, 19 Mar 2019 19:24:07 +0100 Subject: [PATCH 09/27] Prepare release v2.0.0-alpha2 --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd58cce9d..7099ad0af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Change Log +## [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) From cd3835945834784c7d29ad0ed8d16217edbedac5 Mon Sep 17 00:00:00 2001 From: Benjamin Date: Wed, 20 Mar 2019 16:30:07 +0100 Subject: [PATCH 10/27] Fix dead maintainers link on the README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 96f86c08b..b3542c0bb 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,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 From ec1952157b2a2b321c8532697bb95dacf2aa7167 Mon Sep 17 00:00:00 2001 From: Akeem McLennon Date: Wed, 20 Mar 2019 10:36:10 -0500 Subject: [PATCH 11/27] Fix typo in forwardauth middleware documentation --- docs/content/middlewares/forwardauth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/middlewares/forwardauth.md b/docs/content/middlewares/forwardauth.md index 1b55f5cc0..ffac859c8 100644 --- a/docs/content/middlewares/forwardauth.md +++ b/docs/content/middlewares/forwardauth.md @@ -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) From 0f2c4fb5f4c4498883251f90ebb3392c973236ef Mon Sep 17 00:00:00 2001 From: Julien Salleyron Date: Thu, 21 Mar 2019 15:22:06 +0100 Subject: [PATCH 12/27] Add support for tcp labels in docker provider --- docs/content/providers/docker.md | 21 + integration/docker_test.go | 37 + pkg/config/dyn_config.go | 28 + pkg/provider/configuration.go | 86 +- pkg/provider/docker/config.go | 67 ++ pkg/provider/docker/config_test.go | 1637 ++++++++++++++++++---------- 6 files changed, 1310 insertions(+), 566 deletions(-) diff --git a/docs/content/providers/docker.md b/docs/content/providers/docker.md index eb2777c32..b53f87136 100644 --- a/docs/content/providers/docker.md +++ b/docs/content/providers/docker.md @@ -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 diff --git a/integration/docker_test.go b/integration/docker_test.go index e2088a88b..78187f53d 100644 --- a/integration/docker_test.go +++ b/integration/docker_test.go @@ -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 diff --git a/pkg/config/dyn_config.go b/pkg/config/dyn_config.go index 34848bb54..6572f65fa 100644 --- a/pkg/config/dyn_config.go +++ b/pkg/config/dyn_config.go @@ -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 diff --git a/pkg/provider/configuration.go b/pkg/provider/configuration.go index b233d881d..b80781aca 100644 --- a/pkg/provider/configuration.go +++ b/pkg/provider/configuration.go @@ -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 { diff --git a/pkg/provider/docker/config.go b/pkg/provider/docker/config.go index 893c65a22..8bb6a83ec 100644 --- a/pkg/provider/docker/config.go +++ b/pkg/provider/docker/config.go @@ -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) diff --git a/pkg/provider/docker/config_test.go b/pkg/provider/docker/config_test.go index ebab2b95d..a6644d627 100644 --- a/pkg/provider/docker/config_test.go +++ b/pkg/provider/docker/config_test.go @@ -19,7 +19,7 @@ func TestDefaultRule(t *testing.T) { desc string containers []dockerData defaultRule string - expected *config.HTTPConfiguration + expected *config.Configuration }{ { desc: "default rule with no variable", @@ -42,25 +42,31 @@ func TestDefaultRule(t *testing.T) { }, }, defaultRule: "Host(`foo.bar`)", - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`foo.bar`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`foo.bar`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -87,25 +93,31 @@ func TestDefaultRule(t *testing.T) { }, }, defaultRule: "Host(`{{ .Name }}.foo.bar`)", - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.foo.bar`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.foo.bar`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -134,25 +146,31 @@ func TestDefaultRule(t *testing.T) { }, }, defaultRule: `Host("{{ .Name }}.{{ index .Labels "traefik.domain" }}")`, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: `Host("Test.foo.bar")`, - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: `Host("Test.foo.bar")`, + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -179,20 +197,26 @@ func TestDefaultRule(t *testing.T) { }, }, defaultRule: `Host("{{ .Toto }}")`, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -219,20 +243,26 @@ func TestDefaultRule(t *testing.T) { }, }, defaultRule: ``, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -259,25 +289,31 @@ func TestDefaultRule(t *testing.T) { }, }, defaultRule: DefaultTemplateRule, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -287,7 +323,6 @@ func TestDefaultRule(t *testing.T) { for _, test := range testCases { test := test - t.Run(test.desc, func(t *testing.T) { t.Parallel() @@ -307,7 +342,7 @@ func TestDefaultRule(t *testing.T) { configuration := p.buildConfiguration(context.Background(), test.containers) - assert.Equal(t, test.expected, configuration.HTTP) + assert.Equal(t, test.expected, configuration) }) } } @@ -317,7 +352,7 @@ func Test_buildConfiguration(t *testing.T) { desc string containers []dockerData constraints types.Constraints - expected *config.HTTPConfiguration + expected *config.Configuration }{ { desc: "one container no label", @@ -339,25 +374,31 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -399,41 +440,47 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, - "Test2": { - Service: "Test2", - Rule: "Host(`Test2.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - }, - Method: "wrr", - PassHostHeader: true, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", + }, + "Test2": { + Service: "Test2", + Rule: "Host(`Test2.traefik.wtf`)", }, }, - "Test2": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.2:80", - Weight: 1, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, + }, + }, + "Test2": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, + }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -477,29 +524,35 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - { - URL: "http://127.0.0.2:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -527,25 +580,31 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Service1", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Service1": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Service1", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Service1": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "drr", + PassHostHeader: true, }, - Method: "drr", - PassHostHeader: true, }, }, }, @@ -575,25 +634,31 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Router1": { - Service: "Service1", - Rule: "Host(`foo.com`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Service1": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Router1": { + Service: "Service1", + Rule: "Host(`foo.com`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Service1": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -621,26 +686,32 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, - }, - Routers: map[string]*config.Router{ - "Router1": { - Service: "Test", - Rule: "Host(`foo.com`)", + Routers: map[string]*config.Router{ + "Router1": { + Service: "Test", + Rule: "Host(`foo.com`)", + }, }, }, }, @@ -668,25 +739,31 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Router1": { - Service: "Service1", - Rule: "Host(`foo.com`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Service1": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Router1": { + Service: "Service1", + Rule: "Host(`foo.com`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Service1": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -716,32 +793,38 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Service1": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Service1": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, - }, - "Service2": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + "Service2": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -789,15 +872,21 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Service1", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Service1", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{}, }, }, { @@ -861,15 +950,21 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Service1", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Service1", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{}, }, }, { @@ -914,29 +1009,35 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Service1", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Service1": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - { - URL: "http://127.0.0.2:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Service1", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Service1": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, }, + Method: "drr", + PassHostHeader: true, }, - Method: "drr", - PassHostHeader: true, }, }, }, @@ -964,32 +1065,38 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - }, - Method: "wrr", - PassHostHeader: true, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", }, }, - }, - Middlewares: map[string]*config.Middleware{ - "Middleware1": { - MaxConn: &config.MaxConn{ - Amount: 42, - ExtractorFunc: "request.host", + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + }, + Method: "wrr", + PassHostHeader: true, + }, + }, + }, + Middlewares: map[string]*config.Middleware{ + "Middleware1": { + MaxConn: &config.MaxConn{ + Amount: 42, + ExtractorFunc: "request.host", + }, }, }, }, @@ -1037,36 +1144,42 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{ - "Middleware1": { - MaxConn: &config.MaxConn{ - Amount: 42, - ExtractorFunc: "request.host", + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", }, }, - }, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - { - URL: "http://127.0.0.2:80", - Weight: 1, - }, + Middlewares: map[string]*config.Middleware{ + "Middleware1": { + MaxConn: &config.MaxConn{ + Amount: 42, + ExtractorFunc: "request.host", + }, + }, + }, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, + }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1114,29 +1227,35 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - { - URL: "http://127.0.0.2:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1203,33 +1322,39 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - { - URL: "http://127.0.0.2:80", - Weight: 1, - }, - { - URL: "http://127.0.0.3:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, + { + URL: "http://127.0.0.3:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1277,24 +1402,30 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - { - URL: "http://127.0.0.2:80", - Weight: 1, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1361,28 +1492,34 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - { - URL: "http://127.0.0.2:80", - Weight: 1, - }, - { - URL: "http://127.0.0.3:80", - Weight: 1, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, + { + URL: "http://127.0.0.3:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1430,29 +1567,35 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Router1": { - Service: "Test", - Rule: "Host(`foo.com`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, - }, - { - URL: "http://127.0.0.2:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Router1": { + Service: "Test", + Rule: "Host(`foo.com`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1498,32 +1641,38 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, - }, - "Test2": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.2:80", - Weight: 1, + "Test2": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1551,25 +1700,31 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1598,25 +1753,31 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Service1", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Service1": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "h2c://127.0.0.1:8080", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Service1", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Service1": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "h2c://127.0.0.1:8080", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1645,32 +1806,38 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Service1": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Service1": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, - }, - "Service2": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:8080", - Weight: 1, + "Service2": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:8080", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1694,10 +1861,16 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{}, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, + }, }, }, { @@ -1720,10 +1893,16 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{}, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, + }, }, }, { @@ -1748,10 +1927,16 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{}, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, + }, }, }, { @@ -1775,10 +1960,16 @@ func Test_buildConfiguration(t *testing.T) { Health: "not_healthy", }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{}, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, + }, }, }, { @@ -1810,10 +2001,16 @@ func Test_buildConfiguration(t *testing.T) { Regex: "bar", }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{}, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{}, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, + }, }, }, { @@ -1845,25 +2042,31 @@ func Test_buildConfiguration(t *testing.T) { Regex: "foo", }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{}, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, }, + Method: "wrr", + PassHostHeader: true, }, - Method: "wrr", - PassHostHeader: true, }, }, }, @@ -1892,37 +2095,345 @@ func Test_buildConfiguration(t *testing.T) { }, }, }, - expected: &config.HTTPConfiguration{ - Routers: map[string]*config.Router{ - "Test": { - Service: "Test", - Rule: "Host(`Test.traefik.wtf`)", - Middlewares: []string{"Middleware1"}, - }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{}, }, - Middlewares: map[string]*config.Middleware{ - "Middleware1": { - BasicAuth: &config.BasicAuth{ - Users: []string{ - "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", - "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", - }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Test", + Rule: "Host(`Test.traefik.wtf`)", + Middlewares: []string{"Middleware1"}, }, }, - }, - Services: map[string]*config.Service{ - "Test": { - LoadBalancer: &config.LoadBalancerService{ - Servers: []config.Server{ - { - URL: "http://127.0.0.1:80", - Weight: 1, + Middlewares: map[string]*config.Middleware{ + "Middleware1": { + BasicAuth: &config.BasicAuth{ + Users: []string{ + "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", + "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", }, }, - Method: "wrr", - PassHostHeader: true, }, }, + Services: map[string]*config.Service{ + "Test": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + }, + Method: "wrr", + PassHostHeader: true, + }, + }, + }, + }, + }, + }, + { + desc: "tcp with label", + containers: []dockerData{ + { + ServiceName: "Test", + Name: "Test", + Labels: map[string]string{ + "traefik.tcp.routers.foo.rule": "HostSNI(`foo.bar`)", + "traefik.tcp.routers.foo.tls": "true", + }, + NetworkSettings: networkSettings{ + Ports: nat.PortMap{ + nat.Port("80/tcp"): []nat.PortBinding{}, + }, + Networks: map[string]*networkData{ + "bridge": { + Name: "bridge", + Addr: "127.0.0.1", + }, + }, + }, + }, + }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{ + "foo": { + Service: "Test", + Rule: "HostSNI(`foo.bar`)", + TLS: &config.RouterTCPTLSConfig{}, + }, + }, + Services: map[string]*config.TCPService{ + "Test": { + LoadBalancer: &config.TCPLoadBalancerService{ + Servers: []config.TCPServer{ + { + Address: "127.0.0.1:80", + Weight: 1, + }, + }, + Method: "wrr", + }, + }, + }, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, + }, + }, + }, + { + desc: "tcp with label without rule", + containers: []dockerData{ + { + ServiceName: "Test", + Name: "Test", + Labels: map[string]string{ + "traefik.tcp.routers.foo.tls": "true", + }, + NetworkSettings: networkSettings{ + Ports: nat.PortMap{ + nat.Port("80/tcp"): []nat.PortBinding{}, + }, + Networks: map[string]*networkData{ + "bridge": { + Name: "bridge", + Addr: "127.0.0.1", + }, + }, + }, + }, + }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{ + "Test": { + LoadBalancer: &config.TCPLoadBalancerService{ + Servers: []config.TCPServer{ + { + Address: "127.0.0.1:80", + Weight: 1, + }, + }, + Method: "wrr", + }, + }, + }, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, + }, + }, + }, + { + desc: "tcp with label and port", + containers: []dockerData{ + { + ServiceName: "Test", + Name: "Test", + Labels: map[string]string{ + "traefik.tcp.routers.foo.rule": "HostSNI(`foo.bar`)", + "traefik.tcp.routers.foo.tls": "true", + "traefik.tcp.services.foo.loadbalancer.server.port": "8080", + }, + NetworkSettings: networkSettings{ + Ports: nat.PortMap{ + nat.Port("80/tcp"): []nat.PortBinding{}, + }, + Networks: map[string]*networkData{ + "bridge": { + Name: "bridge", + Addr: "127.0.0.1", + }, + }, + }, + }, + }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{ + "foo": { + Service: "foo", + Rule: "HostSNI(`foo.bar`)", + TLS: &config.RouterTCPTLSConfig{}, + }, + }, + Services: map[string]*config.TCPService{ + "foo": { + LoadBalancer: &config.TCPLoadBalancerService{ + Servers: []config.TCPServer{ + { + Address: "127.0.0.1:8080", + Weight: 1, + }, + }, + Method: "wrr", + }, + }, + }, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, + }, + }, + }, + { + desc: "tcp with label and port and http service", + containers: []dockerData{ + { + ServiceName: "Test", + Name: "Test", + Labels: map[string]string{ + "traefik.tcp.routers.foo.rule": "HostSNI(`foo.bar`)", + "traefik.tcp.routers.foo.tls": "true", + "traefik.tcp.services.foo.loadbalancer.server.port": "8080", + "traefik.http.services.Service1.loadbalancer.method": "drr", + }, + NetworkSettings: networkSettings{ + Ports: nat.PortMap{ + nat.Port("80/tcp"): []nat.PortBinding{}, + }, + Networks: map[string]*networkData{ + "bridge": { + Name: "bridge", + Addr: "127.0.0.1", + }, + }, + }, + }, + { + ID: "2", + ServiceName: "Test", + Name: "Test", + Labels: map[string]string{ + "traefik.tcp.routers.foo.rule": "HostSNI(`foo.bar`)", + "traefik.tcp.routers.foo.tls": "true", + "traefik.tcp.services.foo.loadbalancer.server.port": "8080", + "traefik.http.services.Service1.loadbalancer.method": "drr", + }, + NetworkSettings: networkSettings{ + Ports: nat.PortMap{ + nat.Port("80/tcp"): []nat.PortBinding{}, + }, + Networks: map[string]*networkData{ + "bridge": { + Name: "bridge", + Addr: "127.0.0.2", + }, + }, + }, + }, + }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{ + "foo": { + Service: "foo", + Rule: "HostSNI(`foo.bar`)", + TLS: &config.RouterTCPTLSConfig{}, + }, + }, + Services: map[string]*config.TCPService{ + "foo": { + LoadBalancer: &config.TCPLoadBalancerService{ + Servers: []config.TCPServer{ + { + Address: "127.0.0.1:8080", + Weight: 1, + }, + { + Address: "127.0.0.2:8080", + Weight: 1, + }, + }, + Method: "wrr", + }, + }, + }, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{ + "Test": { + Service: "Service1", + Rule: "Host(`Test.traefik.wtf`)", + }, + }, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{ + "Service1": { + LoadBalancer: &config.LoadBalancerService{ + Servers: []config.Server{ + { + URL: "http://127.0.0.1:80", + Weight: 1, + }, + { + URL: "http://127.0.0.2:80", + Weight: 1, + }, + }, + Method: "drr", + PassHostHeader: true, + }, + }, + }, + }, + }, + }, + { + desc: "tcp with label for tcp service", + containers: []dockerData{ + { + ServiceName: "Test", + Name: "Test", + Labels: map[string]string{ + "traefik.tcp.services.foo.loadbalancer.server.port": "8080", + }, + NetworkSettings: networkSettings{ + Ports: nat.PortMap{ + nat.Port("80/tcp"): []nat.PortBinding{}, + }, + Networks: map[string]*networkData{ + "bridge": { + Name: "bridge", + Addr: "127.0.0.1", + }, + }, + }, + }, + }, + expected: &config.Configuration{ + TCP: &config.TCPConfiguration{ + Routers: map[string]*config.TCPRouter{}, + Services: map[string]*config.TCPService{ + "foo": { + LoadBalancer: &config.TCPLoadBalancerService{ + Servers: []config.TCPServer{ + { + Address: "127.0.0.1:8080", + Weight: 1, + }, + }, + Method: "wrr", + }, + }, + }, + }, + HTTP: &config.HTTPConfiguration{ + Routers: map[string]*config.Router{}, + Middlewares: map[string]*config.Middleware{}, + Services: map[string]*config.Service{}, }, }, }, @@ -1951,7 +2462,7 @@ func Test_buildConfiguration(t *testing.T) { configuration := p.buildConfiguration(context.Background(), test.containers) - assert.Equal(t, test.expected, configuration.HTTP) + assert.Equal(t, test.expected, configuration) }) } } From 79ecff7b42391d5dd3311705a4b7c991a17ac877 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 21 Mar 2019 15:34:04 +0100 Subject: [PATCH 13/27] Fix Getting started --- docs/content/getting-started/quick-start.md | 7 ++----- docs/content/providers/docker.md | 4 ++-- docs/content/providers/file.md | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/docs/content/getting-started/quick-start.md b/docs/content/getting-started/quick-start.md index b43eef89c..30582a855 100644 --- a/docs/content/getting-started/quick-start.md +++ b/docs/content/getting-started/quick-start.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: @@ -18,7 +15,7 @@ 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 + 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) @@ -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). diff --git a/docs/content/providers/docker.md b/docs/content/providers/docker.md index b53f87136..66eb792ac 100644 --- a/docs/content/providers/docker.md +++ b/docs/content/providers/docker.md @@ -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" diff --git a/docs/content/providers/file.md b/docs/content/providers/file.md index eed2c6b7d..c31e3cdea 100644 --- a/docs/content/providers/file.md +++ b/docs/content/providers/file.md @@ -22,7 +22,7 @@ You can write these configuration elements: ``` toml # Enabling the file provider - [providers.files] + [providers.file] [http] # Add the router From f8f7edd12462a81ccc8001ed17411888290aadd2 Mon Sep 17 00:00:00 2001 From: Julien Salleyron Date: Thu, 21 Mar 2019 15:54:07 +0100 Subject: [PATCH 14/27] Fix panic while server shutdown --- pkg/server/server_entrypoint_tcp.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/server/server_entrypoint_tcp.go b/pkg/server/server_entrypoint_tcp.go index a3443cc8a..b2ee10eba 100644 --- a/pkg/server/server_entrypoint_tcp.go +++ b/pkg/server/server_entrypoint_tcp.go @@ -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) } } From 2e085fa253bbecc906d4a0bd4c6bacb15326c8c7 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Fri, 22 Mar 2019 15:16:06 +0100 Subject: [PATCH 15/27] Remove old links in readme --- README.md | 4 ---- pkg/provider/label/parser_test.go | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b3542c0bb..f4bc242dd 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/pkg/provider/label/parser_test.go b/pkg/provider/label/parser_test.go index 53a44d3f8..ef2d7ee71 100644 --- a/pkg/provider/label/parser_test.go +++ b/pkg/provider/label/parser_test.go @@ -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", From 119d0134e0917c3a4d951bbcd94aacc8875029eb Mon Sep 17 00:00:00 2001 From: Erin Date: Fri, 22 Mar 2019 09:22:09 -0500 Subject: [PATCH 16/27] Documentation Updates: docker-compose examples --- docs/content/getting-started/configuration-overview.md | 2 +- docs/content/getting-started/quick-start.md | 2 +- docs/content/providers/docker.md | 2 +- docs/content/routing/entrypoints.md | 4 ++-- docs/mkdocs.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/content/getting-started/configuration-overview.md b/docs/content/getting-started/configuration-overview.md index b24e97568..3ae0915e0 100644 --- a/docs/content/getting-started/configuration-overview.md +++ b/docs/content/getting-started/configuration-overview.md @@ -1,4 +1,4 @@ -# Configuration Overview +# Configuration Introduction How the Magic Happens {: .subtitle } diff --git a/docs/content/getting-started/quick-start.md b/docs/content/getting-started/quick-start.md index 30582a855..dd18019b4 100644 --- a/docs/content/getting-started/quick-start.md +++ b/docs/content/getting-started/quick-start.md @@ -14,7 +14,7 @@ version: '3' services: reverse-proxy: - image: traefik # The official Traefik docker image + 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 diff --git a/docs/content/providers/docker.md b/docs/content/providers/docker.md index 66eb792ac..3af842665 100644 --- a/docs/content/providers/docker.md +++ b/docs/content/providers/docker.md @@ -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: diff --git a/docs/content/routing/entrypoints.md b/docs/content/routing/entrypoints.md index d043a83b3..3ef4680b4 100644 --- a/docs/content/routing/entrypoints.md +++ b/docs/content/routing/entrypoints.md @@ -64,7 +64,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 +74,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' ``` diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 32724e1d5..6de0d6d04 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -76,7 +76,7 @@ nav: - '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' From d70add10ab2101486081e707e3caf932d92925d6 Mon Sep 17 00:00:00 2001 From: Mehran Kholdi Date: Mon, 25 Mar 2019 20:24:03 +0430 Subject: [PATCH 17/27] Fix typos in docs --- docs/content/routing/entrypoints.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/content/routing/entrypoints.md b/docs/content/routing/entrypoints.md index 3ef4680b4..3da6597a4 100644 --- a/docs/content/routing/entrypoints.md +++ b/docs/content/routing/entrypoints.md @@ -1,6 +1,6 @@ # EntryPoints -Opening Connections for Incomming Requests +Opening Connections for Incoming Requests {: .subtitle } ![EntryPoints](../assets/img/entrypoints.png) @@ -97,7 +97,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] From a0e2f476799e3d52f9288da1dea8c7c7f473ef06 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Mon, 25 Mar 2019 17:20:04 +0100 Subject: [PATCH 18/27] Update traefik.sample.toml --- traefik.sample.toml | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/traefik.sample.toml b/traefik.sample.toml index 6d3368719..e409edab3 100644 --- a/traefik.sample.toml +++ b/traefik.sample.toml @@ -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 # From 3e76c25887129841ccb4ffe149b4b4cd36805db4 Mon Sep 17 00:00:00 2001 From: mpl Date: Tue, 26 Mar 2019 11:12:04 +0100 Subject: [PATCH 19/27] Document the TLS with ACME case Co-authored-by: Julien Salleyron --- pkg/provider/acme/provider.go | 6 +++ .../kubernetes/crd/fixtures/with_tls_acme.yml | 20 ++++++++++ .../kubernetes/crd/kubernetes_test.go | 37 +++++++++++++++++++ .../crd/traefik/v1alpha1/ingressroute.go | 5 ++- 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 pkg/provider/kubernetes/crd/fixtures/with_tls_acme.yml diff --git a/pkg/provider/acme/provider.go b/pkg/provider/acme/provider.go index 10e8ace5e..5450be014 100644 --- a/pkg/provider/acme/provider.go +++ b/pkg/provider/acme/provider.go @@ -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) diff --git a/pkg/provider/kubernetes/crd/fixtures/with_tls_acme.yml b/pkg/provider/kubernetes/crd/fixtures/with_tls_acme.yml new file mode 100644 index 000000000..dde9941b8 --- /dev/null +++ b/pkg/provider/kubernetes/crd/fixtures/with_tls_acme.yml @@ -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: diff --git a/pkg/provider/kubernetes/crd/kubernetes_test.go b/pkg/provider/kubernetes/crd/kubernetes_test.go index c185ce6e1..689552501 100644 --- a/pkg/provider/kubernetes/crd/kubernetes_test.go +++ b/pkg/provider/kubernetes/crd/kubernetes_test.go @@ -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"}, diff --git a/pkg/provider/kubernetes/crd/traefik/v1alpha1/ingressroute.go b/pkg/provider/kubernetes/crd/traefik/v1alpha1/ingressroute.go index f4e4ded43..77e7b1534 100644 --- a/pkg/provider/kubernetes/crd/traefik/v1alpha1/ingressroute.go +++ b/pkg/provider/kubernetes/crd/traefik/v1alpha1/ingressroute.go @@ -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"` } From fd26cf265d53f7cf09bc33806e22a942ebd95fc2 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Doumenjou Date: Tue, 26 Mar 2019 16:32:06 +0100 Subject: [PATCH 20/27] Fix some minors errors on the documentation --- docs/content/https-tls/overview.md | 2 +- docs/content/middlewares/digestauth.md | 3 ++- docs/content/middlewares/overview.md | 2 +- docs/content/operations/dashboard.md | 6 +++--- docs/content/operations/ping.md | 28 ++++---------------------- docs/content/providers/docker.md | 2 +- docs/content/routing/entrypoints.md | 7 +------ docs/content/routing/routers/index.md | 14 ++++++------- docs/content/routing/services/index.md | 3 +++ 9 files changed, 23 insertions(+), 44 deletions(-) diff --git a/docs/content/https-tls/overview.md b/docs/content/https-tls/overview.md index 6a2a48e2c..3b1a20733 100644 --- a/docs/content/https-tls/overview.md +++ b/docs/content/https-tls/overview.md @@ -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" ``` diff --git a/docs/content/middlewares/digestauth.md b/docs/content/middlewares/digestauth.md index e5c3a97fa..e57f49cb9 100644 --- a/docs/content/middlewares/digestauth.md +++ b/docs/content/middlewares/digestauth.md @@ -14,7 +14,8 @@ The DigestAuth middleware is a quick way to restrict access to your services to ```toml [http.middlewares] [http.middlewares.test-auth.digestauth] - users = ["test:traefik:a2688e031edb4be6a3797f3882655c05", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"] + users = ["test:traefik:a2688e031edb4be6a3797f3882655c05", + "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"] ``` ??? example "Docker -- Using an external file for the authorized users" diff --git a/docs/content/middlewares/overview.md b/docs/content/middlewares/overview.md index 21bc5015f..90cd6febe 100644 --- a/docs/content/middlewares/overview.md +++ b/docs/content/middlewares/overview.md @@ -23,7 +23,7 @@ Pieces of middleware can be combined in chains to fit every scenario. [http.routers.router1] Service = "myService" Middlewares = ["foo-add-prefix"] - Rule = "Host: example.com" + Rule = "Host(`example.com`)" [http.middlewares] [http.middlewares.foo-add-prefix.AddPrefix] diff --git a/docs/content/operations/dashboard.md b/docs/content/operations/dashboard.md index 7a21fca66..c8c4c02dc 100644 --- a/docs/content/operations/dashboard.md +++ b/docs/content/operations/dashboard.md @@ -5,9 +5,9 @@ See What's Going On The dashboard is the central place that shows you the current active routes handled by Traefik. -??? note "Dashboard WIP" - Currently, the dashboard is in a Work In Progress State while being reconstructed for v2. - Therefore, the dashboard is currently not working. +!!! 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.
Dashboard - Providers diff --git a/docs/content/operations/ping.md b/docs/content/operations/ping.md index 6c64a88c7..5313382a6 100644 --- a/docs/content/operations/ping.md +++ b/docs/content/operations/ping.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 diff --git a/docs/content/providers/docker.md b/docs/content/providers/docker.md index 3af842665..2ff3ccc42 100644 --- a/docs/content/providers/docker.md +++ b/docs/content/providers/docker.md @@ -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" ``` diff --git a/docs/content/routing/entrypoints.md b/docs/content/routing/entrypoints.md index 3da6597a4..ce4fecfca 100644 --- a/docs/content/routing/entrypoints.md +++ b/docs/content/routing/entrypoints.md @@ -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 diff --git a/docs/content/routing/routers/index.md b/docs/content/routing/routers/index.md index a5fde96b4..9cdd60c0f 100644 --- a/docs/content/routing/routers/index.md +++ b/docs/content/routing/routers/index.md @@ -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" diff --git a/docs/content/routing/services/index.md b/docs/content/routing/services/index.md index c4af3a8c8..cb4aca7dd 100644 --- a/docs/content/routing/services/index.md +++ b/docs/content/routing/services/index.md @@ -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 From 7932e317c8b08ad995d4bb5eb058f8713f79c2e0 Mon Sep 17 00:00:00 2001 From: ntaranov Date: Wed, 27 Mar 2019 14:08:04 +0300 Subject: [PATCH 21/27] Clarify that manual dnsChallenge provider works only when run as docker run -it --- docs/content/https-tls/acme.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/content/https-tls/acme.md b/docs/content/https-tls/acme.md index ae85279f6..3fdc38f56 100644 --- a/docs/content/https-tls/acme.md +++ b/docs/content/https-tls/acme.md @@ -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 Enter. | YES | +| manual | - | none, but you need to run Traefik interactively [^4], turn on `acmeLogging` to see instructions and press Enter. | 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. From 2916f540c16ef9608e2827016323a2a4a349d221 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Wed, 27 Mar 2019 15:02:06 +0100 Subject: [PATCH 22/27] Remove BaseProvider --- cmd/configuration.go | 1 - pkg/anonymize/anonymize_config_test.go | 63 ++--------- pkg/provider/base_provider.go | 105 ------------------ pkg/provider/constrainer.go | 27 +++++ pkg/provider/docker/docker.go | 5 +- pkg/provider/file/file.go | 65 ++++++++++- pkg/provider/kubernetes/crd/kubernetes.go | 4 +- pkg/provider/kubernetes/ingress/kubernetes.go | 4 +- pkg/provider/marathon/label_test.go | 8 -- pkg/provider/marathon/marathon.go | 6 +- 10 files changed, 107 insertions(+), 181 deletions(-) delete mode 100644 pkg/provider/base_provider.go create mode 100644 pkg/provider/constrainer.go diff --git a/cmd/configuration.go b/cmd/configuration.go index e268e94a5..c5f128109 100644 --- a/cmd/configuration.go +++ b/cmd/configuration.go @@ -171,7 +171,6 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration { // default Kubernetes var defaultKubernetes ingress.Provider - defaultKubernetes.Watch = true defaultProviders := static.Providers{ File: &defaultFile, diff --git a/pkg/anonymize/anonymize_config_test.go b/pkg/anonymize/anonymize_config_test.go index 27d11e9b0..1d0f132aa 100644 --- a/pkg/anonymize/anonymize_config_test.go +++ b/pkg/anonymize/anonymize_config_test.go @@ -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", diff --git a/pkg/provider/base_provider.go b/pkg/provider/base_provider.go deleted file mode 100644 index 5192a9e75..000000000 --- a/pkg/provider/base_provider.go +++ /dev/null @@ -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) -} diff --git a/pkg/provider/constrainer.go b/pkg/provider/constrainer.go new file mode 100644 index 000000000..44a276c51 --- /dev/null +++ b/pkg/provider/constrainer.go @@ -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 +} diff --git a/pkg/provider/docker/docker.go b/pkg/provider/docker/docker.go index 81aca428f..f700f5aba 100644 --- a/pkg/provider/docker/docker.go +++ b/pkg/provider/docker/docker.go @@ -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. diff --git a/pkg/provider/file/file.go b/pkg/provider/file/file.go index 95f5bc6ce..805b672cd 100644 --- a/pkg/provider/file/file.go +++ b/pkg/provider/file/file.go @@ -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 +} diff --git a/pkg/provider/kubernetes/crd/kubernetes.go b/pkg/provider/kubernetes/crd/kubernetes.go index d46861a50..95e0df3d4 100644 --- a/pkg/provider/kubernetes/crd/kubernetes.go +++ b/pkg/provider/kubernetes/crd/kubernetes.go @@ -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,7 +32,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)"` @@ -78,7 +76,7 @@ func (p *Provider) newK8sClient(ctx context.Context, labelSelector string) (*cli // Init the provider. func (p *Provider) Init() error { - return p.BaseProvider.Init() + return nil } // Provide allows the k8s provider to provide configurations to traefik diff --git a/pkg/provider/kubernetes/ingress/kubernetes.go b/pkg/provider/kubernetes/ingress/kubernetes.go index d60daacaa..bc567f599 100644 --- a/pkg/provider/kubernetes/ingress/kubernetes.go +++ b/pkg/provider/kubernetes/ingress/kubernetes.go @@ -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 diff --git a/pkg/provider/marathon/label_test.go b/pkg/provider/marathon/label_test.go index 8eee255e5..7cb011939 100644 --- a/pkg/provider/marathon/label_test.go +++ b/pkg/provider/marathon/label_test.go @@ -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, }, diff --git a/pkg/provider/marathon/marathon.go b/pkg/provider/marathon/marathon.go index 5e6268d1a..2a4ad9c73 100644 --- a/pkg/provider/marathon/marathon.go +++ b/pkg/provider/marathon/marathon.go @@ -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 From 0779c6a139d34a55d326a90b07ac5da0f006a952 Mon Sep 17 00:00:00 2001 From: mpl Date: Wed, 27 Mar 2019 15:16:04 +0100 Subject: [PATCH 23/27] Full ACME+CRD example Co-authored-by: Jean-Baptiste Doumenjou --- docs/content/providers/kubernetes-crd.md | 8 +- docs/content/user-guides/crd-acme/01-crd.yml | 91 ++++++++++++++++ .../user-guides/crd-acme/02-services.yml | 32 ++++++ .../user-guides/crd-acme/03-deployments.yml | 79 ++++++++++++++ .../user-guides/crd-acme/04-ingressroutes.yml | 30 ++++++ docs/content/user-guides/crd-acme/index.md | 100 ++++++++++++++++++ docs/content/user-guides/crd-acme/k3s.yml | 30 ++++++ docs/mkdocs.yml | 2 + integration/fixtures/k8s/03-ingressroute.yml | 1 - 9 files changed, 371 insertions(+), 2 deletions(-) create mode 100644 docs/content/user-guides/crd-acme/01-crd.yml create mode 100644 docs/content/user-guides/crd-acme/02-services.yml create mode 100644 docs/content/user-guides/crd-acme/03-deployments.yml create mode 100644 docs/content/user-guides/crd-acme/04-ingressroutes.yml create mode 100644 docs/content/user-guides/crd-acme/index.md create mode 100644 docs/content/user-guides/crd-acme/k3s.yml diff --git a/docs/content/providers/kubernetes-crd.md b/docs/content/providers/kubernetes-crd.md index 44bb2fe79..6e4398027 100644 --- a/docs/content/providers/kubernetes-crd.md +++ b/docs/content/providers/kubernetes-crd.md @@ -3,7 +3,9 @@ The Kubernetes Ingress Controller, The Custom Resource Way. {: .subtitle } -[comment]: # (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. @@ -120,3 +122,7 @@ spec: ## 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. diff --git a/docs/content/user-guides/crd-acme/01-crd.yml b/docs/content/user-guides/crd-acme/01-crd.yml new file mode 100644 index 000000000..45ace3f90 --- /dev/null +++ b/docs/content/user-guides/crd-acme/01-crd.yml @@ -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 diff --git a/docs/content/user-guides/crd-acme/02-services.yml b/docs/content/user-guides/crd-acme/02-services.yml new file mode 100644 index 000000000..753d9e65b --- /dev/null +++ b/docs/content/user-guides/crd-acme/02-services.yml @@ -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 diff --git a/docs/content/user-guides/crd-acme/03-deployments.yml b/docs/content/user-guides/crd-acme/03-deployments.yml new file mode 100644 index 000000000..712503a53 --- /dev/null +++ b/docs/content/user-guides/crd-acme/03-deployments.yml @@ -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 diff --git a/docs/content/user-guides/crd-acme/04-ingressroutes.yml b/docs/content/user-guides/crd-acme/04-ingressroutes.yml new file mode 100644 index 000000000..9e67cc83d --- /dev/null +++ b/docs/content/user-guides/crd-acme/04-ingressroutes.yml @@ -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: "" diff --git a/docs/content/user-guides/crd-acme/index.md b/docs/content/user-guides/crd-acme/index.md new file mode 100644 index 000000000..84c8db503 --- /dev/null +++ b/docs/content/user-guides/crd-acme/index.md @@ -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. diff --git a/docs/content/user-guides/crd-acme/k3s.yml b/docs/content/user-guides/crd-acme/k3s.yml new file mode 100644 index 000000000..5fe32dfff --- /dev/null +++ b/docs/content/user-guides/crd-acme/k3s.yml @@ -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 diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 6de0d6d04..34e069940 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -122,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' diff --git a/integration/fixtures/k8s/03-ingressroute.yml b/integration/fixtures/k8s/03-ingressroute.yml index 608b52a42..303d8bdfa 100644 --- a/integration/fixtures/k8s/03-ingressroute.yml +++ b/integration/fixtures/k8s/03-ingressroute.yml @@ -15,4 +15,3 @@ spec: services: - name: whoami port: 80 - From fa2c57f7cb8758dfddeaccb561a8b83f6ba9f9a2 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Thu, 28 Mar 2019 11:42:06 +0100 Subject: [PATCH 24/27] Review Makefile --- .travis.yml | 2 +- Makefile | 176 ++++++++++-------- docs/content/contributing/building-testing.md | 13 ++ script/.validate | 12 +- script/crossbinary | 5 - script/crossbinary-others | 74 -------- 6 files changed, 110 insertions(+), 172 deletions(-) delete mode 100755 script/crossbinary delete mode 100755 script/crossbinary-others diff --git a/.travis.yml b/.travis.yml index 71a2d457d..3acae29f5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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; diff --git a/Makefile b/Makefile index 47a73dbea..7b7ac2fe3 100644 --- a/Makefile +++ b/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 diff --git a/docs/content/contributing/building-testing.md b/docs/content/contributing/building-testing.md index 225d0649b..1a399f408 100644 --- a/docs/content/contributing/building-testing.md +++ b/docs/content/contributing/building-testing.md @@ -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+. diff --git a/script/.validate b/script/.validate index 42b4cc70c..c8c87e3bc 100644 --- a/script/.validate +++ b/script/.validate @@ -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 diff --git a/script/crossbinary b/script/crossbinary deleted file mode 100755 index a0ee7817b..000000000 --- a/script/crossbinary +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -set -e - -./script/crossbinary-default -./script/crossbinary-others diff --git a/script/crossbinary-others b/script/crossbinary-others deleted file mode 100755 index aca441662..000000000 --- a/script/crossbinary-others +++ /dev/null @@ -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 From a45f285a5c17adb5a9f6188bedc8f520edb47f87 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Fri, 29 Mar 2019 12:34:05 +0100 Subject: [PATCH 25/27] Enhance middleware examples. --- docs/content/middlewares/addprefix.md | 46 +++--- docs/content/middlewares/basicauth.md | 28 ++-- docs/content/middlewares/buffering.md | 26 ++-- docs/content/middlewares/circuitbreaker.md | 27 ++-- docs/content/middlewares/compress.md | 24 ++-- docs/content/middlewares/digestauth.md | 26 ++-- docs/content/middlewares/errorpages.md | 53 ++++--- docs/content/middlewares/forwardauth.md | 55 ++++--- docs/content/middlewares/headers.md | 34 ++--- docs/content/middlewares/ipwhitelist.md | 26 ++-- docs/content/middlewares/maxconnection.md | 26 ++-- docs/content/middlewares/overview.md | 134 +++++++++--------- docs/content/middlewares/passtlsclientcert.md | 84 ++++++----- docs/content/middlewares/ratelimit.md | 40 +++--- docs/requirements.txt | 2 +- 15 files changed, 286 insertions(+), 345 deletions(-) diff --git a/docs/content/middlewares/addprefix.md b/docs/content/middlewares/addprefix.md index ac9ba6538..66ab2160c 100644 --- a/docs/content/middlewares/addprefix.md +++ b/docs/content/middlewares/addprefix.md @@ -9,34 +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" - ``` - -??? example "Kubernetes -- Prefixing with /bar" - - ```yaml - apiVersion: traefik.containo.us/v1alpha1 - kind: Middleware - metadata: - name: addprefix - spec: - addprefix: - prefix: /bar - ``` +```toml tab="File" +# Prefixing with /foo +[http.middlewares] + [http.middlewares.add-foo.AddPrefix] + prefix = "/foo" +``` ## Configuration Options diff --git a/docs/content/middlewares/basicauth.md b/docs/content/middlewares/basicauth.md index 7060bf11b..f07e56d09 100644 --- a/docs/content/middlewares/basicauth.md +++ b/docs/content/middlewares/basicauth.md @@ -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 diff --git a/docs/content/middlewares/buffering.md b/docs/content/middlewares/buffering.md index 917edab4b..f1b9d2746 100644 --- a/docs/content/middlewares/buffering.md +++ b/docs/content/middlewares/buffering.md @@ -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 diff --git a/docs/content/middlewares/circuitbreaker.md b/docs/content/middlewares/circuitbreaker.md index c1e4e3f21..9c6913cd3 100644 --- a/docs/content/middlewares/circuitbreaker.md +++ b/docs/content/middlewares/circuitbreaker.md @@ -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 diff --git a/docs/content/middlewares/compress.md b/docs/content/middlewares/compress.md index cc19cd2ee..c0b15691d 100644 --- a/docs/content/middlewares/compress.md +++ b/docs/content/middlewares/compress.md @@ -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 diff --git a/docs/content/middlewares/digestauth.md b/docs/content/middlewares/digestauth.md index e57f49cb9..72b87f544 100644 --- a/docs/content/middlewares/digestauth.md +++ b/docs/content/middlewares/digestauth.md @@ -9,23 +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 diff --git a/docs/content/middlewares/errorpages.md b/docs/content/middlewares/errorpages.md index d5f99393c..f890c1605 100644 --- a/docs/content/middlewares/errorpages.md +++ b/docs/content/middlewares/errorpages.md @@ -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 diff --git a/docs/content/middlewares/forwardauth.md b/docs/content/middlewares/forwardauth.md index ffac859c8..53e0dc33a 100644 --- a/docs/content/middlewares/forwardauth.md +++ b/docs/content/middlewares/forwardauth.md @@ -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 diff --git a/docs/content/middlewares/headers.md b/docs/content/middlewares/headers.md index 0f6924dc8..3fdc4930a 100644 --- a/docs/content/middlewares/headers.md +++ b/docs/content/middlewares/headers.md @@ -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 diff --git a/docs/content/middlewares/ipwhitelist.md b/docs/content/middlewares/ipwhitelist.md index 3e979b8e1..0be532b4c 100644 --- a/docs/content/middlewares/ipwhitelist.md +++ b/docs/content/middlewares/ipwhitelist.md @@ -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 diff --git a/docs/content/middlewares/maxconnection.md b/docs/content/middlewares/maxconnection.md index 9b5e9e70e..2863ea5dd 100644 --- a/docs/content/middlewares/maxconnection.md +++ b/docs/content/middlewares/maxconnection.md @@ -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 diff --git a/docs/content/middlewares/overview.md b/docs/content/middlewares/overview.md index 90cd6febe..1d1dec3f6 100644 --- a/docs/content/middlewares/overview.md +++ b/docs/content/middlewares/overview.md @@ -13,79 +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] - - [http.routers] - [http.routers.router1] - Service = "myService" - Middlewares = ["foo-add-prefix"] - Rule = "Host(`example.com`)" - - [http.middlewares] - [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 - ``` - -??? example "As a Docker Label" - - ```yaml - # A container that exposes a simple API - whoami: - image: containous/whoami # A container that exposes an API to show its IP address - labels: - - "traefik.http.middlewares.foo-add-prefix.addprefix.prefix=/foo", - ``` - -??? example "As a Kubernetes Traefik IngressRoute" - - ```yaml - 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 +```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 - metadata: - name: stripprefix - spec: - stripprefix: - prefixes: - - /stripit + plural: middlewares + singular: middleware + scope: Namespaced - --- - apiVersion: traefik.containo.us/v1alpha1 - kind: IngressRoute - metadata: - name: ingressroute.crd - spec: +--- +apiVersion: traefik.containo.us/v1alpha1 +kind: Middleware +metadata: + name: stripprefix +spec: + stripprefix: + prefixes: + - /stripit + +--- +apiVersion: traefik.containo.us/v1alpha1 +kind: IngressRoute +metadata: + name: ingressroute.crd +spec: +# more fields... + routes: # more fields... - routes: - # more fields... - middleware: - - name: stripprefix - ``` + middleware: + - name: stripprefix +``` + +```toml tab="File" +# As Toml Configuration File +[providers] + [providers.file] + +[http.routers] + [http.routers.router1] + Service = "myService" + Middlewares = ["foo-add-prefix"] + Rule = "Host(`example.com`)" + +[http.middlewares] + [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 diff --git a/docs/content/middlewares/passtlsclientcert.md b/docs/content/middlewares/passtlsclientcert.md index 6d7640157..f1a9c5774 100644 --- a/docs/content/middlewares/passtlsclientcert.md +++ b/docs/content/middlewares/passtlsclientcert.md @@ -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 diff --git a/docs/content/middlewares/ratelimit.md b/docs/content/middlewares/ratelimit.md index 2ed64c38b..065723e28 100644 --- a/docs/content/middlewares/ratelimit.md +++ b/docs/content/middlewares/ratelimit.md @@ -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. diff --git a/docs/requirements.txt b/docs/requirements.txt index 4fbf20cb8..e6552aa6a 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -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 From ca7ea68a6ab7d0a9b43e17969722e722857007bb Mon Sep 17 00:00:00 2001 From: Manuel Zapf Date: Fri, 29 Mar 2019 13:12:05 +0100 Subject: [PATCH 26/27] Adds notes about incompatibility between 1.X and 2.X configurations. --- .github/ISSUE_TEMPLATE.md | 11 +++++++++++ .github/ISSUE_TEMPLATE/Bug_report.md | 11 +++++++++++ README.md | 2 +- .../content/getting-started/configuration-overview.md | 4 ++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 6a204a12e..909e71aa6 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -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 + + + ### What did you do? + ### What did you do?