Configure passive health checks for upstream servers
Available as of MKE 3.8.16
Interlock configures the NGINX proxy to perform passive health checks on the upstream servers, which are the tasks that back your Swarm services. By default, when an upstream server fails to respond, NGINX temporarily marks it as unavailable and stops routing traffic to it.
This section describes how to tune the passive health checks for a service by
using the com.docker.lb.max_fails and com.docker.lb.fail_timeout
service labels. Interlock applies the label values to every upstream server of
the service, mapping them directly to the max_fails and fail_timeout
parameters of the NGINX server
directive. For the label descriptions and default values, refer to
Use service labels.
Because Interlock manages these settings, MKE persists them and reapplies them automatically across reconciliation, upgrade, rollback, and restore operations.
Warning
Do not edit nginx.conf manually in the ucp-interlock-proxy
containers. MKE overwrites manual changes when it reconciles the
configuration.
Health check tuning guidelines
NGINX tracks failed requests to each upstream server.
When a server accumulates max_fails failures within the fail_timeout
window, NGINX marks that server unavailable for the duration of
fail_timeout.
For a service that runs multiple replicas and occasionally returns transient
errors or times out under load, the default threshold can cause NGINX to
temporarily disable individual replicas. If enough replicas are marked
unavailable at once, requests fail with 502 Bad Gateway and NGINX logs
no live upstreams, even though the service itself is healthy.
Adjust the max_fails and fail_timeout labels when the proxy
intermittently removes a healthy, busy service from rotation:
Increase
max_failsto require more failures before NGINX marks a replica unavailable.Decrease
fail_timeoutto shorten both the window in which NGINX counts failures and the period for which NGINX excludes a replica.
Note
You cannot disable passive health checks by setting max_fails to 0.
Interlock treats com.docker.lb.max_fails=0 the same as an unset label,
and NGINX applies its default value of 1.
Set the health check labels
Set the max_fails and fail_timeout labels on the service, either at
creation time or in a Compose file.
Caution
Set com.docker.lb.max_fails to a non-negative integer and
com.docker.lb.fail_timeout to a valid NGINX time value. Interlock skips
a service with an invalid value and does not add it to the proxy
configuration.
To configure the labels with docker service create:
docker service create \
--name <service-name> \
--network <network-name> \
--label com.docker.lb.hosts=<hostname> \
--label com.docker.lb.port=<port> \
--label com.docker.lb.max_fails=<max-fails> \
--label com.docker.lb.fail_timeout=<fail-timeout> \
<image>
For example, to create a demo service that tolerates up to 1000
failures within a 2s window:
docker service create \
--name demo \
--network demo \
--label com.docker.lb.hosts=app.example.org \
--label com.docker.lb.port=8080 \
--label com.docker.lb.max_fails=1000 \
--label com.docker.lb.fail_timeout=2s \
mirantiseng/docker-demo
To configure the labels in a Compose file:
In the Compose file, add the labels under the service
deploy.labelskey:version: "3.2" services: <service-name>: image: <image> deploy: replicas: <replicas> labels: com.docker.lb.hosts: <hostname> com.docker.lb.network: <stack-name>_<network-name> com.docker.lb.port: <port> com.docker.lb.max_fails: <max-fails> com.docker.lb.fail_timeout: <fail-timeout> networks: - <network-name> networks: <network-name>: driver: overlay
For example, for a
demostack with three replicas that tolerate up to1000failures within a2swindow:version: "3.2" services: demo: image: mirantiseng/docker-demo deploy: replicas: 3 labels: com.docker.lb.hosts: app.example.org com.docker.lb.network: demo_demo-network com.docker.lb.port: 8080 com.docker.lb.max_fails: 1000 com.docker.lb.fail_timeout: 2s networks: - demo-network networks: demo-network: driver: overlay
Note
When you deploy a stack, Docker prefixes the network name with the stack name. As such, the
com.docker.lb.networklabel must reference<stack-name>_<network-name>.Deploy the stack:
docker stack deploy -c <compose-file> <stack-name>
For example:
docker stack deploy -c demo.yml demo
Interlock detects the label change and reconfigures the proxy.
Verify the configuration
Confirm that Interlock applied the values by printing the rendered NGINX configuration from a proxy container:
On a node that runs the
ucp-interlock-proxyservice, obtain the name of a proxy container:docker ps --filter name=ucp-interlock-proxy --format '{{.Names}}'
Print the rendered NGINX configuration:
docker exec <ucp-interlock-proxy-container> nginx -T
The
upstreamblock for your service listsmax_failsandfail_timeouton eachserverline:upstream up-<hostname> { zone up-<hostname>_backend 64k; server <task-ip-1>:<port> max_fails=<max-fails> fail_timeout=<fail-timeout>; server <task-ip-2>:<port> max_fails=<max-fails> fail_timeout=<fail-timeout>; server <task-ip-3>:<port> max_fails=<max-fails> fail_timeout=<fail-timeout>; }
For example, for the three-replica
demoservice from the Compose file example:upstream up-app.example.org { zone up-app.example.org_backend 64k; server 10.0.2.3:8080 max_fails=1000 fail_timeout=2s; server 10.0.2.4:8080 max_fails=1000 fail_timeout=2s; server 10.0.2.5:8080 max_fails=1000 fail_timeout=2s; }
If you omit a label, the corresponding parameter does not appear on the
serverlines, and NGINX applies its default value.
To change the values, update the labels on the service:
For a service that you created with
docker service create, run:docker service update \ --label-add com.docker.lb.max_fails=<max-fails> \ --label-add com.docker.lb.fail_timeout=<fail-timeout> \ <service-name>
For a stack, update the labels in the Compose file and run
docker stack deploy -c <compose-file> <stack-name>again.
Interlock re-renders the configuration with the new values.