Add a status option to the service health check

This commit is contained in:
Ali Afsharzadeh 2022-11-24 14:10:05 +03:30 committed by GitHub
parent 61325d7b91
commit 46c266661c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 97 additions and 2 deletions

View file

@ -153,6 +153,7 @@
- "traefik.http.services.service01.loadbalancer.healthcheck.interval=foobar" - "traefik.http.services.service01.loadbalancer.healthcheck.interval=foobar"
- "traefik.http.services.service01.loadbalancer.healthcheck.path=foobar" - "traefik.http.services.service01.loadbalancer.healthcheck.path=foobar"
- "traefik.http.services.service01.loadbalancer.healthcheck.method=foobar" - "traefik.http.services.service01.loadbalancer.healthcheck.method=foobar"
- "traefik.http.services.service01.loadbalancer.healthcheck.status=42"
- "traefik.http.services.service01.loadbalancer.healthcheck.port=42" - "traefik.http.services.service01.loadbalancer.healthcheck.port=42"
- "traefik.http.services.service01.loadbalancer.healthcheck.scheme=foobar" - "traefik.http.services.service01.loadbalancer.healthcheck.scheme=foobar"
- "traefik.http.services.service01.loadbalancer.healthcheck.mode=foobar" - "traefik.http.services.service01.loadbalancer.healthcheck.mode=foobar"

View file

@ -56,6 +56,7 @@
mode = "foobar" mode = "foobar"
path = "foobar" path = "foobar"
method = "foobar" method = "foobar"
status = 42
port = 42 port = 42
interval = "42s" interval = "42s"
timeout = "42s" timeout = "42s"

View file

@ -61,6 +61,7 @@ http:
mode: foobar mode: foobar
path: foobar path: foobar
method: foobar method: foobar
status: 42
port: 42 port: 42
interval: 42s interval: 42s
timeout: 42s timeout: 42s

View file

@ -220,6 +220,7 @@
| `traefik/http/services/Service01/loadBalancer/healthCheck/path` | `foobar` | | `traefik/http/services/Service01/loadBalancer/healthCheck/path` | `foobar` |
| `traefik/http/services/Service01/loadBalancer/healthCheck/port` | `42` | | `traefik/http/services/Service01/loadBalancer/healthCheck/port` | `42` |
| `traefik/http/services/Service01/loadBalancer/healthCheck/scheme` | `foobar` | | `traefik/http/services/Service01/loadBalancer/healthCheck/scheme` | `foobar` |
| `traefik/http/services/Service01/loadBalancer/healthCheck/status` | `42` |
| `traefik/http/services/Service01/loadBalancer/healthCheck/timeout` | `42s` | | `traefik/http/services/Service01/loadBalancer/healthCheck/timeout` | `42s` |
| `traefik/http/services/Service01/loadBalancer/passHostHeader` | `true` | | `traefik/http/services/Service01/loadBalancer/passHostHeader` | `true` |
| `traefik/http/services/Service01/loadBalancer/responseForwarding/flushInterval` | `42s` | | `traefik/http/services/Service01/loadBalancer/responseForwarding/flushInterval` | `42s` |

View file

@ -153,6 +153,7 @@
"traefik.http.services.service01.loadbalancer.healthcheck.interval": "42s", "traefik.http.services.service01.loadbalancer.healthcheck.interval": "42s",
"traefik.http.services.service01.loadbalancer.healthcheck.path": "foobar", "traefik.http.services.service01.loadbalancer.healthcheck.path": "foobar",
"traefik.http.services.service01.loadbalancer.healthcheck.method": "foobar", "traefik.http.services.service01.loadbalancer.healthcheck.method": "foobar",
"traefik.http.services.service01.loadbalancer.healthcheck.status": "42",
"traefik.http.services.service01.loadbalancer.healthcheck.port": "42", "traefik.http.services.service01.loadbalancer.healthcheck.port": "42",
"traefik.http.services.service01.loadbalancer.healthcheck.scheme": "foobar", "traefik.http.services.service01.loadbalancer.healthcheck.scheme": "foobar",
"traefik.http.services.service01.loadbalancer.healthcheck.mode": "foobar", "traefik.http.services.service01.loadbalancer.healthcheck.mode": "foobar",

View file

@ -193,6 +193,14 @@ you'd add the tag `traefik.http.services.{name-of-your-choice}.loadbalancer.pass
traefik.http.services.myservice.loadbalancer.healthcheck.method=foobar traefik.http.services.myservice.loadbalancer.healthcheck.method=foobar
``` ```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.status`"
See [health check](../services/index.md#health-check) for more information.
```yaml
traefik.http.services.myservice.loadbalancer.healthcheck.status=42
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`" ??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`"
See [health check](../services/index.md#health-check) for more information. See [health check](../services/index.md#health-check) for more information.

View file

@ -347,6 +347,14 @@ you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.pa
- "traefik.http.services.myservice.loadbalancer.healthcheck.method=foobar" - "traefik.http.services.myservice.loadbalancer.healthcheck.method=foobar"
``` ```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.status`"
See [health check](../services/index.md#health-check) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.healthcheck.status=42"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`" ??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`"
See [health check](../services/index.md#health-check) for more information. See [health check](../services/index.md#health-check) for more information.

View file

@ -195,6 +195,14 @@ you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.pa
traefik.http.services.myservice.loadbalancer.healthcheck.method=foobar traefik.http.services.myservice.loadbalancer.healthcheck.method=foobar
``` ```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.status`"
See [health check](../services/index.md#health-check) for more information.
```yaml
traefik.http.services.myservice.loadbalancer.healthcheck.status=42
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`" ??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`"
See [health check](../services/index.md#health-check) for more information. See [health check](../services/index.md#health-check) for more information.

View file

@ -172,6 +172,14 @@ A Story of key & values
|-------------------------------------------------------------------|----------| |-------------------------------------------------------------------|----------|
| `traefik/http/services/myservice/loadbalancer/healthcheck/method` | `foobar` | | `traefik/http/services/myservice/loadbalancer/healthcheck/method` | `foobar` |
??? info "`traefik/http/services/<service_name>/loadbalancer/healthcheck/status`"
See [health check](../services/index.md#health-check) for more information.
| Key (Path) | Value |
|-------------------------------------------------------------------|-------|
| `traefik/http/services/myservice/loadbalancer/healthcheck/status` | `42` |
??? info "`traefik/http/services/<service_name>/loadbalancer/healthcheck/port`" ??? info "`traefik/http/services/<service_name>/loadbalancer/healthcheck/port`"
See [health check](../services/index.md#health-check) for more information. See [health check](../services/index.md#health-check) for more information.

View file

@ -222,6 +222,14 @@ For example, to change the passHostHeader behavior, you'd add the label `"traefi
"traefik.http.services.myservice.loadbalancer.healthcheck.method": "foobar" "traefik.http.services.myservice.loadbalancer.healthcheck.method": "foobar"
``` ```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.status`"
See [health check](../services/index.md#health-check) for more information.
```json
"traefik.http.services.myservice.loadbalancer.healthcheck.status": "42"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`" ??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`"
See [health check](../services/index.md#health-check) for more information. See [health check](../services/index.md#health-check) for more information.

View file

@ -185,6 +185,14 @@ you'd add the tag `traefik.http.services.{name-of-your-choice}.loadbalancer.pass
traefik.http.services.myservice.loadbalancer.healthcheck.path=/foo traefik.http.services.myservice.loadbalancer.healthcheck.path=/foo
``` ```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.status`"
See [health check](../services/index.md#health-check) for more information.
```yaml
traefik.http.services.myservice.loadbalancer.healthcheck.status=42
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`" ??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`"
See [health check](../services/index.md#health-check) for more information. See [health check](../services/index.md#health-check) for more information.

View file

@ -228,6 +228,14 @@ you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.pa
- "traefik.http.services.myservice.loadbalancer.healthcheck.method=foobar" - "traefik.http.services.myservice.loadbalancer.healthcheck.method=foobar"
``` ```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.status`"
See [health check](../services/index.md#health-check) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.healthcheck.status=42"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`" ??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`"
See [health check](../services/index.md#health-check) for more information. See [health check](../services/index.md#health-check) for more information.

View file

@ -316,7 +316,7 @@ On subsequent requests, to keep the session alive with the same server, the clie
#### Health Check #### Health Check
Configure health check to remove unhealthy servers from the load balancing rotation. Configure health check to remove unhealthy servers from the load balancing rotation.
Traefik will consider your HTTP(s) servers healthy as long as they return status codes between `2XX` and `3XX` to the health check requests (carried out every `interval`). Traefik will consider HTTP(s) servers healthy as long as they return a status code to the health check request (carried out every `interval`) between `2XX` and `3XX`, or matching the configured status.
For gRPC servers, Traefik will consider them healthy as long as they return `SERVING` to [gRPC health check v1](https://github.com/grpc/grpc/blob/master/doc/health-checking.md) requests. For gRPC servers, Traefik will consider them healthy as long as they return `SERVING` to [gRPC health check v1](https://github.com/grpc/grpc/blob/master/doc/health-checking.md) requests.
To propagate status changes (e.g. all servers of this service are down) upwards, HealthCheck must also be enabled on the parent(s) of this service. To propagate status changes (e.g. all servers of this service are down) upwards, HealthCheck must also be enabled on the parent(s) of this service.
@ -333,6 +333,7 @@ Below are the available options for the health check mechanism:
- `headers` (optional), defines custom headers to be sent to the health check endpoint. - `headers` (optional), defines custom headers to be sent to the health check endpoint.
- `followRedirects` (default: true), defines whether redirects should be followed during the health check calls. - `followRedirects` (default: true), defines whether redirects should be followed during the health check calls.
- `method` (default: GET), defines the HTTP method that will be used while connecting to the endpoint. - `method` (default: GET), defines the HTTP method that will be used while connecting to the endpoint.
- `status` (optional), defines the expected HTTP status code of the response to the health check request.
!!! info "Interval & Timeout Format" !!! info "Interval & Timeout Format"

View file

@ -237,6 +237,7 @@ type ServerHealthCheck struct {
Mode string `json:"mode,omitempty" toml:"mode,omitempty" yaml:"mode,omitempty" export:"true"` Mode string `json:"mode,omitempty" toml:"mode,omitempty" yaml:"mode,omitempty" export:"true"`
Path string `json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty" export:"true"` Path string `json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty" export:"true"`
Method string `json:"method,omitempty" toml:"method,omitempty" yaml:"method,omitempty" export:"true"` Method string `json:"method,omitempty" toml:"method,omitempty" yaml:"method,omitempty" export:"true"`
Status int `json:"status,omitempty" toml:"status,omitempty" yaml:"status,omitempty" export:"true"`
Port int `json:"port,omitempty" toml:"port,omitempty,omitzero" yaml:"port,omitempty" export:"true"` Port int `json:"port,omitempty" toml:"port,omitempty,omitzero" yaml:"port,omitempty" export:"true"`
Interval ptypes.Duration `json:"interval,omitempty" toml:"interval,omitempty" yaml:"interval,omitempty" export:"true"` Interval ptypes.Duration `json:"interval,omitempty" toml:"interval,omitempty" yaml:"interval,omitempty" export:"true"`
Timeout ptypes.Duration `json:"timeout,omitempty" toml:"timeout,omitempty" yaml:"timeout,omitempty" export:"true"` Timeout ptypes.Duration `json:"timeout,omitempty" toml:"timeout,omitempty" yaml:"timeout,omitempty" export:"true"`

View file

@ -151,6 +151,7 @@ func TestDecodeConfiguration(t *testing.T) {
"traefik.http.services.Service0.loadbalancer.healthcheck.interval": "1s", "traefik.http.services.Service0.loadbalancer.healthcheck.interval": "1s",
"traefik.http.services.Service0.loadbalancer.healthcheck.path": "foobar", "traefik.http.services.Service0.loadbalancer.healthcheck.path": "foobar",
"traefik.http.services.Service0.loadbalancer.healthcheck.method": "foobar", "traefik.http.services.Service0.loadbalancer.healthcheck.method": "foobar",
"traefik.http.services.Service0.loadbalancer.healthcheck.status": "401",
"traefik.http.services.Service0.loadbalancer.healthcheck.port": "42", "traefik.http.services.Service0.loadbalancer.healthcheck.port": "42",
"traefik.http.services.Service0.loadbalancer.healthcheck.scheme": "foobar", "traefik.http.services.Service0.loadbalancer.healthcheck.scheme": "foobar",
"traefik.http.services.Service0.loadbalancer.healthcheck.mode": "foobar", "traefik.http.services.Service0.loadbalancer.healthcheck.mode": "foobar",
@ -168,6 +169,7 @@ func TestDecodeConfiguration(t *testing.T) {
"traefik.http.services.Service1.loadbalancer.healthcheck.interval": "1s", "traefik.http.services.Service1.loadbalancer.healthcheck.interval": "1s",
"traefik.http.services.Service1.loadbalancer.healthcheck.path": "foobar", "traefik.http.services.Service1.loadbalancer.healthcheck.path": "foobar",
"traefik.http.services.Service1.loadbalancer.healthcheck.method": "foobar", "traefik.http.services.Service1.loadbalancer.healthcheck.method": "foobar",
"traefik.http.services.Service1.loadbalancer.healthcheck.status": "401",
"traefik.http.services.Service1.loadbalancer.healthcheck.port": "42", "traefik.http.services.Service1.loadbalancer.healthcheck.port": "42",
"traefik.http.services.Service1.loadbalancer.healthcheck.scheme": "foobar", "traefik.http.services.Service1.loadbalancer.healthcheck.scheme": "foobar",
"traefik.http.services.Service1.loadbalancer.healthcheck.mode": "foobar", "traefik.http.services.Service1.loadbalancer.healthcheck.mode": "foobar",
@ -655,6 +657,7 @@ func TestDecodeConfiguration(t *testing.T) {
Mode: "foobar", Mode: "foobar",
Path: "foobar", Path: "foobar",
Method: "foobar", Method: "foobar",
Status: 401,
Port: 42, Port: 42,
Interval: ptypes.Duration(time.Second), Interval: ptypes.Duration(time.Second),
Timeout: ptypes.Duration(time.Second), Timeout: ptypes.Duration(time.Second),
@ -684,6 +687,7 @@ func TestDecodeConfiguration(t *testing.T) {
Mode: "foobar", Mode: "foobar",
Path: "foobar", Path: "foobar",
Method: "foobar", Method: "foobar",
Status: 401,
Port: 42, Port: 42,
Interval: ptypes.Duration(time.Second), Interval: ptypes.Duration(time.Second),
Timeout: ptypes.Duration(time.Second), Timeout: ptypes.Duration(time.Second),
@ -1147,6 +1151,7 @@ func TestEncodeConfiguration(t *testing.T) {
Scheme: "foobar", Scheme: "foobar",
Path: "foobar", Path: "foobar",
Method: "foobar", Method: "foobar",
Status: 401,
Port: 42, Port: 42,
Interval: ptypes.Duration(time.Second), Interval: ptypes.Duration(time.Second),
Timeout: ptypes.Duration(time.Second), Timeout: ptypes.Duration(time.Second),
@ -1174,6 +1179,7 @@ func TestEncodeConfiguration(t *testing.T) {
Scheme: "foobar", Scheme: "foobar",
Path: "foobar", Path: "foobar",
Method: "foobar", Method: "foobar",
Status: 401,
Port: 42, Port: 42,
Interval: ptypes.Duration(time.Second), Interval: ptypes.Duration(time.Second),
Timeout: ptypes.Duration(time.Second), Timeout: ptypes.Duration(time.Second),
@ -1335,6 +1341,7 @@ func TestEncodeConfiguration(t *testing.T) {
"traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Interval": "1000000000", "traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Interval": "1000000000",
"traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Path": "foobar", "traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Path": "foobar",
"traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Method": "foobar", "traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Method": "foobar",
"traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Status": "401",
"traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Port": "42", "traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Port": "42",
"traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Scheme": "foobar", "traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Scheme": "foobar",
"traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Timeout": "1000000000", "traefik.HTTP.Services.Service0.LoadBalancer.HealthCheck.Timeout": "1000000000",
@ -1351,6 +1358,7 @@ func TestEncodeConfiguration(t *testing.T) {
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Interval": "1000000000", "traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Interval": "1000000000",
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Path": "foobar", "traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Path": "foobar",
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Method": "foobar", "traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Method": "foobar",
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Status": "401",
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Port": "42", "traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Port": "42",
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Scheme": "foobar", "traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Scheme": "foobar",
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Timeout": "1000000000", "traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Timeout": "1000000000",

View file

@ -173,10 +173,14 @@ func (shc *ServiceHealthChecker) checkHealthHTTP(ctx context.Context, target *ur
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusBadRequest { if shc.config.Status == 0 && (resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusBadRequest) {
return fmt.Errorf("received error status code: %v", resp.StatusCode) return fmt.Errorf("received error status code: %v", resp.StatusCode)
} }
if shc.config.Status != 0 && shc.config.Status != resp.StatusCode {
return fmt.Errorf("received error status code: %v expected status code: %v", resp.StatusCode, shc.config.Status)
}
return nil return nil
} }

View file

@ -249,6 +249,7 @@ func TestServiceHealthChecker_Launch(t *testing.T) {
testCases := []struct { testCases := []struct {
desc string desc string
mode string mode string
status int
server StartTestServer server StartTestServer
expNumRemovedServers int expNumRemovedServers int
expNumUpsertedServers int expNumUpsertedServers int
@ -263,6 +264,15 @@ func TestServiceHealthChecker_Launch(t *testing.T) {
expGaugeValue: 1, expGaugeValue: 1,
targetStatus: runtime.StatusUp, targetStatus: runtime.StatusUp,
}, },
{
desc: "healthy server staying healthy, with custom code status check",
server: newHTTPServer(http.StatusNotFound),
status: http.StatusNotFound,
expNumRemovedServers: 0,
expNumUpsertedServers: 1,
expGaugeValue: 1,
targetStatus: runtime.StatusUp,
},
{ {
desc: "healthy server staying healthy (StatusNoContent)", desc: "healthy server staying healthy (StatusNoContent)",
server: newHTTPServer(http.StatusNoContent), server: newHTTPServer(http.StatusNoContent),
@ -287,6 +297,15 @@ func TestServiceHealthChecker_Launch(t *testing.T) {
expGaugeValue: 0, expGaugeValue: 0,
targetStatus: runtime.StatusDown, targetStatus: runtime.StatusDown,
}, },
{
desc: "healthy server becoming sick, with custom code status check",
server: newHTTPServer(http.StatusOK),
status: http.StatusServiceUnavailable,
expNumRemovedServers: 1,
expNumUpsertedServers: 0,
expGaugeValue: 0,
targetStatus: runtime.StatusDown,
},
{ {
desc: "healthy server toggling to sick and back to healthy", desc: "healthy server toggling to sick and back to healthy",
server: newHTTPServer(http.StatusServiceUnavailable, http.StatusOK), server: newHTTPServer(http.StatusServiceUnavailable, http.StatusOK),
@ -348,6 +367,7 @@ func TestServiceHealthChecker_Launch(t *testing.T) {
config := &dynamic.ServerHealthCheck{ config := &dynamic.ServerHealthCheck{
Mode: test.mode, Mode: test.mode,
Status: test.status,
Path: "/path", Path: "/path",
Interval: ptypes.Duration(500 * time.Millisecond), Interval: ptypes.Duration(500 * time.Millisecond),
Timeout: ptypes.Duration(499 * time.Millisecond), Timeout: ptypes.Duration(499 * time.Millisecond),