This commit adds: - Comprehensive docker-compose examples for health check testing - GitHub runner sources database migration - UI fix for service heading view Files Added: - DOCKER_COMPOSE_EXAMPLES.md - Documentation of health check test cases - docker-compose.*.yml - Test files for various health check scenarios: - excluded.yml: Container with exclude_from_hc flag - healthy.yml: All containers healthy - unhealthy.yml: All containers unhealthy - unknown.yml: Container without healthcheck - mixed-healthy-unknown.yml: Mix of healthy and unknown - mixed-unhealthy-unknown.yml: Mix of unhealthy and unknown - database/migrations/2025_11_19_115504_create_github_runner_sources_table.php Files Modified: - resources/views/livewire/project/service/heading.blade.php 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
7.4 KiB
Docker Compose Examples for Testing Health Status Aggregation
These example docker-compose files demonstrate different container health status scenarios to test the "unknown" health state aggregation fix.
Prerequisites
# Make sure Docker is running
docker --version
Test Cases
1. Healthy - All containers with passing health checks
File: docker-compose.healthy.yml
docker-compose -f docker-compose.healthy.yml up -d
docker-compose -f docker-compose.healthy.yml ps
docker inspect $(docker-compose -f docker-compose.healthy.yml ps -q web) | grep -A 5 '"Health"'
Expected Status: running (healthy)
- Container has healthcheck that successfully connects to nginx on port 80
Cleanup:
docker-compose -f docker-compose.healthy.yml down
2. Unknown - Container without health check
File: docker-compose.unknown.yml
docker-compose -f docker-compose.unknown.yml up -d
docker-compose -f docker-compose.unknown.yml ps
docker inspect $(docker-compose -f docker-compose.unknown.yml ps -q web) | grep -A 5 '"Health"'
Expected Status: running (unknown)
- Container has NO healthcheck defined
State.Healthkey is missing from Docker inspect output
Cleanup:
docker-compose -f docker-compose.unknown.yml down
3. Unhealthy - Container with failing health check
File: docker-compose.unhealthy.yml
docker-compose -f docker-compose.unhealthy.yml up -d
# Wait 30 seconds for health check to fail
sleep 30
docker-compose -f docker-compose.unhealthy.yml ps
docker inspect $(docker-compose -f docker-compose.unhealthy.yml ps -q web) | grep -A 5 '"Health"'
Expected Status: running (unhealthy)
- Container has healthcheck that tries to connect to port 9999 (which doesn't exist)
- Health check will fail after retries
Cleanup:
docker-compose -f docker-compose.unhealthy.yml down
4. Mixed: Healthy + Unknown → Should show "unknown"
File: docker-compose.mixed-healthy-unknown.yml
docker-compose -f docker-compose.mixed-healthy-unknown.yml up -d
docker-compose -f docker-compose.mixed-healthy-unknown.yml ps
docker inspect $(docker-compose -f docker-compose.mixed-healthy-unknown.yml ps -q web) | grep -A 5 '"Health"'
docker inspect $(docker-compose -f docker-compose.mixed-healthy-unknown.yml ps -q worker) | grep -A 5 '"Health"'
Expected Aggregated Status: running (unknown) ← This is the fix!
webcontainer:running (healthy)- has passing healthcheckworkercontainer:running (unknown)- no healthcheck- Before fix: Would show
running (healthy)❌ - After fix: Shows
running (unknown)✅
Cleanup:
docker-compose -f docker-compose.mixed-healthy-unknown.yml down
5. Mixed: Unhealthy + Unknown → Should show "unhealthy"
File: docker-compose.mixed-unhealthy-unknown.yml
docker-compose -f docker-compose.mixed-unhealthy-unknown.yml up -d
# Wait 30 seconds for health check to fail
sleep 30
docker-compose -f docker-compose.mixed-unhealthy-unknown.yml ps
docker inspect $(docker-compose -f docker-compose.mixed-unhealthy-unknown.yml ps -q web) | grep -A 5 '"Health"'
docker inspect $(docker-compose -f docker-compose.mixed-unhealthy-unknown.yml ps -q worker) | grep -A 5 '"Health"'
Expected Aggregated Status: running (unhealthy)
webcontainer:running (unhealthy)- failing healthcheckworkercontainer:running (unknown)- no healthcheck- Unhealthy takes priority over unknown
Cleanup:
docker-compose -f docker-compose.mixed-unhealthy-unknown.yml down
6. Excluded Container - Unhealthy container excluded from health checks
File: docker-compose.excluded.yml
docker-compose -f docker-compose.excluded.yml up -d
# Wait 30 seconds for health check to fail
sleep 30
docker-compose -f docker-compose.excluded.yml ps
docker inspect $(docker-compose -f docker-compose.excluded.yml ps -q web) | grep -A 5 '"Health"'
docker inspect $(docker-compose -f docker-compose.excluded.yml ps -q backup) | grep -A 5 '"Health"'
Expected Aggregated Status: running (healthy)
webcontainer:running (healthy)- passing healthcheckbackupcontainer:running (unhealthy)- but hasexclude_from_hc: true- Excluded containers don't affect aggregation
Cleanup:
docker-compose -f docker-compose.excluded.yml down
Quick Test All Cases
# Test healthy
echo "=== Testing HEALTHY ==="
docker-compose -f docker-compose.healthy.yml up -d && sleep 15
docker inspect $(docker-compose -f docker-compose.healthy.yml ps -q web) --format='{{.State.Status}} ({{if .State.Health}}{{.State.Health.Status}}{{else}}unknown{{end}})'
docker-compose -f docker-compose.healthy.yml down
# Test unknown
echo -e "\n=== Testing UNKNOWN ==="
docker-compose -f docker-compose.unknown.yml up -d && sleep 5
docker inspect $(docker-compose -f docker-compose.unknown.yml ps -q web) --format='{{.State.Status}} ({{if .State.Health}}{{.State.Health.Status}}{{else}}unknown{{end}})'
docker-compose -f docker-compose.unknown.yml down
# Test unhealthy
echo -e "\n=== Testing UNHEALTHY ==="
docker-compose -f docker-compose.unhealthy.yml up -d && sleep 35
docker inspect $(docker-compose -f docker-compose.unhealthy.yml ps -q web) --format='{{.State.Status}} ({{if .State.Health}}{{.State.Health.Status}}{{else}}unknown{{end}})'
docker-compose -f docker-compose.unhealthy.yml down
# Test mixed healthy + unknown
echo -e "\n=== Testing MIXED HEALTHY + UNKNOWN ==="
docker-compose -f docker-compose.mixed-healthy-unknown.yml up -d && sleep 15
echo "Web: $(docker inspect $(docker-compose -f docker-compose.mixed-healthy-unknown.yml ps -q web) --format='{{.State.Status}} ({{if .State.Health}}{{.State.Health.Status}}{{else}}unknown{{end}})')"
echo "Worker: $(docker inspect $(docker-compose -f docker-compose.mixed-healthy-unknown.yml ps -q worker) --format='{{.State.Status}} ({{if .State.Health}}{{.State.Health.Status}}{{else}}unknown{{end}})')"
echo "Expected Aggregated: running (unknown)"
docker-compose -f docker-compose.mixed-healthy-unknown.yml down
# Cleanup all
echo -e "\n=== Cleaning up ==="
docker-compose -f docker-compose.healthy.yml down 2>/dev/null
docker-compose -f docker-compose.unknown.yml down 2>/dev/null
docker-compose -f docker-compose.unhealthy.yml down 2>/dev/null
docker-compose -f docker-compose.mixed-healthy-unknown.yml down 2>/dev/null
docker-compose -f docker-compose.mixed-unhealthy-unknown.yml down 2>/dev/null
docker-compose -f docker-compose.excluded.yml down 2>/dev/null
Understanding the Output
Docker Inspect Health Status
"Health": {
"Status": "healthy", // or "unhealthy", "starting"
"FailingStreak": 0,
"Log": [...]
}
If "Health" key is missing → Container has no healthcheck → Shows as unknown
Coolify Status Format
Individual containers: "<status> (<health>)"
"running (healthy)"- Container running with passing healthcheck"running (unhealthy)"- Container running with failing healthcheck"running (unknown)"- Container running with no healthcheck"running (starting)"- Container running, healthcheck in initial grace period
Aggregation Priority (after fix)
- Unhealthy (highest) - If ANY container is unhealthy
- Unknown (medium) - If no unhealthy, but ≥1 has no healthcheck
- Healthy (lowest) - Only when ALL containers explicitly healthy