Add flags to container/service for health start interval

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
This commit is contained in:
Brian Goff 2023-07-06 19:05:34 +00:00
parent 9bfaa6ff79
commit 986879c071
4 changed files with 137 additions and 117 deletions

View File

@ -31,99 +31,100 @@ var deviceCgroupRuleRegexp = regexp.MustCompile(`^[acb] ([0-9]+|\*):([0-9]+|\*)
// containerOptions is a data object with all the options for creating a container // containerOptions is a data object with all the options for creating a container
type containerOptions struct { type containerOptions struct {
attach opts.ListOpts attach opts.ListOpts
volumes opts.ListOpts volumes opts.ListOpts
tmpfs opts.ListOpts tmpfs opts.ListOpts
mounts opts.MountOpt mounts opts.MountOpt
blkioWeightDevice opts.WeightdeviceOpt blkioWeightDevice opts.WeightdeviceOpt
deviceReadBps opts.ThrottledeviceOpt deviceReadBps opts.ThrottledeviceOpt
deviceWriteBps opts.ThrottledeviceOpt deviceWriteBps opts.ThrottledeviceOpt
links opts.ListOpts links opts.ListOpts
aliases opts.ListOpts aliases opts.ListOpts
linkLocalIPs opts.ListOpts linkLocalIPs opts.ListOpts
deviceReadIOps opts.ThrottledeviceOpt deviceReadIOps opts.ThrottledeviceOpt
deviceWriteIOps opts.ThrottledeviceOpt deviceWriteIOps opts.ThrottledeviceOpt
env opts.ListOpts env opts.ListOpts
labels opts.ListOpts labels opts.ListOpts
deviceCgroupRules opts.ListOpts deviceCgroupRules opts.ListOpts
devices opts.ListOpts devices opts.ListOpts
gpus opts.GpuOpts gpus opts.GpuOpts
ulimits *opts.UlimitOpt ulimits *opts.UlimitOpt
sysctls *opts.MapOpts sysctls *opts.MapOpts
publish opts.ListOpts publish opts.ListOpts
expose opts.ListOpts expose opts.ListOpts
dns opts.ListOpts dns opts.ListOpts
dnsSearch opts.ListOpts dnsSearch opts.ListOpts
dnsOptions opts.ListOpts dnsOptions opts.ListOpts
extraHosts opts.ListOpts extraHosts opts.ListOpts
volumesFrom opts.ListOpts volumesFrom opts.ListOpts
envFile opts.ListOpts envFile opts.ListOpts
capAdd opts.ListOpts capAdd opts.ListOpts
capDrop opts.ListOpts capDrop opts.ListOpts
groupAdd opts.ListOpts groupAdd opts.ListOpts
securityOpt opts.ListOpts securityOpt opts.ListOpts
storageOpt opts.ListOpts storageOpt opts.ListOpts
labelsFile opts.ListOpts labelsFile opts.ListOpts
loggingOpts opts.ListOpts loggingOpts opts.ListOpts
privileged bool privileged bool
pidMode string pidMode string
utsMode string utsMode string
usernsMode string usernsMode string
cgroupnsMode string cgroupnsMode string
publishAll bool publishAll bool
stdin bool stdin bool
tty bool tty bool
oomKillDisable bool oomKillDisable bool
oomScoreAdj int oomScoreAdj int
containerIDFile string containerIDFile string
entrypoint string entrypoint string
hostname string hostname string
domainname string domainname string
memory opts.MemBytes memory opts.MemBytes
memoryReservation opts.MemBytes memoryReservation opts.MemBytes
memorySwap opts.MemSwapBytes memorySwap opts.MemSwapBytes
kernelMemory opts.MemBytes kernelMemory opts.MemBytes
user string user string
workingDir string workingDir string
cpuCount int64 cpuCount int64
cpuShares int64 cpuShares int64
cpuPercent int64 cpuPercent int64
cpuPeriod int64 cpuPeriod int64
cpuRealtimePeriod int64 cpuRealtimePeriod int64
cpuRealtimeRuntime int64 cpuRealtimeRuntime int64
cpuQuota int64 cpuQuota int64
cpus opts.NanoCPUs cpus opts.NanoCPUs
cpusetCpus string cpusetCpus string
cpusetMems string cpusetMems string
blkioWeight uint16 blkioWeight uint16
ioMaxBandwidth opts.MemBytes ioMaxBandwidth opts.MemBytes
ioMaxIOps uint64 ioMaxIOps uint64
swappiness int64 swappiness int64
netMode opts.NetworkOpt netMode opts.NetworkOpt
macAddress string macAddress string
ipv4Address string ipv4Address string
ipv6Address string ipv6Address string
ipcMode string ipcMode string
pidsLimit int64 pidsLimit int64
restartPolicy string restartPolicy string
readonlyRootfs bool readonlyRootfs bool
loggingDriver string loggingDriver string
cgroupParent string cgroupParent string
volumeDriver string volumeDriver string
stopSignal string stopSignal string
stopTimeout int stopTimeout int
isolation string isolation string
shmSize opts.MemBytes shmSize opts.MemBytes
noHealthcheck bool noHealthcheck bool
healthCmd string healthCmd string
healthInterval time.Duration healthInterval time.Duration
healthTimeout time.Duration healthTimeout time.Duration
healthStartPeriod time.Duration healthStartPeriod time.Duration
healthRetries int healthStartInterval time.Duration
runtime string healthRetries int
autoRemove bool runtime string
init bool autoRemove bool
annotations *opts.MapOpts init bool
annotations *opts.MapOpts
Image string Image string
Args []string Args []string
@ -250,6 +251,8 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
flags.DurationVar(&copts.healthTimeout, "health-timeout", 0, "Maximum time to allow one check to run (ms|s|m|h) (default 0s)") flags.DurationVar(&copts.healthTimeout, "health-timeout", 0, "Maximum time to allow one check to run (ms|s|m|h) (default 0s)")
flags.DurationVar(&copts.healthStartPeriod, "health-start-period", 0, "Start period for the container to initialize before starting health-retries countdown (ms|s|m|h) (default 0s)") flags.DurationVar(&copts.healthStartPeriod, "health-start-period", 0, "Start period for the container to initialize before starting health-retries countdown (ms|s|m|h) (default 0s)")
flags.SetAnnotation("health-start-period", "version", []string{"1.29"}) flags.SetAnnotation("health-start-period", "version", []string{"1.29"})
flags.DurationVar(&copts.healthStartInterval, "health-start-interval", 0, "Time between running the check during the start period (ms|s|m|h) (default 0s)")
flags.SetAnnotation("health-start-interval", "version", []string{"1.44"})
flags.BoolVar(&copts.noHealthcheck, "no-healthcheck", false, "Disable any container-specified HEALTHCHECK") flags.BoolVar(&copts.noHealthcheck, "no-healthcheck", false, "Disable any container-specified HEALTHCHECK")
// Resource management // Resource management
@ -526,7 +529,8 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
copts.healthInterval != 0 || copts.healthInterval != 0 ||
copts.healthTimeout != 0 || copts.healthTimeout != 0 ||
copts.healthStartPeriod != 0 || copts.healthStartPeriod != 0 ||
copts.healthRetries != 0 copts.healthRetries != 0 ||
copts.healthStartInterval != 0
if copts.noHealthcheck { if copts.noHealthcheck {
if haveHealthSettings { if haveHealthSettings {
return nil, errors.Errorf("--no-healthcheck conflicts with --health-* options") return nil, errors.Errorf("--no-healthcheck conflicts with --health-* options")
@ -549,13 +553,17 @@ func parse(flags *pflag.FlagSet, copts *containerOptions, serverOS string) (*con
if copts.healthStartPeriod < 0 { if copts.healthStartPeriod < 0 {
return nil, fmt.Errorf("--health-start-period cannot be negative") return nil, fmt.Errorf("--health-start-period cannot be negative")
} }
if copts.healthStartInterval < 0 {
return nil, fmt.Errorf("--health-start-interval cannot be negative")
}
healthConfig = &container.HealthConfig{ healthConfig = &container.HealthConfig{
Test: probe, Test: probe,
Interval: copts.healthInterval, Interval: copts.healthInterval,
Timeout: copts.healthTimeout, Timeout: copts.healthTimeout,
StartPeriod: copts.healthStartPeriod, StartPeriod: copts.healthStartPeriod,
Retries: copts.healthRetries, StartInterval: copts.healthStartInterval,
Retries: copts.healthRetries,
} }
} }

View File

@ -720,8 +720,8 @@ func TestParseHealth(t *testing.T) {
checkError("--no-healthcheck conflicts with --health-* options", checkError("--no-healthcheck conflicts with --health-* options",
"--no-healthcheck", "--health-cmd=/check.sh -q", "img", "cmd") "--no-healthcheck", "--health-cmd=/check.sh -q", "img", "cmd")
health = checkOk("--health-timeout=2s", "--health-retries=3", "--health-interval=4.5s", "--health-start-period=5s", "img", "cmd") health = checkOk("--health-timeout=2s", "--health-retries=3", "--health-interval=4.5s", "--health-start-period=5s", "--health-start-interval=1s", "img", "cmd")
if health.Timeout != 2*time.Second || health.Retries != 3 || health.Interval != 4500*time.Millisecond || health.StartPeriod != 5*time.Second { if health.Timeout != 2*time.Second || health.Retries != 3 || health.Interval != 4500*time.Millisecond || health.StartPeriod != 5*time.Second || health.StartInterval != 1*time.Second {
t.Fatalf("--health-*: got %#v", health) t.Fatalf("--health-*: got %#v", health)
} }
} }

View File

@ -428,6 +428,7 @@ type healthCheckOptions struct {
timeout opts.PositiveDurationOpt timeout opts.PositiveDurationOpt
retries int retries int
startPeriod opts.PositiveDurationOpt startPeriod opts.PositiveDurationOpt
startInterval opts.PositiveDurationOpt
noHealthcheck bool noHealthcheck bool
} }
@ -436,6 +437,8 @@ func (opts *healthCheckOptions) toHealthConfig() (*container.HealthConfig, error
haveHealthSettings := opts.cmd != "" || haveHealthSettings := opts.cmd != "" ||
opts.interval.Value() != nil || opts.interval.Value() != nil ||
opts.timeout.Value() != nil || opts.timeout.Value() != nil ||
opts.startPeriod.Value() != nil ||
opts.startInterval.Value() != nil ||
opts.retries != 0 opts.retries != 0
if opts.noHealthcheck { if opts.noHealthcheck {
if haveHealthSettings { if haveHealthSettings {
@ -447,7 +450,7 @@ func (opts *healthCheckOptions) toHealthConfig() (*container.HealthConfig, error
if opts.cmd != "" { if opts.cmd != "" {
test = []string{"CMD-SHELL", opts.cmd} test = []string{"CMD-SHELL", opts.cmd}
} }
var interval, timeout, startPeriod time.Duration var interval, timeout, startPeriod, startInterval time.Duration
if ptr := opts.interval.Value(); ptr != nil { if ptr := opts.interval.Value(); ptr != nil {
interval = *ptr interval = *ptr
} }
@ -457,12 +460,16 @@ func (opts *healthCheckOptions) toHealthConfig() (*container.HealthConfig, error
if ptr := opts.startPeriod.Value(); ptr != nil { if ptr := opts.startPeriod.Value(); ptr != nil {
startPeriod = *ptr startPeriod = *ptr
} }
if ptr := opts.startInterval.Value(); ptr != nil {
startInterval = *ptr
}
healthConfig = &container.HealthConfig{ healthConfig = &container.HealthConfig{
Test: test, Test: test,
Interval: interval, Interval: interval,
Timeout: timeout, Timeout: timeout,
Retries: opts.retries, Retries: opts.retries,
StartPeriod: startPeriod, StartPeriod: startPeriod,
StartInterval: startInterval,
} }
} }
return healthConfig, nil return healthConfig, nil
@ -906,6 +913,8 @@ func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions, defaultFlagValu
flags.SetAnnotation(flagHealthRetries, "version", []string{"1.25"}) flags.SetAnnotation(flagHealthRetries, "version", []string{"1.25"})
flags.Var(&opts.healthcheck.startPeriod, flagHealthStartPeriod, "Start period for the container to initialize before counting retries towards unstable (ms|s|m|h)") flags.Var(&opts.healthcheck.startPeriod, flagHealthStartPeriod, "Start period for the container to initialize before counting retries towards unstable (ms|s|m|h)")
flags.SetAnnotation(flagHealthStartPeriod, "version", []string{"1.29"}) flags.SetAnnotation(flagHealthStartPeriod, "version", []string{"1.29"})
flags.Var(&opts.healthcheck.startInterval, flagHealthStartInterval, "Time between running the check during the start period (ms|s|m|h)")
flags.SetAnnotation(flagHealthStartInterval, "version", []string{"1.44"})
flags.BoolVar(&opts.healthcheck.noHealthcheck, flagNoHealthcheck, false, "Disable any container-specified HEALTHCHECK") flags.BoolVar(&opts.healthcheck.noHealthcheck, flagNoHealthcheck, false, "Disable any container-specified HEALTHCHECK")
flags.SetAnnotation(flagNoHealthcheck, "version", []string{"1.25"}) flags.SetAnnotation(flagNoHealthcheck, "version", []string{"1.25"})
@ -1016,6 +1025,7 @@ const (
flagHealthRetries = "health-retries" flagHealthRetries = "health-retries"
flagHealthTimeout = "health-timeout" flagHealthTimeout = "health-timeout"
flagHealthStartPeriod = "health-start-period" flagHealthStartPeriod = "health-start-period"
flagHealthStartInterval = "health-start-interval"
flagNoHealthcheck = "no-healthcheck" flagNoHealthcheck = "no-healthcheck"
flagSecret = "secret" flagSecret = "secret"
flagSecretAdd = "secret-add" flagSecretAdd = "secret-add"

View File

@ -108,20 +108,22 @@ func TestUint64OptSetAndValue(t *testing.T) {
func TestHealthCheckOptionsToHealthConfig(t *testing.T) { func TestHealthCheckOptionsToHealthConfig(t *testing.T) {
dur := time.Second dur := time.Second
opt := healthCheckOptions{ opt := healthCheckOptions{
cmd: "curl", cmd: "curl",
interval: opts.PositiveDurationOpt{DurationOpt: *opts.NewDurationOpt(&dur)}, interval: opts.PositiveDurationOpt{DurationOpt: *opts.NewDurationOpt(&dur)},
timeout: opts.PositiveDurationOpt{DurationOpt: *opts.NewDurationOpt(&dur)}, timeout: opts.PositiveDurationOpt{DurationOpt: *opts.NewDurationOpt(&dur)},
startPeriod: opts.PositiveDurationOpt{DurationOpt: *opts.NewDurationOpt(&dur)}, startPeriod: opts.PositiveDurationOpt{DurationOpt: *opts.NewDurationOpt(&dur)},
retries: 10, startInterval: opts.PositiveDurationOpt{DurationOpt: *opts.NewDurationOpt(&dur)},
retries: 10,
} }
config, err := opt.toHealthConfig() config, err := opt.toHealthConfig()
assert.NilError(t, err) assert.NilError(t, err)
assert.Check(t, is.DeepEqual(&container.HealthConfig{ assert.Check(t, is.DeepEqual(&container.HealthConfig{
Test: []string{"CMD-SHELL", "curl"}, Test: []string{"CMD-SHELL", "curl"},
Interval: time.Second, Interval: time.Second,
Timeout: time.Second, Timeout: time.Second,
StartPeriod: time.Second, StartPeriod: time.Second,
Retries: 10, StartInterval: time.Second,
Retries: 10,
}, config)) }, config))
} }