diff --git a/drivers/docker/config.go b/drivers/docker/config.go index aff5c5d69..aa556d1d4 100644 --- a/drivers/docker/config.go +++ b/drivers/docker/config.go @@ -354,6 +354,7 @@ var ( "extra_hosts": hclspec.NewAttr("extra_hosts", "list(string)", false), "force_pull": hclspec.NewAttr("force_pull", "bool", false), "hostname": hclspec.NewAttr("hostname", "string", false), + "init": hclspec.NewAttr("init", "bool", false), "interactive": hclspec.NewAttr("interactive", "bool", false), "ipc_mode": hclspec.NewAttr("ipc_mode", "string", false), "ipv4_address": hclspec.NewAttr("ipv4_address", "string", false), @@ -434,6 +435,7 @@ type TaskConfig struct { ExtraHosts []string `codec:"extra_hosts"` ForcePull bool `codec:"force_pull"` Hostname string `codec:"hostname"` + Init bool `codec:"init"` Interactive bool `codec:"interactive"` IPCMode string `codec:"ipc_mode"` IPv4Address string `codec:"ipv4_address"` diff --git a/drivers/docker/driver.go b/drivers/docker/driver.go index 968223460..cd00a359e 100644 --- a/drivers/docker/driver.go +++ b/drivers/docker/driver.go @@ -853,6 +853,11 @@ func (d *Driver) createContainerConfig(task *drivers.TaskConfig, driverConfig *T hostConfig.CPUSetCPUs = driverConfig.CPUSetCPUs } + // Enable tini (docker-init) init system. + if driverConfig.Init { + hostConfig.Init = driverConfig.Init + } + // Calculate CPU Quota // cfs_quota_us is the time per core, so we must // multiply the time by the number of cores available diff --git a/drivers/docker/driver_test.go b/drivers/docker/driver_test.go index aa542a58b..a149da1b9 100644 --- a/drivers/docker/driver_test.go +++ b/drivers/docker/driver_test.go @@ -1526,6 +1526,31 @@ func TestDockerDriver_DNS(t *testing.T) { } +func TestDockerDriver_Init(t *testing.T) { + if !tu.IsCI() { + t.Parallel() + } + testutil.DockerCompatible(t) + if runtime.GOOS == "windows" { + t.Skip("Windows does not support init.") + } + + task, cfg, ports := dockerTask(t) + defer freeport.Return(ports) + + cfg.Init = true + require.NoError(t, task.EncodeConcreteDriverConfig(cfg)) + + client, d, handle, cleanup := dockerSetup(t, task, nil) + defer cleanup() + require.NoError(t, d.WaitUntilStarted(task.ID, 5*time.Second)) + + container, err := client.InspectContainer(handle.containerID) + require.NoError(t, err) + + require.Equal(t, cfg.Init, container.HostConfig.Init) +} + func TestDockerDriver_CPUSetCPUs(t *testing.T) { if !tu.IsCI() { t.Parallel() diff --git a/website/content/docs/drivers/docker.mdx b/website/content/docs/drivers/docker.mdx index e85b79d23..3aefd92a5 100644 --- a/website/content/docs/drivers/docker.mdx +++ b/website/content/docs/drivers/docker.mdx @@ -124,6 +124,16 @@ config { launching more than one of a task (using `count`) with this option set, every container the task starts will have the same hostname. +- `init` - (Optional) `true` or `false` (default). Enable init (tini) system when + launching your container. When enabled, an init process will be used as the PID1 + in the container. Specifying an init process ensures the usual responsibilities + of an init system, such as reaping zombie processes, are performed inside the + created container. + + The default init process used is the first `docker-init` executable found in the + system path of the Docker daemon process. This `docker-init` binary, included in + the default installation, is backed by [tini][tini]. + - `interactive` - (Optional) `true` or `false` (default). Keep STDIN open on the container. @@ -1152,6 +1162,7 @@ Windows is relatively new and rapidly evolving you may want to consult the [cap_drop]: /docs/drivers/docker#cap_drop [no_net_raw]: /docs/upgrade/upgrade-specific#nomad-1-1-0-rc1-1-0-5-0-12-12 [upgrade_guide_extra_hosts]: /docs/upgrade/upgrade-specific#docker-driver +[tini]: https://github.com/krallin/tini [docker_caps]: https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities [allow_caps]: /docs/drivers/docker#allow_caps [Connect]: /docs/job-specification/connect