From 5d1342fc58c82b74c780447a0de809986ce0669d Mon Sep 17 00:00:00 2001 From: Ygal Blum Date: Mon, 20 Mar 2023 08:41:16 +0200 Subject: [PATCH 1/2] Quadlet - Add support for health checks configuration in .container files Signed-off-by: Ygal Blum --- docs/source/markdown/podman-systemd.unit.5.md | 67 +++++++++++++++++++ pkg/systemd/quadlet/quadlet.go | 48 +++++++++++++ test/e2e/quadlet/health.container | 24 +++++++ test/e2e/quadlet_test.go | 1 + 4 files changed, 140 insertions(+) create mode 100644 test/e2e/quadlet/health.container diff --git a/docs/source/markdown/podman-systemd.unit.5.md b/docs/source/markdown/podman-systemd.unit.5.md index bbd556bd87..832fbeb974 100644 --- a/docs/source/markdown/podman-systemd.unit.5.md +++ b/docs/source/markdown/podman-systemd.unit.5.md @@ -86,6 +86,17 @@ Valid options for `[Container]` are listed below: | Exec=/usr/bin/command | Command after image specification - /usr/bin/command | | ExposeHostPort=50-59 | --expose 50-59 | | Group=1234 | --user UID:1234 | +| HealthCmd="/usr/bin/command" | --health-cmd="/usr/bin/command" | +| HealthInterval=2m | --health-interval=2m | +| HealthOnFailure=restart | --health-on-failure=restart | +| HealthRetries=5 | --health-retries=5 | +| HealthStartPeriod=1m | --health-start-period=period=1m | +| HealthStartupCmd="/usr/bin/command" | --health-startup-cmd="/usr/bin/command" | +| HealthStartupInterval=1m | --health-startup-interval=2m | +| HealthStartupRetries=8 | --health-startup-retries=8 | +| HealthStartupSuccess=2 | --health-startup-success=2 | +| HealthStartupTimeout=1m33s | --health-startup-timeout=1m33s | +| HealthTimeout=20s | --health-timeout=20s | | Image=ubi8 | Image specification - ubi8 | | IP=192.5.0.1 | --ip 192.5.0.0 | | IP6=fd46:db93:aa76:ac37::10 | --ip6 2001:db8::1 | @@ -196,6 +207,62 @@ This key can be listed multiple times. The (numeric) gid to run as inside the container. This does not need to match the gid on the host, which can be modified with `RemapUsers`, but if that is not specified, this gid is also used on the host. + +### `HealthCmd=` + +Set or alter a healthcheck command for a container. A value of none disables existing healthchecks. +Equivalent to the Podman `--health-cmd` option. + +### `HealthInterval=` + +Set an interval for the healthchecks. An interval of disable results in no automatic timer setup. +Equivalent to the Podman `--health-interval` option. + +### `HealthOnFailure=` + +Action to take once the container transitions to an unhealthy state. +Equivalent to the Podman `--health-on-failure` option. + +### `HealthRetries=` + +The number of retries allowed before a healthcheck is considered to be unhealthy. +Equivalent to the Podman `--health-retries` option. + +### `HealthStartPeriod=` + +The initialization time needed for a container to bootstrap. +Equivalent to the Podman `--health-start-period` option. + +### `HealthStartupCmd=` + +Set a startup healthcheck command for a container. +Equivalent to the Podman `--health-startup-cmd` option. + +### `HealthStartupInterval=` + +Set an interval for the startup healthcheck. An interval of disable results in no automatic timer setup. +Equivalent to the Podman `--health-startup-interval` option. + +### `HealthStartupRetries=` + +The number of attempts allowed before the startup healthcheck restarts the container. +Equivalent to the Podman `--health-startup-retries` option. + +### `HealthStartupSuccess=` + +The number of successful runs required before the startup healthcheck will succeed and the regular healthcheck will begin. +Equivalent to the Podman `--health-startup-success` option. + +### `HealthStartupTimeout=` + +The maximum time a startup healthcheck command has to complete before it is marked as failed. +Equivalent to the Podman `--health-startup-timeout` option. + +### `HealthTimeout=` + +The maximum time allowed to complete the healthcheck before an interval is considered failed. +Equivalent to the Podman `--health-timeout` option. + ### `Image=` The image to run in the container. This image must be locally installed for the service to work diff --git a/pkg/systemd/quadlet/quadlet.go b/pkg/systemd/quadlet/quadlet.go index cfdac299ab..ecee2225e1 100644 --- a/pkg/systemd/quadlet/quadlet.go +++ b/pkg/systemd/quadlet/quadlet.go @@ -48,6 +48,17 @@ const ( KeyExec = "Exec" KeyExposeHostPort = "ExposeHostPort" KeyGroup = "Group" + KeyHealthCmd = "HealthCmd" + KeyHealthInterval = "HealthInterval" + KeyHealthOnFailure = "HealthOnFailure" + KeyHealthRetries = "HealthRetries" + KeyHealthStartPeriod = "HealthStartPeriod" + KeyHealthStartupCmd = "HealthStartupCmd" + KeyHealthStartupInterval = "HealthStartupInterval" + KeyHealthStartupRetries = "HealthStartupRetries" + KeyHealthStartupSuccess = "HealthStartupSuccess" + KeyHealthStartupTimeout = "HealthStartupTimeout" + KeyHealthTimeout = "HealthTimeout" KeyImage = "Image" KeyIP = "IP" KeyIP6 = "IP6" @@ -106,6 +117,17 @@ var ( KeyExec: true, KeyExposeHostPort: true, KeyGroup: true, + KeyHealthCmd: true, + KeyHealthInterval: true, + KeyHealthOnFailure: true, + KeyHealthRetries: true, + KeyHealthStartPeriod: true, + KeyHealthStartupCmd: true, + KeyHealthStartupInterval: true, + KeyHealthStartupRetries: true, + KeyHealthStartupSuccess: true, + KeyHealthStartupTimeout: true, + KeyHealthTimeout: true, KeyImage: true, KeyIP: true, KeyIP6: true, @@ -560,6 +582,8 @@ func ConvertContainer(container *parser.UnitFile, isUser bool) (*parser.UnitFile podman.add("--mount", mountStr) } + handleHealth(container, ContainerGroup, podman) + podmanArgs := container.LookupAllArgs(ContainerGroup, KeyPodmanArgs) podman.add(podmanArgs...) @@ -1042,3 +1066,27 @@ func handleStorageSource(unitFile *parser.UnitFile, source string) string { return source } + +func handleHealth(unitFile *parser.UnitFile, groupName string, podman *PodmanCmdline) { + keyArgMap := [][2]string{ + {KeyHealthCmd, "cmd"}, + {KeyHealthInterval, "interval"}, + {KeyHealthOnFailure, "on-failure"}, + {KeyHealthRetries, "retries"}, + {KeyHealthStartPeriod, "start-period"}, + {KeyHealthTimeout, "timeout"}, + {KeyHealthStartupCmd, "startup-cmd"}, + {KeyHealthStartupInterval, "startup-interval"}, + {KeyHealthStartupRetries, "startup-retries"}, + {KeyHealthStartupSuccess, "startup-success"}, + {KeyHealthStartupTimeout, "startup-timeout"}, + } + + for _, keyArg := range keyArgMap { + val, found := unitFile.Lookup(groupName, keyArg[0]) + if found && len(val) > 0 { + podman.addf("--health-%s", keyArg[1]) + podman.addf("%s", val) + } + } +} diff --git a/test/e2e/quadlet/health.container b/test/e2e/quadlet/health.container new file mode 100644 index 0000000000..a80b67fbc9 --- /dev/null +++ b/test/e2e/quadlet/health.container @@ -0,0 +1,24 @@ +[Container] +Image=localhost/imagename +## assert-podman-args "--health-cmd" "\"hello world\"" +HealthCmd="hello world" +## assert-podman-args "--health-interval" "1m" +HealthInterval=1m +## assert-podman-args "--health-on-failure" "stop" +HealthOnFailure=stop +## assert-podman-args "--health-retries" "9" +HealthRetries=9 +## assert-podman-args "--health-start-period" "2m3s" +HealthStartPeriod=2m3s +## assert-podman-args "--health-timeout" "20s" +HealthTimeout=20s +## assert-podman-args "--health-startup-cmd" "'[\"hello\", world]'" +HealthStartupCmd='["hello", world]' +## assert-podman-args "--health-startup-interval" "5m" +HealthStartupInterval=5m +## assert-podman-args "--health-startup-retries" "10" +HealthStartupRetries=10 +## assert-podman-args "--health-startup-success" "2" +HealthStartupSuccess=2 +## assert-podman-args "--health-startup-timeout" "2h" +HealthStartupTimeout=2h diff --git a/test/e2e/quadlet_test.go b/test/e2e/quadlet_test.go index 466310cb04..ddccbcfce4 100644 --- a/test/e2e/quadlet_test.go +++ b/test/e2e/quadlet_test.go @@ -531,6 +531,7 @@ var _ = Describe("quadlet system generator", func() { Entry("secrets.container", "secrets.container"), Entry("logdriver.container", "logdriver.container"), Entry("mount.container", "mount.container"), + Entry("health.container", "health.container"), Entry("basic.volume", "basic.volume"), Entry("label.volume", "label.volume"), From 26d5df77dfd0b526dac88da5e23c9cdd9ae58dea Mon Sep 17 00:00:00 2001 From: Ygal Blum Date: Mon, 20 Mar 2023 09:53:15 +0200 Subject: [PATCH 2/2] Quadlet Doc: Suggest the kill operation for HealthOnFailure Co-authored-by: Valentin Rothberg Signed-off-by: Ygal Blum --- docs/source/markdown/podman-systemd.unit.5.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/source/markdown/podman-systemd.unit.5.md b/docs/source/markdown/podman-systemd.unit.5.md index 832fbeb974..86e07d4352 100644 --- a/docs/source/markdown/podman-systemd.unit.5.md +++ b/docs/source/markdown/podman-systemd.unit.5.md @@ -88,7 +88,7 @@ Valid options for `[Container]` are listed below: | Group=1234 | --user UID:1234 | | HealthCmd="/usr/bin/command" | --health-cmd="/usr/bin/command" | | HealthInterval=2m | --health-interval=2m | -| HealthOnFailure=restart | --health-on-failure=restart | +| HealthOnFailure=kill | --health-on-failure=kill | | HealthRetries=5 | --health-retries=5 | | HealthStartPeriod=1m | --health-start-period=period=1m | | HealthStartupCmd="/usr/bin/command" | --health-startup-cmd="/usr/bin/command" | @@ -221,6 +221,9 @@ Equivalent to the Podman `--health-interval` option. ### `HealthOnFailure=` Action to take once the container transitions to an unhealthy state. +The "kill" action in combination integrates best with systemd. Once +the container turns unhealthy, it gets killed and systemd will restart +service. Equivalent to the Podman `--health-on-failure` option. ### `HealthRetries=`