feat: add support for healthcheck in Compose

This commit is contained in:
Pasha Sviderski
2026-02-25 14:54:24 +10:00
parent 7bfaf31138
commit 3056e2af11
8 changed files with 220 additions and 88 deletions
+46 -16
View File
@@ -7,6 +7,7 @@ import (
"regexp"
"slices"
"strings"
"time"
mapset "github.com/deckarep/golang-set/v2"
"github.com/distribution/reference"
@@ -74,14 +75,6 @@ type ServiceSpec struct {
Configs []ConfigSpec
}
// UpdateConfig configures how a service is updated during a deployment.
type UpdateConfig struct {
// Order specifies the order of operations during an update.
// Valid values are "start-first" (default for stateless services) and "stop-first" (default for services with volumes).
// Empty value means the strategy will determine the order based on service characteristics.
Order string `json:",omitempty"`
}
// CaddyConfig returns the Caddy reverse proxy configuration for the service or an empty string if it's not defined.
func (s *ServiceSpec) CaddyConfig() string {
if s.Caddy == nil {
@@ -251,8 +244,11 @@ type ContainerSpec struct {
// Entrypoint overrides the default ENTRYPOINT of the image.
Entrypoint []string
// Env defines the environment variables to set inside the container.
Env EnvVars
Image string
Env EnvVars
// Healthcheck defines the health check configuration for the container or overrides the health check options
// defined in the image. If nil, the image's default health check is used.
Healthcheck *HealthcheckSpec `json:",omitempty"`
Image string
// Run a custom init inside the container. If nil, use the daemon's configured settings.
Init *bool
// LogDriver overrides the default logging driver for the container. Each Docker daemon can have its own default.
@@ -347,6 +343,17 @@ func (s *ContainerSpec) Clone() ContainerSpec {
spec.Entrypoint = make([]string, len(s.Entrypoint))
copy(spec.Entrypoint, s.Entrypoint)
}
if s.Env != nil {
spec.Env = make(EnvVars, len(s.Env))
for k, v := range s.Env {
spec.Env[k] = v
}
}
if s.Healthcheck != nil {
hc := *s.Healthcheck
hc.Test = slices.Clone(s.Healthcheck.Test)
spec.Healthcheck = &hc
}
if s.LogDriver != nil {
logDriver := *s.LogDriver
if s.LogDriver.Options != nil {
@@ -354,12 +361,6 @@ func (s *ContainerSpec) Clone() ContainerSpec {
}
spec.LogDriver = &logDriver
}
if s.Env != nil {
spec.Env = make(EnvVars, len(s.Env))
for k, v := range s.Env {
spec.Env[k] = v
}
}
if s.Volumes != nil {
spec.Volumes = make([]string, len(s.Volumes))
copy(spec.Volumes, s.Volumes)
@@ -389,6 +390,7 @@ func (s *ContainerSpec) Clone() ContainerSpec {
if s.Resources.DeviceReservations != nil {
spec.Resources.DeviceReservations = slices.Clone(s.Resources.DeviceReservations)
}
return spec
}
@@ -406,6 +408,26 @@ func (e EnvVars) ToSlice() []string {
return env
}
// HealthcheckSpec defines the health check configuration for a container.
type HealthcheckSpec struct {
// Test is the command used to check health.
// Formats: ["CMD", args...], ["CMD-SHELL", "command"], or ["NONE"] to disable.
Test []string `json:",omitempty"`
// Interval is the time between health checks.
// Zero means to inherit the value from the image or use the Docker default (30s) if not defined in the image.
Interval time.Duration `json:",omitempty"`
// Timeout is how long to wait before considering the checck to have hung.
Timeout time.Duration `json:",omitempty"`
// StartPeriod is the initialisation time for a container before the retries start to count down.
StartPeriod time.Duration `json:",omitempty"`
// StartInterval is the time between health checks during the start period.
StartInterval time.Duration `json:",omitempty"`
// Retries is the number of consecutive failures needed to consider a container unhealthy.
Retries uint `json:",omitempty"`
// Disable disables the health check defined in the image. true is equivalent to setting Test to ["NONE"].
Disable bool `json:",omitempty"`
}
type LogDriver struct {
// Name of the logging driver to use.
Name string
@@ -413,6 +435,14 @@ type LogDriver struct {
Options map[string]string
}
// UpdateConfig configures how a service is updated during a deployment.
type UpdateConfig struct {
// Order specifies the order of operations during an update.
// Valid values are "start-first" (default for stateless services) and "stop-first" (default for services with volumes).
// Empty value means the strategy will determine the order based on service characteristics.
Order string `json:",omitempty"`
}
type RunServiceResponse struct {
ID string
Name string