feat: configure Traefik readiness healthchecks based on app.json config
Closes #6834
This commit is contained in:
@@ -32,6 +32,42 @@ The Traefik plugin has specific rules for routing requests:
|
|||||||
- If no `https:443` mapping is found, the first `https` port mapping is used for https requests.
|
- If no `https:443` mapping is found, the first `https` port mapping is used for https requests.
|
||||||
- If no `https` mapping is found, the container port from `http:80` will be used for https requests.
|
- If no `https` mapping is found, the container port from `http:80` will be used for https requests.
|
||||||
- Requests are routed as soon as the container is running and passing healthchecks.
|
- Requests are routed as soon as the container is running and passing healthchecks.
|
||||||
|
- Readiness healthchecks defined in `app.json` with a `path` property are automatically transformed into Traefik healthcheck labels.
|
||||||
|
|
||||||
|
### Healthchecks
|
||||||
|
|
||||||
|
When an app has a readiness healthcheck defined in its `app.json` file with a `path` property, Dokku automatically generates Traefik healthcheck labels. These labels configure Traefik to perform health checks on the container before routing traffic to it.
|
||||||
|
|
||||||
|
The following `app.json` healthcheck properties are mapped to Traefik labels:
|
||||||
|
|
||||||
|
| app.json Property | Traefik Label Property | Description |
|
||||||
|
|-------------------|------------------------|-------------|
|
||||||
|
| `path` | `healthcheck.path` | The HTTP path to check (required) |
|
||||||
|
| `scheme` | `healthcheck.scheme` | The scheme to use (`http` or `https`) |
|
||||||
|
| `port` | `healthcheck.port` | The port to check |
|
||||||
|
| `timeout` | `healthcheck.timeout` | Timeout in seconds (formatted as `Xs`) |
|
||||||
|
| `wait` | `healthcheck.interval` | Interval between checks in seconds (formatted as `Xs`) |
|
||||||
|
|
||||||
|
Example `app.json` configuration:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"healthchecks": {
|
||||||
|
"web": [
|
||||||
|
{
|
||||||
|
"name": "web readiness check",
|
||||||
|
"path": "/health",
|
||||||
|
"timeout": 5,
|
||||||
|
"type": "readiness",
|
||||||
|
"wait": 10
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Only the first readiness healthcheck with a `path` property is used. Liveness, startup, and command-based healthchecks are not transformed into Traefik labels.
|
||||||
|
|
||||||
### Switching to Traefik
|
### Switching to Traefik
|
||||||
|
|
||||||
|
|||||||
@@ -129,6 +129,33 @@ trigger-traefik-vhosts-docker-args-process-deploy() {
|
|||||||
output="$output --label \"traefik.http.routers.$APP-$PROC_TYPE-https.rule=$traefik_domains\""
|
output="$output --label \"traefik.http.routers.$APP-$PROC_TYPE-https.rule=$traefik_domains\""
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
local app_json hc_path hc_scheme hc_port hc_timeout hc_interval hc_filter
|
||||||
|
app_json="$(plugn trigger app-json-get-content "$APP" 2>/dev/null || echo "{}")"
|
||||||
|
hc_filter='.healthchecks.web // [] | map(select(.type == "readiness" and .path != null and .path != "")) | .[0]'
|
||||||
|
hc_path=$(echo "$app_json" | jq -r "$hc_filter | .path // empty")
|
||||||
|
if [[ -n "$hc_path" ]]; then
|
||||||
|
hc_scheme=$(echo "$app_json" | jq -r "$hc_filter | .scheme // empty")
|
||||||
|
hc_port=$(echo "$app_json" | jq -r "$hc_filter | .port // empty")
|
||||||
|
hc_timeout=$(echo "$app_json" | jq -r "$hc_filter | .timeout // empty")
|
||||||
|
hc_interval=$(echo "$app_json" | jq -r "$hc_filter | .wait // empty")
|
||||||
|
|
||||||
|
if [[ -n "$proxy_container_http_port" ]]; then
|
||||||
|
output="$output --label traefik.http.services.$APP-$PROC_TYPE-http.loadbalancer.healthcheck.path=$hc_path"
|
||||||
|
[[ -n "$hc_scheme" ]] && output="$output --label traefik.http.services.$APP-$PROC_TYPE-http.loadbalancer.healthcheck.scheme=$hc_scheme"
|
||||||
|
[[ -n "$hc_port" ]] && output="$output --label traefik.http.services.$APP-$PROC_TYPE-http.loadbalancer.healthcheck.port=$hc_port"
|
||||||
|
[[ -n "$hc_timeout" ]] && output="$output --label traefik.http.services.$APP-$PROC_TYPE-http.loadbalancer.healthcheck.timeout=${hc_timeout}s"
|
||||||
|
[[ -n "$hc_interval" ]] && output="$output --label traefik.http.services.$APP-$PROC_TYPE-http.loadbalancer.healthcheck.interval=${hc_interval}s"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$proxy_container_https_port" ]]; then
|
||||||
|
output="$output --label traefik.http.services.$APP-$PROC_TYPE-https.loadbalancer.healthcheck.path=$hc_path"
|
||||||
|
[[ -n "$hc_scheme" ]] && output="$output --label traefik.http.services.$APP-$PROC_TYPE-https.loadbalancer.healthcheck.scheme=$hc_scheme"
|
||||||
|
[[ -n "$hc_port" ]] && output="$output --label traefik.http.services.$APP-$PROC_TYPE-https.loadbalancer.healthcheck.port=$hc_port"
|
||||||
|
[[ -n "$hc_timeout" ]] && output="$output --label traefik.http.services.$APP-$PROC_TYPE-https.loadbalancer.healthcheck.timeout=${hc_timeout}s"
|
||||||
|
[[ -n "$hc_interval" ]] && output="$output --label traefik.http.services.$APP-$PROC_TYPE-https.loadbalancer.healthcheck.interval=${hc_interval}s"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local proxy_labels_file_path=$(fn-proxy-get-labels-file-path "traefik" "$APP")
|
local proxy_labels_file_path=$(fn-proxy-get-labels-file-path "traefik" "$APP")
|
||||||
|
|||||||
13
tests/apps/python/app-traefik.json
Normal file
13
tests/apps/python/app-traefik.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"healthchecks": {
|
||||||
|
"web": [
|
||||||
|
{
|
||||||
|
"name": "web readiness check",
|
||||||
|
"path": "/",
|
||||||
|
"timeout": 5,
|
||||||
|
"type": "readiness",
|
||||||
|
"wait": 2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -734,3 +734,61 @@ teardown() {
|
|||||||
run /bin/bash -c "dokku traefik:set --global dns-provider-cf_api_email"
|
run /bin/bash -c "dokku traefik:set --global dns-provider-cf_api_email"
|
||||||
run /bin/bash -c "dokku traefik:set --global dns-provider-cf_api_key"
|
run /bin/bash -c "dokku traefik:set --global dns-provider-cf_api_key"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@test "(traefik) healthcheck labels from app.json" {
|
||||||
|
run /bin/bash -c "dokku proxy:set $TEST_APP traefik"
|
||||||
|
echo "output: $output"
|
||||||
|
echo "status: $status"
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP setup_traefik_healthcheck
|
||||||
|
echo "output: $output"
|
||||||
|
echo "status: $status"
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"traefik.http.services.$TEST_APP-web-http.loadbalancer.healthcheck.path\" }}'"
|
||||||
|
echo "output: $output"
|
||||||
|
echo "status: $status"
|
||||||
|
assert_success
|
||||||
|
assert_output "/"
|
||||||
|
|
||||||
|
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"traefik.http.services.$TEST_APP-web-http.loadbalancer.healthcheck.timeout\" }}'"
|
||||||
|
echo "output: $output"
|
||||||
|
echo "status: $status"
|
||||||
|
assert_success
|
||||||
|
assert_output "5s"
|
||||||
|
|
||||||
|
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"traefik.http.services.$TEST_APP-web-http.loadbalancer.healthcheck.interval\" }}'"
|
||||||
|
echo "output: $output"
|
||||||
|
echo "status: $status"
|
||||||
|
assert_success
|
||||||
|
assert_output "2s"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "(traefik) no healthcheck labels without readiness check" {
|
||||||
|
run /bin/bash -c "dokku proxy:set $TEST_APP traefik"
|
||||||
|
echo "output: $output"
|
||||||
|
echo "status: $status"
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP
|
||||||
|
echo "output: $output"
|
||||||
|
echo "status: $status"
|
||||||
|
assert_success
|
||||||
|
|
||||||
|
run /bin/bash -c "docker inspect $TEST_APP.web.1 --format '{{ index .Config.Labels \"traefik.http.services.$TEST_APP-web-http.loadbalancer.healthcheck.path\" }}'"
|
||||||
|
echo "output: $output"
|
||||||
|
echo "status: $status"
|
||||||
|
assert_success
|
||||||
|
assert_output_not_exists
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_traefik_healthcheck() {
|
||||||
|
local APP="$1"
|
||||||
|
local APP_REPO_DIR="$2"
|
||||||
|
[[ -z "$APP" ]] && local APP="$TEST_APP"
|
||||||
|
APP_REPO_DIR="$(realpath "$APP_REPO_DIR")"
|
||||||
|
|
||||||
|
mv "$APP_REPO_DIR/app-traefik.json" "$APP_REPO_DIR/app.json"
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user