Merge pull request #1208 from containous/merge-v1.2.0-rc2-master
Merge v1.2.0 rc2 master
This commit is contained in:
commit
7d83027954
23 changed files with 752 additions and 68 deletions
|
@ -9,7 +9,7 @@ env:
|
||||||
- secure: btt4r13t09gQlHb6gYrvGC2yGCMMHfnp1Mz1RQedc4Mpf/FfT8aE6xmK2a2i9CCvskjrP0t/BFaS4yxIURjnFRn+ugQIEa0pLspB9UJArW/vgOSpIWM9/OQ/fg8z5XuMxN6Md4DL1/iLypMNSageA1x0TRdt89+D1N1dALpg5XRCXLFbC84TLi0gjlFuib9ibPKzEhLT+anCRJ6iZMzeupDSoaCVbAtJMoDvXw4+4AcRZ1+k4MybBLyCib5boaEOt4pTT88mz4Kk0YaMwPVJyg9Qv36VqyUcPS09Yd95LuyVQ4+tZt8Y1ccbIzULsK+sLM3hLCzxlmlpN3dQBlZJiiRtQde0mgGAKyC0P0A1XjuDTywcsa5edB+fTk1Dsewz9xZ9V0NmMz8t+UNZnaSsAPga9i86jULbXUUwMVSzVRc+Xgx02liB/8qI1xYC9FM6ilStt7rn7mF0k3KbiWhcptgeXjO6Lah9FjEKd5w4MXsdUSTi/86rQaLo+kj+XdaTrXCTulKHyRyQEUj+8V1w0oVz7pcGjePHd7y5oU9ByifVQy6sytuFBfRZvugM5bKHo+i0pcWvixrZS42DrzwxZJsspANOvqSe5ifVbvOkfUppQdCBIwptxV5N1b49XPKU3W/w34QJ8xGmKp3TFA7WwVCztriFHjPgiRpB3EG99Bg=
|
- secure: btt4r13t09gQlHb6gYrvGC2yGCMMHfnp1Mz1RQedc4Mpf/FfT8aE6xmK2a2i9CCvskjrP0t/BFaS4yxIURjnFRn+ugQIEa0pLspB9UJArW/vgOSpIWM9/OQ/fg8z5XuMxN6Md4DL1/iLypMNSageA1x0TRdt89+D1N1dALpg5XRCXLFbC84TLi0gjlFuib9ibPKzEhLT+anCRJ6iZMzeupDSoaCVbAtJMoDvXw4+4AcRZ1+k4MybBLyCib5boaEOt4pTT88mz4Kk0YaMwPVJyg9Qv36VqyUcPS09Yd95LuyVQ4+tZt8Y1ccbIzULsK+sLM3hLCzxlmlpN3dQBlZJiiRtQde0mgGAKyC0P0A1XjuDTywcsa5edB+fTk1Dsewz9xZ9V0NmMz8t+UNZnaSsAPga9i86jULbXUUwMVSzVRc+Xgx02liB/8qI1xYC9FM6ilStt7rn7mF0k3KbiWhcptgeXjO6Lah9FjEKd5w4MXsdUSTi/86rQaLo+kj+XdaTrXCTulKHyRyQEUj+8V1w0oVz7pcGjePHd7y5oU9ByifVQy6sytuFBfRZvugM5bKHo+i0pcWvixrZS42DrzwxZJsspANOvqSe5ifVbvOkfUppQdCBIwptxV5N1b49XPKU3W/w34QJ8xGmKp3TFA7WwVCztriFHjPgiRpB3EG99Bg=
|
||||||
- REPO: $TRAVIS_REPO_SLUG
|
- REPO: $TRAVIS_REPO_SLUG
|
||||||
- VERSION: $TRAVIS_TAG
|
- VERSION: $TRAVIS_TAG
|
||||||
- CODENAME: camembert
|
- CODENAME: morbier
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
|
|
146
CHANGELOG.md
146
CHANGELOG.md
|
@ -1,5 +1,151 @@
|
||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
|
||||||
|
## [v1.2.0-rc2](https://github.com/containous/traefik/tree/v1.2.0-rc2) (2017-03-01)
|
||||||
|
[Full Changelog](https://github.com/containous/traefik/compare/v1.2.0-rc1...v1.2.0-rc2)
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- Are there plans to support the service type ExternalName in Kubernetes? [\#1142](https://github.com/containous/traefik/issues/1142)
|
||||||
|
- Kubernetes Ingress and sticky support [\#911](https://github.com/containous/traefik/issues/911)
|
||||||
|
- kubernetes client does not support InsecureSkipVerify [\#876](https://github.com/containous/traefik/issues/876)
|
||||||
|
- Support active health checking like HAProxy [\#824](https://github.com/containous/traefik/issues/824)
|
||||||
|
- Allow k8s ingress controller serviceAccountToken and serviceAccountCACert to be changed [\#611](https://github.com/containous/traefik/issues/611)
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- \[rancher\] invalid memory address or nil pointer dereference [\#1134](https://github.com/containous/traefik/issues/1134)
|
||||||
|
- Kubernetes default backend should work [\#1073](https://github.com/containous/traefik/issues/1073)
|
||||||
|
|
||||||
|
**Closed issues:**
|
||||||
|
|
||||||
|
- Are release Download links broken? [\#1201](https://github.com/containous/traefik/issues/1201)
|
||||||
|
- Bind to specific ip address [\#1193](https://github.com/containous/traefik/issues/1193)
|
||||||
|
- DNS01 challenge use the wrong zone through route53 [\#1192](https://github.com/containous/traefik/issues/1192)
|
||||||
|
- Reverse proxy https to http backends fails [\#1180](https://github.com/containous/traefik/issues/1180)
|
||||||
|
- Swarm Mode + Letsecrypt + KV Store [\#1176](https://github.com/containous/traefik/issues/1176)
|
||||||
|
- docker deploy -c example.yml e [\#1169](https://github.com/containous/traefik/issues/1169)
|
||||||
|
- Traefik not finding dynamically added services \(Docker Swarm Mode\) [\#1168](https://github.com/containous/traefik/issues/1168)
|
||||||
|
- Traefik with Kubernetes backend - keep getting 401 on all GET requests to kube-apiserver [\#1166](https://github.com/containous/traefik/issues/1166)
|
||||||
|
- Near line 15 \(last key parsed 'backends.backend-monitor-viz.servers'\): Key 'backends.backend-monitor-viz.servers.server-monitor\_viz-1' has already been defined. [\#1154](https://github.com/containous/traefik/issues/1154)
|
||||||
|
- How to reuse SSL certificates automatically fetched from Let´s encrypt? [\#1152](https://github.com/containous/traefik/issues/1152)
|
||||||
|
- Dynamically ban ip when backend repeatedly returns specified status code. \( 403 \) [\#1136](https://github.com/containous/traefik/issues/1136)
|
||||||
|
- Always get 404 accessing my nginx backend service [\#1112](https://github.com/containous/traefik/issues/1112)
|
||||||
|
- Incomplete Docu [\#1091](https://github.com/containous/traefik/issues/1091)
|
||||||
|
- LoadCertificateForDomains: runtime error: invalid memory address [\#1069](https://github.com/containous/traefik/issues/1069)
|
||||||
|
- Traefik creating backends & mappings for ingress annotated with ingress.class: nginx [\#1058](https://github.com/containous/traefik/issues/1058)
|
||||||
|
- ACME file format description [\#1012](https://github.com/containous/traefik/issues/1012)
|
||||||
|
- SwarmMode - Not routing on worker node [\#838](https://github.com/containous/traefik/issues/838)
|
||||||
|
- Migrate k8s to kubernetes/client-go [\#678](https://github.com/containous/traefik/issues/678)
|
||||||
|
- Support for sticky session with kubernetes ingress as backend [\#674](https://github.com/containous/traefik/issues/674)
|
||||||
|
|
||||||
|
**Merged pull requests:**
|
||||||
|
|
||||||
|
- Revert "Ensure that we don't add balancees with no health check runs … [\#1198](https://github.com/containous/traefik/pull/1198) ([jangie](https://github.com/jangie))
|
||||||
|
- Small fixes and improvments [\#1173](https://github.com/containous/traefik/pull/1173) ([SantoDE](https://github.com/SantoDE))
|
||||||
|
- Fix docker issues with global and dead tasks [\#1167](https://github.com/containous/traefik/pull/1167) ([christopherobin](https://github.com/christopherobin))
|
||||||
|
- Better ECS error checking [\#1143](https://github.com/containous/traefik/pull/1143) ([lpetre](https://github.com/lpetre))
|
||||||
|
- Fix stats race condition [\#1141](https://github.com/containous/traefik/pull/1141) ([emilevauge](https://github.com/emilevauge))
|
||||||
|
- ECS: Docs - info about cred. resolution and required access policies [\#1137](https://github.com/containous/traefik/pull/1137) ([rickard-von-essen](https://github.com/rickard-von-essen))
|
||||||
|
- Healthcheck tests and doc [\#1132](https://github.com/containous/traefik/pull/1132) ([Juliens](https://github.com/Juliens))
|
||||||
|
|
||||||
|
## [v1.2.0-rc1](https://github.com/containous/traefik/tree/v1.2.0-rc1) (2017-02-06)
|
||||||
|
[Full Changelog](https://github.com/containous/traefik/compare/v1.1.2...v1.2.0-rc1)
|
||||||
|
|
||||||
|
**Implemented enhancements:**
|
||||||
|
|
||||||
|
- Add FreeBSD and OpenBSD to release builds [\#923](https://github.com/containous/traefik/issues/923)
|
||||||
|
- Write authenticated user to header key [\#802](https://github.com/containous/traefik/issues/802)
|
||||||
|
- Question: Wildcard Host for Kubernetes Ingress [\#792](https://github.com/containous/traefik/issues/792)
|
||||||
|
- First commit prometheus middleware. [\#1022](https://github.com/containous/traefik/pull/1022) ([enxebre](https://github.com/enxebre))
|
||||||
|
- Use deployment primitives from travis [\#843](https://github.com/containous/traefik/pull/843) ([guilhem](https://github.com/guilhem))
|
||||||
|
|
||||||
|
**Fixed bugs:**
|
||||||
|
|
||||||
|
- Increase Docker API version to work with Windows Containers [\#1094](https://github.com/containous/traefik/issues/1094)
|
||||||
|
|
||||||
|
**Closed issues:**
|
||||||
|
|
||||||
|
- How could I know whether forwarding path is correctly set? [\#1111](https://github.com/containous/traefik/issues/1111)
|
||||||
|
- ACME + Docker-compose labels [\#1099](https://github.com/containous/traefik/issues/1099)
|
||||||
|
- Loadbalance between 2 containers in Docker Swarm Mode [\#1095](https://github.com/containous/traefik/issues/1095)
|
||||||
|
- Add DNS01 letsencrypt challenge support through AWS. [\#1093](https://github.com/containous/traefik/issues/1093)
|
||||||
|
- New Release Cut [\#1092](https://github.com/containous/traefik/issues/1092)
|
||||||
|
- Marathon integration changed default backend server port from task-level to application-level [\#1072](https://github.com/containous/traefik/issues/1072)
|
||||||
|
- websockets not working when compress = true in toml config. [\#1059](https://github.com/containous/traefik/issues/1059)
|
||||||
|
- Proxying 403 http status into the application [\#1044](https://github.com/containous/traefik/issues/1044)
|
||||||
|
- Normalize auto generated frontend-rule \(docker\) [\#1043](https://github.com/containous/traefik/issues/1043)
|
||||||
|
- Traefik with Consul catalog backend + Registrator [\#1039](https://github.com/containous/traefik/issues/1039)
|
||||||
|
- \[Configuration help\] Can't connect to docker containers under a domain path [\#1032](https://github.com/containous/traefik/issues/1032)
|
||||||
|
- Kubernetes and etcd backend : `storeconfig` fails. [\#1031](https://github.com/containous/traefik/issues/1031)
|
||||||
|
- kubernetes: Undefined backend 'X/' for frontend X/" [\#1026](https://github.com/containous/traefik/issues/1026)
|
||||||
|
- TLS handshake error [\#1025](https://github.com/containous/traefik/issues/1025)
|
||||||
|
- Traefik failing on POST request [\#1008](https://github.com/containous/traefik/issues/1008)
|
||||||
|
- how config traffic.toml http 80 without basic auth, traefik WebUI 8080 with basic auth [\#1001](https://github.com/containous/traefik/issues/1001)
|
||||||
|
- Docs 404 [\#995](https://github.com/containous/traefik/issues/995)
|
||||||
|
- Disable acme for non https endpoints [\#989](https://github.com/containous/traefik/issues/989)
|
||||||
|
- Add parameter to configure TLS entrypoints with ca-bundle file [\#984](https://github.com/containous/traefik/issues/984)
|
||||||
|
- docker multiple networks routing [\#970](https://github.com/containous/traefik/issues/970)
|
||||||
|
- don't add Docker containers not on the same network as traefik [\#959](https://github.com/containous/traefik/issues/959)
|
||||||
|
- Multiple frontend routes [\#957](https://github.com/containous/traefik/issues/957)
|
||||||
|
- SNI based routing without TLS offloading [\#933](https://github.com/containous/traefik/issues/933)
|
||||||
|
- NEO4J + traefik proxy Issues [\#907](https://github.com/containous/traefik/issues/907)
|
||||||
|
- ACME OnDemand ignores entrypoint certificate [\#672](https://github.com/containous/traefik/issues/672)
|
||||||
|
- Ability to use self-signed certificates for local development [\#399](https://github.com/containous/traefik/issues/399)
|
||||||
|
|
||||||
|
**Merged pull requests:**
|
||||||
|
|
||||||
|
- Fix checkout initial before calling rmpr [\#1124](https://github.com/containous/traefik/pull/1124) ([emilevauge](https://github.com/emilevauge))
|
||||||
|
- Feature rancher integration [\#1120](https://github.com/containous/traefik/pull/1120) ([SantoDE](https://github.com/SantoDE))
|
||||||
|
- Fix glide go units [\#1119](https://github.com/containous/traefik/pull/1119) ([emilevauge](https://github.com/emilevauge))
|
||||||
|
- Carry \#818 — Add systemd watchdog feature [\#1116](https://github.com/containous/traefik/pull/1116) ([vdemeester](https://github.com/vdemeester))
|
||||||
|
- Skip file permission check on Windows [\#1115](https://github.com/containous/traefik/pull/1115) ([StefanScherer](https://github.com/StefanScherer))
|
||||||
|
- Fix Docker API version for Windows [\#1113](https://github.com/containous/traefik/pull/1113) ([StefanScherer](https://github.com/StefanScherer))
|
||||||
|
- Fix git rpr [\#1109](https://github.com/containous/traefik/pull/1109) ([emilevauge](https://github.com/emilevauge))
|
||||||
|
- Fix docker version specifier [\#1108](https://github.com/containous/traefik/pull/1108) ([timoreimann](https://github.com/timoreimann))
|
||||||
|
- Merge v1.1.2 master [\#1105](https://github.com/containous/traefik/pull/1105) ([emilevauge](https://github.com/emilevauge))
|
||||||
|
- add sh before script in deploy... [\#1103](https://github.com/containous/traefik/pull/1103) ([emilevauge](https://github.com/emilevauge))
|
||||||
|
- \[doc\] typo fixes for kubernetes user guide [\#1102](https://github.com/containous/traefik/pull/1102) ([bamarni](https://github.com/bamarni))
|
||||||
|
- add skip\_cleanup in deploy [\#1101](https://github.com/containous/traefik/pull/1101) ([emilevauge](https://github.com/emilevauge))
|
||||||
|
- Fix k8s example UI port. [\#1098](https://github.com/containous/traefik/pull/1098) ([ddunkin](https://github.com/ddunkin))
|
||||||
|
- Fix marathon provider [\#1090](https://github.com/containous/traefik/pull/1090) ([diegooliveira](https://github.com/diegooliveira))
|
||||||
|
- Add an ECS provider [\#1088](https://github.com/containous/traefik/pull/1088) ([lpetre](https://github.com/lpetre))
|
||||||
|
- Update comment to reflect the code [\#1087](https://github.com/containous/traefik/pull/1087) ([np](https://github.com/np))
|
||||||
|
- update NYTimes/gziphandler fixes \#1059 [\#1084](https://github.com/containous/traefik/pull/1084) ([JamesKyburz](https://github.com/JamesKyburz))
|
||||||
|
- Ensure that we don't add balancees with no health check runs if there is a health check defined on it [\#1080](https://github.com/containous/traefik/pull/1080) ([jangie](https://github.com/jangie))
|
||||||
|
- Add FreeBSD & OpenBSD to crossbinary [\#1078](https://github.com/containous/traefik/pull/1078) ([geoffgarside](https://github.com/geoffgarside))
|
||||||
|
- Fix metrics for multiple entry points [\#1071](https://github.com/containous/traefik/pull/1071) ([matevzmihalic](https://github.com/matevzmihalic))
|
||||||
|
- Allow setting load balancer method and sticky using service annotations [\#1068](https://github.com/containous/traefik/pull/1068) ([bakins](https://github.com/bakins))
|
||||||
|
- Fix travis script [\#1067](https://github.com/containous/traefik/pull/1067) ([emilevauge](https://github.com/emilevauge))
|
||||||
|
- Add missing fmt verb specifier in k8s provider. [\#1066](https://github.com/containous/traefik/pull/1066) ([timoreimann](https://github.com/timoreimann))
|
||||||
|
- Add git rpr command [\#1063](https://github.com/containous/traefik/pull/1063) ([emilevauge](https://github.com/emilevauge))
|
||||||
|
- Fix k8s example [\#1062](https://github.com/containous/traefik/pull/1062) ([emilevauge](https://github.com/emilevauge))
|
||||||
|
- Replace underscores to dash in autogenerated urls \(docker provider\) [\#1061](https://github.com/containous/traefik/pull/1061) ([WTFKr0](https://github.com/WTFKr0))
|
||||||
|
- Don't run go test on .glide cache folder [\#1057](https://github.com/containous/traefik/pull/1057) ([vdemeester](https://github.com/vdemeester))
|
||||||
|
- Allow setting circuitbreaker expression via Kubernetes annotation [\#1056](https://github.com/containous/traefik/pull/1056) ([bakins](https://github.com/bakins))
|
||||||
|
- Improving instrumentation. [\#1042](https://github.com/containous/traefik/pull/1042) ([enxebre](https://github.com/enxebre))
|
||||||
|
- Update user guide for upcoming `docker stack deploy` [\#1041](https://github.com/containous/traefik/pull/1041) ([twelvelabs](https://github.com/twelvelabs))
|
||||||
|
- Support sticky sessions under SWARM Mode. \#1024 [\#1033](https://github.com/containous/traefik/pull/1033) ([foleymic](https://github.com/foleymic))
|
||||||
|
- Allow for wildcards in k8s ingress host, fixes \#792 [\#1029](https://github.com/containous/traefik/pull/1029) ([sheerun](https://github.com/sheerun))
|
||||||
|
- Don't fetch ACME certificates for frontends using non-TLS entrypoints \(\#989\) [\#1023](https://github.com/containous/traefik/pull/1023) ([syfonseq](https://github.com/syfonseq))
|
||||||
|
- Return Proper Non-ACME certificate - Fixes Issue 672 [\#1018](https://github.com/containous/traefik/pull/1018) ([dtomcej](https://github.com/dtomcej))
|
||||||
|
- Fix docs build and add missing benchmarks page [\#1017](https://github.com/containous/traefik/pull/1017) ([csabapalfi](https://github.com/csabapalfi))
|
||||||
|
- Set a NopCloser request body with retry middleware [\#1016](https://github.com/containous/traefik/pull/1016) ([bamarni](https://github.com/bamarni))
|
||||||
|
- instruct to flatten dependencies with glide [\#1010](https://github.com/containous/traefik/pull/1010) ([bamarni](https://github.com/bamarni))
|
||||||
|
- check permissions on acme.json during startup [\#1009](https://github.com/containous/traefik/pull/1009) ([bamarni](https://github.com/bamarni))
|
||||||
|
- \[doc\] few tweaks on the basics page [\#1005](https://github.com/containous/traefik/pull/1005) ([bamarni](https://github.com/bamarni))
|
||||||
|
- Import order as goimports does [\#1004](https://github.com/containous/traefik/pull/1004) ([vdemeester](https://github.com/vdemeester))
|
||||||
|
- See the right go report badge [\#991](https://github.com/containous/traefik/pull/991) ([guilhem](https://github.com/guilhem))
|
||||||
|
- Add multiple values for one rule to docs [\#978](https://github.com/containous/traefik/pull/978) ([j0hnsmith](https://github.com/j0hnsmith))
|
||||||
|
- Add ACME/Let’s Encrypt integration tests [\#975](https://github.com/containous/traefik/pull/975) ([trecloux](https://github.com/trecloux))
|
||||||
|
- deploy.sh: upload release source tarball [\#969](https://github.com/containous/traefik/pull/969) ([Mic92](https://github.com/Mic92))
|
||||||
|
- toml zookeeper doc fix [\#948](https://github.com/containous/traefik/pull/948) ([brdude](https://github.com/brdude))
|
||||||
|
- Add Rule AddPrefix [\#931](https://github.com/containous/traefik/pull/931) ([Juliens](https://github.com/Juliens))
|
||||||
|
- Add bug command [\#921](https://github.com/containous/traefik/pull/921) ([emilevauge](https://github.com/emilevauge))
|
||||||
|
- \(WIP\) feat: HealthCheck [\#918](https://github.com/containous/traefik/pull/918) ([Juliens](https://github.com/Juliens))
|
||||||
|
- Add ability to set authenticated user in request header [\#889](https://github.com/containous/traefik/pull/889) ([ViViDboarder](https://github.com/ViViDboarder))
|
||||||
|
- IP-per-task: [\#841](https://github.com/containous/traefik/pull/841) ([diegooliveira](https://github.com/diegooliveira))
|
||||||
|
|
||||||
## [v1.1.2](https://github.com/containous/traefik/tree/v1.1.2) (2016-12-15)
|
## [v1.1.2](https://github.com/containous/traefik/tree/v1.1.2) (2016-12-15)
|
||||||
[Full Changelog](https://github.com/containous/traefik/compare/v1.1.1...v1.1.2)
|
[Full Changelog](https://github.com/containous/traefik/compare/v1.1.1...v1.1.2)
|
||||||
|
|
||||||
|
|
|
@ -239,6 +239,20 @@ For example:
|
||||||
[backends.backend1.loadbalancer]
|
[backends.backend1.loadbalancer]
|
||||||
sticky = true
|
sticky = true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Healthcheck URL can be configured with a relative URL for `healthcheck.URL`.
|
||||||
|
Interval between healthcheck can be configured by using `healthcheck.interval`
|
||||||
|
(default: 30s)
|
||||||
|
|
||||||
|
For example:
|
||||||
|
```toml
|
||||||
|
[backends]
|
||||||
|
[backends.backend1]
|
||||||
|
[backends.backend1.healthcheck]
|
||||||
|
URL = "/health"
|
||||||
|
interval = "10s"
|
||||||
|
```
|
||||||
|
|
||||||
## Servers
|
## Servers
|
||||||
|
|
||||||
Servers are simply defined using a `URL`. You can also apply a custom `weight` to each server (this will be used by load-balancing).
|
Servers are simply defined using a `URL`. You can also apply a custom `weight` to each server (this will be used by load-balancing).
|
||||||
|
|
99
docs/toml.md
99
docs/toml.md
|
@ -1423,3 +1423,102 @@ Labels can be used on task containers to override default behaviour:
|
||||||
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
|
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
|
||||||
- `traefik.frontend.priority=10`: override default frontend priority
|
- `traefik.frontend.priority=10`: override default frontend priority
|
||||||
- `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`.
|
- `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`.
|
||||||
|
|
||||||
|
If `AccessKeyID`/`SecretAccessKey` is not given credentials will be resolved in the following order:
|
||||||
|
|
||||||
|
- From environment variables; `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN`.
|
||||||
|
- Shared credentials, determined by `AWS_PROFILE` and `AWS_SHARED_CREDENTIALS_FILE`, defaults to `default` and `~/.aws/credentials`.
|
||||||
|
- EC2 instance role or ECS task role
|
||||||
|
|
||||||
|
Træfɪk needs the following policy to read ECS information:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Sid": "Traefik ECS read access",
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Action": [
|
||||||
|
"ecs:ListTasks",
|
||||||
|
"ecs:DescribeTasks",
|
||||||
|
"ecs:DescribeContainerInstances",
|
||||||
|
"ecs:DescribeTaskDefinition",
|
||||||
|
"ec2:DescribeInstances"
|
||||||
|
],
|
||||||
|
"Resource": [
|
||||||
|
"*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Rancher backend
|
||||||
|
|
||||||
|
Træfɪk can be configured to use Rancher as a backend configuration:
|
||||||
|
|
||||||
|
|
||||||
|
```toml
|
||||||
|
################################################################
|
||||||
|
# Rancher configuration backend
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
# Enable Rancher configuration backend
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
#
|
||||||
|
[rancher]
|
||||||
|
|
||||||
|
# Default domain used.
|
||||||
|
# Can be overridden by setting the "traefik.domain" label on an service.
|
||||||
|
#
|
||||||
|
# Required
|
||||||
|
#
|
||||||
|
domain = "rancher.localhost"
|
||||||
|
|
||||||
|
# Enable watch Rancher changes
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
# Default: true
|
||||||
|
#
|
||||||
|
Watch = true
|
||||||
|
|
||||||
|
# Expose Rancher services by default in traefik
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
# Default: true
|
||||||
|
#
|
||||||
|
ExposedByDefault = false
|
||||||
|
|
||||||
|
# Endpoint to use when connecting to Rancher
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
# Endpoint = "http://rancherserver.example.com"
|
||||||
|
|
||||||
|
# AccessKey to use when connecting to Rancher
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
# AccessKey = "XXXXXXXXX"
|
||||||
|
|
||||||
|
# SecretKey to use when connecting to Rancher
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
# SecretKey = "XXXXXXXXXXX"
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
If you're deploying traefik as a service within rancher, you can alternatively set these labels on the service to let it only fetch data of its current environment. The settings `endpoint`, `accesskey` and `secretkey` can be omitted then.
|
||||||
|
|
||||||
|
- `io.rancher.container.create_agent=true`
|
||||||
|
- `io.rancher.container.agent.role=environment`
|
||||||
|
|
||||||
|
Labels can be used on task containers to override default behaviour:
|
||||||
|
|
||||||
|
- `traefik.protocol=https`: override the default `http` protocol
|
||||||
|
- `traefik.weight=10`: assign this weight to the container
|
||||||
|
- `traefik.enable=false`: disable this container in Træfɪk
|
||||||
|
- `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{containerName}.{domain}`).
|
||||||
|
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
|
||||||
|
- `traefik.frontend.priority=10`: override default frontend priority
|
||||||
|
- `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`.
|
||||||
|
|
10
examples/compose-rancher.yml
Normal file
10
examples/compose-rancher.yml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
traefik:
|
||||||
|
image: traefik
|
||||||
|
command: --web --rancher --rancher.domain=rancher.localhost --logLevel=DEBUG
|
||||||
|
labels:
|
||||||
|
io.rancher.container.agent.role: environment
|
||||||
|
io.rancher.container.create_agent: 'true'
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
- "8080:8080"
|
6
glide.lock
generated
6
glide.lock
generated
|
@ -1,5 +1,5 @@
|
||||||
hash: b2ac93355c3f551a75216a800337cee9321f6c9a04a18ab1fa8d8152e89b7595
|
hash: f2a0b9af55c8312762e4148bd876e5bd2451c240b407fbb6d4a5dbc56bf46c05
|
||||||
updated: 2017-02-20T16:04:18.834166585+01:00
|
updated: 2017-03-03T10:21:14.720631882+01:00
|
||||||
imports:
|
imports:
|
||||||
- name: bitbucket.org/ww/goautoneg
|
- name: bitbucket.org/ww/goautoneg
|
||||||
version: 75cd24fc2f2c2a2088577d12123ddee5f54e0675
|
version: 75cd24fc2f2c2a2088577d12123ddee5f54e0675
|
||||||
|
@ -444,7 +444,7 @@ imports:
|
||||||
- assert
|
- assert
|
||||||
- mock
|
- mock
|
||||||
- name: github.com/thoas/stats
|
- name: github.com/thoas/stats
|
||||||
version: 79b768ff1780f4e5b0ed132e192bfeefe9f85a9c
|
version: 152b5d051953fdb6e45f14b6826962aadc032324
|
||||||
- name: github.com/timewasted/linode
|
- name: github.com/timewasted/linode
|
||||||
version: 37e84520dcf74488f67654f9c775b9752c232dc1
|
version: 37e84520dcf74488f67654f9c775b9752c232dc1
|
||||||
subpackages:
|
subpackages:
|
||||||
|
|
|
@ -53,6 +53,7 @@ import:
|
||||||
subpackages:
|
subpackages:
|
||||||
- mock
|
- mock
|
||||||
- package: github.com/thoas/stats
|
- package: github.com/thoas/stats
|
||||||
|
version: 152b5d051953fdb6e45f14b6826962aadc032324
|
||||||
- package: github.com/unrolled/render
|
- package: github.com/unrolled/render
|
||||||
- package: github.com/vdemeester/docker-events
|
- package: github.com/vdemeester/docker-events
|
||||||
version: be74d4929ec1ad118df54349fda4b0cba60f849b
|
version: be74d4929ec1ad118df54349fda4b0cba60f849b
|
||||||
|
|
|
@ -26,6 +26,7 @@ func GetHealthCheck() *HealthCheck {
|
||||||
// BackendHealthCheck HealthCheck configuration for a backend
|
// BackendHealthCheck HealthCheck configuration for a backend
|
||||||
type BackendHealthCheck struct {
|
type BackendHealthCheck struct {
|
||||||
URL string
|
URL string
|
||||||
|
Interval time.Duration
|
||||||
DisabledURLs []*url.URL
|
DisabledURLs []*url.URL
|
||||||
lb loadBalancer
|
lb loadBalancer
|
||||||
}
|
}
|
||||||
|
@ -49,8 +50,8 @@ func newHealthCheck() *HealthCheck {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBackendHealthCheck Instantiate a new BackendHealthCheck
|
// NewBackendHealthCheck Instantiate a new BackendHealthCheck
|
||||||
func NewBackendHealthCheck(URL string, lb loadBalancer) *BackendHealthCheck {
|
func NewBackendHealthCheck(URL string, interval time.Duration, lb loadBalancer) *BackendHealthCheck {
|
||||||
return &BackendHealthCheck{URL, nil, lb}
|
return &BackendHealthCheck{URL, interval, nil, lb}
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetBackendsConfiguration set backends configuration
|
//SetBackendsConfiguration set backends configuration
|
||||||
|
@ -70,7 +71,7 @@ func (hc *HealthCheck) execute(ctx context.Context) {
|
||||||
currentBackendID := backendID
|
currentBackendID := backendID
|
||||||
safe.Go(func() {
|
safe.Go(func() {
|
||||||
for {
|
for {
|
||||||
ticker := time.NewTicker(time.Second * 30)
|
ticker := time.NewTicker(currentBackend.Interval)
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
log.Debugf("Stopping all current Healthcheck goroutines")
|
log.Debugf("Stopping all current Healthcheck goroutines")
|
||||||
|
|
27
integration/fixtures/healthcheck/simple.toml
Normal file
27
integration/fixtures/healthcheck/simple.toml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
defaultEntryPoints = ["http"]
|
||||||
|
|
||||||
|
logLevel = "DEBUG"
|
||||||
|
|
||||||
|
[entryPoints]
|
||||||
|
[entryPoints.http]
|
||||||
|
address = ":8000"
|
||||||
|
|
||||||
|
[web]
|
||||||
|
address = ":8080"
|
||||||
|
|
||||||
|
[file]
|
||||||
|
[backends]
|
||||||
|
[backends.backend1]
|
||||||
|
[backends.backend1.healthcheck]
|
||||||
|
url = "/health"
|
||||||
|
interval = "1s"
|
||||||
|
[backends.backend1.servers.server1]
|
||||||
|
url = "http://{{.Server1}}:80"
|
||||||
|
[backends.backend1.servers.server2]
|
||||||
|
url = "http://{{.Server2}}:80"
|
||||||
|
|
||||||
|
[frontends]
|
||||||
|
[frontends.frontend1]
|
||||||
|
backend = "backend1"
|
||||||
|
[frontends.frontend1.routes.test_1]
|
||||||
|
rule = "Host:test.localhost"
|
91
integration/healthcheck_test.go
Normal file
91
integration/healthcheck_test.go
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/containous/traefik/integration/utils"
|
||||||
|
"github.com/go-check/check"
|
||||||
|
|
||||||
|
checker "github.com/vdemeester/shakers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// HealchCheck test suites (using libcompose)
|
||||||
|
type HealchCheckSuite struct{ BaseSuite }
|
||||||
|
|
||||||
|
func (s *HealchCheckSuite) SetUpSuite(c *check.C) {
|
||||||
|
s.createComposeProject(c, "healthcheck")
|
||||||
|
s.composeProject.Start(c)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *HealchCheckSuite) TestSimpleConfiguration(c *check.C) {
|
||||||
|
|
||||||
|
whoami1Host := s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress
|
||||||
|
whoami2Host := s.composeProject.Container(c, "whoami2").NetworkSettings.IPAddress
|
||||||
|
|
||||||
|
file := s.adaptFile(c, "fixtures/healthcheck/simple.toml", struct {
|
||||||
|
Server1 string
|
||||||
|
Server2 string
|
||||||
|
}{whoami1Host, whoami2Host})
|
||||||
|
defer os.Remove(file)
|
||||||
|
cmd := exec.Command(traefikBinary, "--configFile="+file)
|
||||||
|
|
||||||
|
err := cmd.Start()
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
defer cmd.Process.Kill()
|
||||||
|
|
||||||
|
// wait for traefik
|
||||||
|
err = utils.TryRequest("http://127.0.0.1:8080/api/providers", 60*time.Second, func(res *http.Response) error {
|
||||||
|
body, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(body), "Host:test.localhost") {
|
||||||
|
return errors.New("Incorrect traefik config: " + string(body))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
client := &http.Client{}
|
||||||
|
req, err := http.NewRequest("GET", "http://127.0.0.1:8000/health", nil)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
req.Host = "test.localhost"
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(resp.StatusCode, checker.Equals, 200)
|
||||||
|
|
||||||
|
resp, err = client.Do(req)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(resp.StatusCode, checker.Equals, 200)
|
||||||
|
|
||||||
|
healthReq, err := http.NewRequest("POST", "http://"+whoami1Host+"/health", bytes.NewBuffer([]byte("500")))
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
_, err = client.Do(healthReq)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 3)
|
||||||
|
|
||||||
|
resp, err = client.Do(req)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(resp.StatusCode, checker.Equals, 200)
|
||||||
|
|
||||||
|
resp, err = client.Do(req)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(resp.StatusCode, checker.Equals, 200)
|
||||||
|
|
||||||
|
// TODO validate : run on 80
|
||||||
|
resp, err = http.Get("http://127.0.0.1:8000/")
|
||||||
|
|
||||||
|
// Expected a 404 as we did not configure anything
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(resp.StatusCode, checker.Equals, 404)
|
||||||
|
}
|
5
integration/resources/compose/healthcheck.yml
Normal file
5
integration/resources/compose/healthcheck.yml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
whoami1:
|
||||||
|
image: emilevauge/whoami
|
||||||
|
|
||||||
|
whoami2:
|
||||||
|
image: emilevauge/whoami
|
|
@ -626,11 +626,12 @@ func (provider *Docker) listServices(ctx context.Context, dockerClient client.AP
|
||||||
for _, service := range serviceList {
|
for _, service := range serviceList {
|
||||||
dockerData := parseService(service, networkMap)
|
dockerData := parseService(service, networkMap)
|
||||||
useSwarmLB, _ := strconv.ParseBool(provider.getIsBackendLBSwarm(dockerData))
|
useSwarmLB, _ := strconv.ParseBool(provider.getIsBackendLBSwarm(dockerData))
|
||||||
|
isGlobalSvc := service.Spec.Mode.Global != nil
|
||||||
|
|
||||||
if useSwarmLB {
|
if useSwarmLB {
|
||||||
dockerDataList = append(dockerDataList, dockerData)
|
dockerDataList = append(dockerDataList, dockerData)
|
||||||
} else {
|
} else {
|
||||||
dockerDataListTasks, err = listTasks(ctx, dockerClient, service.ID, dockerData, networkMap)
|
dockerDataListTasks, err = listTasks(ctx, dockerClient, service.ID, dockerData, networkMap, isGlobalSvc)
|
||||||
|
|
||||||
for _, dockerDataTask := range dockerDataListTasks {
|
for _, dockerDataTask := range dockerDataListTasks {
|
||||||
dockerDataList = append(dockerDataList, dockerDataTask)
|
dockerDataList = append(dockerDataList, dockerDataTask)
|
||||||
|
@ -675,9 +676,10 @@ func parseService(service swarmtypes.Service, networkMap map[string]*dockertypes
|
||||||
}
|
}
|
||||||
|
|
||||||
func listTasks(ctx context.Context, dockerClient client.APIClient, serviceID string,
|
func listTasks(ctx context.Context, dockerClient client.APIClient, serviceID string,
|
||||||
serviceDockerData dockerData, networkMap map[string]*dockertypes.NetworkResource) ([]dockerData, error) {
|
serviceDockerData dockerData, networkMap map[string]*dockertypes.NetworkResource, isGlobalSvc bool) ([]dockerData, error) {
|
||||||
serviceIDFilter := filters.NewArgs()
|
serviceIDFilter := filters.NewArgs()
|
||||||
serviceIDFilter.Add("service", serviceID)
|
serviceIDFilter.Add("service", serviceID)
|
||||||
|
serviceIDFilter.Add("desired-state", "running")
|
||||||
taskList, err := dockerClient.TaskList(ctx, dockertypes.TaskListOptions{Filter: serviceIDFilter})
|
taskList, err := dockerClient.TaskList(ctx, dockertypes.TaskListOptions{Filter: serviceIDFilter})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -686,13 +688,13 @@ func listTasks(ctx context.Context, dockerClient client.APIClient, serviceID str
|
||||||
var dockerDataList []dockerData
|
var dockerDataList []dockerData
|
||||||
|
|
||||||
for _, task := range taskList {
|
for _, task := range taskList {
|
||||||
dockerData := parseTasks(task, serviceDockerData, networkMap)
|
dockerData := parseTasks(task, serviceDockerData, networkMap, isGlobalSvc)
|
||||||
dockerDataList = append(dockerDataList, dockerData)
|
dockerDataList = append(dockerDataList, dockerData)
|
||||||
}
|
}
|
||||||
return dockerDataList, err
|
return dockerDataList, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTasks(task swarmtypes.Task, serviceDockerData dockerData, networkMap map[string]*dockertypes.NetworkResource) dockerData {
|
func parseTasks(task swarmtypes.Task, serviceDockerData dockerData, networkMap map[string]*dockertypes.NetworkResource, isGlobalSvc bool) dockerData {
|
||||||
dockerData := dockerData{
|
dockerData := dockerData{
|
||||||
ServiceName: serviceDockerData.Name,
|
ServiceName: serviceDockerData.Name,
|
||||||
Name: serviceDockerData.Name + "." + strconv.Itoa(task.Slot),
|
Name: serviceDockerData.Name + "." + strconv.Itoa(task.Slot),
|
||||||
|
@ -700,6 +702,10 @@ func parseTasks(task swarmtypes.Task, serviceDockerData dockerData, networkMap m
|
||||||
NetworkSettings: networkSettings{},
|
NetworkSettings: networkSettings{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isGlobalSvc == true {
|
||||||
|
dockerData.Name = serviceDockerData.Name + "." + task.ID
|
||||||
|
}
|
||||||
|
|
||||||
if task.NetworksAttachments != nil {
|
if task.NetworksAttachments != nil {
|
||||||
dockerData.NetworkSettings.Networks = make(map[string]*networkData)
|
dockerData.NetworkSettings.Networks = make(map[string]*networkData)
|
||||||
for _, virtualIP := range task.NetworksAttachments {
|
for _, virtualIP := range task.NetworksAttachments {
|
||||||
|
|
|
@ -2184,3 +2184,90 @@ func TestSwarmLoadDockerConfig(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSwarmTaskParsing(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
service swarm.Service
|
||||||
|
tasks []swarm.Task
|
||||||
|
isGlobalSvc bool
|
||||||
|
expectedNames map[string]string
|
||||||
|
networks map[string]*docker.NetworkResource
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
service: swarm.Service{
|
||||||
|
Spec: swarm.ServiceSpec{
|
||||||
|
Annotations: swarm.Annotations{
|
||||||
|
Name: "container",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tasks: []swarm.Task{
|
||||||
|
{
|
||||||
|
ID: "id1",
|
||||||
|
Slot: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "id2",
|
||||||
|
Slot: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "id3",
|
||||||
|
Slot: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isGlobalSvc: false,
|
||||||
|
expectedNames: map[string]string{
|
||||||
|
"id1": "container.1",
|
||||||
|
"id2": "container.2",
|
||||||
|
"id3": "container.3",
|
||||||
|
},
|
||||||
|
networks: map[string]*docker.NetworkResource{
|
||||||
|
"1": {
|
||||||
|
Name: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
service: swarm.Service{
|
||||||
|
Spec: swarm.ServiceSpec{
|
||||||
|
Annotations: swarm.Annotations{
|
||||||
|
Name: "container",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tasks: []swarm.Task{
|
||||||
|
{
|
||||||
|
ID: "id1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "id2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: "id3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isGlobalSvc: true,
|
||||||
|
expectedNames: map[string]string{
|
||||||
|
"id1": "container.id1",
|
||||||
|
"id2": "container.id2",
|
||||||
|
"id3": "container.id3",
|
||||||
|
},
|
||||||
|
networks: map[string]*docker.NetworkResource{
|
||||||
|
"1": {
|
||||||
|
Name: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, e := range cases {
|
||||||
|
dockerData := parseService(e.service, e.networks)
|
||||||
|
|
||||||
|
for _, task := range e.tasks {
|
||||||
|
taskDockerData := parseTasks(task, dockerData, map[string]*docker.NetworkResource{}, e.isGlobalSvc)
|
||||||
|
if !reflect.DeepEqual(taskDockerData.Name, e.expectedNames[task.ID]) {
|
||||||
|
t.Fatalf("expect %v, got %v", e.expectedNames[task.ID], taskDockerData.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -275,37 +275,48 @@ func (provider *ECS) listInstances(ctx context.Context, client *awsClient) ([]ec
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *ECS) lookupEc2Instances(ctx context.Context, client *awsClient, containerArns []*string) ([]*ec2.Instance, error) {
|
func (provider *ECS) lookupEc2Instances(ctx context.Context, client *awsClient, containerArns []*string) ([]*ec2.Instance, error) {
|
||||||
req, containerResp := client.ecs.DescribeContainerInstancesRequest(&ecs.DescribeContainerInstancesInput{
|
|
||||||
ContainerInstances: containerArns,
|
|
||||||
Cluster: &provider.Cluster,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err := wrapAws(ctx, req); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
order := make(map[string]int)
|
order := make(map[string]int)
|
||||||
|
instanceIds := make([]*string, len(containerArns))
|
||||||
|
instances := make([]*ec2.Instance, len(containerArns))
|
||||||
for i, arn := range containerArns {
|
for i, arn := range containerArns {
|
||||||
order[*arn] = i
|
order[*arn] = i
|
||||||
}
|
}
|
||||||
|
|
||||||
instanceIds := make([]*string, len(containerArns))
|
req, _ := client.ecs.DescribeContainerInstancesRequest(&ecs.DescribeContainerInstancesInput{
|
||||||
for i, container := range containerResp.ContainerInstances {
|
ContainerInstances: containerArns,
|
||||||
order[*container.Ec2InstanceId] = order[*container.ContainerInstanceArn]
|
Cluster: &provider.Cluster,
|
||||||
instanceIds[i] = container.Ec2InstanceId
|
})
|
||||||
|
|
||||||
|
for ; req != nil; req = req.NextPage() {
|
||||||
|
if err := wrapAws(ctx, req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
containerResp := req.Data.(*ecs.DescribeContainerInstancesOutput)
|
||||||
|
for i, container := range containerResp.ContainerInstances {
|
||||||
|
order[*container.Ec2InstanceId] = order[*container.ContainerInstanceArn]
|
||||||
|
instanceIds[i] = container.Ec2InstanceId
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
req, instancesResp := client.ec2.DescribeInstancesRequest(&ec2.DescribeInstancesInput{
|
req, _ = client.ec2.DescribeInstancesRequest(&ec2.DescribeInstancesInput{
|
||||||
InstanceIds: instanceIds,
|
InstanceIds: instanceIds,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := wrapAws(ctx, req); err != nil {
|
for ; req != nil; req = req.NextPage() {
|
||||||
return nil, err
|
if err := wrapAws(ctx, req); err != nil {
|
||||||
}
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
instances := make([]*ec2.Instance, len(containerArns))
|
instancesResp := req.Data.(*ec2.DescribeInstancesOutput)
|
||||||
for _, r := range instancesResp.Reservations {
|
for _, r := range instancesResp.Reservations {
|
||||||
instances[order[*r.Instances[0].InstanceId]] = r.Instances[0]
|
for _, i := range r.Instances {
|
||||||
|
if i.InstanceId != nil {
|
||||||
|
instances[order[*i.InstanceId]] = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return instances, nil
|
return instances, nil
|
||||||
}
|
}
|
||||||
|
@ -340,6 +351,23 @@ func (provider *ECS) filterInstance(i ecsInstance) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if i.machine == nil ||
|
||||||
|
i.machine.State == nil ||
|
||||||
|
i.machine.State.Name == nil {
|
||||||
|
log.Debugf("Filtering ecs instance in an missing ec2 information %s (%s)", i.Name, i.ID)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if *i.machine.State.Name != ec2.InstanceStateNameRunning {
|
||||||
|
log.Debugf("Filtering ecs instance in an incorrect state %s (%s) (state = %s)", i.Name, i.ID, *i.machine.State.Name)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if i.machine.PrivateIpAddress == nil {
|
||||||
|
log.Debugf("Filtering ecs instance without an ip address %s (%s)", i.Name, i.ID)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
label := i.label("traefik.enable")
|
label := i.label("traefik.enable")
|
||||||
enabled := provider.ExposedByDefault && label != "false" || label == "true"
|
enabled := provider.ExposedByDefault && label != "false" || label == "true"
|
||||||
if !enabled {
|
if !enabled {
|
||||||
|
|
|
@ -37,6 +37,9 @@ func makeEcsInstance(containerDef *ecs.ContainerDefinition) ecsInstance {
|
||||||
containerDefinition: containerDef,
|
containerDefinition: containerDef,
|
||||||
machine: &ec2.Instance{
|
machine: &ec2.Instance{
|
||||||
PrivateIpAddress: aws.String("10.0.0.0"),
|
PrivateIpAddress: aws.String("10.0.0.0"),
|
||||||
|
State: &ec2.InstanceState{
|
||||||
|
Name: aws.String(ec2.InstanceStateNameRunning),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,10 +73,10 @@ func TestEcsProtocol(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for i, c := range cases {
|
||||||
value := c.instanceInfo.Protocol()
|
value := c.instanceInfo.Protocol()
|
||||||
if value != c.expected {
|
if value != c.expected {
|
||||||
t.Fatalf("Should have been %s, got %s", c.expected, value)
|
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,10 +92,10 @@ func TestEcsHost(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for i, c := range cases {
|
||||||
value := c.instanceInfo.Host()
|
value := c.instanceInfo.Host()
|
||||||
if value != c.expected {
|
if value != c.expected {
|
||||||
t.Fatalf("Should have been %s, got %s", c.expected, value)
|
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,10 +111,10 @@ func TestEcsPort(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for i, c := range cases {
|
||||||
value := c.instanceInfo.Port()
|
value := c.instanceInfo.Port()
|
||||||
if value != c.expected {
|
if value != c.expected {
|
||||||
t.Fatalf("Should have been %s, got %s", c.expected, value)
|
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,10 +136,10 @@ func TestEcsWeight(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for i, c := range cases {
|
||||||
value := c.instanceInfo.Weight()
|
value := c.instanceInfo.Weight()
|
||||||
if value != c.expected {
|
if value != c.expected {
|
||||||
t.Fatalf("Should have been %s, got %s", c.expected, value)
|
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,10 +161,10 @@ func TestEcsPassHostHeader(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for i, c := range cases {
|
||||||
value := c.instanceInfo.PassHostHeader()
|
value := c.instanceInfo.PassHostHeader()
|
||||||
if value != c.expected {
|
if value != c.expected {
|
||||||
t.Fatalf("Should have been %s, got %s", c.expected, value)
|
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,10 +186,10 @@ func TestEcsPriority(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for i, c := range cases {
|
||||||
value := c.instanceInfo.Priority()
|
value := c.instanceInfo.Priority()
|
||||||
if value != c.expected {
|
if value != c.expected {
|
||||||
t.Fatalf("Should have been %s, got %s", c.expected, value)
|
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,10 +217,94 @@ func TestEcsEntryPoints(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for i, c := range cases {
|
||||||
value := c.instanceInfo.EntryPoints()
|
value := c.instanceInfo.EntryPoints()
|
||||||
if !reflect.DeepEqual(value, c.expected) {
|
if !reflect.DeepEqual(value, c.expected) {
|
||||||
t.Fatalf("Should have been %s, got %s", c.expected, value)
|
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFilterInstance(t *testing.T) {
|
||||||
|
|
||||||
|
nilPrivateIP := simpleEcsInstance(map[string]*string{})
|
||||||
|
nilPrivateIP.machine.PrivateIpAddress = nil
|
||||||
|
|
||||||
|
nilMachine := simpleEcsInstance(map[string]*string{})
|
||||||
|
nilMachine.machine = nil
|
||||||
|
|
||||||
|
nilMachineState := simpleEcsInstance(map[string]*string{})
|
||||||
|
nilMachineState.machine.State = nil
|
||||||
|
|
||||||
|
nilMachineStateName := simpleEcsInstance(map[string]*string{})
|
||||||
|
nilMachineStateName.machine.State.Name = nil
|
||||||
|
|
||||||
|
invalidMachineState := simpleEcsInstance(map[string]*string{})
|
||||||
|
invalidMachineState.machine.State.Name = aws.String(ec2.InstanceStateNameStopped)
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
expected bool
|
||||||
|
exposedByDefault bool
|
||||||
|
instanceInfo ecsInstance
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
expected: true,
|
||||||
|
exposedByDefault: true,
|
||||||
|
instanceInfo: simpleEcsInstance(map[string]*string{}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expected: false,
|
||||||
|
exposedByDefault: false,
|
||||||
|
instanceInfo: simpleEcsInstance(map[string]*string{}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expected: false,
|
||||||
|
exposedByDefault: true,
|
||||||
|
instanceInfo: simpleEcsInstance(map[string]*string{
|
||||||
|
"traefik.enable": aws.String("false"),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expected: true,
|
||||||
|
exposedByDefault: false,
|
||||||
|
instanceInfo: simpleEcsInstance(map[string]*string{
|
||||||
|
"traefik.enable": aws.String("true"),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expected: false,
|
||||||
|
exposedByDefault: true,
|
||||||
|
instanceInfo: nilPrivateIP,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expected: false,
|
||||||
|
exposedByDefault: true,
|
||||||
|
instanceInfo: nilMachine,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expected: false,
|
||||||
|
exposedByDefault: true,
|
||||||
|
instanceInfo: nilMachineState,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expected: false,
|
||||||
|
exposedByDefault: true,
|
||||||
|
instanceInfo: nilMachineStateName,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
expected: false,
|
||||||
|
exposedByDefault: true,
|
||||||
|
instanceInfo: invalidMachineState,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, c := range cases {
|
||||||
|
provider := &ECS{
|
||||||
|
ExposedByDefault: c.exposedByDefault,
|
||||||
|
}
|
||||||
|
value := provider.filterInstance(c.instanceInfo)
|
||||||
|
if value != c.expected {
|
||||||
|
t.Fatalf("Should have been %v, got %v (case %d)", c.expected, value, i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -264,9 +264,6 @@ func (provider *Marathon) taskFilter(task marathon.Task, applications *marathon.
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
log.Debugf("Filtering marathon task %s with defined healthcheck as no healthcheck has run yet", task.AppID)
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -629,7 +629,7 @@ func TestMarathonTaskFilter(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: false,
|
expected: true,
|
||||||
exposedByDefault: true,
|
exposedByDefault: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,13 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/BurntSushi/ty/fun"
|
"github.com/BurntSushi/ty/fun"
|
||||||
"github.com/cenk/backoff"
|
"github.com/cenk/backoff"
|
||||||
"github.com/containous/traefik/job"
|
"github.com/containous/traefik/job"
|
||||||
|
@ -11,11 +18,6 @@ import (
|
||||||
"github.com/containous/traefik/safe"
|
"github.com/containous/traefik/safe"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
rancher "github.com/rancher/go-rancher/client"
|
rancher "github.com/rancher/go-rancher/client"
|
||||||
"math"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -72,7 +74,7 @@ func (provider *Rancher) getFrontendRule(service rancherData) string {
|
||||||
if label, err := getServiceLabel(service, "traefik.frontend.rule"); err == nil {
|
if label, err := getServiceLabel(service, "traefik.frontend.rule"); err == nil {
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
return "Host:" + strings.ToLower(strings.Replace(service.Name, "/", "_", -1)) + "." + provider.Domain
|
return "Host:" + strings.ToLower(strings.Replace(service.Name, "/", ".", -1)) + "." + provider.Domain
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Rancher) getFrontendName(service rancherData) string {
|
func (provider *Rancher) getFrontendName(service rancherData) string {
|
||||||
|
@ -193,13 +195,26 @@ func getServiceLabel(service rancherData, label string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Rancher) createClient() (*rancher.RancherClient, error) {
|
func (provider *Rancher) createClient() (*rancher.RancherClient, error) {
|
||||||
|
|
||||||
|
rancherURL := getenv("CATTLE_URL", provider.Endpoint)
|
||||||
|
accessKey := getenv("CATTLE_ACCESS_KEY", provider.AccessKey)
|
||||||
|
secretKey := getenv("CATTLE_SECRET_KEY", provider.SecretKey)
|
||||||
|
|
||||||
return rancher.NewRancherClient(&rancher.ClientOpts{
|
return rancher.NewRancherClient(&rancher.ClientOpts{
|
||||||
Url: provider.Endpoint,
|
Url: rancherURL,
|
||||||
AccessKey: provider.AccessKey,
|
AccessKey: accessKey,
|
||||||
SecretKey: provider.SecretKey,
|
SecretKey: secretKey,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getenv(key, fallback string) string {
|
||||||
|
value := os.Getenv(key)
|
||||||
|
if len(value) == 0 {
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
// Provide allows the provider to provide configurations to traefik
|
// Provide allows the provider to provide configurations to traefik
|
||||||
// using the given configuration channel.
|
// using the given configuration channel.
|
||||||
func (provider *Rancher) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
func (provider *Rancher) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error {
|
||||||
|
@ -207,6 +222,12 @@ func (provider *Rancher) Provide(configurationChan chan<- types.ConfigMessage, p
|
||||||
safe.Go(func() {
|
safe.Go(func() {
|
||||||
operation := func() error {
|
operation := func() error {
|
||||||
rancherClient, err := provider.createClient()
|
rancherClient, err := provider.createClient()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to create a client for rancher, error: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
var environments = listRancherEnvironments(rancherClient)
|
var environments = listRancherEnvironments(rancherClient)
|
||||||
var services = listRancherServices(rancherClient)
|
var services = listRancherServices(rancherClient)
|
||||||
|
@ -214,11 +235,6 @@ func (provider *Rancher) Provide(configurationChan chan<- types.ConfigMessage, p
|
||||||
|
|
||||||
var rancherData = parseRancherData(environments, services, container)
|
var rancherData = parseRancherData(environments, services, container)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Failed to create a client for rancher, error: %s", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
configuration := provider.loadRancherConfig(rancherData)
|
configuration := provider.loadRancherConfig(rancherData)
|
||||||
configurationChan <- types.ConfigMessage{
|
configurationChan <- types.ConfigMessage{
|
||||||
ProviderName: "rancher",
|
ProviderName: "rancher",
|
||||||
|
|
|
@ -87,6 +87,12 @@ func TestRancherGetFrontendRule(t *testing.T) {
|
||||||
},
|
},
|
||||||
expected: "Host:foo.rancher.localhost",
|
expected: "Host:foo.rancher.localhost",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
service: rancherData{
|
||||||
|
Name: "foo/bar",
|
||||||
|
},
|
||||||
|
expected: "Host:foo.bar.rancher.localhost",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
service: rancherData{
|
service: rancherData{
|
||||||
Name: "test-service",
|
Name: "test-service",
|
||||||
|
@ -388,7 +394,7 @@ func TestRancherLoadRancherConfig(t *testing.T) {
|
||||||
{
|
{
|
||||||
services: []rancherData{
|
services: []rancherData{
|
||||||
{
|
{
|
||||||
Name: "test-service",
|
Name: "test/service",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"traefik.port": "80",
|
"traefik.port": "80",
|
||||||
},
|
},
|
||||||
|
@ -405,7 +411,7 @@ func TestRancherLoadRancherConfig(t *testing.T) {
|
||||||
|
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"route-frontend-Host-test-service-rancher-localhost": {
|
"route-frontend-Host-test-service-rancher-localhost": {
|
||||||
Rule: "Host:test-service.rancher.localhost",
|
Rule: "Host:test.service.rancher.localhost",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
if [ -n "$TRAVIS_TAG" ] && [ "$DOCKER_VERSION" = "1.10.1" ]; then
|
if [ -n "$TRAVIS_TAG" ] && [ "$DOCKER_VERSION" = "1.10.3" ]; then
|
||||||
echo "Deploying..."
|
echo "Deploying..."
|
||||||
else
|
else
|
||||||
echo "Skipping deploy"
|
echo "Skipping deploy"
|
||||||
|
|
20
server.go
20
server.go
|
@ -658,7 +658,15 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
|
||||||
continue frontend
|
continue frontend
|
||||||
}
|
}
|
||||||
if configuration.Backends[frontend.Backend].HealthCheck != nil {
|
if configuration.Backends[frontend.Backend].HealthCheck != nil {
|
||||||
backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(configuration.Backends[frontend.Backend].HealthCheck.URL, rebalancer)
|
var interval time.Duration
|
||||||
|
if configuration.Backends[frontend.Backend].HealthCheck.Interval != "" {
|
||||||
|
interval, err = time.ParseDuration(configuration.Backends[frontend.Backend].HealthCheck.Interval)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Wrong healthcheck interval: %s", err)
|
||||||
|
interval = time.Second * 30
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(configuration.Backends[frontend.Backend].HealthCheck.URL, interval, rebalancer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case types.Wrr:
|
case types.Wrr:
|
||||||
|
@ -684,7 +692,15 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if configuration.Backends[frontend.Backend].HealthCheck != nil {
|
if configuration.Backends[frontend.Backend].HealthCheck != nil {
|
||||||
backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(configuration.Backends[frontend.Backend].HealthCheck.URL, rr)
|
var interval time.Duration
|
||||||
|
if configuration.Backends[frontend.Backend].HealthCheck.Interval != "" {
|
||||||
|
interval, err = time.ParseDuration(configuration.Backends[frontend.Backend].HealthCheck.Interval)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Wrong healthcheck interval: %s", err)
|
||||||
|
interval = time.Second * 30
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backendsHealthcheck[frontend.Backend] = healthcheck.NewBackendHealthCheck(configuration.Backends[frontend.Backend].HealthCheck.URL, interval, rr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
maxConns := configuration.Backends[frontend.Backend].MaxConn
|
maxConns := configuration.Backends[frontend.Backend].MaxConn
|
||||||
|
|
|
@ -935,6 +935,52 @@
|
||||||
#
|
#
|
||||||
# filename = "ecs.tmpl"
|
# filename = "ecs.tmpl"
|
||||||
|
|
||||||
|
################################################################
|
||||||
|
# Rancher configuration backend
|
||||||
|
################################################################
|
||||||
|
|
||||||
|
# Enable Rancher configuration backend
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
#
|
||||||
|
[rancher]
|
||||||
|
|
||||||
|
# Default domain used.
|
||||||
|
# Can be overridden by setting the "traefik.domain" label on an service.
|
||||||
|
#
|
||||||
|
# Required
|
||||||
|
#
|
||||||
|
domain = "rancher.localhost"
|
||||||
|
|
||||||
|
# Enable watch Rancher changes
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
# Default: true
|
||||||
|
#
|
||||||
|
Watch = true
|
||||||
|
|
||||||
|
# Expose Rancher services by default in traefik
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
# Default: true
|
||||||
|
#
|
||||||
|
ExposedByDefault = false
|
||||||
|
|
||||||
|
# Endpoint to use when connecting to Rancher
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
# Endpoint = "http://rancherserver.example.com"
|
||||||
|
|
||||||
|
# AccessKey to use when connecting to Rancher
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
# AccessKey = "XXXXXXXXX"
|
||||||
|
|
||||||
|
# SecretKey to use when connecting to Rancher
|
||||||
|
#
|
||||||
|
# Optional
|
||||||
|
# SecretKey = "XXXXXXXXXXX"
|
||||||
|
|
||||||
|
|
||||||
################################################################
|
################################################################
|
||||||
# Sample rules
|
# Sample rules
|
||||||
|
|
|
@ -39,7 +39,8 @@ type CircuitBreaker struct {
|
||||||
|
|
||||||
// HealthCheck holds HealthCheck configuration
|
// HealthCheck holds HealthCheck configuration
|
||||||
type HealthCheck struct {
|
type HealthCheck struct {
|
||||||
URL string `json:"url,omitempty"`
|
URL string `json:"url,omitempty"`
|
||||||
|
Interval string `json:"interval,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server holds server configuration.
|
// Server holds server configuration.
|
||||||
|
|
Loading…
Reference in a new issue