Add health check label to ECS

This commit is contained in:
Tait Clarridge 2017-11-21 05:06:03 -05:00 committed by Traefiker
parent 4b91204686
commit 6d2f4a0813
7 changed files with 111 additions and 26 deletions

View file

@ -117,7 +117,7 @@ func templatesDockerTmpl() (*asset, error) {
return a, nil
}
var _templatesEcsTmpl = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x53\x4d\x6f\xdb\x30\x0c\xbd\xe7\x57\x10\x46\x8e\xad\x7a\x2f\x90\xc3\xba\x0f\x74\x40\x37\x04\xeb\x61\x87\xa0\x07\xc5\x66\x6c\x21\xae\x54\x88\xf4\xb6\x40\xd0\x7f\x1f\x64\x49\x96\xbd\x64\x40\xb6\x93\x25\xf2\x3d\x8a\xef\x91\xde\xed\x65\x7d\x44\xdd\xd0\x8b\x73\x56\xea\x16\x61\x4d\x68\x7f\xa8\x1a\xbf\xca\x57\xbc\x81\xb5\xd2\xc4\x52\xd7\x48\x70\xbf\x01\xf1\x1c\x73\xe4\xfd\x0a\x60\xe2\x8a\x74\xb8\x75\x6e\x41\x07\xef\x45\x6f\x64\xb3\x97\x7d\x28\x61\x5f\x56\x00\x00\xaf\xc8\x9d\x69\x60\x03\x95\x73\xd0\x22\x3f\x19\xd9\x3c\x24\xc4\x97\x98\x2b\xaf\x7a\x5f\x8d\x24\x62\x55\x1f\x4f\xb0\x81\x73\xce\x73\x4c\xcd\x39\x23\xc5\x39\x75\x80\x4e\xd2\x98\x57\x1a\x89\x9e\xe4\x1e\xfb\x05\x10\x46\xe4\x3f\x0b\x11\x34\xd5\x8c\x9a\x00\x6a\x63\x8e\x2a\x82\x47\x65\x2d\x72\x79\xf8\x7d\x49\x9e\x4b\x73\x0e\x75\xe3\xfd\x6a\x15\x8e\x69\x06\x4a\x37\xf8\x2b\xb8\x1f\x5c\x3f\x53\x76\xb9\x5f\x25\x72\xab\xa1\x73\xb4\x94\xbe\xcb\x64\xbc\x7c\xfe\x00\xde\xe7\xd6\x07\xdb\x97\x69\x6c\xad\x61\x53\x9b\x60\x13\x78\x7f\x7f\x77\x17\xc3\x8f\x86\x38\x85\x12\xce\xd8\x14\xa8\x52\x99\x9f\xa8\xda\x8e\xa7\x11\x7d\x8f\xd7\xb5\x1a\x9b\xce\x22\x27\xb1\xbb\x83\x35\x9a\xff\x73\xf3\x32\xe3\xa0\x7a\x46\xfb\x29\x57\xba\xe0\xd4\xf4\x8a\xc8\xa7\x0b\xb3\xcd\x46\x24\x37\x83\x19\x7f\x5f\x84\x2c\xf7\x4d\x12\x05\x57\x1e\x51\x36\x68\x27\xd9\xdb\x65\x58\xa4\x46\x00\xde\xac\x32\x56\x71\xd9\xe1\x6d\x0e\x14\x0c\x6a\xb6\xa7\xad\x51\x9a\x09\x36\xb0\xcb\x32\x03\xfa\xe3\x2c\x55\x08\x95\x73\xc2\xfb\xea\x66\xbe\x48\x45\x0d\xa9\xfa\xdd\xc0\xdd\xbc\x54\x8b\xfc\x30\xc5\xaf\xa9\x73\x9d\x83\xc2\x9a\x81\x91\xe2\xe7\xf6\x0a\xab\xed\xd0\x97\x1f\x25\x0f\xf0\x5b\x08\x8a\x68\xf1\x1f\x0b\xf3\x3b\x00\x00\xff\xff\x86\x8c\x3e\xf5\xa8\x04\x00\x00")
var _templatesEcsTmpl = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x54\x4d\x6f\xdb\x30\x0c\xbd\xe7\x57\x10\x46\x8e\xad\x7a\x2f\x90\xc3\xda\x6d\x48\x81\x6e\x30\xd6\xc3\x0e\x41\x0f\x8a\xcd\xd8\x42\x5c\xa9\x90\x98\x6e\x85\xa0\xff\x3e\xc8\xfa\xb2\x17\x0f\xc8\x7a\xb2\x4c\xf2\x91\xef\x51\xcf\xde\xed\x79\x73\x44\xd9\x9a\x67\x6b\x35\x97\x1d\xc2\xda\xa0\x7e\x13\x0d\x7e\xe7\x2f\x78\x05\x6b\x21\x0d\x71\xd9\xa0\x81\xdb\x0d\xb0\xa7\x90\x33\xce\xad\x00\x32\x96\xc5\xc3\xb5\xb5\x33\x38\x38\xc7\x06\xc5\xdb\x3d\x1f\x7c\x0b\xfd\xbc\x02\x00\x78\x41\xea\x55\x0b\x1b\xa8\xac\x85\x0e\xe9\x51\xf1\xf6\x2e\x56\x7c\x0b\xb9\x32\xd5\xb9\x6a\x04\x19\x12\xcd\xf1\x1d\x36\x70\x8e\x79\x0a\xa9\x29\x66\x84\x58\x2b\x0e\xd0\x73\x33\xe6\x85\x44\x63\x1e\xf9\x1e\x87\x59\x21\x8c\x95\xff\x2d\x84\x99\xdc\x33\x68\x02\x68\x94\x3a\x8a\x50\x3c\x2a\xeb\x90\xca\xe0\xfb\x92\x3c\x97\x66\x2d\xca\x36\x73\x86\x40\x7a\x8b\x7c\xa0\xfe\xbe\xc7\xe6\x38\xb2\x36\xd3\x9b\x88\xc5\x17\xd1\xee\xc7\x46\x8d\x6f\x94\xa8\xbe\x72\xea\x33\xc9\xc9\xa0\xda\xc7\x67\x63\xaa\x88\x10\x92\x50\xbf\xf1\x61\x09\xf5\x90\x72\x0b\xc8\x24\x6d\xe5\x8f\xd1\x5e\x42\xb6\xf8\xdb\x1b\xcb\x1b\xea\xec\xd2\x96\x35\x09\x96\xe4\x78\x75\xa8\x4d\x7c\xce\x93\xe1\xe5\xe1\x33\x38\x97\xa4\x9e\xf4\x50\x8c\x56\x6b\x45\xaa\x51\x9e\x29\x38\x77\x7b\x73\x13\xc2\x5b\x65\x28\x86\x62\x9d\xd2\x31\x90\xf4\xff\x42\xd1\xf5\x94\xdd\xf7\x33\xbc\xae\xc5\x48\x3a\x89\xcc\x62\x77\x07\xad\x24\x7d\xf0\xa3\x4a\x88\x83\x18\x08\xf5\xd7\xd4\x69\x61\x53\x79\x0a\x4b\xa7\x85\xfb\x4f\x8b\x88\xdb\xf4\xcb\xf8\xb7\x59\xaa\x6c\x10\x63\xfc\x56\xb6\xc8\x5b\xd4\x59\x76\x3d\x0f\xb3\x48\x04\xe0\x55\x0b\xa5\x05\x95\xcf\xb3\x4e\x81\x52\x83\x92\xf4\x7b\xad\x84\x24\x03\x1b\xd8\x25\x99\xbe\xfa\xcb\x24\x55\x00\x95\xb5\xcc\xb9\xea\x6a\x6a\xa4\xa2\xc6\x88\xe6\xd3\x69\xb4\x71\x6e\xd5\x21\xdd\xe5\xf8\x25\x7d\x2e\xdb\x20\xd3\xea\x44\x68\xc2\xe3\xfa\x82\x55\xeb\xd3\x50\xfe\x01\xe9\x02\x7f\xf8\x20\x0b\x2b\xfe\xcb\x30\x7f\x02\x00\x00\xff\xff\xca\x00\x13\x83\x83\x05\x00\x00")
func templatesEcsTmplBytes() ([]byte, error) {
return bindataRead(
@ -132,7 +132,7 @@ func templatesEcsTmpl() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "templates/ecs.tmpl", size: 1192, mode: os.FileMode(436), modTime: time.Unix(1509884496, 0)}
info := bindataFileInfo{name: "templates/ecs.tmpl", size: 1411, mode: os.FileMode(436), modTime: time.Unix(1509884496, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -330,15 +330,15 @@ func AssetNames() []string {
// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
"templates/consul_catalog.tmpl": templatesConsul_catalogTmpl,
"templates/docker.tmpl": templatesDockerTmpl,
"templates/ecs.tmpl": templatesEcsTmpl,
"templates/eureka.tmpl": templatesEurekaTmpl,
"templates/kubernetes.tmpl": templatesKubernetesTmpl,
"templates/kv.tmpl": templatesKvTmpl,
"templates/marathon.tmpl": templatesMarathonTmpl,
"templates/mesos.tmpl": templatesMesosTmpl,
"templates/notFound.tmpl": templatesNotfoundTmpl,
"templates/rancher.tmpl": templatesRancherTmpl,
"templates/docker.tmpl": templatesDockerTmpl,
"templates/ecs.tmpl": templatesEcsTmpl,
"templates/eureka.tmpl": templatesEurekaTmpl,
"templates/kubernetes.tmpl": templatesKubernetesTmpl,
"templates/kv.tmpl": templatesKvTmpl,
"templates/marathon.tmpl": templatesMarathonTmpl,
"templates/mesos.tmpl": templatesMesosTmpl,
"templates/notFound.tmpl": templatesNotfoundTmpl,
"templates/rancher.tmpl": templatesRancherTmpl,
}
// AssetDir returns the file names below a certain
@ -380,19 +380,18 @@ type bintree struct {
Func func() (*asset, error)
Children map[string]*bintree
}
var _bintree = &bintree{nil, map[string]*bintree{
"templates": &bintree{nil, map[string]*bintree{
"consul_catalog.tmpl": &bintree{templatesConsul_catalogTmpl, map[string]*bintree{}},
"docker.tmpl": &bintree{templatesDockerTmpl, map[string]*bintree{}},
"ecs.tmpl": &bintree{templatesEcsTmpl, map[string]*bintree{}},
"eureka.tmpl": &bintree{templatesEurekaTmpl, map[string]*bintree{}},
"kubernetes.tmpl": &bintree{templatesKubernetesTmpl, map[string]*bintree{}},
"kv.tmpl": &bintree{templatesKvTmpl, map[string]*bintree{}},
"marathon.tmpl": &bintree{templatesMarathonTmpl, map[string]*bintree{}},
"mesos.tmpl": &bintree{templatesMesosTmpl, map[string]*bintree{}},
"notFound.tmpl": &bintree{templatesNotfoundTmpl, map[string]*bintree{}},
"rancher.tmpl": &bintree{templatesRancherTmpl, map[string]*bintree{}},
"docker.tmpl": &bintree{templatesDockerTmpl, map[string]*bintree{}},
"ecs.tmpl": &bintree{templatesEcsTmpl, map[string]*bintree{}},
"eureka.tmpl": &bintree{templatesEurekaTmpl, map[string]*bintree{}},
"kubernetes.tmpl": &bintree{templatesKubernetesTmpl, map[string]*bintree{}},
"kv.tmpl": &bintree{templatesKvTmpl, map[string]*bintree{}},
"marathon.tmpl": &bintree{templatesMarathonTmpl, map[string]*bintree{}},
"mesos.tmpl": &bintree{templatesMesosTmpl, map[string]*bintree{}},
"notFound.tmpl": &bintree{templatesNotfoundTmpl, map[string]*bintree{}},
"rancher.tmpl": &bintree{templatesRancherTmpl, map[string]*bintree{}},
}},
}}
@ -442,3 +441,4 @@ func _filePath(dir, name string) string {
cannonicalName := strings.Replace(name, "\\", "/", -1)
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
}

View file

@ -134,6 +134,8 @@ Labels can be used on task containers to override default behaviour:
| `traefik.backend.loadbalancer.stickiness=true` | enable backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Manually set the cookie name for sticky sessions |
| `traefik.backend.loadbalancer.sticky=true` | enable backend sticky sessions (DEPRECATED) |
| `traefik.backend.healthcheck.path=/health` | enable health checks for the backend, hitting the container at `path` |
| `traefik.backend.healthcheck.interval=1s` | configure the health check interval |
| `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 |

View file

@ -28,10 +28,11 @@ func GetHealthCheck() *HealthCheck {
// Options are the public health check options.
type Options struct {
Path string
Port int
Interval time.Duration
LB LoadBalancer
Path string
Port int
Transport http.RoundTripper
Interval time.Duration
LB LoadBalancer
}
func (opt Options) String() string {
@ -146,7 +147,8 @@ func (backend *BackendHealthCheck) newRequest(serverURL *url.URL) (*http.Request
func checkHealth(serverURL *url.URL, backend *BackendHealthCheck) bool {
client := http.Client{
Timeout: backend.requestTimeout,
Timeout: backend.requestTimeout,
Transport: backend.Options.Transport,
}
req, err := backend.newRequest(serverURL)
if err != nil {

View file

@ -195,6 +195,9 @@ func (p *Provider) generateECSConfig(services map[string][]ecsInstance) (*types.
"getPassHostHeader": p.getPassHostHeader,
"getPriority": p.getPriority,
"getEntryPoints": p.getEntryPoints,
"hasHealthCheckLabels": p.hasHealthCheckLabels,
"getHealthCheckPath": p.getHealthCheckPath,
"getHealthCheckInterval": p.getHealthCheckInterval,
}
return p.GetConfiguration("templates/ecs.tmpl", ecsFuncMap, struct {
Services map[string][]ecsInstance
@ -526,6 +529,18 @@ func (p *Provider) getLoadBalancerMethod(instances []ecsInstance) string {
return "wrr"
}
func (p *Provider) hasHealthCheckLabels(instances []ecsInstance) bool {
return p.getHealthCheckPath(instances) != ""
}
func (p *Provider) getHealthCheckPath(instances []ecsInstance) string {
return p.getFirstInstanceLabel(instances, types.LabelBackendHealthcheckPath)
}
func (p *Provider) getHealthCheckInterval(instances []ecsInstance) string {
return p.getFirstInstanceLabel(instances, types.LabelBackendHealthcheckInterval)
}
// Provider expects no more than 100 parameters be passed to a DescribeTask call; thus, pack
// each string into an array capped at 100 elements
func (p *Provider) chunkedTaskArns(tasks []*string) [][]*string {

View file

@ -643,6 +643,65 @@ func TestGenerateECSConfig(t *testing.T) {
},
},
},
{
desc: "config parsed successfully with health check labels",
services: map[string][]ecsInstance{
"testing": {
{
Name: "instance-1",
containerDefinition: &ecs.ContainerDefinition{
DockerLabels: map[string]*string{
types.LabelBackendHealthcheckPath: func(s string) *string { return &s }("/health"),
types.LabelBackendHealthcheckInterval: func(s string) *string { return &s }("1s"),
},
},
machine: &ec2.Instance{
PrivateIpAddress: func(s string) *string { return &s }("10.0.0.1"),
},
container: &ecs.Container{
NetworkBindings: []*ecs.NetworkBinding{
{
HostPort: func(i int64) *int64 { return &i }(1337),
},
},
},
},
},
},
exp: &types.Configuration{
Backends: map[string]*types.Backend{
"backend-instance-1": {
Servers: map[string]types.Server{
"server-instance-1": {
URL: "http://10.0.0.1:1337",
},
},
},
"backend-testing": {
LoadBalancer: &types.LoadBalancer{
Method: "wrr",
},
HealthCheck: &types.HealthCheck{
Path: "/health",
Interval: "1s",
},
},
},
Frontends: map[string]*types.Frontend{
"frontend-testing": {
EntryPoints: []string{},
Backend: "backend-testing",
Routes: map[string]types.Route{
"route-frontend-testing": {
Rule: "Host:instance-1.",
},
},
PassHostHeader: true,
BasicAuth: []string{},
},
},
},
},
}
for _, test := range tests {

View file

@ -1019,6 +1019,7 @@ func (server *Server) loadConfig(configurations types.Configurations, globalConf
hcOpts := parseHealthCheckOptions(rebalancer, frontend.Backend, config.Backends[frontend.Backend].HealthCheck, globalConfiguration.HealthCheck)
if hcOpts != nil {
log.Debugf("Setting up backend health check %s", *hcOpts)
hcOpts.Transport = server.defaultForwardingRoundTripper
backendsHealthCheck[entryPointName+frontend.Backend] = healthcheck.NewBackendHealthCheck(*hcOpts)
}
lb = middlewares.NewEmptyBackendHandler(rebalancer, lb)
@ -1040,6 +1041,7 @@ func (server *Server) loadConfig(configurations types.Configurations, globalConf
hcOpts := parseHealthCheckOptions(rr, frontend.Backend, config.Backends[frontend.Backend].HealthCheck, globalConfiguration.HealthCheck)
if hcOpts != nil {
log.Debugf("Setting up backend health check %s", *hcOpts)
hcOpts.Transport = server.defaultForwardingRoundTripper
backendsHealthCheck[entryPointName+frontend.Backend] = healthcheck.NewBackendHealthCheck(*hcOpts)
}
lb = middlewares.NewEmptyBackendHandler(rr, lb)

View file

@ -6,6 +6,11 @@
[backends.backend-{{ $serviceName }}.loadbalancer.stickiness]
cookieName = "{{getStickinessCookieName $instances}}"
{{end}}
{{ if hasHealthCheckLabels $instances }}
[backends.backend-{{ $serviceName }}.healthcheck]
path = "{{getHealthCheckPath $instances }}"
interval = "{{getHealthCheckInterval $instances }}"
{{end}}
{{range $index, $i := $instances}}
[backends.backend-{{ $i.Name }}.servers.server-{{ $i.Name }}{{ $i.ID }}]