Skip to content

Commit

Permalink
docker: create a docker task config setting for disable built-in heal…
Browse files Browse the repository at this point in the history
…thcheck

This PR adds a docker driver task configuration setting for turning off
built-in HEALTHCHECK of a container.

References)
https://docs.docker.com/engine/reference/builder/#healthcheck
https://github.com/docker/engine-api/blob/master/types/container/config.go#L16

Closes #5310
Closes #14068
  • Loading branch information
shoenig committed Aug 11, 2022
1 parent 1692112 commit 0bd42a5
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 5 deletions.
3 changes: 3 additions & 0 deletions .changelog/14089.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:improvement
docker: Added config option to disable container healthcheck
```
23 changes: 18 additions & 5 deletions drivers/docker/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,21 +112,19 @@ func PluginLoader(opts map[string]string) (map[string]interface{}, error) {
}

var (
// PluginID is the rawexec plugin metadata registered in the plugin
// catalog.
// PluginID is the docker plugin metadata registered in the plugin catalog.
PluginID = loader.PluginID{
Name: pluginName,
PluginType: base.PluginTypeDriver,
}

// PluginConfig is the rawexec factory function registered in the
// plugin catalog.
// PluginConfig is the docker config factory function registered in the plugin catalog.
PluginConfig = &loader.InternalPluginConfig{
Config: map[string]interface{}{},
Factory: func(ctx context.Context, l hclog.Logger) interface{} { return NewDockerDriver(ctx, l) },
}

// pluginInfo is the response returned for the PluginInfo RPC
// pluginInfo is the response returned for the PluginInfo RPC.
pluginInfo = &base.PluginInfoResponse{
Type: base.PluginTypeDriver,
PluginApiVersions: []string{drivers.ApiVersion010},
Expand Down Expand Up @@ -321,6 +319,11 @@ var (
})),
})

// healthchecksBodySpec is the hcl specification for the `healthchecks` block
healthchecksBodySpec = hclspec.NewObject(map[string]*hclspec.Spec{
"disable": hclspec.NewAttr("disable", "bool", false),
})

// taskConfigSpec is the hcl specification for the driver config section of
// a task within a job. It is returned in the TaskConfigSchema RPC
taskConfigSpec = hclspec.NewObject(map[string]*hclspec.Spec{
Expand Down Expand Up @@ -354,6 +357,7 @@ var (
"entrypoint": hclspec.NewAttr("entrypoint", "list(string)", false),
"extra_hosts": hclspec.NewAttr("extra_hosts", "list(string)", false),
"force_pull": hclspec.NewAttr("force_pull", "bool", false),
"healthchecks": hclspec.NewBlock("healthchecks", false, healthchecksBodySpec),
"hostname": hclspec.NewAttr("hostname", "string", false),
"init": hclspec.NewAttr("init", "bool", false),
"interactive": hclspec.NewAttr("interactive", "bool", false),
Expand Down Expand Up @@ -435,6 +439,7 @@ type TaskConfig struct {
Entrypoint []string `codec:"entrypoint"`
ExtraHosts []string `codec:"extra_hosts"`
ForcePull bool `codec:"force_pull"`
Healthchecks DockerHealthchecks `codec:"healthchecks"`
Hostname string `codec:"hostname"`
Init bool `codec:"init"`
Interactive bool `codec:"interactive"`
Expand Down Expand Up @@ -514,6 +519,14 @@ type DockerLogging struct {
Config hclutils.MapStrStr `codec:"config"`
}

type DockerHealthchecks struct {
Disable bool `codec:"disable"`
}

func (dh *DockerHealthchecks) Disabled() bool {
return dh == nil || dh.Disable
}

type DockerMount struct {
Type string `codec:"type"`
Target string `codec:"target"`
Expand Down
4 changes: 4 additions & 0 deletions drivers/docker/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,9 @@ config {
entrypoint = ["/bin/bash", "-c"]
extra_hosts = ["127.0.0.1 localhost.example.com"]
force_pull = true
healthchecks {
disable = true
}
hostname = "self.example.com"
interactive = true
ipc_mode = "host"
Expand Down Expand Up @@ -376,6 +379,7 @@ config {
Entrypoint: []string{"/bin/bash", "-c"},
ExtraHosts: []string{"127.0.0.1 localhost.example.com"},
ForcePull: true,
Healthchecks: DockerHealthchecks{Disable: true},
Hostname: "self.example.com",
Interactive: true,
IPCMode: "host",
Expand Down
7 changes: 7 additions & 0 deletions drivers/docker/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,13 @@ func (d *Driver) createContainerConfig(task *drivers.TaskConfig, driverConfig *T
logger.Debug("setting container mac address", "mac_address", config.MacAddress)
}

if driverConfig.Healthchecks.Disabled() {
// Override any image-supplied health-check with disable sentinel.
// https://github.com/docker/engine-api/blob/master/types/container/config.go#L16
config.Healthcheck = &docker.HealthConfig{Test: []string{"NONE"}}
logger.Debug("setting container healthchecks to be disabled")
}

return docker.CreateContainerOptions{
Name: containerName,
Config: config,
Expand Down
21 changes: 21 additions & 0 deletions drivers/docker/driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/hashicorp/nomad/plugins/drivers"
dtestutil "github.com/hashicorp/nomad/plugins/drivers/testutils"
tu "github.com/hashicorp/nomad/testutil"
"github.com/shoenig/test/must"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -845,6 +846,26 @@ func TestDockerDriver_LoggingConfiguration(t *testing.T) {
require.Equal(t, loggerConfig, container.HostConfig.LogConfig.Config)
}

func TestDockerDriver_HealthchecksDisable(t *testing.T) {
ci.Parallel(t)
testutil.DockerCompatible(t)

task, cfg, ports := dockerTask(t)
cfg.Healthchecks.Disable = true
defer freeport.Return(ports)
must.NoError(t, task.EncodeConcreteDriverConfig(cfg))

client, d, handle, cleanup := dockerSetup(t, task, nil)
defer cleanup()
must.NoError(t, d.WaitUntilStarted(task.ID, 5*time.Second))

container, err := client.InspectContainer(handle.containerID)
must.NoError(t, err)

must.NotNil(t, container.Config.Healthcheck)
must.Eq(t, []string{"NONE"}, container.Config.Healthcheck.Test)
}

func TestDockerDriver_ForcePull(t *testing.T) {
ci.Parallel(t)
testutil.DockerCompatible(t)
Expand Down
12 changes: 12 additions & 0 deletions website/content/docs/drivers/docker.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@ config {
are mutable. If image's tag is `latest` or omitted, the image will always be pulled
regardless of this setting.

- `healthchecks` - (Optional) A configuration block for controlling how the
docker driver manages HEALTHCHECK directives built into the container. Set
`healthchecks.disable` to disable any built-in healthcheck.

```hcl
config {
healthchecks {
disable = true
}
}
```

- `hostname` - (Optional) The hostname to assign to the container. When
launching more than one of a task (using `count`) with this option set, every
container the task starts will have the same hostname.
Expand Down

0 comments on commit 0bd42a5

Please sign in to comment.