docker: new container_exists_attempts configuration field (#22419)

This allows users to set a custom value of attempts that will be made to purge
an existing (not running) container if one is found during task creation.

---------

Co-authored-by: Tim Gross <tgross@hashicorp.com>
This commit is contained in:
Piotr Kazmierczak
2024-05-30 19:22:14 +02:00
committed by GitHub
parent bf11e39ac8
commit 307fd590d7
5 changed files with 109 additions and 63 deletions

3
.changelog/22419.txt Normal file
View File

@@ -0,0 +1,3 @@
```release-note:improvement
docker: Added container_exists_attempts plugin configuration variable
```

View File

@@ -284,6 +284,11 @@ var (
hclspec.NewAttr("infra_image_pull_timeout", "string", false),
hclspec.NewLiteral(`"5m"`),
),
// number of attempts to try to purge an existing container if it already exists
"container_exists_attempts": hclspec.NewDefault(
hclspec.NewAttr("container_exists_attempts", "number", false),
hclspec.NewLiteral(`5`),
),
// the duration that the driver will wait for activity from the Docker engine during an image pull
// before canceling the request
@@ -350,6 +355,7 @@ var (
hclspec.NewAttr("cpu_cfs_period", "number", false),
hclspec.NewLiteral(`100000`),
),
"container_exists_attempts": hclspec.NewAttr("container_exists_attempts", "number", false),
"devices": hclspec.NewBlockList("devices", hclspec.NewObject(map[string]*hclspec.Spec{
"host_path": hclspec.NewAttr("host_path", "string", false),
"container_path": hclspec.NewAttr("container_path", "string", false),
@@ -427,60 +433,61 @@ var (
)
type TaskConfig struct {
Image string `codec:"image"`
AdvertiseIPv6Addr bool `codec:"advertise_ipv6_address"`
Args []string `codec:"args"`
Auth DockerAuth `codec:"auth"`
AuthSoftFail bool `codec:"auth_soft_fail"`
CapAdd []string `codec:"cap_add"`
CapDrop []string `codec:"cap_drop"`
Command string `codec:"command"`
CPUCFSPeriod int64 `codec:"cpu_cfs_period"`
CPUHardLimit bool `codec:"cpu_hard_limit"`
CPUSetCPUs string `codec:"cpuset_cpus"`
Devices []DockerDevice `codec:"devices"`
DNSSearchDomains []string `codec:"dns_search_domains"`
DNSOptions []string `codec:"dns_options"`
DNSServers []string `codec:"dns_servers"`
Entrypoint []string `codec:"entrypoint"`
ExtraHosts []string `codec:"extra_hosts"`
ForcePull bool `codec:"force_pull"`
GroupAdd []string `codec:"group_add"`
Healthchecks DockerHealthchecks `codec:"healthchecks"`
Hostname string `codec:"hostname"`
Init bool `codec:"init"`
Interactive bool `codec:"interactive"`
IPCMode string `codec:"ipc_mode"`
IPv4Address string `codec:"ipv4_address"`
IPv6Address string `codec:"ipv6_address"`
Isolation string `codec:"isolation"`
Labels hclutils.MapStrStr `codec:"labels"`
LoadImage string `codec:"load"`
Logging DockerLogging `codec:"logging"`
MacAddress string `codec:"mac_address"`
MemoryHardLimit int64 `codec:"memory_hard_limit"`
Mounts []DockerMount `codec:"mount"`
NetworkAliases []string `codec:"network_aliases"`
NetworkMode string `codec:"network_mode"`
Runtime string `codec:"runtime"`
PidsLimit int64 `codec:"pids_limit"`
PidMode string `codec:"pid_mode"`
Ports []string `codec:"ports"`
PortMap hclutils.MapStrInt `codec:"port_map"`
Privileged bool `codec:"privileged"`
ImagePullTimeout string `codec:"image_pull_timeout"`
ReadonlyRootfs bool `codec:"readonly_rootfs"`
SecurityOpt []string `codec:"security_opt"`
ShmSize int64 `codec:"shm_size"`
StorageOpt map[string]string `codec:"storage_opt"`
Sysctl hclutils.MapStrStr `codec:"sysctl"`
TTY bool `codec:"tty"`
Ulimit hclutils.MapStrStr `codec:"ulimit"`
UTSMode string `codec:"uts_mode"`
UsernsMode string `codec:"userns_mode"`
Volumes []string `codec:"volumes"`
VolumeDriver string `codec:"volume_driver"`
WorkDir string `codec:"work_dir"`
Image string `codec:"image"`
AdvertiseIPv6Addr bool `codec:"advertise_ipv6_address"`
Args []string `codec:"args"`
Auth DockerAuth `codec:"auth"`
AuthSoftFail bool `codec:"auth_soft_fail"`
CapAdd []string `codec:"cap_add"`
CapDrop []string `codec:"cap_drop"`
Command string `codec:"command"`
ContainerExistsAttempts uint64 `codec:"container_exists_attempts"`
CPUCFSPeriod int64 `codec:"cpu_cfs_period"`
CPUHardLimit bool `codec:"cpu_hard_limit"`
CPUSetCPUs string `codec:"cpuset_cpus"`
Devices []DockerDevice `codec:"devices"`
DNSSearchDomains []string `codec:"dns_search_domains"`
DNSOptions []string `codec:"dns_options"`
DNSServers []string `codec:"dns_servers"`
Entrypoint []string `codec:"entrypoint"`
ExtraHosts []string `codec:"extra_hosts"`
ForcePull bool `codec:"force_pull"`
GroupAdd []string `codec:"group_add"`
Healthchecks DockerHealthchecks `codec:"healthchecks"`
Hostname string `codec:"hostname"`
Init bool `codec:"init"`
Interactive bool `codec:"interactive"`
IPCMode string `codec:"ipc_mode"`
IPv4Address string `codec:"ipv4_address"`
IPv6Address string `codec:"ipv6_address"`
Isolation string `codec:"isolation"`
Labels hclutils.MapStrStr `codec:"labels"`
LoadImage string `codec:"load"`
Logging DockerLogging `codec:"logging"`
MacAddress string `codec:"mac_address"`
MemoryHardLimit int64 `codec:"memory_hard_limit"`
Mounts []DockerMount `codec:"mount"`
NetworkAliases []string `codec:"network_aliases"`
NetworkMode string `codec:"network_mode"`
Runtime string `codec:"runtime"`
PidsLimit int64 `codec:"pids_limit"`
PidMode string `codec:"pid_mode"`
Ports []string `codec:"ports"`
PortMap hclutils.MapStrInt `codec:"port_map"`
Privileged bool `codec:"privileged"`
ImagePullTimeout string `codec:"image_pull_timeout"`
ReadonlyRootfs bool `codec:"readonly_rootfs"`
SecurityOpt []string `codec:"security_opt"`
ShmSize int64 `codec:"shm_size"`
StorageOpt map[string]string `codec:"storage_opt"`
Sysctl hclutils.MapStrStr `codec:"sysctl"`
TTY bool `codec:"tty"`
Ulimit hclutils.MapStrStr `codec:"ulimit"`
UTSMode string `codec:"uts_mode"`
UsernsMode string `codec:"userns_mode"`
Volumes []string `codec:"volumes"`
VolumeDriver string `codec:"volume_driver"`
WorkDir string `codec:"work_dir"`
// MountsList supports the pre-1.0 mounts array syntax
MountsList []DockerMount `codec:"mounts"`
@@ -648,6 +655,7 @@ type DriverConfig struct {
InfraImage string `codec:"infra_image"`
InfraImagePullTimeout string `codec:"infra_image_pull_timeout"`
infraImagePullTimeoutDuration time.Duration `codec:"-"`
ContainerExistsAttempts uint64 `codec:"container_exists_attempts"`
DisableLogCollection bool `codec:"disable_log_collection"`
PullActivityTimeout string `codec:"pull_activity_timeout"`
PidsLimit int64 `codec:"pids_limit"`

View File

@@ -215,6 +215,7 @@ config {
cap_add = ["CAP_SYS_NICE"]
cap_drop = ["CAP_SYS_ADMIN", "CAP_SYS_TIME"]
command = "/bin/bash"
container_exists_attempts = 10
cpu_hard_limit = true
cpu_cfs_period = 20
devices = [
@@ -351,8 +352,6 @@ config {
}`
expected := &TaskConfig{
Image: "redis:7",
ImagePullTimeout: "15m",
AdvertiseIPv6Addr: true,
Args: []string{"command_arg1", "command_arg2"},
Auth: DockerAuth{
@@ -361,12 +360,13 @@ config {
Email: "myemail@example.com",
ServerAddr: "https://example.com",
},
AuthSoftFail: true,
CapAdd: []string{"CAP_SYS_NICE"},
CapDrop: []string{"CAP_SYS_ADMIN", "CAP_SYS_TIME"},
Command: "/bin/bash",
CPUHardLimit: true,
CPUCFSPeriod: 20,
AuthSoftFail: true,
CapAdd: []string{"CAP_SYS_NICE"},
CapDrop: []string{"CAP_SYS_ADMIN", "CAP_SYS_TIME"},
Command: "/bin/bash",
ContainerExistsAttempts: 10,
CPUHardLimit: true,
CPUCFSPeriod: 20,
Devices: []DockerDevice{
{
HostPath: "/dev/null",
@@ -393,6 +393,8 @@ config {
GroupAdd: []string{"group1", "group2"},
Healthchecks: DockerHealthchecks{Disable: true},
Hostname: "self.example.com",
Image: "redis:7",
ImagePullTimeout: "15m",
Interactive: true,
IPCMode: "host",
IPv4Address: "10.0.2.1",
@@ -689,6 +691,35 @@ func TestConfig_Capabilities(t *testing.T) {
}
}
func TestConfig_DriverConfig_ContainerExistsAttempts(t *testing.T) {
ci.Parallel(t)
cases := []struct {
name string
config string
expected uint64
}{
{
name: "default",
config: `{}`,
expected: 5,
},
{
name: "set explicitly",
config: `{ container_exists_attempts = 10 }`,
expected: 10,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
var tc DriverConfig
hclutils.NewConfigParser(configSpec).ParseHCL(t, "config "+c.config, &tc)
must.Eq(t, c.expected, tc.ContainerExistsAttempts)
})
}
}
func TestConfig_DriverConfig_InfraImagePullTimeout(t *testing.T) {
ci.Parallel(t)

View File

@@ -538,7 +538,7 @@ CREATE:
}
}
if attempted < 5 {
if attempted < d.config.ContainerExistsAttempts {
attempted++
backoff = helper.Backoff(50*time.Millisecond, time.Minute, attempted)
time.Sleep(backoff)

View File

@@ -84,6 +84,10 @@ The `docker` driver supports the following configuration in the job spec. Only
}
```
- `container_exists_attempts` - (Optional) A number of attempts to be made to
purge a container if during task creation Nomad encounters an existing one in
non-running state for the same task. Defaults to `5`.
- `dns_search_domains` - (Optional) A list of DNS search domains for
the container to use. If you are using bridge networking mode with a
`network` block in the task group, you must set all DNS options in