Compare commits

...

10 Commits

Author SHA1 Message Date
Ludovic Fernandez
d67e06037e Prepare release v2.2.0-rc2 2020-03-11 18:12:04 +01:00
Emile Vauge
4ce90a7eb4 Remove @dduportal from the maintainers team (#6464) 2020-03-11 13:07:54 +01:00
mpl
4408c634b0 Specify passthrough for TCP/TLS in its own section 2020-03-10 17:28:04 +01:00
John Molakvoæ
df351511de Fix example values for swarmModeRefreshSeconds 2020-03-10 16:08:05 +01:00
robotte
3b85dc9618 Improve kubernetes external name service support
Co-authored-by: jbdoumenjou <jb.doumenjou@gmail.com>
2020-03-10 12:46:05 +01:00
robotte
e511cfe2e4 Improve documentation for kubernetes ingress configuration
Co-authored-by: jbdoumenjou <jb.doumenjou@gmail.com>
2020-03-09 13:48:06 +01:00
Ludovic Fernandez
d0f8c1834d Update migration documentation 2020-03-09 13:22:06 +01:00
Ludovic Fernandez
d02bb28920 Router entry points on reload. 2020-03-09 11:12:05 +01:00
Patrizio Bekerle
99861ac808 Fix broken documentation link 2020-03-06 10:30:06 +01:00
Traefiker Bot
13ebd2c4e4 Update version references. 2020-03-05 21:46:04 +01:00
42 changed files with 1185 additions and 350 deletions

View File

@@ -3,11 +3,11 @@ PLEASE READ THIS MESSAGE.
Documentation fixes or enhancements:
- for Traefik v1: use branch v1.7
- for Traefik v2: use branch v2.1
- for Traefik v2: use branch v2.2
Bug fixes:
- for Traefik v1: use branch v1.7
- for Traefik v2: use branch v2.1
- for Traefik v2: use branch v2.2
Enhancements:
- for Traefik v1: we only accept bug fixes

View File

@@ -10,7 +10,7 @@ else
export VERSION=''
fi
export CODENAME=cantal
export CODENAME=chevrotin
export N_MAKE_JOBS=2

View File

@@ -11,7 +11,7 @@ env:
global:
- REPO=$TRAVIS_REPO_SLUG
- VERSION=$TRAVIS_TAG
- CODENAME=cantal
- CODENAME=chevrotin
- GO111MODULE=on
script:

View File

@@ -1,3 +1,19 @@
## [v2.2.0-rc2](https://github.com/containous/traefik/tree/v2.2.0-rc2) (2020-03-11)
[All Commits](https://github.com/containous/traefik/compare/v2.2.0-rc1...v2.2.0-rc2)
**Bug fixes:**
- **[internal]** Router entry points on reload. ([#6444](https://github.com/containous/traefik/pull/6444) by [ldez](https://github.com/ldez))
- **[k8s,k8s/crd]** Improve kubernetes external name service support ([#6428](https://github.com/containous/traefik/pull/6428) by [rtribotte](https://github.com/rtribotte))
**Documentation:**
- **[docker]** Fix example values for swarmModeRefreshSeconds ([#6460](https://github.com/containous/traefik/pull/6460) by [skjnldsv](https://github.com/skjnldsv))
- **[k8s,k8s/ingress]** Improve documentation for kubernetes ingress configuration ([#6440](https://github.com/containous/traefik/pull/6440) by [rtribotte](https://github.com/rtribotte))
- **[tcp,tls]** Specify passthrough for TCP/TLS in its own section ([#6459](https://github.com/containous/traefik/pull/6459) by [mpl](https://github.com/mpl))
- Remove @dduportal from the maintainers team ([#6464](https://github.com/containous/traefik/pull/6464) by [emilevauge](https://github.com/emilevauge))
- Update migration documentation ([#6447](https://github.com/containous/traefik/pull/6447) by [ldez](https://github.com/ldez))
- Update version references. ([#6434](https://github.com/containous/traefik/pull/6434) by [ldez](https://github.com/ldez))
- Fix broken documentation link ([#6430](https://github.com/containous/traefik/pull/6430) by [pbek](https://github.com/pbek))
## [v2.2.0-rc1](https://github.com/containous/traefik/tree/v2.2.0-rc1) (2020-03-05)
[All Commits](https://github.com/containous/traefik/compare/v2.1.0-rc1...v2.2.0-rc1)

View File

@@ -7,6 +7,7 @@ import (
"net/http"
"os"
"path/filepath"
"sort"
"strings"
"time"
@@ -191,7 +192,7 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
managerFactory := service.NewManagerFactory(*staticConfiguration, routinesPool, metricsRegistry)
routerFactory := server.NewRouterFactory(*staticConfiguration, managerFactory, tlsManager, chainBuilder)
var eps []string
var defaultEntryPoints []string
for name, cfg := range staticConfiguration.EntryPoints {
protocol, err := cfg.GetProtocol()
if err != nil {
@@ -200,15 +201,17 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
}
if protocol != "udp" {
eps = append(eps, name)
defaultEntryPoints = append(defaultEntryPoints, name)
}
}
sort.Strings(defaultEntryPoints)
watcher := server.NewConfigurationWatcher(
routinesPool,
providerAggregator,
time.Duration(staticConfiguration.Providers.ProvidersThrottleDuration),
eps,
defaultEntryPoints,
)
watcher.AddListener(func(conf dynamic.Configuration) {

View File

@@ -15,7 +15,6 @@
* Michaël Matur [@mmatur](https://github.com/mmatur)
* Gérald Croës [@geraldcroes](https://github.com/geraldcroes)
* Jean-Baptiste Doumenjou [@jbdoumenjou](https://github.com/jbdoumenjou)
* Damien Duportal [@dduportal](https://github.com/dduportal)
* Mathieu Lonjaret [@mpl](https://github.com/mpl)
## Contributions Daily Meeting

View File

@@ -9,11 +9,11 @@ You can install Traefik with the following flavors:
## Use the Official Docker Image
Choose one of the [official Docker images](https://hub.docker.com/_/traefik) and run it with the [sample configuration file](https://raw.githubusercontent.com/containous/traefik/v2.1/traefik.sample.toml):
Choose one of the [official Docker images](https://hub.docker.com/_/traefik) and run it with the [sample configuration file](https://raw.githubusercontent.com/containous/traefik/v2.2/traefik.sample.toml):
```bash
docker run -d -p 8080:8080 -p 80:80 \
-v $PWD/traefik.toml:/etc/traefik/traefik.toml traefik:v2.1
-v $PWD/traefik.toml:/etc/traefik/traefik.toml traefik:v2.2
```
For more details, go to the [Docker provider documentation](../providers/docker.md)

View File

@@ -15,7 +15,7 @@ version: '3'
services:
reverse-proxy:
# The official v2 Traefik docker image
image: traefik:v2.1
image: traefik:v2.2
# Enables the web UI and tells Traefik to listen to docker
command: --api.insecure=true --providers.docker
ports:

View File

@@ -319,7 +319,7 @@ For example, `CF_API_EMAIL_FILE=/run/secrets/traefik_cf-api-email` could be used
| [Linode](https://www.linode.com) | `linode` | `LINODE_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/linode) |
| [Linode v4](https://www.linode.com) | `linodev4` | `LINODE_TOKEN` | [Additional configuration](https://go-acme.github.io/lego/dns/linodev4) |
| [Liquid Web](https://www.liquidweb.com/) | `liquidweb` | `LIQUID_WEB_PASSWORD`, `LIQUID_WEB_USERNAME`, `LIQUID_WEB_ZONE` | [Additional configuration](https://go-acme.github.io/lego/dns/liquidweb) |
| manual | - | none, but you need to run Traefik interactively [^4], turn on debug log to see instructions and press <kbd>Enter</kbd>. | |
| manual | `manual` | none, but you need to run Traefik interactively [^4], turn on debug log to see instructions and press <kbd>Enter</kbd>. | |
| [MyDNS.jp](https://www.mydns.jp/) | `mydnsjp` | `MYDNSJP_MASTER_ID`, `MYDNSJP_PASSWORD` | [Additional configuration](https://go-acme.github.io/lego/dns/mydnsjp) |
| [Namecheap](https://www.namecheap.com) | `namecheap` | `NAMECHEAP_API_USER`, `NAMECHEAP_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/namecheap) |
| [name.com](https://www.name.com/) | `namedotcom` | `NAMECOM_USERNAME`, `NAMECOM_API_TOKEN`, `NAMECOM_SERVER` | [Additional configuration](https://go-acme.github.io/lego/dns/namedotcom) |

View File

@@ -104,7 +104,7 @@ Then any router can refer to an instance of the wanted middleware.
```yaml tab="K8s IngressRoute"
# The definitions below require the definitions for the Middleware and IngressRoute kinds.
# https://docs.traefik.io/v2.1/reference/dynamic-configuration/kubernetes-crd/#definitions
# https://docs.traefik.io/v2.2/reference/dynamic-configuration/kubernetes-crd/#definitions
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
@@ -275,7 +275,7 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
```yaml tab="K8s IngressRoute"
# The definitions below require the definitions for the TLSOption and IngressRoute kinds.
# https://docs.traefik.io/v2.1/reference/dynamic-configuration/kubernetes-crd/#definitions
# https://docs.traefik.io/v2.2/reference/dynamic-configuration/kubernetes-crd/#definitions
apiVersion: traefik.containo.us/v1alpha1
kind: TLSOption
metadata:
@@ -322,9 +322,12 @@ Then, a [router's TLS field](../routing/routers/index.md#tls) can refer to one o
## HTTP to HTTPS Redirection is Now Configured on Routers
Previously on Traefik v1, the redirection was applied on an entry point or on a frontend.
With Traefik v2 it is applied on a [Router](../routing/routers/index.md).
With Traefik v2 it is applied on an entry point or a [Router](../routing/routers/index.md).
To apply a redirection, one of the redirect middlewares, [RedirectRegex](../middlewares/redirectregex.md) or [RedirectScheme](../middlewares/redirectscheme.md), has to be configured and added to the router middlewares list.
To apply a redirection:
- on an entry point, the [HTTP redirection](../routing/entrypoints.md#redirection) has to be configured.
- on a router, one of the redirect middlewares, [RedirectRegex](../middlewares/redirectregex.md) or [RedirectScheme](../middlewares/redirectscheme.md), has to be configured and added to the router middlewares list.
!!! example "Global HTTP to HTTPS redirection"
@@ -352,90 +355,28 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
!!! info "v2"
```yaml tab="Docker"
# ...
traefik:
image: traefik:v2.1
command:
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --providers.docker=true
ports:
- 80:80
- 443:443
labels:
traefik.http.routers.http_catchall.rule: HostRegexp(`{any:.+}`)
traefik.http.routers.http_catchall.entrypoints: web
traefik.http.routers.http_catchall.middlewares: https_redirect
traefik.http.middlewares.https_redirect.redirectscheme.scheme: https
traefik.http.middlewares.https_redirect.redirectscheme.permanent: true
volumes:
- /var/run/docker.sock:/var/run/docker.sock
```
```bash tab="CLI"
## static configuration
```yaml tab="K8s IngressRoute"
# The entry points web (port 80) and websecure (port 443) must be defined the static configuration.
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: http_catchall
namespace: traefik
spec:
entryPoints:
- web
routes:
- match: HostRegexp(`{any:.+}`)
kind: Rule
services:
# the noop service will be never called
- name: noop@internal
middlewares:
- name: https_redirect
# if the Middleware has distinct namespace
namespace: traefik
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: https_redirect
namespace: traefik
spec:
redirectScheme:
scheme: https
permanent: true
--entrypoints.web.address=:80
--entrypoints.web.http.redirections.entrypoint.to=websecure
--entrypoints.web.http.redirections.entrypoint.scheme=https
--entrypoints.websecure.address=:443
--providers.docker=true
```
```toml tab="File (TOML)"
# traefik.toml
## static configuration
[entryPoints]
[entryPoints.web]
address = 80
[entryPoints.websecure]
address = 443
[providers.file]
directory = "/dynamic/"
##--------------------##
# /dynamic/redirect.toml
## dynamic configuration
[http.routers]
[http.routers.http_catchall]
entryPoints = ["web"]
middlewares = ["https_redirect"]
rule = "HostRegexp(`{any:.+}`)"
# the noop service will be never called
service = "noop@internal"
[http.middlewares]
[http.middlewares.https_redirect.redirectScheme]
[entryPoints.web]
address = 80
[entryPoints.web.http.redirections.entryPoint]
to = "websecure"
scheme = "https"
permanent = true
[entryPoints.websecure]
address = 443
```
```yaml tab="File (YAML)"
@@ -445,34 +386,14 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
entryPoints:
web:
address: 80
http:
redirections:
entrypoint:
to: websecure
scheme: https
websecure:
address: 443
providers:
file:
directory: /dynamic/
##--------------------##
# /dynamic/redirect.yml
## dynamic configuration
http:
routers:
http_catchall:
entryPoints:
- web
middlewares:
- https_redirect
rule: "HostRegexp(`{any:.+}`)"
# the noop service will be never called
service: noop@internal
middlewares:
https_redirect:
redirectScheme:
scheme: https
permanent: true
```
!!! example "HTTP to HTTPS redirection per domain"
@@ -480,26 +401,24 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
!!! info "v1"
```toml tab="File (TOML)"
# static configuration
defaultEntryPoints = ["web", "websecure"]
[entryPoints]
[entryPoints.web]
address = ":80"
[entryPoints.web.redirect]
entryPoint = "websecure"
[entryPoints.websecure]
address = ":443"
[entryPoints.websecure.tls]
[[entryPoints.websecure.tls.certificates]]
certFile = "examples/traefik.crt"
keyFile = "examples/traefik.key"
```
```bash tab="CLI"
--entrypoints=Name:web Address::80 Redirect.EntryPoint:websecure
--entryPoints='Name:websecure Address::443 TLS:path/to/my.cert,path/to/my.key'
[file]
[frontends]
[frontends.frontend1]
entryPoints = ["web", "websecure"]
[frontends.frontend1.routes]
[frontends.frontend1.routes.route0]
rule = "Host:foo.com"
[frontends.frontend1.redirect]
entryPoint = "websecure"
```
!!! info "v2"
@@ -565,17 +484,6 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
```
```toml tab="File (TOML)"
## static configuration
# traefik.toml
[entryPoints.web]
address = ":80"
[entryPoints.websecure]
address = ":443"
##---------------------##
## dynamic configuration
# dynamic-conf.toml
@@ -591,36 +499,14 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
service = "my-service"
entrypoints = ["websecure"]
[http.routers.router1.tls]
[http.services]
[[http.services.my-service.loadBalancer.servers]]
url = "http://10.10.10.1:80"
[[http.services.my-service.loadBalancer.servers]]
url = "http://10.10.10.2:80"
[http.middlewares]
[http.middlewares.https_redirect.redirectScheme]
scheme = "https"
permanent = true
[[tls.certificates]]
certFile = "/path/to/domain.cert"
keyFile = "/path/to/domain.key"
```
```yaml tab="File (YAML)"
## static configuration
# traefik.yml
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
##---------------------##
## dynamic configuration
# dynamic-conf.yml
@@ -641,23 +527,11 @@ To apply a redirection, one of the redirect middlewares, [RedirectRegex](../midd
service: my-service
tls: {}
services:
my-service:
loadBalancer:
servers:
- url: http://10.10.10.1:80
- url: http://10.10.10.2:80
middlewares:
https_redirect:
redirectScheme:
scheme: https
permanent: true
tls:
certificates:
- certFile: /app/certs/server/server.pem
keyFile: /app/certs/server/server.pem
```
## Strip and Rewrite Path Prefixes
@@ -670,8 +544,8 @@ after the routing step with [router rule `PathPrefix`](../routing/routers/index.
Use Case: Incoming requests to `http://company.org/admin` are forwarded to the webapplication "admin",
with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, you must:
* First, configure a router named `admin` with a rule matching at least the path prefix with the `PathPrefix` keyword,
* Then, define a middleware of type [`stripprefix`](../middlewares/stripprefix.md), which removes the prefix `/admin`, associated to the router `admin`.
- First, configure a router named `admin` with a rule matching at least the path prefix with the `PathPrefix` keyword,
- Then, define a middleware of type [`stripprefix`](../middlewares/stripprefix.md), which removes the prefix `/admin`, associated to the router `admin`.
!!! example "Strip Path Prefix When Forwarding to Backend"
@@ -787,10 +661,10 @@ with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, yo
Instead of removing the path prefix with the [`stripprefix` middleware](../../middlewares/stripprefix/), you can also:
* Add a path prefix with the [`addprefix` middleware](../../middlewares/addprefix/)
* Replace the complete path of the request with the [`replacepath` middleware](../../middlewares/replacepath/)
* ReplaceRewrite path using Regexp with the [`replacepathregex` middleware](../../middlewares/replacepathregex/)
* And a lot more on the [`middlewares` page](../../middlewares/overview/)
- Add a path prefix with the [`addprefix` middleware](../../middlewares/addprefix/)
- Replace the complete path of the request with the [`replacepath` middleware](../../middlewares/replacepath/)
- ReplaceRewrite path using Regexp with the [`replacepathregex` middleware](../../middlewares/replacepathregex/)
- And a lot more on the [`middlewares` page](../../middlewares/overview/)
## ACME (LetsEncrypt)
@@ -817,8 +691,7 @@ with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, yo
storage = "acme.json"
entryPoint = "websecure"
onHostRule = true
[acme.httpChallenge]
entryPoint = "web"
[acme.tlsChallenge]
```
```bash tab="CLI"
@@ -829,7 +702,7 @@ with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, yo
--acme.storage=acme.json
--acme.entryPoint=websecure
--acme.onHostRule=true
--acme.httpchallenge.entrypoint=http
--acme.tlschallenge=true
```
!!! info "v2"
@@ -842,13 +715,13 @@ with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, yo
[entryPoints.websecure]
address = ":443"
[entryPoints.websecure.http.tls]
certResolver = "myresolver"
[certificatesResolvers.myresolver.acme]
email = "your-email@your-domain.org"
storage = "acme.json"
[certificatesResolvers.myresolver.acme.httpChallenge]
# used during the challenge
entryPoint = "web"
[certificatesResolvers.myresolver.acme.tlsChallenge]
```
```yaml tab="File (YAML)"
@@ -858,23 +731,24 @@ with the path `/admin` stripped, e.g. to `http://<IP>:<port>/`. In this case, yo
websecure:
address: ":443"
http:
tls:
certResolver: myresolver
certificatesResolvers:
myresolver:
acme:
email: your-email@your-domain.org
storage: acme.json
httpChallenge:
# used during the challenge
entryPoint: web
tlsChallenge: {}
```
```bash tab="CLI"
--entryPoints.web.address=:80
--entryPoints.websecure.address=:443
--certificatesResolvers.myresolver.acme.email=your-email@your-domain.org
--certificatesResolvers.myresolver.acme.storage=acme.json
--certificatesResolvers.myresolver.acme.httpChallenge.entryPoint=web
--entrypoints.web.address=:80
--entrypoints.websecure.address=:443
--certificatesresolvers.myresolver.acme.email=your-email@your-domain.org
--certificatesresolvers.myresolver.acme.storage=acme.json
--certificatesresolvers.myresolver.acme.tlschallenge=true
```
## Traefik Logs
@@ -1123,14 +997,11 @@ Each root item has been moved to a related section or removed.
## Dashboard
You need to activate the API to access the [dashboard](../operations/dashboard.md).
As the dashboard access is now secured by default you can either:
* define a [specific router](../operations/api.md#configuration) with the `api@internal` service and one authentication middleware like the following example
* or use the [insecure](../operations/api.md#insecure) option of the API
To activate the dashboard, you can either:
!!! info "Dashboard with k8s and dedicated router"
As `api@internal` is not a Kubernetes service, you have to use the file provider or the `insecure` API option.
- use the [secure mode](../operations/dashboard.md#secure-mode) with the `api@internal` service like in the following examples
- or use the [insecure mode](../operations/api.md#insecure)
!!! example "Activate and access the dashboard"
@@ -1164,7 +1035,7 @@ As the dashboard access is now secured by default you can either:
# dynamic configuration
labels:
- "traefik.http.routers.api.rule=Host(`traefik.docker.localhost`)"
- "traefik.http.routers.api.entrypoints=websecured"
- "traefik.http.routers.api.entrypoints=websecure"
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.middlewares=myAuth"
- "traefik.http.routers.api.tls"
@@ -1242,28 +1113,28 @@ As the dashboard access is now secured by default you can either:
Supported [providers](../providers/overview.md), for now:
* [ ] Azure Service Fabric
* [x] Consul
* [x] Consul Catalog
* [x] Docker
* [ ] DynamoDB
* [ ] ECS
* [x] Etcd
* [ ] Eureka
* [x] File
* [x] Kubernetes Ingress (without annotations)
* [x] Kubernetes IngressRoute
* [x] Marathon
* [ ] Mesos
* [x] Rancher
* [x] Redis
* [x] Rest
* [x] Zookeeper
- [ ] Azure Service Fabric
- [x] Consul
- [x] Consul Catalog
- [x] Docker
- [ ] DynamoDB
- [ ] ECS
- [x] Etcd
- [ ] Eureka
- [x] File
- [x] Kubernetes Ingress
- [x] Kubernetes IngressRoute
- [x] Marathon
- [ ] Mesos
- [x] Rancher
- [x] Redis
- [x] Rest
- [x] Zookeeper
## Some Tips You Should Know
* Different sources of static configuration (file, CLI flags, ...) cannot be [mixed](../getting-started/configuration-overview.md#the-static-configuration).
* Now, configuration elements can be referenced between different providers by using the provider namespace notation: `@<provider>`.
- Different sources of static configuration (file, CLI flags, ...) cannot be [mixed](../getting-started/configuration-overview.md#the-static-configuration).
- Now, configuration elements can be referenced between different providers by using the provider namespace notation: `@<provider>`.
For instance, a router named `myrouter` in a File Provider can refer to a service named `myservice` defined in Docker Provider with the following notation: `myservice@docker`.
* Middlewares are applied in the same order as their declaration in router.
* If you have any questions feel free to join our [community forum](https://community.containo.us).
- Middlewares are applied in the same order as their declaration in router.
- If you have any questions feel free to join our [community forum](https://community.containo.us).

View File

@@ -261,7 +261,7 @@ See the sections [Docker API Access](#docker-api-access) and [Docker Swarm API A
services:
traefik:
image: traefik:v2.1 # The official v2 Traefik docker image
image: traefik:v2.2 # The official v2 Traefik docker image
ports:
- "80:80"
volumes:
@@ -473,19 +473,19 @@ _Optional, Default=15_
```toml tab="File (TOML)"
[providers.docker]
swarmModeRefreshSeconds = "30s"
swarmModeRefreshSeconds = 30
# ...
```
```yaml tab="File (YAML)"
providers:
docker:
swarmModeRefreshSeconds: "30s"
swarmModeRefreshSeconds: 30
# ...
```
```bash tab="CLI"
--providers.docker.swarmModeRefreshSeconds=30s
--providers.docker.swarmModeRefreshSeconds=30
# ...
```

View File

@@ -357,7 +357,7 @@ providers:
### Further
If one wants to know more about the various aspects of the Ingress spec that Traefik supports,
many examples of Ingresses definitions are located in the tests [data](https://github.com/containous/traefik/tree/v2.1/pkg/provider/kubernetes/ingress/fixtures) of the Traefik repository.
many examples of Ingresses definitions are located in the tests [data](https://github.com/containous/traefik/tree/v2.2/pkg/provider/kubernetes/ingress/fixtures) of the Traefik repository.
## LetsEncrypt Support with the Ingress Provider

View File

@@ -43,7 +43,7 @@ The Kubernetes Ingress Controller, The Custom Resource Way.
serviceAccountName: traefik-ingress-controller
containers:
- name: traefik
image: traefik:v2.1
image: traefik:v2.2
args:
- --log.level=DEBUG
- --api
@@ -355,25 +355,25 @@ Register the `IngressRoute` [kind](../../reference/dynamic-configuration/kuberne
- b.foo.com
```
| Ref | Attribute | Purpose |
|------|----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [1] | `entryPoints` | List of [entry points](../routers/index.md#entrypoints) names |
| [2] | `routes` | List of routes |
| [3] | `routes[n].match` | Defines the [rule](../routers/index.md#rule) corresponding to an underlying router. |
| [4] | `routes[n].priority` | [Disambiguate](../routers/index.md#priority) rules of the same length, for route matching |
| [5] | `routes[n].middlewares` | List of reference to [Middleware](#kind-middleware) |
| [6] | `middlewares[n].name` | Defines the [Middleware](#kind-middleware) name |
| [7] | `middlewares[n].namespace` | Defines the [Middleware](#kind-middleware) namespace |
| [8] | `routes[n].services` | List of any combination of [TraefikService](#kind-traefikservice) and reference to a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) |
| [9] | `tls` | Defines [TLS](../routers/index.md#tls) certificate configuration |
| [10] | `tls.secretName` | Defines the [secret](https://kubernetes.io/docs/concepts/configuration/secret/) name used to store the certificate (in the `IngressRoute` namespace) |
| [11] | `tls.options` | Defines the reference to a [TLSOption](#kind-tlsoption) |
| [12] | `options.name` | Defines the [TLSOption](#kind-tlsoption) name |
| [13] | `options.namespace` | Defines the [TLSOption](#kind-tlsoption) namespace |
| [14] | `tls.certResolver` | Defines the reference to a [CertResolver](../routers/index.md#certresolver) |
| [15] | `tls.domains` | List of [domains](../routers/index.md#domains) |
| [16] | `domains[n].main` | Defines the main domain name |
| [17] | `domains[n].sans` | List of SANs (alternative domains) |
| Ref | Attribute | Purpose |
|------|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [1] | `entryPoints` | List of [entry points](../routers/index.md#entrypoints) names |
| [2] | `routes` | List of routes |
| [3] | `routes[n].match` | Defines the [rule](../routers/index.md#rule) corresponding to an underlying router. |
| [4] | `routes[n].priority` | [Disambiguate](../routers/index.md#priority) rules of the same length, for route matching |
| [5] | `routes[n].middlewares` | List of reference to [Middleware](#kind-middleware) |
| [6] | `middlewares[n].name` | Defines the [Middleware](#kind-middleware) name |
| [7] | `middlewares[n].namespace` | Defines the [Middleware](#kind-middleware) namespace |
| [8] | `routes[n].services` | List of any combination of [TraefikService](#kind-traefikservice) and reference to a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) (See below for `ExternalName Service` setup) |
| [9] | `tls` | Defines [TLS](../routers/index.md#tls) certificate configuration |
| [10] | `tls.secretName` | Defines the [secret](https://kubernetes.io/docs/concepts/configuration/secret/) name used to store the certificate (in the `IngressRoute` namespace) |
| [11] | `tls.options` | Defines the reference to a [TLSOption](#kind-tlsoption) |
| [12] | `options.name` | Defines the [TLSOption](#kind-tlsoption) name |
| [13] | `options.namespace` | Defines the [TLSOption](#kind-tlsoption) namespace |
| [14] | `tls.certResolver` | Defines the reference to a [CertResolver](../routers/index.md#certresolver) |
| [15] | `tls.domains` | List of [domains](../routers/index.md#domains) |
| [16] | `domains[n].main` | Defines the main domain name |
| [17] | `domains[n].sans` | List of SANs (alternative domains) |
??? example "Declaring an IngressRoute"
@@ -467,6 +467,112 @@ Register the `IngressRoute` [kind](../../reference/dynamic-configuration/kuberne
- Setting the kubernetes service port to use port 443 (https)
If you do not configure the above, Traefik will assume an http connection.
!!! important "Using Kubernetes ExternalName Service"
Traefik backends creation needs a port to be set, however Kubernetes [ExternalName Service](https://kubernetes.io/fr/docs/concepts/services-networking/service/#externalname) could be defined without any port.
Accordingly, Traefik supports defining a port in two ways:
- only on `IngressRoute` service
- on both sides, you'll be warned if the ports don't match, and the `IngressRoute` service port is used
Thus, in case of two sides port definition, Traefik expects a match between ports.
??? example "Examples"
```yaml tab="IngressRoute"
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
routes:
- match: Host(`foo.com`)
kind: Rule
services:
- name: external-svc
port: 80
---
apiVersion: v1
kind: Service
metadata:
name: external-svc
namespace: default
spec:
externalName: external.domain
type: ExternalName
```
```yaml tab="ExternalName Service"
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
routes:
- match: Host(`foo.com`)
kind: Rule
services:
- name: external-svc
---
apiVersion: v1
kind: Service
metadata:
name: external-svc
namespace: default
spec:
externalName: external.domain
type: ExternalName
ports:
- port: 80
```
```yaml tab="Both sides"
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
routes:
- match: Host(`foo.com`)
kind: Rule
services:
- name: external-svc
port: 80
---
apiVersion: v1
kind: Service
metadata:
name: external-svc
namespace: default
spec:
externalName: external.domain
type: ExternalName
ports:
- port: 80
```
### Kind: `Middleware`
@@ -853,7 +959,7 @@ Register the `IngressRouteTCP` [kind](../../reference/dynamic-configuration/kube
| [1] | `entryPoints` | List of [entrypoints](../routers/index.md#entrypoints_1) names |
| [2] | `routes` | List of routes |
| [3] | `routes[n].match` | Defines the [rule](../routers/index.md#rule_1) corresponding to an underlying router |
| [4] | `routes[n].services` | List of [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) definitions |
| [4] | `routes[n].services` | List of [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) definitions (See below for `ExternalName Service` setup) |
| [5] | `services[n].name` | Defines the name of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) |
| [6] | `services[n].port` | Defines the port of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) |
| [7] | `services[n].weight` | Defines the weight to apply to the server load balancing |
@@ -928,6 +1034,111 @@ Register the `IngressRouteTCP` [kind](../../reference/dynamic-configuration/kube
tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=
```
!!! important "Using Kubernetes ExternalName Service"
Traefik backends creation needs a port to be set, however Kubernetes [ExternalName Service](https://kubernetes.io/fr/docs/concepts/services-networking/service/#externalname) could be defined without any port.
Accordingly, Traefik supports defining a port in two ways:
- only on `IngressRouteTCP` service
- on both sides, you'll be warned if the ports don't match, and the `IngressRouteTCP` service port is used
Thus, in case of two sides port definition, Traefik expects a match between ports.
??? example "Examples"
```yaml tab="IngressRouteTCP"
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
routes:
- match: HostSNI(`*`)
kind: Rule
services:
- name: external-svc
port: 80
---
apiVersion: v1
kind: Service
metadata:
name: external-svc
namespace: default
spec:
externalName: external.domain
type: ExternalName
```
```yaml tab="ExternalName Service"
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
routes:
- match: HostSNI(`*`)
kind: Rule
services:
- name: external-svc
---
apiVersion: v1
kind: Service
metadata:
name: external-svc
namespace: default
spec:
externalName: external.domain
type: ExternalName
ports:
- port: 80
```
```yaml tab="Both sides"
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
routes:
- match: HostSNI(`*`)
kind: Rule
services:
- name: external-svc
port: 80
---
apiVersion: v1
kind: Service
metadata:
name: external-svc
namespace: default
spec:
externalName: external.domain
type: ExternalName
ports:
- port: 80
```
### Kind `IngressRouteUDP`
`IngressRouteUDP` is the CRD implementation of a [Traefik UDP router](../routers/index.md#configuring-udp-routers).

View File

@@ -9,74 +9,184 @@ The provider then watches for incoming ingresses events, such as the example bel
and derives the corresponding dynamic configuration from it,
which in turn will create the resulting routers, services, handlers, etc.
```yaml
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: foo
namespace: production
## Configuration Example
spec:
rules:
- host: foo.com
http:
paths:
- path: /bar
backend:
serviceName: service1
servicePort: 80
- path: /foo
backend:
serviceName: service1
servicePort: 80
tls:
- secretName: mySecret
```
### Annotations
??? example
??? example "Configuring Kubernetes Ingress Controller"
```yaml tab="RBAC"
---
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
---
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
```
```yaml tab="Ingress"
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: foo
namespace: production
name: myingress
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web
spec:
rules:
- host: foo.com
http:
paths:
- path: /bar
backend:
serviceName: service1
servicePort: 80
- path: /foo
backend:
serviceName: service1
servicePort: 80
- host: mydomain.com
http:
paths:
- path: /bar
backend:
serviceName: whoami
servicePort: 80
- path: /foo
backend:
serviceName: whoami
servicePort: 80
```
```yaml tab="Service"
kind: Service
```yaml tab="Traefik"
apiVersion: v1
kind: ServiceAccount
metadata:
name: service1
namespace: testing
annotations:
traefik.ingress.kubernetes.io/service.passhostheader: "false"
name: traefik-ingress-controller
---
kind: Deployment
apiVersion: apps/v1
metadata:
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.2
args:
- --log.level=DEBUG
- --api
- --api.insecure
- --entrypoints.web.address=:80
- --providers.kubernetesingress
ports:
- name: web
containerPort: 80
- name: admin
containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: traefik
spec:
type: LoadBalancer
selector:
app: traefik
ports:
- protocol: TCP
port: 80
name: web
targetPort: 80
- protocol: TCP
port: 8080
name: admin
targetPort: 8080
```
```yaml tab="Whoami"
kind: Deployment
apiVersion: apps/v1
metadata:
name: whoami
labels:
app: containous
name: whoami
spec:
replicas: 2
selector:
matchLabels:
app: containous
task: whoami
template:
metadata:
labels:
app: containous
task: whoami
spec:
containers:
- name: containouswhoami
image: containous/whoami
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: whoami
spec:
ports:
- port: 80
clusterIp: 10.0.0.1
- name: http
port: 80
selector:
app: containous
task: whoami
```
## Annotations
#### On Ingress
??? info "`traefik.ingress.kubernetes.io/router.entrypoints`"

View File

@@ -795,11 +795,10 @@ Services are the target for the router.
When a TLS section is specified,
it instructs Traefik that the current router is dedicated to TLS requests only (and that the router should ignore non-TLS requests).
By default, Traefik will terminate the SSL connections (meaning that it will send decrypted data to the services),
but Traefik can be configured in order to let the requests pass through (keeping the data encrypted), and be forwarded to the service "as is".
??? example "Configuring TLS Termination"
By default, a router with a TLS section will terminate the TLS connections, meaning that it will send decrypted data to the services.
??? example "Router for TLS requests"
```toml tab="File (TOML)"
## Dynamic configuration
@@ -822,6 +821,13 @@ but Traefik can be configured in order to let the requests pass through (keeping
tls: {}
```
#### `passthrough`
As seen above, a TLS router will terminate the TLS connection by default.
However, the `passthrough` option can be specified to set whether the requests should be forwarded "as is", keeping all data encrypted.
It defaults to `false`.
??? example "Configuring passthrough"
```toml tab="File (TOML)"

View File

@@ -26,7 +26,7 @@ spec:
serviceAccountName: traefik-ingress-controller
containers:
- name: traefik
image: traefik:v2.1
image: traefik:v2.2
args:
- --api.insecure
- --accesslog

View File

@@ -26,5 +26,5 @@ node:
- 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.1 image.
# 'docker save'), if you want to use it, instead of the traefik:v2.2 image.
- /sowewhere/on/your/host/custom-image:/var/lib/rancher/k3s/agent/images

View File

@@ -3,7 +3,7 @@ version: "3.3"
services:
traefik:
image: "traefik:v2.1"
image: "traefik:v2.2"
container_name: "traefik"
command:
#- "--log.level=DEBUG"

View File

@@ -13,7 +13,7 @@ secrets:
services:
traefik:
image: "traefik:v2.1"
image: "traefik:v2.2"
container_name: "traefik"
command:
#- "--log.level=DEBUG"

View File

@@ -3,7 +3,7 @@ version: "3.3"
services:
traefik:
image: "traefik:v2.1"
image: "traefik:v2.2"
container_name: "traefik"
command:
#- "--log.level=DEBUG"

View File

@@ -3,7 +3,7 @@ version: "3.3"
services:
traefik:
image: "traefik:v2.1"
image: "traefik:v2.2"
container_name: "traefik"
command:
#- "--log.level=DEBUG"

View File

@@ -3,7 +3,7 @@ version: "3.3"
services:
traefik:
image: "traefik:v2.1"
image: "traefik:v2.2"
container_name: "traefik"
command:
#- "--log.level=DEBUG"

View File

@@ -15,5 +15,5 @@
[mkdocs-material]: https://squidfunk.github.io/mkdocs-material/ "Material for MkDocs"
[mkdocs-material-src]: https://github.com/squidfunk/mkdocs-material "Material for MkDocs - Sources"
[pymdown-extensions]: https://facelessuser.github.io/pymdown-extensions/extensions "PyMdown Extensions"
[pymdown-extensions]: https://facelessuser.github.io/pymdown-extensions "PyMdown Extensions"
[pymdown-extensions-src]: https://github.com/facelessuser/pymdown-extensions "PyMdown Extensions - Sources"

View File

@@ -126,3 +126,13 @@ spec:
selector:
app: containous
task: whoamiudp
---
apiVersion: v1
kind: Service
metadata:
name: externalname-svc
namespace: default
spec:
externalName: domain.com
type: ExternalName

View File

@@ -13,6 +13,8 @@ spec:
- name: whoamitcp
namespace: default
port: 8080
- name: externalname-svc
port: 9090
tls:
options:
name: mytlsoption

View File

@@ -194,18 +194,44 @@
}
},
"tcpServices": {
"default-test3.route-673acf455cb2dab0b43a@kubernetescrd": {
"default-test3.route-673acf455cb2dab0b43a-externalname-svc-9090@kubernetescrd": {
"loadBalancer": {
"terminationDelay": 100,
"servers": [
{
"address": "10.42.0.4:8080"
"address": "domain.com:9090"
}
]
},
"status": "enabled"
},
"default-test3.route-673acf455cb2dab0b43a-whoamitcp-8080@kubernetescrd": {
"loadBalancer": {
"terminationDelay": 100,
"servers": [
{
"address": "10.42.0.3:8080"
},
{
"address": "10.42.0.8:8080"
}
]
},
"status": "enabled"
},
"default-test3.route-673acf455cb2dab0b43a@kubernetescrd": {
"weighted": {
"services": [
{
"name": "default-test3.route-673acf455cb2dab0b43a-whoamitcp-8080",
"weight": 1
},
{
"name": "default-test3.route-673acf455cb2dab0b43a-externalname-svc-9090",
"weight": 1
}
]
},
"status": "enabled",
"usedBy": [
"default-test3.route-673acf455cb2dab0b43a@kubernetescrd"

View File

@@ -30,8 +30,8 @@
},
"test-ingress-default-whoami-test-whoami@kubernetes": {
"entryPoints": [
"web",
"traefik"
"traefik",
"web"
],
"service": "default-whoami-http",
"rule": "Host(`whoami.test`) \u0026\u0026 PathPrefix(`/whoami`)",
@@ -43,8 +43,8 @@
},
"test-ingress-https-default-whoami-test-https-whoami@kubernetes": {
"entryPoints": [
"web",
"traefik"
"traefik",
"web"
],
"service": "default-whoami-http",
"rule": "Host(`whoami.test.https`) \u0026\u0026 PathPrefix(`/whoami`)",

View File

@@ -118,3 +118,44 @@ subsets:
ports:
- name: websecure2
port: 8443
---
apiVersion: v1
kind: Service
metadata:
name: external-svc
namespace: default
spec:
externalName: external.domain
type: ExternalName
---
apiVersion: v1
kind: Service
metadata:
name: external-svc-with-http
namespace: default
spec:
externalName: external.domain
type: ExternalName
ports:
- name: http
protocol: TCP
port: 80
---
apiVersion: v1
kind: Service
metadata:
name: external-svc-with-https
namespace: default
spec:
externalName: external.domain
type: ExternalName
ports:
- name: https
protocol: TCP
port: 443

View File

@@ -131,3 +131,40 @@ subsets:
ports:
- name: myapp4
port: 8084
---
apiVersion: v1
kind: Service
metadata:
name: external-svc
namespace: default
spec:
externalName: external.domain
type: ExternalName
---
apiVersion: v1
kind: Service
metadata:
name: external.service.with.port
namespace: default
spec:
externalName: external.domain
type: ExternalName
ports:
- name: http
protocol: TCP
port: 80
---
apiVersion: v1
kind: Service
metadata:
name: external.service.without.port
namespace: default
spec:
externalName: external.domain
type: ExternalName
ports:
- name: http
protocol: TCP

View File

@@ -0,0 +1,15 @@
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
routes:
- match: HostSNI(`foo.com`)
services:
- name: external-svc
port: 8000

View File

@@ -0,0 +1,15 @@
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
routes:
- match: HostSNI(`foo.com`)
services:
- name: external.service.with.port
port: 80

View File

@@ -0,0 +1,14 @@
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
routes:
- match: HostSNI(`foo.com`)
services:
- name: external-svc

View File

@@ -0,0 +1,16 @@
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
routes:
- match: Host(`foo.com`)
kind: Rule
services:
- name: external-svc
port: 80

View File

@@ -0,0 +1,16 @@
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
routes:
- match: Host(`foo.com`)
kind: Rule
services:
- name: external-svc-with-http
port: 80

View File

@@ -0,0 +1,16 @@
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
routes:
- match: Host(`foo.com`)
kind: Rule
services:
- name: external-svc-with-https
port: 443

View File

@@ -0,0 +1,15 @@
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
routes:
- match: Host(`foo.com`)
kind: Rule
services:
- name: external-svc

View File

@@ -5,6 +5,7 @@ import (
"bytes"
"context"
"crypto/sha256"
"errors"
"fmt"
"os"
"sort"
@@ -248,6 +249,38 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
return conf
}
func getServicePort(svc *corev1.Service, port int32) (*corev1.ServicePort, error) {
if svc == nil {
return nil, errors.New("service is not defined")
}
if port == 0 {
return nil, errors.New("ingressRoute service port not defined")
}
hasValidPort := false
for _, p := range svc.Spec.Ports {
if p.Port == port {
return &p, nil
}
if p.Port != 0 {
hasValidPort = true
}
}
if svc.Spec.Type != corev1.ServiceTypeExternalName {
return nil, fmt.Errorf("service port not found: %d", port)
}
if hasValidPort {
log.WithoutContext().
Warning("The port %d from IngressRoute doesn't match with ports defined in the ExternalName service %s/%s.", port, svc.Namespace, svc.Name)
}
return &corev1.ServicePort{Port: port}, nil
}
func createErrorPageMiddleware(client Client, namespace string, errorPage *v1alpha1.ErrorPage) (*dynamic.ErrorPage, *dynamic.Service, error) {
if errorPage == nil {
return nil, nil, nil

View File

@@ -294,27 +294,20 @@ func (c configBuilder) loadServers(fallbackNamespace string, svc v1alpha1.LoadBa
return nil, fmt.Errorf("kubernetes service not found: %s/%s", namespace, sanitizedName)
}
confPort := svc.Port
var portSpec *corev1.ServicePort
for _, p := range service.Spec.Ports {
if confPort == p.Port {
portSpec = &p
break
}
}
if portSpec == nil {
return nil, errors.New("service port not found")
svcPort, err := getServicePort(service, svc.Port)
if err != nil {
return nil, err
}
var servers []dynamic.Server
if service.Spec.Type == corev1.ServiceTypeExternalName {
protocol, err := parseServiceProtocol(svc.Scheme, portSpec.Name, portSpec.Port)
protocol, err := parseServiceProtocol(svc.Scheme, svcPort.Name, svcPort.Port)
if err != nil {
return nil, err
}
return append(servers, dynamic.Server{
URL: fmt.Sprintf("%s://%s:%d", protocol, service.Spec.ExternalName, portSpec.Port),
URL: fmt.Sprintf("%s://%s:%d", protocol, service.Spec.ExternalName, svcPort.Port),
}), nil
}
@@ -332,7 +325,7 @@ func (c configBuilder) loadServers(fallbackNamespace string, svc v1alpha1.LoadBa
var port int32
for _, subset := range endpoints.Subsets {
for _, p := range subset.Ports {
if portSpec.Name == p.Name {
if svcPort.Name == p.Name {
port = p.Port
break
}
@@ -342,7 +335,7 @@ func (c configBuilder) loadServers(fallbackNamespace string, svc v1alpha1.LoadBa
return nil, fmt.Errorf("cannot define a port for %s/%s", namespace, sanitizedName)
}
protocol, err := parseServiceProtocol(svc.Scheme, portSpec.Name, portSpec.Port)
protocol, err := parseServiceProtocol(svc.Scheme, svcPort.Name, svcPort.Port)
if err != nil {
return nil, err
}

View File

@@ -162,22 +162,15 @@ func loadTCPServers(client Client, namespace string, svc v1alpha1.ServiceTCP) ([
return nil, errors.New("service not found")
}
var portSpec *corev1.ServicePort
for _, p := range service.Spec.Ports {
if svc.Port == p.Port {
portSpec = &p
break
}
}
if portSpec == nil {
return nil, errors.New("service port not found")
svcPort, err := getServicePort(service, svc.Port)
if err != nil {
return nil, err
}
var servers []dynamic.TCPServer
if service.Spec.Type == corev1.ServiceTypeExternalName {
servers = append(servers, dynamic.TCPServer{
Address: fmt.Sprintf("%s:%d", service.Spec.ExternalName, portSpec.Port),
Address: fmt.Sprintf("%s:%d", service.Spec.ExternalName, svcPort.Port),
})
} else {
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, svc.Name)
@@ -196,7 +189,7 @@ func loadTCPServers(client Client, namespace string, svc v1alpha1.ServiceTCP) ([
var port int32
for _, subset := range endpoints.Subsets {
for _, p := range subset.Ports {
if portSpec.Name == p.Name {
if svcPort.Name == p.Name {
port = p.Port
break
}

View File

@@ -4,6 +4,8 @@ import (
"context"
"testing"
corev1 "k8s.io/api/core/v1"
"github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/provider"
"github.com/containous/traefik/v2/pkg/tls"
@@ -906,6 +908,106 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
},
},
},
{
desc: "Simple Ingress Route, with externalName service",
paths: []string{"tcp/services.yml", "tcp/with_externalname.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"},
Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)",
},
},
Services: map[string]*dynamic.TCPService{
"default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "external.domain:8000",
Port: "",
},
},
},
},
},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Ingress Route, externalName service with port",
paths: []string{"tcp/services.yml", "tcp/with_externalname_with_port.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"},
Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)",
},
},
Services: map[string]*dynamic.TCPService{
"default-test.route-fdd3e9338e47a45efefc": {
LoadBalancer: &dynamic.TCPServersLoadBalancer{
Servers: []dynamic.TCPServer{
{
Address: "external.domain:80",
Port: "",
},
},
},
},
},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Ingress Route, externalName service without port",
paths: []string{"tcp/services.yml", "tcp/with_externalname_without_ports.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"default-test.route-fdd3e9338e47a45efefc": {
EntryPoints: []string{"foo"},
Service: "default-test.route-fdd3e9338e47a45efefc",
Rule: "HostSNI(`foo.com`)",
},
},
Services: map[string]*dynamic.TCPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
}
for _, test := range testCases {
@@ -2860,6 +2962,134 @@ func TestLoadIngressRoutes(t *testing.T) {
{
desc: "port selected by name (TODO)",
},
{
desc: "Simple Ingress Route, with externalName service",
paths: []string{"services.yml", "with_externalname.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-test-route-6f97418635c7e18853da": {
EntryPoints: []string{"foo"},
Service: "default-test-route-6f97418635c7e18853da",
Rule: "Host(`foo.com`)",
}},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-test-route-6f97418635c7e18853da": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://external.domain:80",
},
},
PassHostHeader: Bool(true),
},
},
},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Ingress Route, externalName service with http",
paths: []string{"services.yml", "with_externalname_with_http.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-test-route-6f97418635c7e18853da": {
EntryPoints: []string{"foo"},
Service: "default-test-route-6f97418635c7e18853da",
Rule: "Host(`foo.com`)",
}},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-test-route-6f97418635c7e18853da": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://external.domain:80",
},
},
PassHostHeader: Bool(true),
},
},
},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Ingress Route, externalName service with https",
paths: []string{"services.yml", "with_externalname_with_https.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-test-route-6f97418635c7e18853da": {
EntryPoints: []string{"foo"},
Service: "default-test-route-6f97418635c7e18853da",
Rule: "Host(`foo.com`)",
}},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-test-route-6f97418635c7e18853da": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "https://external.domain:443",
},
},
PassHostHeader: Bool(true),
},
},
},
},
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Ingress Route, externalName service without ports",
paths: []string{"services.yml", "with_externalname_without_ports.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Services: map[string]*dynamic.TCPService{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
}
for _, test := range testCases {
@@ -3255,3 +3485,148 @@ func TestParseServiceProtocol(t *testing.T) {
})
}
}
func TestGetServicePort(t *testing.T) {
testCases := []struct {
desc string
svc *corev1.Service
port int32
expected *corev1.ServicePort
expectError bool
}{
{
desc: "Basic",
expectError: true,
},
{
desc: "Matching ports, with no service type",
svc: &corev1.Service{
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{
{
Port: 80,
},
},
},
},
port: 80,
expected: &corev1.ServicePort{
Port: 80,
},
},
{
desc: "Matching ports 0",
svc: &corev1.Service{
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{
{},
},
},
},
expectError: true,
},
{
desc: "Matching ports 0 (with external name)",
svc: &corev1.Service{
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeExternalName,
Ports: []corev1.ServicePort{
{},
},
},
},
expectError: true,
},
{
desc: "Mismatching, only port(Ingress) defined",
svc: &corev1.Service{
Spec: corev1.ServiceSpec{},
},
port: 80,
expectError: true,
},
{
desc: "Mismatching, only port(Ingress) defined with external name",
svc: &corev1.Service{
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeExternalName,
},
},
port: 80,
expected: &corev1.ServicePort{
Port: 80,
},
},
{
desc: "Mismatching, only Service port defined",
svc: &corev1.Service{
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{
{
Port: 80,
},
},
},
},
expectError: true,
},
{
desc: "Mismatching, only Service port defined with external name",
svc: &corev1.Service{
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeExternalName,
Ports: []corev1.ServicePort{
{
Port: 80,
},
},
},
},
expectError: true,
},
{
desc: "Two different ports defined",
svc: &corev1.Service{
Spec: corev1.ServiceSpec{
Ports: []corev1.ServicePort{
{
Port: 80,
},
},
},
},
port: 443,
expectError: true,
},
{
desc: "Two different ports defined (with external name)",
svc: &corev1.Service{
Spec: corev1.ServiceSpec{
Type: corev1.ServiceTypeExternalName,
Ports: []corev1.ServicePort{
{
Port: 80,
},
},
},
},
port: 443,
expected: &corev1.ServicePort{
Port: 443,
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
actual, err := getServicePort(test.svc, test.port)
if test.expectError {
assert.Error(t, err)
} else {
assert.Equal(t, test.expected, actual)
}
})
}
}

View File

@@ -7,7 +7,7 @@ import (
"github.com/containous/traefik/v2/pkg/tls"
)
func mergeConfiguration(configurations dynamic.Configurations, entryPoints []string) dynamic.Configuration {
func mergeConfiguration(configurations dynamic.Configurations, defaultEntryPoints []string) dynamic.Configuration {
conf := dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: make(map[string]*dynamic.Router),
@@ -37,8 +37,8 @@ func mergeConfiguration(configurations dynamic.Configurations, entryPoints []str
if len(router.EntryPoints) == 0 {
log.WithoutContext().
WithField(log.RouterName, routerName).
Debugf("No entryPoint defined for this router, using the default one(s) instead: %+v", entryPoints)
router.EntryPoints = entryPoints
Debugf("No entryPoint defined for this router, using the default one(s) instead: %+v", defaultEntryPoints)
router.EntryPoints = defaultEntryPoints
}
conf.HTTP.Routers[provider.MakeQualifiedName(pvd, routerName)] = router
@@ -120,7 +120,9 @@ func applyModel(cfg dynamic.Configuration) dynamic.Configuration {
rts := make(map[string]*dynamic.Router)
for name, router := range cfg.HTTP.Routers {
for name, rt := range cfg.HTTP.Routers {
router := rt.DeepCopy()
eps := router.EntryPoints
router.EntryPoints = nil

View File

@@ -18,7 +18,7 @@ import (
type ConfigurationWatcher struct {
provider provider.Provider
entryPoints []string
defaultEntryPoints []string
providersThrottleDuration time.Duration
@@ -38,7 +38,7 @@ func NewConfigurationWatcher(
routinesPool *safe.Pool,
pvd provider.Provider,
providersThrottleDuration time.Duration,
entryPoints []string,
defaultEntryPoints []string,
) *ConfigurationWatcher {
watcher := &ConfigurationWatcher{
provider: pvd,
@@ -47,7 +47,7 @@ func NewConfigurationWatcher(
providerConfigUpdateMap: make(map[string]chan dynamic.Message),
providersThrottleDuration: providersThrottleDuration,
routinesPool: routinesPool,
entryPoints: entryPoints,
defaultEntryPoints: defaultEntryPoints,
}
currentConfigurations := make(dynamic.Configurations)
@@ -143,7 +143,7 @@ func (c *ConfigurationWatcher) loadMessage(configMsg dynamic.Message) {
c.currentConfigurations.Set(newConfigurations)
conf := mergeConfiguration(newConfigurations, c.entryPoints)
conf := mergeConfiguration(newConfigurations, c.defaultEntryPoints)
conf = applyModel(conf)
for _, listener := range c.configurationListeners {