Skip to content

Commit

Permalink
Configure HealthCheck with podman update
Browse files Browse the repository at this point in the history
New flags in a `podman update` can change the configuration of HealthCheck when the container is started, without having to restart or recreate the container.

This can help determine why a given container suddenly started failing HealthCheck without interfering with the services it provides. For example, reconfigure HealthCheck to keep logs longer than the usual last X results, store logs to other destinations, etc.

Fixes: https://issues.redhat.com/browse/RHEL-60561

Signed-off-by: Jan Rodák <[email protected]>
  • Loading branch information
Honny1 committed Nov 12, 2024
1 parent c8af2f2 commit dfb98ce
Show file tree
Hide file tree
Showing 31 changed files with 1,015 additions and 180 deletions.
251 changes: 134 additions & 117 deletions cmd/podman/common/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,78 +168,6 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
_ = cmd.RegisterFlagCompletionFunc(groupAddFlagName, completion.AutocompleteNone)

healthCmdFlagName := "health-cmd"
createFlags.StringVar(
&cf.HealthCmd,
healthCmdFlagName, "",
"set a healthcheck command for the container ('none' disables the existing healthcheck)",
)
_ = cmd.RegisterFlagCompletionFunc(healthCmdFlagName, completion.AutocompleteNone)

healthIntervalFlagName := "health-interval"
createFlags.StringVar(
&cf.HealthInterval,
healthIntervalFlagName, define.DefaultHealthCheckInterval,
"set an interval for the healthcheck (a value of disable results in no automatic timer setup)",
)
_ = cmd.RegisterFlagCompletionFunc(healthIntervalFlagName, completion.AutocompleteNone)

healthLogDestinationFlagName := "health-log-destination"
createFlags.StringVar(
&cf.HealthLogDestination,
healthLogDestinationFlagName, define.DefaultHealthCheckLocalDestination,
"set the destination of the HealthCheck log. Directory path, local or events_logger (local use container state file)",
)
_ = cmd.RegisterFlagCompletionFunc(healthLogDestinationFlagName, completion.AutocompleteNone)

healthMaxLogCountFlagName := "health-max-log-count"
createFlags.UintVar(
&cf.HealthMaxLogCount,
healthMaxLogCountFlagName, define.DefaultHealthMaxLogCount,
"set maximum number of attempts in the HealthCheck log file. ('0' value means an infinite number of attempts in the log file)",
)
_ = cmd.RegisterFlagCompletionFunc(healthMaxLogCountFlagName, completion.AutocompleteNone)

healthMaxLogSizeFlagName := "health-max-log-size"
createFlags.UintVar(
&cf.HealthMaxLogSize,
healthMaxLogSizeFlagName, define.DefaultHealthMaxLogSize,
"set maximum length in characters of stored HealthCheck log. ('0' value means an infinite log length)",
)
_ = cmd.RegisterFlagCompletionFunc(healthMaxLogSizeFlagName, completion.AutocompleteNone)

healthRetriesFlagName := "health-retries"
createFlags.UintVar(
&cf.HealthRetries,
healthRetriesFlagName, define.DefaultHealthCheckRetries,
"the number of retries allowed before a healthcheck is considered to be unhealthy",
)
_ = cmd.RegisterFlagCompletionFunc(healthRetriesFlagName, completion.AutocompleteNone)

healthStartPeriodFlagName := "health-start-period"
createFlags.StringVar(
&cf.HealthStartPeriod,
healthStartPeriodFlagName, define.DefaultHealthCheckStartPeriod,
"the initialization time needed for a container to bootstrap",
)
_ = cmd.RegisterFlagCompletionFunc(healthStartPeriodFlagName, completion.AutocompleteNone)

healthTimeoutFlagName := "health-timeout"
createFlags.StringVar(
&cf.HealthTimeout,
healthTimeoutFlagName, define.DefaultHealthCheckTimeout,
"the maximum time allowed to complete the healthcheck before an interval is considered failed",
)
_ = cmd.RegisterFlagCompletionFunc(healthTimeoutFlagName, completion.AutocompleteNone)

healthOnFailureFlagName := "health-on-failure"
createFlags.StringVar(
&cf.HealthOnFailure,
healthOnFailureFlagName, "none",
"action to take once the container turns unhealthy",
)
_ = cmd.RegisterFlagCompletionFunc(healthOnFailureFlagName, AutocompleteHealthOnFailure)

createFlags.BoolVar(
&cf.HTTPProxy,
"http-proxy", podmanConfig.ContainersConfDefaultsRO.Containers.HTTPProxy,
Expand Down Expand Up @@ -311,11 +239,6 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
_ = cmd.RegisterFlagCompletionFunc(logOptFlagName, AutocompleteLogOpt)

createFlags.BoolVar(
&cf.NoHealthCheck,
"no-healthcheck", false,
"Disable healthchecks on container",
)
createFlags.BoolVar(
&cf.OOMKillDisable,
"oom-kill-disable", false,
Expand Down Expand Up @@ -452,46 +375,6 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
_ = cmd.RegisterFlagCompletionFunc(secretFlagName, AutocompleteSecrets)

startupHCCmdFlagName := "health-startup-cmd"
createFlags.StringVar(
&cf.StartupHCCmd,
startupHCCmdFlagName, "",
"Set a startup healthcheck command for the container",
)
_ = cmd.RegisterFlagCompletionFunc(startupHCCmdFlagName, completion.AutocompleteNone)

startupHCIntervalFlagName := "health-startup-interval"
createFlags.StringVar(
&cf.StartupHCInterval,
startupHCIntervalFlagName, define.DefaultHealthCheckInterval,
"Set an interval for the startup healthcheck",
)
_ = cmd.RegisterFlagCompletionFunc(startupHCIntervalFlagName, completion.AutocompleteNone)

startupHCRetriesFlagName := "health-startup-retries"
createFlags.UintVar(
&cf.StartupHCRetries,
startupHCRetriesFlagName, 0,
"Set the maximum number of retries before the startup healthcheck will restart the container",
)
_ = cmd.RegisterFlagCompletionFunc(startupHCRetriesFlagName, completion.AutocompleteNone)

startupHCSuccessesFlagName := "health-startup-success"
createFlags.UintVar(
&cf.StartupHCSuccesses,
startupHCSuccessesFlagName, 0,
"Set the number of consecutive successes before the startup healthcheck is marked as successful and the normal healthcheck begins (0 indicates any success will start the regular healthcheck)",
)
_ = cmd.RegisterFlagCompletionFunc(startupHCSuccessesFlagName, completion.AutocompleteNone)

startupHCTimeoutFlagName := "health-startup-timeout"
createFlags.StringVar(
&cf.StartupHCTimeout,
startupHCTimeoutFlagName, define.DefaultHealthCheckTimeout,
"Set the maximum amount of time that the startup healthcheck may take before it is considered failed",
)
_ = cmd.RegisterFlagCompletionFunc(startupHCTimeoutFlagName, completion.AutocompleteNone)

stopSignalFlagName := "stop-signal"
createFlags.StringVar(
&cf.StopSignal,
Expand Down Expand Up @@ -665,6 +548,140 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
`If a container with the same name exists, replace it`,
)
}
if mode == entities.CreateMode || mode == entities.UpdateMode {
createFlags.BoolVar(
&cf.NoHealthCheck,
"no-healthcheck", false,
"Disable healthchecks on container",
)

healthCmdFlagName := "health-cmd"
createFlags.StringVar(
&cf.HealthCmd,
healthCmdFlagName, "",
"set a healthcheck command for the container ('none' disables the existing healthcheck)",
)
_ = cmd.RegisterFlagCompletionFunc(healthCmdFlagName, completion.AutocompleteNone)

info := ""
if mode == entities.UpdateMode {
info = "Changing this setting resets timer."
}
healthIntervalFlagName := "health-interval"
createFlags.StringVar(
&cf.HealthInterval,
healthIntervalFlagName, define.DefaultHealthCheckInterval,
"set an interval for the healthcheck. (a value of disable results in no automatic timer setup) "+info,
)
_ = cmd.RegisterFlagCompletionFunc(healthIntervalFlagName, completion.AutocompleteNone)

warning := ""
if mode == entities.UpdateMode {
warning = "Warning: Changing this setting may cause the loss of previous logs!"
}
healthLogDestinationFlagName := "health-log-destination"
createFlags.StringVar(
&cf.HealthLogDestination,
healthLogDestinationFlagName, define.DefaultHealthCheckLocalDestination,
"set the destination of the HealthCheck log. Directory path, local or events_logger (local use container state file) "+warning,
)
_ = cmd.RegisterFlagCompletionFunc(healthLogDestinationFlagName, completion.AutocompleteNone)

healthMaxLogCountFlagName := "health-max-log-count"
createFlags.UintVar(
&cf.HealthMaxLogCount,
healthMaxLogCountFlagName, define.DefaultHealthMaxLogCount,
"set maximum number of attempts in the HealthCheck log file. ('0' value means an infinite number of attempts in the log file)",
)
_ = cmd.RegisterFlagCompletionFunc(healthMaxLogCountFlagName, completion.AutocompleteNone)

healthMaxLogSizeFlagName := "health-max-log-size"
createFlags.UintVar(
&cf.HealthMaxLogSize,
healthMaxLogSizeFlagName, define.DefaultHealthMaxLogSize,
"set maximum length in characters of stored HealthCheck log. ('0' value means an infinite log length)",
)
_ = cmd.RegisterFlagCompletionFunc(healthMaxLogSizeFlagName, completion.AutocompleteNone)

healthRetriesFlagName := "health-retries"
createFlags.UintVar(
&cf.HealthRetries,
healthRetriesFlagName, define.DefaultHealthCheckRetries,
"the number of retries allowed before a healthcheck is considered to be unhealthy",
)
_ = cmd.RegisterFlagCompletionFunc(healthRetriesFlagName, completion.AutocompleteNone)

healthStartPeriodFlagName := "health-start-period"
createFlags.StringVar(
&cf.HealthStartPeriod,
healthStartPeriodFlagName, define.DefaultHealthCheckStartPeriod,
"the initialization time needed for a container to bootstrap",
)
_ = cmd.RegisterFlagCompletionFunc(healthStartPeriodFlagName, completion.AutocompleteNone)

healthTimeoutFlagName := "health-timeout"
createFlags.StringVar(
&cf.HealthTimeout,
healthTimeoutFlagName, define.DefaultHealthCheckTimeout,
"the maximum time allowed to complete the healthcheck before an interval is considered failed",
)
_ = cmd.RegisterFlagCompletionFunc(healthTimeoutFlagName, completion.AutocompleteNone)

healthOnFailureFlagName := "health-on-failure"
createFlags.StringVar(
&cf.HealthOnFailure,
healthOnFailureFlagName, "none",
"action to take once the container turns unhealthy",
)
_ = cmd.RegisterFlagCompletionFunc(healthOnFailureFlagName, AutocompleteHealthOnFailure)

// Startup HealthCheck

startupHCCmdFlagName := "health-startup-cmd"
createFlags.StringVar(
&cf.StartupHCCmd,
startupHCCmdFlagName, "",
"Set a startup healthcheck command for the container",
)
_ = cmd.RegisterFlagCompletionFunc(startupHCCmdFlagName, completion.AutocompleteNone)

info = ""
if mode == entities.UpdateMode {
info = "Changing this setting resets the timer, depending on the state of the container."
}
startupHCIntervalFlagName := "health-startup-interval"
createFlags.StringVar(
&cf.StartupHCInterval,
startupHCIntervalFlagName, define.DefaultHealthCheckInterval,
"Set an interval for the startup healthcheck. "+info,
)
_ = cmd.RegisterFlagCompletionFunc(startupHCIntervalFlagName, completion.AutocompleteNone)

startupHCRetriesFlagName := "health-startup-retries"
createFlags.UintVar(
&cf.StartupHCRetries,
startupHCRetriesFlagName, 0,
"Set the maximum number of retries before the startup healthcheck will restart the container",
)
_ = cmd.RegisterFlagCompletionFunc(startupHCRetriesFlagName, completion.AutocompleteNone)

startupHCSuccessesFlagName := "health-startup-success"
createFlags.UintVar(
&cf.StartupHCSuccesses,
startupHCSuccessesFlagName, 0,
"Set the number of consecutive successes before the startup healthcheck is marked as successful and the normal healthcheck begins (0 indicates any success will start the regular healthcheck)",
)
_ = cmd.RegisterFlagCompletionFunc(startupHCSuccessesFlagName, completion.AutocompleteNone)

startupHCTimeoutFlagName := "health-startup-timeout"
createFlags.StringVar(
&cf.StartupHCTimeout,
startupHCTimeoutFlagName, define.DefaultHealthCheckTimeout,
"Set the maximum amount of time that the startup healthcheck may take before it is considered failed",
)
_ = cmd.RegisterFlagCompletionFunc(startupHCTimeoutFlagName, completion.AutocompleteNone)
}

// Restart is allowed for created, updated, and infra ctr
if mode == entities.InfraMode || mode == entities.CreateMode || mode == entities.UpdateMode {
restartFlagName := "restart"
Expand Down
12 changes: 9 additions & 3 deletions cmd/podman/containers/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
)

var (
updateDescription = `Updates the cgroup configuration of a given container`
updateDescription = `Updates the configuration of an existing container, allowing changes to resource limits and healthchecks`

updateCommand = &cobra.Command{
Use: "update [options] CONTAINER",
Expand Down Expand Up @@ -89,9 +89,15 @@ func update(cmd *cobra.Command, args []string) error {
return err
}

healthCheckConfig := specgenutil.GetChangedHealthCheckConfiguration(cmd)
if err != nil {
return err
}

opts := &entities.ContainerUpdateOptions{
NameOrID: strings.TrimPrefix(args[0], "/"),
Specgen: s,
NameOrID: strings.TrimPrefix(args[0], "/"),
Specgen: s,
ChangedHealthCheckConfiguration: &healthCheckConfig,
}
rep, err := registry.ContainerEngine().ContainerUpdate(context.Background(), opts)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/health-cmd.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman create, run
####> podman create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--health-cmd**=*"command"* | *'["command", "arg1", ...]'*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/health-interval.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman create, run
####> podman create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--health-interval**=*interval*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/health-log-destination.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman create, run
####> podman create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--health-log-destination**=*directory_path*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/health-max-log-count.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman create, run
####> podman create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--health-max-log-count**=*number of stored logs*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/health-max-log-size.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman create, run
####> podman create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--health-max-log-size**=*size of stored logs*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/health-on-failure.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman create, run
####> podman create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--health-on-failure**=*action*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/health-retries.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman create, run
####> podman create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--health-retries**=*retries*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/health-start-period.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman create, run
####> podman create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--health-start-period**=*period*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/health-startup-cmd.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman create, run
####> podman create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--health-startup-cmd**=*"command"* | *'["command", "arg1", ...]'*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/health-startup-interval.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman create, run
####> podman create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--health-startup-interval**=*interval*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/health-startup-retries.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman create, run
####> podman create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--health-startup-retries**=*retries*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/health-startup-success.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman create, run
####> podman create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--health-startup-success**=*retries*
Expand Down
2 changes: 1 addition & 1 deletion docs/source/markdown/options/health-startup-timeout.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
####> This option file is used in:
####> podman create, run
####> podman create, run, update
####> If file is edited, make sure the changes
####> are applicable to all of those.
#### **--health-startup-timeout**=*timeout*
Expand Down
Loading

0 comments on commit dfb98ce

Please sign in to comment.