From f552bd57f4227949eadc042e1626974f05a5aa96 Mon Sep 17 00:00:00 2001 From: flouthoc Date: Thu, 6 Jun 2024 16:02:19 -0700 Subject: [PATCH] healthcheck: Add support for `--start-interval` Docker now supports `--start-interval`, start interval is the time between health checks during the start period. Ref: https://docs.docker.com/reference/dockerfile/#healthcheck Signed-off-by: flouthoc --- cmd/buildah/config.go | 70 ++++++++++++++++++-------------- config.go | 22 +++++----- docs/buildah-config.1.md | 6 +++ imagebuildah/stage_executor.go | 11 ++--- tests/bud.bats | 5 ++- tests/bud/healthcheck/Dockerfile | 2 +- tests/config.bats | 3 ++ 7 files changed, 71 insertions(+), 48 deletions(-) diff --git a/cmd/buildah/config.go b/cmd/buildah/config.go index 64d65ef1617..2eabe77a5f1 100644 --- a/cmd/buildah/config.go +++ b/cmd/buildah/config.go @@ -18,36 +18,37 @@ import ( ) type configResults struct { - addHistory bool - annotation []string - arch string - author string - cmd string - comment string - createdBy string - domainName string - entrypoint string - env []string - healthcheck string - healthcheckInterval string - healthcheckRetries int - healthcheckStartPeriod string - healthcheckTimeout string - historyComment string - hostname string - label []string - onbuild []string - os string - osfeature []string - osversion string - ports []string - shell string - stopSignal string - user string - variant string - volume []string - workingDir string - unsetLabels []string + addHistory bool + annotation []string + arch string + author string + cmd string + comment string + createdBy string + domainName string + entrypoint string + env []string + healthcheck string + healthcheckInterval string + healthcheckRetries int + healthcheckStartPeriod string + healthcheckStartInterval string + healthcheckTimeout string + historyComment string + hostname string + label []string + onbuild []string + os string + osfeature []string + osversion string + ports []string + shell string + stopSignal string + user string + variant string + volume []string + workingDir string + unsetLabels []string } func init() { @@ -84,6 +85,7 @@ func init() { flags.StringVar(&opts.healthcheckInterval, "healthcheck-interval", "", "set the `interval` between runs of the `healthcheck` command for the target image") flags.IntVar(&opts.healthcheckRetries, "healthcheck-retries", 0, "set the `number` of times the `healthcheck` command has to fail") flags.StringVar(&opts.healthcheckStartPeriod, "healthcheck-start-period", "", "set the amount of `time` to wait after starting a container before a failed `healthcheck` command will count as a failure") + flags.StringVar(&opts.healthcheckStartInterval, "healthcheck-start-interval", "", "set the time between health checks during the start period. Only available with format `docker`") flags.StringVar(&opts.healthcheckTimeout, "healthcheck-timeout", "", "set the maximum amount of `time` to wait for a `healthcheck` command for the target image") flags.StringVar(&opts.historyComment, "history-comment", "", "set a `comment` for the history of the target image") flags.StringVar(&opts.hostname, "hostname", "", "set a host`name` for containers based on image") @@ -395,6 +397,14 @@ func updateHealthcheck(builder *buildah.Builder, c *cobra.Command, iopts configR healthcheck.StartPeriod = duration args = args + "--start-period=" + iopts.healthcheckStartPeriod + " " } + if c.Flag("healthcheck-start-interval").Changed { + duration, err := time.ParseDuration(iopts.healthcheckStartInterval) + if err != nil { + return fmt.Errorf("parsing --healthcheck-start-interval %q: %w", iopts.healthcheckStartInterval, err) + } + healthcheck.StartInterval = duration + args = args + "--start-interval=" + iopts.healthcheckStartInterval + " " + } if c.Flag("healthcheck-timeout").Changed { duration, err := time.ParseDuration(iopts.healthcheckTimeout) if err != nil { diff --git a/config.go b/config.go index 7b00f983148..46120a46cb3 100644 --- a/config.go +++ b/config.go @@ -675,11 +675,12 @@ func (b *Builder) Healthcheck() *docker.HealthConfig { return nil } return &docker.HealthConfig{ - Test: slices.Clone(b.Docker.Config.Healthcheck.Test), - Interval: b.Docker.Config.Healthcheck.Interval, - Timeout: b.Docker.Config.Healthcheck.Timeout, - StartPeriod: b.Docker.Config.Healthcheck.StartPeriod, - Retries: b.Docker.Config.Healthcheck.Retries, + Test: slices.Clone(b.Docker.Config.Healthcheck.Test), + Interval: b.Docker.Config.Healthcheck.Interval, + Timeout: b.Docker.Config.Healthcheck.Timeout, + StartPeriod: b.Docker.Config.Healthcheck.StartPeriod, + StartInterval: b.Docker.Config.Healthcheck.StartInterval, + Retries: b.Docker.Config.Healthcheck.Retries, } } @@ -696,11 +697,12 @@ func (b *Builder) SetHealthcheck(config *docker.HealthConfig) { b.Logger.Warnf("HEALTHCHECK is not supported for OCI image format and will be ignored. Must use `docker` format") } b.Docker.Config.Healthcheck = &docker.HealthConfig{ - Test: slices.Clone(config.Test), - Interval: config.Interval, - Timeout: config.Timeout, - StartPeriod: config.StartPeriod, - Retries: config.Retries, + Test: slices.Clone(config.Test), + Interval: config.Interval, + Timeout: config.Timeout, + StartPeriod: config.StartPeriod, + StartInterval: config.StartInterval, + Retries: config.Retries, } } } diff --git a/docs/buildah-config.1.md b/docs/buildah-config.1.md index b62b6b0fe20..43cadf2d7ce 100644 --- a/docs/buildah-config.1.md +++ b/docs/buildah-config.1.md @@ -110,6 +110,12 @@ can fail before the container is considered to be unhealthy. Note: this setting is not present in the OCIv1 image format, so it is discarded when writing images using OCIv1 formats. +**--healthcheck-start-interval** *interval* + +Specify the time between health checks during the start period. + +Note: this setting is not present in the OCIv1 image format, so it is discarded when writing images using OCIv1 formats. + **--healthcheck-start-period** *interval* Specify how much time can elapse after a container has started before a failure diff --git a/imagebuildah/stage_executor.go b/imagebuildah/stage_executor.go index bc004baae59..a68d7442e2a 100644 --- a/imagebuildah/stage_executor.go +++ b/imagebuildah/stage_executor.go @@ -2193,11 +2193,12 @@ func (s *StageExecutor) commit(ctx context.Context, createdBy string, emptyLayer s.builder.SetStopSignal(config.StopSignal) if config.Healthcheck != nil { s.builder.SetHealthcheck(&buildahdocker.HealthConfig{ - Test: append([]string{}, config.Healthcheck.Test...), - Interval: config.Healthcheck.Interval, - Timeout: config.Healthcheck.Timeout, - StartPeriod: config.Healthcheck.StartPeriod, - Retries: config.Healthcheck.Retries, + Test: append([]string{}, config.Healthcheck.Test...), + Interval: config.Healthcheck.Interval, + Timeout: config.Healthcheck.Timeout, + StartPeriod: config.Healthcheck.StartPeriod, + StartInterval: config.Healthcheck.StartInterval, + Retries: config.Healthcheck.Retries, }) } else { s.builder.SetHealthcheck(nil) diff --git a/tests/bud.bats b/tests/bud.bats index 9884f9e22ca..f68328c674d 100644 --- a/tests/bud.bats +++ b/tests/bud.bats @@ -3509,12 +3509,13 @@ _EOF _prefetch alpine target=alpine-image run_buildah build $WITH_POLICY_JSON -t ${target} --format docker $BUDFILES/healthcheck - run_buildah inspect -f '{{printf "%q" .Docker.Config.Healthcheck.Test}} {{printf "%d" .Docker.Config.Healthcheck.StartPeriod}} {{printf "%d" .Docker.Config.Healthcheck.Interval}} {{printf "%d" .Docker.Config.Healthcheck.Timeout}} {{printf "%d" .Docker.Config.Healthcheck.Retries}}' ${target} + run_buildah inspect -f '{{printf "%q" .Docker.Config.Healthcheck.Test}} {{printf "%d" .Docker.Config.Healthcheck.StartInterval}} {{printf "%d" .Docker.Config.Healthcheck.StartPeriod}} {{printf "%d" .Docker.Config.Healthcheck.Interval}} {{printf "%d" .Docker.Config.Healthcheck.Timeout}} {{printf "%d" .Docker.Config.Healthcheck.Retries}}' ${target} second=1000000000 threeseconds=$(( 3 * $second )) + thirtyseconds=$(( 30 * $second )) fiveminutes=$(( 5 * 60 * $second )) tenminutes=$(( 10 * 60 * $second )) - expect_output '["CMD-SHELL" "curl -f http://localhost/ || exit 1"]'" $tenminutes $fiveminutes $threeseconds 4" "Healthcheck config" + expect_output '["CMD-SHELL" "curl -f http://localhost/ || exit 1"]'" $thirtyseconds $tenminutes $fiveminutes $threeseconds 4" "Healthcheck config" } @test "bud with unused build arg" { diff --git a/tests/bud/healthcheck/Dockerfile b/tests/bud/healthcheck/Dockerfile index 3fe36447fdf..b79abbac0b6 100644 --- a/tests/bud/healthcheck/Dockerfile +++ b/tests/bud/healthcheck/Dockerfile @@ -1,3 +1,3 @@ FROM alpine -HEALTHCHECK --start-period=10m --interval=5m --timeout=3s --retries=4 \ +HEALTHCHECK --start-interval=30s --start-period=10m --interval=5m --timeout=3s --retries=4 \ CMD curl -f http://localhost/ || exit 1 diff --git a/tests/config.bats b/tests/config.bats index 3fb1221ceb0..e46e82ec68f 100644 --- a/tests/config.bats +++ b/tests/config.bats @@ -232,6 +232,7 @@ function check_matrix() { --hostname cleverhostname \ --healthcheck "CMD /bin/true" \ --healthcheck-start-period 5s \ + --healthcheck-start-interval 30s \ --healthcheck-interval 6s \ --healthcheck-timeout 7s \ --healthcheck-retries 8 \ @@ -290,6 +291,8 @@ function check_matrix() { expect_output "[CMD /bin/true]" run_buildah inspect -f '{{.Docker.Config.Healthcheck.StartPeriod}}' scratch-image-docker expect_output "5s" + run_buildah inspect -f '{{.Docker.Config.Healthcheck.StartInterval}}' scratch-image-docker + expect_output "30s" run_buildah inspect -f '{{.Docker.Config.Healthcheck.Interval}}' scratch-image-docker expect_output "6s" run_buildah inspect -f '{{.Docker.Config.Healthcheck.Timeout}}' scratch-image-docker