Add health check timeout parameter

This commit is contained in:
Jared Biel 2018-09-27 13:16:03 -05:00 committed by Traefiker Bot
parent f10516deb7
commit 5acd43efaf
45 changed files with 189 additions and 28 deletions

View file

@ -88,6 +88,7 @@ var _templatesConsul_catalogTmpl = []byte(`[backends]
path = "{{ $healthCheck.Path }}"
port = {{ $healthCheck.Port }}
interval = "{{ $healthCheck.Interval }}"
timeout = "{{ $healthCheck.Timeout }}"
hostname = "{{ $healthCheck.Hostname }}"
{{if $healthCheck.Headers }}
[backends."backend-{{ $backendName }}".healthCheck.headers]
@ -356,6 +357,7 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
path = "{{ $healthCheck.Path }}"
port = {{ $healthCheck.Port }}
interval = "{{ $healthCheck.Interval }}"
timeout = "{{ $healthCheck.Timeout }}"
hostname = "{{ $healthCheck.Hostname }}"
{{if $healthCheck.Headers }}
[backends."backend-{{ $backendName }}".healthCheck.headers]
@ -624,6 +626,7 @@ var _templatesEcsTmpl = []byte(`[backends]
path = "{{ $healthCheck.Path }}"
port = {{ $healthCheck.Port }}
interval = "{{ $healthCheck.Interval }}"
timeout = "{{ $healthCheck.Timeout }}"
hostname = "{{ $healthCheck.Hostname }}"
{{if $healthCheck.Headers }}
[backends."backend-{{ $serviceName }}".healthCheck.headers]
@ -1152,6 +1155,7 @@ var _templatesKvTmpl = []byte(`[backends]
path = "{{ $healthCheck.Path }}"
port = {{ $healthCheck.Port }}
interval = "{{ $healthCheck.Interval }}"
timeout = "{{ $healthCheck.Timeout }}"
hostname = "{{ $healthCheck.Hostname }}"
{{if $healthCheck.Headers }}
[backends."{{ $backendName }}".healthCheck.headers]
@ -1437,6 +1441,7 @@ var _templatesMarathonTmpl = []byte(`{{ $apps := .Applications }}
path = "{{ $healthCheck.Path }}"
port = {{ $healthCheck.Port }}
interval = "{{ $healthCheck.Interval }}"
timeout = "{{ $healthCheck.Timeout }}"
hostname = "{{ $healthCheck.Hostname }}"
{{if $healthCheck.Headers }}
[backends.{{ $backendName }}.healthCheck.headers]
@ -1707,6 +1712,7 @@ var _templatesMesosTmpl = []byte(`[backends]
path = "{{ $healthCheck.Path }}"
port = {{ $healthCheck.Port }}
interval = "{{ $healthCheck.Interval }}"
timeout = "{{ $healthCheck.Timeout }}"
hostname = "{{ $healthCheck.Hostname }}"
{{if $healthCheck.Headers }}
[backends."backend-{{ $backendName }}".healthCheck.headers]
@ -2000,6 +2006,7 @@ var _templatesRancherTmpl = []byte(`{{ $backendServers := .Backends }}
path = "{{ $healthCheck.Path }}"
port = {{ $healthCheck.Port }}
interval = "{{ $healthCheck.Interval }}"
timeout = "{{ $healthCheck.Timeout }}"
hostname = "{{ $healthCheck.Hostname }}"
{{if $healthCheck.Headers }}
[backends."backend-{{ $backendName }}".healthCheck.headers]

View file

@ -177,6 +177,7 @@ func NewTraefikDefaultPointersConfiguration() *TraefikConfiguration {
// default HealthCheckConfig
healthCheck := configuration.HealthCheckConfig{
Interval: parse.Duration(configuration.DefaultHealthCheckInterval),
Timeout: parse.Duration(configuration.DefaultHealthCheckTimeout),
}
// default RespondingTimeouts
@ -302,6 +303,7 @@ func NewTraefikConfiguration() *TraefikConfiguration {
MaxIdleConnsPerHost: 200,
HealthCheck: &configuration.HealthCheckConfig{
Interval: parse.Duration(configuration.DefaultHealthCheckInterval),
Timeout: parse.Duration(configuration.DefaultHealthCheckTimeout),
},
LifeCycle: &configuration.LifeCycle{
GraceTimeOut: parse.Duration(configuration.DefaultGraceTimeout),

View file

@ -42,6 +42,9 @@ const (
// DefaultHealthCheckInterval is the default health check interval.
DefaultHealthCheckInterval = 30 * time.Second
// DefaultHealthCheckTimeout is the default health check request timeout.
DefaultHealthCheckTimeout = 5 * time.Second
// DefaultDialTimeout when connecting to a backend server.
DefaultDialTimeout = 30 * time.Second
@ -372,6 +375,7 @@ type Retry struct {
// HealthCheckConfig contains health check configuration parameters.
type HealthCheckConfig struct {
Interval parse.Duration `description:"Default periodicity of enabled health checks" export:"true"`
Timeout parse.Duration `description:"Default request timeout of enabled health checks" export:"true"`
}
// RespondingTimeouts contains timeout configurations for incoming requests to the Traefik instance.

View file

@ -452,9 +452,11 @@ If not, a new backend will be assigned.
#### Health Check
A health check can be configured in order to remove a backend from LB rotation as long as it keeps returning HTTP status codes other than `2xx` or `3xx` to HTTP GET requests periodically carried out by Traefik.
The check is defined by a path appended to the backend URL and an interval (given in a format understood by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration)) specifying how often the health check should be executed (the default being 30 seconds).
Each backend must respond to the health check within 5 seconds.
A health check can be configured in order to remove a backend from LB rotation as long as it keeps returning HTTP status codes other than `2xx` or `3xx` to HTTP GET requests periodically carried out by Traefik.
The check is defined by a path appended to the backend URL and an interval specifying how often the health check should be executed (the default being 30 seconds.)
Each backend must respond to the health check within a timeout duration (the default being 5 seconds.)
Interval and timeout are to be given in a format understood by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration).
The interval must be greater than the timeout. If configuration doesn't reflect this, the interval will be set to timeout + 1 second.
By default, the port of the backend server is used, however, this may be overridden.
A recovering backend returning `2xx` or `3xx` responses again is being returned to the LB rotation pool.
@ -466,6 +468,7 @@ For example:
[backends.backend1.healthcheck]
path = "/health"
interval = "10s"
timeout = "3s"
```
To use a different port for the health check:
@ -475,6 +478,7 @@ To use a different port for the health check:
[backends.backend1.healthcheck]
path = "/health"
interval = "10s"
timeout = "3s"
port = 8080
```
@ -486,6 +490,7 @@ To use a different scheme for the health check:
[backends.backend1.healthcheck]
path = "/health"
interval = "10s"
timeout = "3s"
scheme = "http"
```
@ -496,6 +501,7 @@ Additional http headers and hostname to health check request can be specified, f
[backends.backend1.healthcheck]
path = "/health"
interval = "10s"
timeout = "3s"
hostname = "myhost.com"
port = 8080
[backends.backend1.healthcheck.headers]

View file

@ -106,7 +106,8 @@ Additional settings can be defined using Consul Catalog tags.
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `<prefix>.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend. ex: `NetworkErrorRatio() > 0.` |
| `<prefix>.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
| `<prefix>.backend.healthcheck.interval=1s` | Defines the health check interval. |
| `<prefix>.backend.healthcheck.interval=5s` | Defines the health check interval. |
| `<prefix>.backend.healthcheck.timeout=3s` | Defines the health check request timeout |
| `<prefix>.backend.healthcheck.port=8080` | Sets a different port for the health check. |
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
| `<prefix>.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |

View file

@ -223,7 +223,8 @@ Labels can be used on containers to override default behavior.
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. |
| `traefik.backend.healthcheck.interval=5s` | Defines the health check interval. |
| `traefik.backend.healthcheck.timeout=3s` | Defines the health check request timeout. |
| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. |
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |

View file

@ -145,7 +145,8 @@ Labels can be used on task containers to override default behavior:
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. (Default: 30s) |
| `traefik.backend.healthcheck.interval=5s` | Defines the health check interval. (Default: 30s) |
| `traefik.backend.healthcheck.timeout=3s` | Defines the health check request timeout. (Default: 5s) |
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. |
| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |

View file

@ -37,6 +37,7 @@ Træfik can be configured with a file.
path = "/health"
port = 88
interval = "30s"
timeout = "5s"
scheme = "http"
hostname = "myhost.com"
[backends.backend1.healthcheck.headers]

View file

@ -209,7 +209,8 @@ The following labels can be defined on Marathon applications. They adjust the be
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. (Default: 30s) |
| `traefik.backend.healthcheck.interval=5s` | Defines the health check interval. (Default: 30s) |
| `traefik.backend.healthcheck.timeout=3s` | Defines the health check request timeout. (Default: 5s) |
| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. |
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |

View file

@ -123,7 +123,8 @@ The following labels can be defined on Mesos tasks. They adjust the behavior for
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. (Default: 30s) |
| `traefik.backend.healthcheck.interval=5s` | Defines the health check interval. (Default: 30s) |
| `traefik.backend.healthcheck.timeout=3s` | Defines the health check request timeout. (Default: 5s) |
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. |
| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |

View file

@ -153,7 +153,8 @@ Labels can be used on task containers to override default behavior:
| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. |
| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend |
| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. |
| `traefik.backend.healthcheck.interval=5s` | Defines the health check interval. |
| `traefik.backend.healthcheck.timeout=3s ` | Defines the health check request timeout. |
| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. |
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |

View file

@ -103,7 +103,8 @@ Labels, set through extensions or the property manager, can be used on services
| `traefik.servicefabric.enablelabeloverrides` | Toggle whether labels can be overridden using the Service Fabric Property Manager API |
| `traefik.backend.healthcheck.path=/health` | Enable health check for the backend, hitting the container at `path`. |
| `traefik.backend.healthcheck.port=8080` | Allow to use a different port for the health check. |
| `traefik.backend.healthcheck.interval=1s` | Define the health check interval. |
| `traefik.backend.healthcheck.interval=5s` | Define the health check interval. |
| `traefik.backend.healthcheck.timeout=3s` | Define the health check request timeout. |
| `traefik.backend.healthcheck.hostname=foobar.com` | Define the health check hostname. |
| `traefik.backend.healthcheck.headers=EXPR` | Define the health check request headers <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `traefik.backend.loadbalancer.method=drr` | Override the default `wrr` load balancer algorithm |

View file

@ -241,19 +241,23 @@ Example configuration:
# Enable custom health check options.
[healthcheck]
# Set the default health check interval.
# Set the default health check interval and timeout.
#
# Optional
# Default: "30s"
#
# interval = "30s"
# timeout = "5s"
```
- `interval` set the default health check interval.
Will only be effective if health check paths are defined.
Given provider-specific support, the value may be overridden on a per-backend basis.
Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw values (digits).
- `interval` sets the default health check interval.
- `timeout` sets the default health check request timeout.
These options will only be effective if health check paths are defined.
Given provider-specific support, the value may be overridden on a per-backend basis.
Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw values (digits).
If no units are provided, the value is parsed assuming seconds.
**Note:** the interval must be greater than the timeout. If configuration doesn't reflect this, the interval will be set to timeout + 1 second.
## Life Cycle

View file

@ -71,7 +71,7 @@ Beginning with version 1.4, Traefik respects readiness check results if the Trae
!!! note
Due to the way readiness check results are currently exposed by the Marathon API, ready tasks may be taken into rotation with a small delay.
It is on the order of one readiness check timeout interval (as configured on the application specifiation) and guarantees that non-ready tasks do not receive traffic prematurely.
It is on the order of one readiness check timeout interval (as configured on the application specification) and guarantees that non-ready tasks do not receive traffic prematurely.
If readiness checks are not possible, a current mitigation strategy is to enable [retries](/configuration/commons#retry-configuration) and make sure that a sufficient number of healthy application tasks exist so that one retry will likely hit one of those.
Apart from its probabilistic nature, the workaround comes at the price of increased latency.

View file

@ -42,11 +42,12 @@ type Options struct {
Port int
Transport http.RoundTripper
Interval time.Duration
Timeout time.Duration
LB BalancerHandler
}
func (opt Options) String() string {
return fmt.Sprintf("[Hostname: %s Headers: %v Path: %s Port: %d Interval: %s]", opt.Hostname, opt.Headers, opt.Path, opt.Port, opt.Interval)
return fmt.Sprintf("[Hostname: %s Headers: %v Path: %s Port: %d Interval: %s Timeout: %s]", opt.Hostname, opt.Headers, opt.Path, opt.Port, opt.Interval, opt.Timeout)
}
// BackendConfig HealthCheck configuration for a backend
@ -180,9 +181,8 @@ func newHealthCheck(metrics metricsRegistry) *HealthCheck {
// NewBackendConfig Instantiate a new BackendConfig
func NewBackendConfig(options Options, backendName string) *BackendConfig {
return &BackendConfig{
Options: options,
name: backendName,
requestTimeout: 5 * time.Second,
Options: options,
name: backendName,
}
}
@ -197,7 +197,7 @@ func checkHealth(serverURL *url.URL, backend *BackendConfig) error {
req = backend.addHeadersAndHost(req)
client := http.Client{
Timeout: backend.requestTimeout,
Timeout: backend.Options.Timeout,
Transport: backend.Options.Transport,
}

View file

@ -15,7 +15,8 @@ import (
"github.com/vulcand/oxy/roundrobin"
)
const healthCheckInterval = 100 * time.Millisecond
const healthCheckInterval = 200 * time.Millisecond
const healthCheckTimeout = 100 * time.Millisecond
type testHandler struct {
done func()
@ -105,6 +106,7 @@ func TestSetBackendsConfiguration(t *testing.T) {
backend := NewBackendConfig(Options{
Path: "/path",
Interval: healthCheckInterval,
Timeout: healthCheckTimeout,
LB: lb,
}, "backendName")

View file

@ -83,6 +83,7 @@ func (s *ConsulCatalogSuite) registerAgentService(name string, address string, p
healthCheck = &api.AgentServiceCheck{
HTTP: "http://" + address,
Interval: "10s",
Timeout: "3s",
}
} else {
healthCheck = nil

View file

@ -18,6 +18,7 @@ logLevel = "DEBUG"
[backends.backend1.healthcheck]
path = "/health"
interval = "1s"
timeout = "0.9s"
[backends.backend1.servers.server1]
url = "http://{{.Server1}}:80"
weight = 1

View file

@ -18,6 +18,7 @@ logLevel = "DEBUG"
[backends.backend1.healthcheck]
path = "/health"
interval = "1s"
timeout = "0.9s"
[backends.backend1.servers.server1]
url = "http://{{.Server1}}:80"
weight = 1

View file

@ -15,6 +15,7 @@ logLevel = "DEBUG"
path = "/health"
port = 80
interval = "1s"
timeout = "0.9s"
[backends.backend1.servers.server1]
url = "http://{{.Server1}}:81"
weight = 1

View file

@ -14,6 +14,7 @@ logLevel = "DEBUG"
[backends.backend1.healthcheck]
path = "/health"
interval = "1s"
timeout = "0.9s"
[backends.backend1.servers.server1]
url = "http://{{.Server1}}:80"
weight = 1

View file

@ -410,6 +410,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
label.TraefikBackendHealthCheckScheme + "=http",
label.TraefikBackendHealthCheckPort + "=880",
label.TraefikBackendHealthCheckInterval + "=6",
label.TraefikBackendHealthCheckTimeout + "=3",
label.TraefikBackendHealthCheckHostname + "=foo.com",
label.TraefikBackendHealthCheckHeaders + "=Foo:bar || Bar:foo",
label.TraefikBackendLoadBalancerMethod + "=drr",
@ -691,6 +692,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
Path: "/health",
Port: 880,
Interval: "6",
Timeout: "3",
Hostname: "foo.com",
Headers: map[string]string{
"Foo": "bar",

View file

@ -437,6 +437,7 @@ func TestDockerBuildConfiguration(t *testing.T) {
label.TraefikBackendHealthCheckPath: "/health",
label.TraefikBackendHealthCheckPort: "880",
label.TraefikBackendHealthCheckInterval: "6",
label.TraefikBackendHealthCheckTimeout: "3",
label.TraefikBackendHealthCheckHostname: "foo.com",
label.TraefikBackendHealthCheckHeaders: "Foo:bar || Bar:foo",
label.TraefikBackendLoadBalancerMethod: "drr",
@ -683,6 +684,7 @@ func TestDockerBuildConfiguration(t *testing.T) {
Path: "/health",
Port: 880,
Interval: "6",
Timeout: "3",
Hostname: "foo.com",
Headers: map[string]string{
"Foo": "bar",

View file

@ -385,6 +385,7 @@ func TestSwarmBuildConfiguration(t *testing.T) {
label.TraefikBackendHealthCheckPath: "/health",
label.TraefikBackendHealthCheckPort: "880",
label.TraefikBackendHealthCheckInterval: "6",
label.TraefikBackendHealthCheckTimeout: "3",
label.TraefikBackendHealthCheckHostname: "foo.com",
label.TraefikBackendHealthCheckHeaders: "Foo:bar || Bar:foo",
label.TraefikBackendLoadBalancerMethod: "drr",
@ -600,6 +601,7 @@ func TestSwarmBuildConfiguration(t *testing.T) {
Path: "/health",
Port: 880,
Interval: "6",
Timeout: "3",
Hostname: "foo.com",
Headers: map[string]string{
"Foo": "bar",

View file

@ -68,7 +68,8 @@ func TestBuildConfiguration(t *testing.T) {
ID("1"),
dockerLabels(map[string]*string{
label.TraefikBackendHealthCheckPath: aws.String("/health"),
label.TraefikBackendHealthCheckInterval: aws.String("1s"),
label.TraefikBackendHealthCheckInterval: aws.String("6s"),
label.TraefikBackendHealthCheckTimeout: aws.String("3s"),
}),
iMachine(
mState(ec2.InstanceStateNameRunning),
@ -84,7 +85,8 @@ func TestBuildConfiguration(t *testing.T) {
"backend-instance": {
HealthCheck: &types.HealthCheck{
Path: "/health",
Interval: "1s",
Interval: "6s",
Timeout: "3s",
},
Servers: map[string]types.Server{
"server-instance-1": {
@ -343,6 +345,7 @@ func TestBuildConfiguration(t *testing.T) {
label.TraefikBackendHealthCheckPath: aws.String("/health"),
label.TraefikBackendHealthCheckPort: aws.String("880"),
label.TraefikBackendHealthCheckInterval: aws.String("6"),
label.TraefikBackendHealthCheckTimeout: aws.String("3"),
label.TraefikBackendHealthCheckHostname: aws.String("foo.com"),
label.TraefikBackendHealthCheckHeaders: aws.String("Foo:bar || Bar:foo"),
label.TraefikBackendLoadBalancerMethod: aws.String("drr"),
@ -470,6 +473,7 @@ func TestBuildConfiguration(t *testing.T) {
Path: "/health",
Port: 880,
Interval: "6",
Timeout: "3",
Hostname: "foo.com",
Headers: map[string]string{
"Foo": "bar",
@ -633,6 +637,7 @@ func TestBuildConfiguration(t *testing.T) {
label.TraefikBackendHealthCheckPath: aws.String("/health"),
label.TraefikBackendHealthCheckPort: aws.String("880"),
label.TraefikBackendHealthCheckInterval: aws.String("6"),
label.TraefikBackendHealthCheckTimeout: aws.String("3"),
label.TraefikBackendHealthCheckHostname: aws.String("foo.com"),
label.TraefikBackendHealthCheckHeaders: aws.String("Foo:bar || Bar:foo"),
label.TraefikBackendLoadBalancerMethod: aws.String("drr"),
@ -719,6 +724,7 @@ func TestBuildConfiguration(t *testing.T) {
label.TraefikBackendHealthCheckPath: aws.String("/health"),
label.TraefikBackendHealthCheckPort: aws.String("880"),
label.TraefikBackendHealthCheckInterval: aws.String("6"),
label.TraefikBackendHealthCheckTimeout: aws.String("3"),
label.TraefikBackendHealthCheckHostname: aws.String("bar.com"),
label.TraefikBackendHealthCheckHeaders: aws.String("Foo:bar || Bar:foo"),
label.TraefikBackendLoadBalancerMethod: aws.String("drr"),
@ -822,6 +828,7 @@ func TestBuildConfiguration(t *testing.T) {
Path: "/health",
Port: 880,
Interval: "6",
Timeout: "3",
Hostname: "foo.com",
Headers: map[string]string{
"Foo": "bar",

View file

@ -7,6 +7,7 @@ const (
pathBackendHealthCheckPath = "/healthcheck/path"
pathBackendHealthCheckPort = "/healthcheck/port"
pathBackendHealthCheckInterval = "/healthcheck/interval"
pathBackendHealthCheckTimeout = "/healthcheck/timeout"
pathBackendHealthCheckHostname = "/healthcheck/hostname"
pathBackendHealthCheckHeaders = "/healthcheck/headers/"
pathBackendLoadBalancerMethod = "/loadbalancer/method"

View file

@ -271,6 +271,7 @@ func (p *Provider) getHealthCheck(rootPath string) *types.HealthCheck {
scheme := p.get("", rootPath, pathBackendHealthCheckScheme)
port := p.getInt(label.DefaultBackendHealthCheckPort, rootPath, pathBackendHealthCheckPort)
interval := p.get("30s", rootPath, pathBackendHealthCheckInterval)
timeout := p.get("5s", rootPath, pathBackendHealthCheckTimeout)
hostname := p.get("", rootPath, pathBackendHealthCheckHostname)
headers := p.getMap(rootPath, pathBackendHealthCheckHeaders)
@ -279,6 +280,7 @@ func (p *Provider) getHealthCheck(rootPath string) *types.HealthCheck {
Path: path,
Port: port,
Interval: interval,
Timeout: timeout,
Hostname: hostname,
Headers: headers,
}

View file

@ -260,6 +260,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
withPair(pathBackendHealthCheckPath, "/health"),
withPair(pathBackendHealthCheckPort, "80"),
withPair(pathBackendHealthCheckInterval, "30s"),
withPair(pathBackendHealthCheckTimeout, "5s"),
withPair(pathBackendHealthCheckHostname, "foo.com"),
withPair(pathBackendHealthCheckHeaders+"Foo", "bar"),
withPair(pathBackendHealthCheckHeaders+"Bar", "foo"),
@ -387,6 +388,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
Path: "/health",
Port: 80,
Interval: "30s",
Timeout: "5s",
Hostname: "foo.com",
Headers: map[string]string{
"Foo": "bar",
@ -1986,9 +1988,12 @@ func TestProviderGetHealthCheck(t *testing.T) {
backend("foo",
withPair(pathBackendHealthCheckPath, "/health"),
withPair(pathBackendHealthCheckPort, "80"),
withPair(pathBackendHealthCheckInterval, "10s"))),
withPair(pathBackendHealthCheckInterval, "10s"),
withPair(pathBackendHealthCheckTimeout, "3s"))),
expected: &types.HealthCheck{
Interval: "10s",
Timeout: "3s",
Path: "/health",
Port: 80,
},
@ -2001,6 +2006,7 @@ func TestProviderGetHealthCheck(t *testing.T) {
withPair(pathBackendHealthCheckPath, "/health"))),
expected: &types.HealthCheck{
Interval: "30s",
Timeout: "5s",
Path: "/health",
Port: 0,
},
@ -2011,7 +2017,8 @@ func TestProviderGetHealthCheck(t *testing.T) {
kvPairs: filler("traefik",
backend("foo",
withPair(pathBackendHealthCheckPort, "80"),
withPair(pathBackendHealthCheckInterval, "30s"))),
withPair(pathBackendHealthCheckInterval, "30s"),
withPair(pathBackendHealthCheckTimeout, "5s"))),
expected: nil,
},
}

View file

@ -19,6 +19,7 @@ const (
SuffixBackendHealthCheckPath = "backend.healthcheck.path"
SuffixBackendHealthCheckPort = "backend.healthcheck.port"
SuffixBackendHealthCheckInterval = "backend.healthcheck.interval"
SuffixBackendHealthCheckTimeout = "backend.healthcheck.timeout"
SuffixBackendHealthCheckHostname = "backend.healthcheck.hostname"
SuffixBackendHealthCheckHeaders = "backend.healthcheck.headers"
SuffixBackendLoadBalancer = "backend.loadbalancer"
@ -120,6 +121,7 @@ const (
TraefikBackendHealthCheckPath = Prefix + SuffixBackendHealthCheckPath
TraefikBackendHealthCheckPort = Prefix + SuffixBackendHealthCheckPort
TraefikBackendHealthCheckInterval = Prefix + SuffixBackendHealthCheckInterval
TraefikBackendHealthCheckTimeout = Prefix + SuffixBackendHealthCheckTimeout
TraefikBackendHealthCheckHostname = Prefix + SuffixBackendHealthCheckHostname
TraefikBackendHealthCheckHeaders = Prefix + SuffixBackendHealthCheckHeaders
TraefikBackendLoadBalancer = Prefix + SuffixBackendLoadBalancer

View file

@ -342,6 +342,7 @@ func GetHealthCheck(labels map[string]string) *types.HealthCheck {
scheme := GetStringValue(labels, TraefikBackendHealthCheckScheme, "")
port := GetIntValue(labels, TraefikBackendHealthCheckPort, DefaultBackendHealthCheckPort)
interval := GetStringValue(labels, TraefikBackendHealthCheckInterval, "")
timeout := GetStringValue(labels, TraefikBackendHealthCheckTimeout, "")
hostname := GetStringValue(labels, TraefikBackendHealthCheckHostname, "")
headers := GetMapValue(labels, TraefikBackendHealthCheckHeaders)
@ -350,6 +351,7 @@ func GetHealthCheck(labels map[string]string) *types.HealthCheck {
Path: path,
Port: port,
Interval: interval,
Timeout: timeout,
Hostname: hostname,
Headers: headers,
}

View file

@ -379,6 +379,7 @@ func TestGetHealthCheck(t *testing.T) {
labels: map[string]string{
TraefikBackendHealthCheckPort: "80",
TraefikBackendHealthCheckInterval: "6",
TraefikBackendHealthCheckTimeout: "3",
},
expected: nil,
},
@ -388,6 +389,7 @@ func TestGetHealthCheck(t *testing.T) {
TraefikBackendHealthCheckPath: "/health",
TraefikBackendHealthCheckPort: "80",
TraefikBackendHealthCheckInterval: "6",
TraefikBackendHealthCheckTimeout: "3",
TraefikBackendHealthCheckHeaders: "Foo:bar || Goo:bir",
TraefikBackendHealthCheckHostname: "traefik",
TraefikBackendHealthCheckScheme: "http",
@ -397,6 +399,7 @@ func TestGetHealthCheck(t *testing.T) {
Path: "/health",
Port: 80,
Interval: "6",
Timeout: "3",
Hostname: "traefik",
Headers: map[string]string{
"Foo": "bar",

View file

@ -359,6 +359,7 @@ func TestBuildConfiguration(t *testing.T) {
withLabel(label.TraefikBackendHealthCheckPath, "/health"),
withLabel(label.TraefikBackendHealthCheckPort, "880"),
withLabel(label.TraefikBackendHealthCheckInterval, "6"),
withLabel(label.TraefikBackendHealthCheckTimeout, "3"),
withLabel(label.TraefikBackendHealthCheckHostname, "foo.com"),
withLabel(label.TraefikBackendHealthCheckHeaders, "Foo:bar || Bar:foo"),
@ -603,6 +604,7 @@ func TestBuildConfiguration(t *testing.T) {
Path: "/health",
Port: 880,
Interval: "6",
Timeout: "3",
Hostname: "foo.com",
Headers: map[string]string{
"Foo": "bar",
@ -779,6 +781,7 @@ func TestBuildConfigurationSegments(t *testing.T) {
withLabel(label.TraefikBackendHealthCheckPath, "/health"),
withLabel(label.TraefikBackendHealthCheckPort, "880"),
withLabel(label.TraefikBackendHealthCheckInterval, "6"),
withLabel(label.TraefikBackendHealthCheckTimeout, "3"),
withLabel(label.TraefikBackendLoadBalancerMethod, "drr"),
withLabel(label.TraefikBackendLoadBalancerStickiness, "true"),
withLabel(label.TraefikBackendLoadBalancerStickinessCookieName, "chocolate"),
@ -1017,6 +1020,7 @@ func TestBuildConfigurationSegments(t *testing.T) {
Path: "/health",
Port: 880,
Interval: "6",
Timeout: "3",
},
Buffering: &types.Buffering{
MaxResponseBodyBytes: 10485760,

View file

@ -316,6 +316,7 @@ func TestBuildConfiguration(t *testing.T) {
withLabel(label.TraefikBackendHealthCheckPath, "/health"),
withLabel(label.TraefikBackendHealthCheckPort, "880"),
withLabel(label.TraefikBackendHealthCheckInterval, "6"),
withLabel(label.TraefikBackendHealthCheckTimeout, "3"),
withLabel(label.TraefikBackendHealthCheckHostname, "foo.com"),
withLabel(label.TraefikBackendHealthCheckHeaders, "Foo:bar || Bar:foo"),
@ -563,6 +564,7 @@ func TestBuildConfiguration(t *testing.T) {
Path: "/health",
Port: 880,
Interval: "6",
Timeout: "3",
Hostname: "foo.com",
Headers: map[string]string{
"Foo": "bar",
@ -696,6 +698,7 @@ func TestBuildConfigurationSegments(t *testing.T) {
withLabel(label.TraefikBackendHealthCheckPath, "/health"),
withLabel(label.TraefikBackendHealthCheckPort, "880"),
withLabel(label.TraefikBackendHealthCheckInterval, "6"),
withLabel(label.TraefikBackendHealthCheckTimeout, "3"),
withLabel(label.TraefikBackendHealthCheckHostname, "foo.com"),
withLabel(label.TraefikBackendHealthCheckHeaders, "Foo:bar || Bar:foo"),
withLabel(label.TraefikBackendLoadBalancerMethod, "drr"),
@ -940,6 +943,7 @@ func TestBuildConfigurationSegments(t *testing.T) {
Path: "/health",
Port: 880,
Interval: "6",
Timeout: "3",
Hostname: "foo.com",
Headers: map[string]string{
"Bar": "foo",

View file

@ -45,6 +45,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
label.TraefikBackendHealthCheckPath: "/health",
label.TraefikBackendHealthCheckPort: "880",
label.TraefikBackendHealthCheckInterval: "6",
label.TraefikBackendHealthCheckTimeout: "3",
label.TraefikBackendHealthCheckHostname: "foo.com",
label.TraefikBackendHealthCheckHeaders: "Foo:bar || Bar:foo",
label.TraefikBackendLoadBalancerMethod: "drr",
@ -295,6 +296,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
Path: "/health",
Port: 880,
Interval: "6",
Timeout: "3",
Hostname: "foo.com",
Headers: map[string]string{
"Foo": "bar",

View file

@ -90,7 +90,10 @@ func TestServerLoadConfigHealthCheckOptions(t *testing.T) {
for _, healthCheck := range healthChecks {
t.Run(fmt.Sprintf("%s/hc=%t", lbMethod, healthCheck != nil), func(t *testing.T) {
globalConfig := configuration.GlobalConfiguration{
HealthCheck: &configuration.HealthCheckConfig{Interval: parse.Duration(5 * time.Second)},
HealthCheck: &configuration.HealthCheckConfig{
Interval: parse.Duration(5 * time.Second),
Timeout: parse.Duration(3 * time.Second),
},
}
entryPoints := map[string]EntryPoint{
"http": {
@ -424,6 +427,7 @@ func TestServerMultipleFrontendRules(t *testing.T) {
func TestServerBuildHealthCheckOptions(t *testing.T) {
lb := &testLoadBalancer{}
globalInterval := 15 * time.Second
globalTimeout := 3 * time.Second
testCases := []struct {
desc string
@ -452,6 +456,7 @@ func TestServerBuildHealthCheckOptions(t *testing.T) {
Path: "/path",
Interval: globalInterval,
LB: lb,
Timeout: 3 * time.Second,
},
},
{
@ -464,6 +469,7 @@ func TestServerBuildHealthCheckOptions(t *testing.T) {
Path: "/path",
Interval: globalInterval,
LB: lb,
Timeout: 3 * time.Second,
},
},
{
@ -476,6 +482,49 @@ func TestServerBuildHealthCheckOptions(t *testing.T) {
Path: "/path",
Interval: 5 * time.Minute,
LB: lb,
Timeout: 3 * time.Second,
},
},
{
desc: "unparseable timeout",
hc: &types.HealthCheck{
Path: "/path",
Interval: "15s",
Timeout: "unparseable",
},
expectedOpts: &healthcheck.Options{
Path: "/path",
Interval: globalInterval,
Timeout: globalTimeout,
LB: lb,
},
},
{
desc: "sub-zero timeout",
hc: &types.HealthCheck{
Path: "/path",
Interval: "15s",
Timeout: "-42s",
},
expectedOpts: &healthcheck.Options{
Path: "/path",
Interval: globalInterval,
Timeout: globalTimeout,
LB: lb,
},
},
{
desc: "parseable timeout",
hc: &types.HealthCheck{
Path: "/path",
Interval: "15s",
Timeout: "10s",
},
expectedOpts: &healthcheck.Options{
Path: "/path",
Interval: globalInterval,
Timeout: 10 * time.Second,
LB: lb,
},
},
}
@ -485,7 +534,10 @@ func TestServerBuildHealthCheckOptions(t *testing.T) {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
opts := buildHealthCheckOptions(lb, "backend", test.hc, &configuration.HealthCheckConfig{Interval: parse.Duration(globalInterval)})
opts := buildHealthCheckOptions(lb, "backend", test.hc, &configuration.HealthCheckConfig{
Interval: parse.Duration(globalInterval),
Timeout: parse.Duration(globalTimeout),
})
assert.Equal(t, test.expectedOpts, opts, "health check options")
})
}

View file

@ -409,11 +409,28 @@ func buildHealthCheckOptions(lb healthcheck.BalancerHandler, backend string, hc
}
}
timeout := time.Duration(hcConfig.Timeout)
if hc.Timeout != "" {
timeoutOverride, err := time.ParseDuration(hc.Timeout)
if err != nil {
log.Errorf("Illegal health check timeout for backend '%s': %s", backend, err)
} else if timeoutOverride <= 0 {
log.Errorf("Health check timeout smaller than zero for backend '%s', backend", backend)
} else {
timeout = timeoutOverride
}
}
if timeout >= interval {
log.Warnf("Health check timeout for backend '%s' should be lower than the health check interval. Interval set to timeout + 1 second (%s).", backend)
}
return &healthcheck.Options{
Scheme: hc.Scheme,
Path: hc.Path,
Port: hc.Port,
Interval: interval,
Timeout: timeout,
LB: lb,
Hostname: hc.Hostname,
Headers: hc.Headers,

View file

@ -32,6 +32,7 @@
path = "{{ $healthCheck.Path }}"
port = {{ $healthCheck.Port }}
interval = "{{ $healthCheck.Interval }}"
timeout = "{{ $healthCheck.Timeout }}"
hostname = "{{ $healthCheck.Hostname }}"
{{if $healthCheck.Headers }}
[backends."backend-{{ $backendName }}".healthCheck.headers]

View file

@ -33,6 +33,7 @@
path = "{{ $healthCheck.Path }}"
port = {{ $healthCheck.Port }}
interval = "{{ $healthCheck.Interval }}"
timeout = "{{ $healthCheck.Timeout }}"
hostname = "{{ $healthCheck.Hostname }}"
{{if $healthCheck.Headers }}
[backends."backend-{{ $backendName }}".healthCheck.headers]

View file

@ -32,6 +32,7 @@
path = "{{ $healthCheck.Path }}"
port = {{ $healthCheck.Port }}
interval = "{{ $healthCheck.Interval }}"
timeout = "{{ $healthCheck.Timeout }}"
hostname = "{{ $healthCheck.Hostname }}"
{{if $healthCheck.Headers }}
[backends."backend-{{ $serviceName }}".healthCheck.headers]

View file

@ -32,6 +32,7 @@
path = "{{ $healthCheck.Path }}"
port = {{ $healthCheck.Port }}
interval = "{{ $healthCheck.Interval }}"
timeout = "{{ $healthCheck.Timeout }}"
hostname = "{{ $healthCheck.Hostname }}"
{{if $healthCheck.Headers }}
[backends."{{ $backendName }}".healthCheck.headers]

View file

@ -35,6 +35,7 @@
path = "{{ $healthCheck.Path }}"
port = {{ $healthCheck.Port }}
interval = "{{ $healthCheck.Interval }}"
timeout = "{{ $healthCheck.Timeout }}"
hostname = "{{ $healthCheck.Hostname }}"
{{if $healthCheck.Headers }}
[backends.{{ $backendName }}.healthCheck.headers]

View file

@ -35,6 +35,7 @@
path = "{{ $healthCheck.Path }}"
port = {{ $healthCheck.Port }}
interval = "{{ $healthCheck.Interval }}"
timeout = "{{ $healthCheck.Timeout }}"
hostname = "{{ $healthCheck.Hostname }}"
{{if $healthCheck.Headers }}
[backends."backend-{{ $backendName }}".healthCheck.headers]

View file

@ -34,6 +34,7 @@
path = "{{ $healthCheck.Path }}"
port = {{ $healthCheck.Port }}
interval = "{{ $healthCheck.Interval }}"
timeout = "{{ $healthCheck.Timeout }}"
hostname = "{{ $healthCheck.Hostname }}"
{{if $healthCheck.Headers }}
[backends."backend-{{ $backendName }}".healthCheck.headers]

View file

@ -74,6 +74,7 @@ type HealthCheck struct {
Path string `json:"path,omitempty"`
Port int `json:"port,omitempty"`
Interval string `json:"interval,omitempty"`
Timeout string `json:"timeout,omitempty"`
Hostname string `json:"hostname,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
}

View file

@ -632,6 +632,12 @@
<span class="tag is-info">{{ p.healthCheck.interval }}</span>
</div>
</div>
<div class="control" *ngIf="p.healthCheck.timeout">
<div class="tags has-addons">
<span class="tag is-light">Timeout</span>
<span class="tag is-info">{{ p.healthCheck.timeout }}</span>
</div>
</div>
<div class="control" *ngIf="p.healthCheck.port">
<div class="tags has-addons">
<span class="tag is-light">Port</span>