Skip to content

healthcheck.start_interval is ineffective and incorrectly mapped to --health-startup-interval #1500

Description

@wakairo

Describe the bug

podman-compose accepts the Compose Specification field
healthcheck.start_interval, but it does not cause health checks to run at
that interval during healthcheck.start_period.

The current implementation maps:

healthcheck:
  start_interval: 1s

to:

--health-startup-interval 1s

Source:

# interval, timeout, start_period, and start_interval are specified as durations.
if "interval" in healthcheck:
podman_args.extend(["--health-interval", healthcheck["interval"]])
if "timeout" in healthcheck:
podman_args.extend(["--health-timeout", healthcheck["timeout"]])
if "start_period" in healthcheck:
podman_args.extend(["--health-start-period", healthcheck["start_period"]])
if "start_interval" in healthcheck:
podman_args.extend(["--health-startup-interval", healthcheck["start_interval"]])

However, Podman's --health-startup-interval belongs to Podman's separate
startup-healthcheck mechanism
.
That mechanism is gated by --health-startup-cmd.
podman-compose generates --health-cmd, but does
not generate --health-startup-cmd, so the startup interval does not create
or affect a startup healthcheck.

More importantly, the two settings have different semantics:

  • Compose start_interval changes the interval of the regular healthcheck
    during start_period.
  • Podman --health-startup-interval controls a separate startup healthcheck,
    which stops after its configured success condition is met.
  • Podman's startup healthcheck is not bounded by --health-start-period.

Therefore, mapping start_interval to --health-startup-interval is not
equivalent to the Compose Specification, even if an
--health-startup-cmd were also generated.

This mapping was introduced as support for start_interval in #1271. The
current unit test verifies the generated CLI argument, but does not verify
the resulting healthcheck schedule:

async def test_healthcheck_options(self) -> None:
c = create_compose_mock()
cnt = get_minimal_container()
cnt["healthcheck"] = {
"test": ["CMD", "cmd", "arg1", "arg2"],
"interval": "1m",
"timeout": "10s",
"retries": "3",
"start_period": "5s",
"start_interval": "6s",
}
args = await container_to_args(c, cnt)
self.assertEqual(
args,
[
"--name=project_name_service_name1",
"-d",
"--network=bridge:alias=service_name",
"--health-cmd",
'["cmd", "arg1", "arg2"]',
'--health-interval',
'1m',
'--health-timeout',
'10s',
'--health-start-period',
'5s',
'--health-startup-interval',
'6s',
'--health-retries',
'3',
"busybox",
],

This is partly related to a missing Podman runtime feature, but the
podman-compose-specific bug is that it accepts the Compose field and
silently translates it to a different and ineffective Podman option.

To Reproduce

  1. Create a directory containing only this compose.yaml:
services:
  test:
    image: docker.io/library/busybox:latest
    container_name: health-start-interval-repro
    command: ["sh", "-c", "sleep 120"]
    healthcheck:
      test:
        - CMD-SHELL
        - "date +%s >> /tmp/healthcheck-times; exit 1"
      interval: 30s
      timeout: 2s
      retries: 100
      start_period: 10s
      start_interval: 1s

The healthcheck always fails and records each execution time inside the
container. It intentionally keeps failing so that it remains in the startup
period for the full 10 seconds.

  1. Run:
$ podman-compose up -d
$ sleep 12
$ podman exec health-start-interval-repro \
    sh -c 'cat /tmp/healthcheck-times; printf "count="; wc -l < /tmp/healthcheck-times'
  1. Clean up:
$ podman-compose down

Expected behavior

According to the Compose Specification, the regular healthcheck should run
approximately every second during the 10-second start_period. After the
startup period, it should run every 30 seconds.

The output after 12 seconds should therefore contain approximately 10 health
check timestamps.

If the installed Podman version cannot implement Compose
healthcheck.start_interval, podman-compose should report the field as
unsupported with an explicit warning or error.

Compose Specification:

https://github.com/compose-spec/compose-spec/blob/main/spec.md#healthcheck

Actual behavior

The healthcheck does not run every second during start_period. On my
system, the output was:

1784066724
count=1

The checks follow the normal interval instead. The generated
--health-startup-interval has no effect because no Podman startup
healthcheck command is configured.

Output

$ podman-compose version
podman-compose version 1.6.0
podman version 4.9.3

$ podman-compose up -d
d5550213217795690767e832a32565298d1ecf552b5398c27686d170065fc642
Trying to pull docker.io/library/busybox:latest...
Getting image source signatures
Copying blob b05093807bb0 done   |
Copying config c6348fa86b done   |
Writing manifest to image destination
c3754f331c11e41b810a8a290f1a10bb4eabaac3077f46dff97ea122a2e31da5
health-start-interval-repro
$ sleep 12
$ podman exec health-start-interval-repro \
    sh -c 'cat /tmp/healthcheck-times; printf "count="; wc -l < /tmp/healthcheck-times'
1784066724
count=1
$ podman-compose down
health-start-interval-repro
health-start-interval-repro
d5550213217795690767e832a32565298d1ecf552b5398c27686d170065fc642
pc_test_default

Environment:

  • OS: WSL
  • Podman version: 4.9.3
  • podman-compose version: 1.6.0

Additional context

Podman documents --health-startup-cmd and
--health-startup-interval as a separate startup-healthcheck mechanism:

https://github.com/podman-container-tools/podman/blob/v6.0.1/docs/source/markdown/podman-healthcheck.1.md#startup-healthcheck-vs-regular-healthcheck

Podman's regular --health-start-period documentation states that checks
continue to use --health-interval:

https://docs.podman.io/en/latest/markdown/podman-run.1.html

The missing Docker-compatible start_interval functionality in Podman itself
is tracked separately in:

podman-container-tools/podman#26505

A possible podman-compose resolution would be:

  1. Stop translating Compose start_interval to
    --health-startup-interval, because the semantics are different.
  2. Until Podman provides an exact equivalent, emit an explicit unsupported
    warning or error.
  3. Once Podman supports the field, map it to the corresponding native
    option/API field.
  4. (Optional) Add an integration test that verifies the actual execution timestamps,
    rather than only checking the generated CLI arguments.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions