From 38b034d568aa4fb1ea7a54d3f5329028c510c236 Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Lendholt Date: Tue, 20 Sep 2016 09:41:58 +0200 Subject: [PATCH 1/8] Added logging options support for docker driver --- client/driver/docker.go | 42 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/client/driver/docker.go b/client/driver/docker.go index 172117d3e3a..bcf6ba521a5 100644 --- a/client/driver/docker.go +++ b/client/driver/docker.go @@ -74,6 +74,12 @@ type DockerDriverAuth struct { ServerAddress string `mapstructure:"server_address"` // server address of the registry } +type DockerLoggingOpts struct { + Type string `mapstructure:"type"` + ConfigRaw []map[string]string `mapstructure:"config"` + Config map[string]string `mapstructure:"-"` +} + type DockerDriverConfig struct { ImageName string `mapstructure:"image"` // Container's Image Name LoadImages []string `mapstructure:"load"` // LoadImage is array of paths to image archive files @@ -97,6 +103,7 @@ type DockerDriverConfig struct { Interactive bool `mapstructure:"interactive"` // Keep STDIN open even if not attached ShmSize int64 `mapstructure:"shm_size"` // Size of /dev/shm of the container in bytes WorkDir string `mapstructure:"work_dir"` // Working directory inside the container + Logging []DockerLoggingOpts `mapstructure:"logging"` // Logging options for syslog server } // Validate validates a docker driver config @@ -108,6 +115,18 @@ func (c *DockerDriverConfig) Validate() error { c.PortMap = mapMergeStrInt(c.PortMapRaw...) c.Labels = mapMergeStrStr(c.LabelsRaw...) + //if no logging is present, set default values. Otherwise, convert the raw logging data into a logging object + if len(c.Logging) != 0 { + c.Logging[0].Config = mapMergeStrStr(c.Logging[0].ConfigRaw...) + } else { + c.Logging = []DockerLoggingOpts{ + { + Type: "syslog", + Config: make(map[string]string), + }, + } + } + return nil } @@ -227,6 +246,9 @@ func (d *DockerDriver) Validate(config map[string]interface{}) error { "work_dir": &fields.FieldSchema{ Type: fields.TypeString, }, + "logging": &fields.FieldSchema{ + Type: fields.TypeArray, + }, }, } @@ -403,6 +425,20 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, } memLimit := int64(task.Resources.MemoryMB) * 1024 * 1024 + + if len(driverConfig.Logging) != 0 { + d.logger.Printf("[DEBUG] driver.docker: Setting default logging options to syslog and %s", syslogAddr) + if driverConfig.Logging[0].Type == "" { + driverConfig.Logging[0].Type = "syslog" + } + + if driverConfig.Logging[0].Config["syslog-address"] == "" { + driverConfig.Logging[0].Config["syslog-address"] = syslogAddr + } + } + + d.logger.Printf("[DEBUG] driver.docker: Using config for logging: %+v", driverConfig.Logging[0]) + hostConfig := &docker.HostConfig{ // Convert MB to bytes. This is an absolute value. Memory: memLimit, @@ -415,10 +451,8 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, // used to share data between different tasks in the same task group. Binds: binds, LogConfig: docker.LogConfig{ - Type: "syslog", - Config: map[string]string{ - "syslog-address": syslogAddr, - }, + Type: driverConfig.Logging[0].Type, + Config: driverConfig.Logging[0].Config, }, } From 7c077d2dae59af9207cc6703a98d428e5b49449d Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Lendholt Date: Tue, 20 Sep 2016 11:22:27 +0200 Subject: [PATCH 2/8] Added support to mount host folders into container. For example if you don't want to bake certificates into the container, you can mount them into the directory directly. Furthermore, I added support for volumes-from. Currently, there is no support to move the data from one container to another, hence: If a container spawns on another host, it is very likely, that the data will not be found. --- client/driver/docker.go | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/client/driver/docker.go b/client/driver/docker.go index bcf6ba521a5..3e73be12acf 100644 --- a/client/driver/docker.go +++ b/client/driver/docker.go @@ -104,6 +104,8 @@ type DockerDriverConfig struct { ShmSize int64 `mapstructure:"shm_size"` // Size of /dev/shm of the container in bytes WorkDir string `mapstructure:"work_dir"` // Working directory inside the container Logging []DockerLoggingOpts `mapstructure:"logging"` // Logging options for syslog server + Volumes []string `mapstructure:"volumes"` // Host-Volumes to mount in, syntax: /path/to/host/directory:/destination/path/in/container + VolumesFrom []string `mapstructure:"volumes_from"` // List of volumes-from } // Validate validates a docker driver config @@ -127,6 +129,14 @@ func (c *DockerDriverConfig) Validate() error { } } + if c.Volumes == nil { + c.Volumes = make([]string, 0) + } + + if c.VolumesFrom == nil { + c.VolumesFrom = make([]string, 0) + } + return nil } @@ -249,6 +259,12 @@ func (d *DockerDriver) Validate(config map[string]interface{}) error { "logging": &fields.FieldSchema{ Type: fields.TypeArray, }, + "volumes": &fields.FieldSchema{ + Type: fields.TypeArray, + }, + "volumes_from": &fields.FieldSchema{ + Type: fields.TypeArray, + }, }, } @@ -439,6 +455,10 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, d.logger.Printf("[DEBUG] driver.docker: Using config for logging: %+v", driverConfig.Logging[0]) + //Merge nomad container binds and user specified binds + d.logger.Printf("[DEBUG] Unmodified binds from nomad: %+v\n", binds) + binds = append(binds, driverConfig.Volumes...) + hostConfig := &docker.HostConfig{ // Convert MB to bytes. This is an absolute value. Memory: memLimit, @@ -449,7 +469,8 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, // Binds are used to mount a host volume into the container. We mount a // local directory for storage and a shared alloc directory that can be // used to share data between different tasks in the same task group. - Binds: binds, + Binds: binds, + VolumesFrom: driverConfig.VolumesFrom, LogConfig: docker.LogConfig{ Type: driverConfig.Logging[0].Type, Config: driverConfig.Logging[0].Config, @@ -459,6 +480,7 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, d.logger.Printf("[DEBUG] driver.docker: using %d bytes memory for %s", hostConfig.Memory, task.Name) d.logger.Printf("[DEBUG] driver.docker: using %d cpu shares for %s", hostConfig.CPUShares, task.Name) d.logger.Printf("[DEBUG] driver.docker: binding directories %#v for %s", hostConfig.Binds, task.Name) + d.logger.Printf("[DEBUG] driver.docker: binding Volumes-From: %#v for %s", hostConfig.VolumesFrom, task.Name) // set privileged mode hostPrivileged := d.config.ReadBoolDefault("docker.privileged.enabled", false) From 32a8e5b116822ad6d84a35477cf5bacd4956627b Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Lendholt Date: Thu, 22 Sep 2016 08:39:36 +0200 Subject: [PATCH 3/8] Fixed a bug when giving in another logging driver than syslog. Before this commit, if the Logging config did not contain a logging option "syslog-address", it would definitely insert this option. If then, you decide to take another logdriver than syslog, docker would fail because it received a wrong log option for the selected driver. Now, nomad will only insert the syslog address in a hard way if there are no logging options at all - this way it keeps the default nomad settings. --- client/driver/docker.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/client/driver/docker.go b/client/driver/docker.go index 3e73be12acf..ad522f94b85 100644 --- a/client/driver/docker.go +++ b/client/driver/docker.go @@ -446,9 +446,6 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, d.logger.Printf("[DEBUG] driver.docker: Setting default logging options to syslog and %s", syslogAddr) if driverConfig.Logging[0].Type == "" { driverConfig.Logging[0].Type = "syslog" - } - - if driverConfig.Logging[0].Config["syslog-address"] == "" { driverConfig.Logging[0].Config["syslog-address"] = syslogAddr } } From fe1e3c792fd6a0f94225312027de69a2dcd10b14 Mon Sep 17 00:00:00 2001 From: Michael Schurter Date: Tue, 27 Sep 2016 13:13:55 -0700 Subject: [PATCH 4/8] Put docker volume support behind conf flag Also add tests and fix bug with logging driver configuration. --- client/driver/docker.go | 91 +++++++++++---------- client/driver/docker_test.go | 94 ++++++++++++++++++++++ command/agent/config.go | 3 + website/source/docs/drivers/docker.html.md | 16 +++- 4 files changed, 161 insertions(+), 43 deletions(-) diff --git a/client/driver/docker.go b/client/driver/docker.go index ad522f94b85..f1ad0bae9cf 100644 --- a/client/driver/docker.go +++ b/client/driver/docker.go @@ -58,6 +58,10 @@ const ( // driver dockerDriverAttr = "driver.docker" + dockerSELinuxLabelConfigOption = "docker.volumes.selinuxlabel" + dockerVolumesConfigOption = "docker.volumes.enabled" + dockerPrivilegedConfigOption = "docker.privileged.enabled" + // dockerTimeout is the length of time a request can be outstanding before // it is timed out. dockerTimeout = 1 * time.Minute @@ -116,27 +120,9 @@ func (c *DockerDriverConfig) Validate() error { c.PortMap = mapMergeStrInt(c.PortMapRaw...) c.Labels = mapMergeStrStr(c.LabelsRaw...) - - //if no logging is present, set default values. Otherwise, convert the raw logging data into a logging object - if len(c.Logging) != 0 { + if len(c.Logging) > 0 { c.Logging[0].Config = mapMergeStrStr(c.Logging[0].ConfigRaw...) - } else { - c.Logging = []DockerLoggingOpts{ - { - Type: "syslog", - Config: make(map[string]string), - }, - } - } - - if c.Volumes == nil { - c.Volumes = make([]string, 0) } - - if c.VolumesFrom == nil { - c.VolumesFrom = make([]string, 0) - } - return nil } @@ -358,9 +344,9 @@ func (d *DockerDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool return false, nil } - privileged := d.config.ReadBoolDefault("docker.privileged.enabled", false) + privileged := d.config.ReadBoolDefault(dockerPrivilegedConfigOption, false) if privileged { - node.Attributes["docker.privileged.enabled"] = "1" + node.Attributes[dockerPrivilegedConfigOption] = "1" } // This is the first operation taken on the client so we'll try to @@ -377,10 +363,17 @@ func (d *DockerDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool node.Attributes[dockerDriverAttr] = "1" node.Attributes["driver.docker.version"] = env.Get("Version") + + if d.config.ReadBoolDefault(dockerVolumesConfigOption, false) { + node.Attributes["driver."+dockerVolumesConfigOption] = "1" + } + return true, nil } -func (d *DockerDriver) containerBinds(alloc *allocdir.AllocDir, task *structs.Task) ([]string, error) { +func (d *DockerDriver) containerBinds(driverConfig *DockerDriverConfig, alloc *allocdir.AllocDir, + task *structs.Task) ([]string, error) { + shared := alloc.SharedDir local, ok := alloc.TaskDirs[task.Name] if !ok { @@ -394,17 +387,34 @@ func (d *DockerDriver) containerBinds(alloc *allocdir.AllocDir, task *structs.Ta allocDirBind := fmt.Sprintf("%s:%s", shared, allocdir.SharedAllocContainerPath) taskLocalBind := fmt.Sprintf("%s:%s", local, allocdir.TaskLocalContainerPath) secretDirBind := fmt.Sprintf("%s:%s", secret, allocdir.TaskSecretsContainerPath) + binds := []string{allocDirBind, taskLocalBind, secretDirBind} - if selinuxLabel := d.config.Read("docker.volumes.selinuxlabel"); selinuxLabel != "" { - allocDirBind = fmt.Sprintf("%s:%s", allocDirBind, selinuxLabel) - taskLocalBind = fmt.Sprintf("%s:%s", taskLocalBind, selinuxLabel) - secretDirBind = fmt.Sprintf("%s:%s", secretDirBind, selinuxLabel) + var merr multierror.Error + volumesEnabled := d.config.ReadBoolDefault(dockerVolumesConfigOption, false) + if len(driverConfig.Volumes) > 0 && !volumesEnabled { + merr.Errors = append(merr.Errors, fmt.Errorf(dockerVolumesConfigOption+" is false; cannot use Docker Volumes: %+q", driverConfig.Volumes)) } - return []string{ - allocDirBind, - taskLocalBind, - secretDirBind, - }, nil + + if len(driverConfig.VolumesFrom) > 0 && !volumesEnabled { + merr.Errors = append(merr.Errors, fmt.Errorf(dockerVolumesConfigOption+" is false; cannot use Docker VolumesFrom: %+q", driverConfig.VolumesFrom)) + } + + if err := merr.ErrorOrNil(); err != nil { + return nil, err + } + + if len(driverConfig.Volumes) > 0 { + binds = append(binds, driverConfig.Volumes...) + } + + if selinuxLabel := d.config.Read(dockerSELinuxLabelConfigOption); selinuxLabel != "" { + // Apply SELinux Label to each volume + for i := range binds { + binds[i] = fmt.Sprintf("%s:%s", binds[i], selinuxLabel) + } + } + + return binds, nil } // createContainer initializes a struct needed to call docker.client.CreateContainer() @@ -418,7 +428,7 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, return c, fmt.Errorf("task.Resources is empty") } - binds, err := d.containerBinds(ctx.AllocDir, task) + binds, err := d.containerBinds(driverConfig, ctx.AllocDir, task) if err != nil { return c, err } @@ -442,20 +452,15 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, memLimit := int64(task.Resources.MemoryMB) * 1024 * 1024 - if len(driverConfig.Logging) != 0 { + if len(driverConfig.Logging) == 0 { d.logger.Printf("[DEBUG] driver.docker: Setting default logging options to syslog and %s", syslogAddr) - if driverConfig.Logging[0].Type == "" { - driverConfig.Logging[0].Type = "syslog" - driverConfig.Logging[0].Config["syslog-address"] = syslogAddr + driverConfig.Logging = []DockerLoggingOpts{ + {Type: "syslog", Config: map[string]string{"syslog-address": syslogAddr}}, } } d.logger.Printf("[DEBUG] driver.docker: Using config for logging: %+v", driverConfig.Logging[0]) - //Merge nomad container binds and user specified binds - d.logger.Printf("[DEBUG] Unmodified binds from nomad: %+v\n", binds) - binds = append(binds, driverConfig.Volumes...) - hostConfig := &docker.HostConfig{ // Convert MB to bytes. This is an absolute value. Memory: memLimit, @@ -477,10 +482,12 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, d.logger.Printf("[DEBUG] driver.docker: using %d bytes memory for %s", hostConfig.Memory, task.Name) d.logger.Printf("[DEBUG] driver.docker: using %d cpu shares for %s", hostConfig.CPUShares, task.Name) d.logger.Printf("[DEBUG] driver.docker: binding directories %#v for %s", hostConfig.Binds, task.Name) - d.logger.Printf("[DEBUG] driver.docker: binding Volumes-From: %#v for %s", hostConfig.VolumesFrom, task.Name) + if d.config.ReadBoolDefault(dockerVolumesConfigOption, false) { + d.logger.Printf("[DEBUG] driver.docker: binding Volumes-From: %#v for %s", hostConfig.VolumesFrom, task.Name) + } // set privileged mode - hostPrivileged := d.config.ReadBoolDefault("docker.privileged.enabled", false) + hostPrivileged := d.config.ReadBoolDefault(dockerPrivilegedConfigOption, false) if driverConfig.Privileged && !hostPrivileged { return c, fmt.Errorf(`Docker privileged mode is disabled on this Nomad agent`) } diff --git a/client/driver/docker_test.go b/client/driver/docker_test.go index 5029d9e787d..390652f1dca 100644 --- a/client/driver/docker_test.go +++ b/client/driver/docker_test.go @@ -4,6 +4,8 @@ import ( "fmt" "io/ioutil" "math/rand" + "os" + "path" "path/filepath" "reflect" "runtime/debug" @@ -17,6 +19,7 @@ import ( "github.com/hashicorp/nomad/client/config" "github.com/hashicorp/nomad/client/driver/env" "github.com/hashicorp/nomad/client/testutil" + "github.com/hashicorp/nomad/nomad/mock" "github.com/hashicorp/nomad/nomad/structs" tu "github.com/hashicorp/nomad/testutil" ) @@ -861,6 +864,97 @@ func TestDockerDriver_Stats(t *testing.T) { } +func setupDockerVolumes(t *testing.T, cfg *config.Config) (*structs.Task, Driver, *ExecContext, string, func()) { + if !testutil.DockerIsConnected(t) { + t.SkipNow() + } + + tmpvol, err := ioutil.TempDir("", "nomadtest_dockerdriver_volumes") + if err != nil { + t.Fatalf("error creating temporary dir: %v", err) + } + + randfn := fmt.Sprintf("test-%d", rand.Int()) + hostpath := path.Join(tmpvol, randfn) + contpath := path.Join("/mnt/vol", randfn) + + task := &structs.Task{ + Name: "ls", + Config: map[string]interface{}{ + "image": "busybox", + "load": []string{"busybox.tar"}, + "command": "touch", + "args": []string{contpath}, + "volumes": []string{fmt.Sprintf("%s:/mnt/vol", tmpvol)}, + }, + LogConfig: &structs.LogConfig{ + MaxFiles: 10, + MaxFileSizeMB: 10, + }, + Resources: basicResources, + } + + allocDir := allocdir.NewAllocDir(filepath.Join(cfg.AllocDir, structs.GenerateUUID()), task.Resources.DiskMB) + allocDir.Build([]*structs.Task{task}) + alloc := mock.Alloc() + execCtx := NewExecContext(allocDir, alloc.ID) + cleanup := func() { + execCtx.AllocDir.Destroy() + os.RemoveAll(tmpvol) + } + + taskEnv, err := GetTaskEnv(allocDir, cfg.Node, task, alloc, "") + if err != nil { + cleanup() + t.Fatalf("Failed to get task env: %v", err) + } + + driverCtx := NewDriverContext(task.Name, cfg, cfg.Node, testLogger(), taskEnv) + driver := NewDockerDriver(driverCtx) + copyImage(execCtx, task, "busybox.tar", t) + + return task, driver, execCtx, hostpath, cleanup +} + +func TestDockerDriver_VolumesDisabled(t *testing.T) { + cfg := testConfig() + + task, driver, execCtx, _, cleanup := setupDockerVolumes(t, cfg) + defer cleanup() + + _, err := driver.Start(execCtx, task) + if err == nil { + t.Fatalf("Started driver successfully when volumes should have been disabled.") + } +} + +func TestDockerDriver_VolumesEnabled(t *testing.T) { + cfg := testConfig() + cfg.Options = map[string]string{dockerVolumesConfigOption: "true"} + + task, driver, execCtx, hostpath, cleanup := setupDockerVolumes(t, cfg) + defer cleanup() + + handle, err := driver.Start(execCtx, task) + if err != nil { + t.Fatalf("Failed to start docker driver: %v", err) + } + defer handle.Kill() + + select { + case res := <-handle.WaitCh(): + if !res.Successful() { + t.Fatalf("unexpected err: %v", res) + } + case <-time.After(time.Duration(tu.TestMultiplier()*10) * time.Second): + t.Fatalf("timeout") + } + + if _, err := ioutil.ReadFile(hostpath); err != nil { + t.Fatalf("unexpected error reading %s: %v", hostpath, err) + } +} + func copyImage(execCtx *ExecContext, task *structs.Task, image string, t *testing.T) { taskDir, _ := execCtx.AllocDir.TaskDirs[task.Name] dst := filepath.Join(taskDir, allocdir.TaskLocal, image) diff --git a/command/agent/config.go b/command/agent/config.go index 27de7fff920..bb7692289e8 100644 --- a/command/agent/config.go +++ b/command/agent/config.go @@ -432,6 +432,9 @@ func DevConfig() *Config { conf.Client.Options = map[string]string{ "driver.raw_exec.enable": "true", } + conf.Client.Options = map[string]string{ + "driver.docker.volumes": "true", + } return conf } diff --git a/website/source/docs/drivers/docker.html.md b/website/source/docs/drivers/docker.html.md index 6051a5fb1a9..fef8aac9412 100644 --- a/website/source/docs/drivers/docker.html.md +++ b/website/source/docs/drivers/docker.html.md @@ -137,6 +137,14 @@ The `docker` driver supports the following configuration in the job spec: * `shm_size` - (Optional) The size (bytes) of /dev/shm for the container. +* `volumes` - (Optional) A list of `host_path:container_path` strings to bind + host paths to container paths. Can only be run on clients with the + `docker.volumes.enabled` option set to true. + +* `volumes_from` - (Optional) A list of volumes to inherit from another + container. Can only be run on clients with the `docker.volumes.enabled` + option set to true. + * `work_dir` - (Optional) The working directory inside the container. ### Container Name @@ -329,8 +337,14 @@ options](/docs/agent/config.html#options): * `docker.cleanup.image` Defaults to `true`. Changing this to `false` will prevent Nomad from removing images from stopped tasks. +* `docker.volumes.enabled`: Defaults to `false`. Allows tasks to bind host + paths (`volumes`) or other containers (`volums_from`) inside their container. + Disabled by default as it removes the isolation between containers' data. + * `docker.volumes.selinuxlabel`: Allows the operator to set a SELinux - label to the allocation and task local bind-mounts to containers. + label to the allocation and task local bind-mounts to containers. If used + with `docker.volumes.enabled` set to false, the labels will still be applied + to the standard binds in the container. * `docker.privileged.enabled` Defaults to `false`. Changing this to `true` will allow containers to use `privileged` mode, which gives the containers full From cc5b40e54e65b09e169e53932427dfd9e4d3e0f0 Mon Sep 17 00:00:00 2001 From: Michael Schurter Date: Mon, 3 Oct 2016 15:22:10 -0700 Subject: [PATCH 5/8] Only launch syslog server if container uses syslog --- client/driver/docker.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/client/driver/docker.go b/client/driver/docker.go index f1ad0bae9cf..18359d46c02 100644 --- a/client/driver/docker.go +++ b/client/driver/docker.go @@ -791,12 +791,18 @@ func (d *DockerDriver) Start(ctx *ExecContext, task *structs.Task) (DriverHandle PortLowerBound: d.config.ClientMinPort, PortUpperBound: d.config.ClientMaxPort, } - ss, err := exec.LaunchSyslogServer(executorCtx) - if err != nil { - return nil, fmt.Errorf("failed to start syslog collector: %v", err) + + // Only launch syslog server if we're going to use it! + syslogAddr := "" + if len(driverConfig.Logging) == 0 || driverConfig.Logging[0].Type == "syslog" { + ss, err := exec.LaunchSyslogServer(executorCtx) + if err != nil { + return nil, fmt.Errorf("failed to start syslog collector: %v", err) + } + syslogAddr = ss.Addr } - config, err := d.createContainer(ctx, task, driverConfig, ss.Addr) + config, err := d.createContainer(ctx, task, driverConfig, syslogAddr) if err != nil { d.logger.Printf("[ERR] driver.docker: failed to create container configuration for image %s: %s", image, err) pluginClient.Kill() From 297d637a5989bdc917dfb37e46c3e7ab51b0d52c Mon Sep 17 00:00:00 2001 From: Michael Schurter Date: Mon, 3 Oct 2016 16:04:33 -0700 Subject: [PATCH 6/8] Add comments to config key constants --- client/driver/docker.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/client/driver/docker.go b/client/driver/docker.go index 18359d46c02..fb948779658 100644 --- a/client/driver/docker.go +++ b/client/driver/docker.go @@ -58,9 +58,17 @@ const ( // driver dockerDriverAttr = "driver.docker" + // dockerSELinuxLabelConfigOption is the key for configuring the + // SELinux label for binds. dockerSELinuxLabelConfigOption = "docker.volumes.selinuxlabel" - dockerVolumesConfigOption = "docker.volumes.enabled" - dockerPrivilegedConfigOption = "docker.privileged.enabled" + + // dockerVolumesConfigOption is the key for enabling the use of custom + // bind volumes. + dockerVolumesConfigOption = "docker.volumes.enabled" + + // dockerPrivilegedConfigOption is the key for running containers in + // Docker's privileged mode. + dockerPrivilegedConfigOption = "docker.privileged.enabled" // dockerTimeout is the length of time a request can be outstanding before // it is timed out. From e876c6c1a02ea2775e03ab9cdb0538298f01f14a Mon Sep 17 00:00:00 2001 From: Michael Schurter Date: Mon, 3 Oct 2016 16:28:02 -0700 Subject: [PATCH 7/8] Remove VolumesFrom feature Since containers are named with alloc ids it's difficult to use safely. Not to mention task scheduling ordering issues could break it as well. --- client/driver/docker.go | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/client/driver/docker.go b/client/driver/docker.go index fb948779658..66e77416f5f 100644 --- a/client/driver/docker.go +++ b/client/driver/docker.go @@ -117,7 +117,6 @@ type DockerDriverConfig struct { WorkDir string `mapstructure:"work_dir"` // Working directory inside the container Logging []DockerLoggingOpts `mapstructure:"logging"` // Logging options for syslog server Volumes []string `mapstructure:"volumes"` // Host-Volumes to mount in, syntax: /path/to/host/directory:/destination/path/in/container - VolumesFrom []string `mapstructure:"volumes_from"` // List of volumes-from } // Validate validates a docker driver config @@ -256,9 +255,6 @@ func (d *DockerDriver) Validate(config map[string]interface{}) error { "volumes": &fields.FieldSchema{ Type: fields.TypeArray, }, - "volumes_from": &fields.FieldSchema{ - Type: fields.TypeArray, - }, }, } @@ -397,18 +393,9 @@ func (d *DockerDriver) containerBinds(driverConfig *DockerDriverConfig, alloc *a secretDirBind := fmt.Sprintf("%s:%s", secret, allocdir.TaskSecretsContainerPath) binds := []string{allocDirBind, taskLocalBind, secretDirBind} - var merr multierror.Error volumesEnabled := d.config.ReadBoolDefault(dockerVolumesConfigOption, false) if len(driverConfig.Volumes) > 0 && !volumesEnabled { - merr.Errors = append(merr.Errors, fmt.Errorf(dockerVolumesConfigOption+" is false; cannot use Docker Volumes: %+q", driverConfig.Volumes)) - } - - if len(driverConfig.VolumesFrom) > 0 && !volumesEnabled { - merr.Errors = append(merr.Errors, fmt.Errorf(dockerVolumesConfigOption+" is false; cannot use Docker VolumesFrom: %+q", driverConfig.VolumesFrom)) - } - - if err := merr.ErrorOrNil(); err != nil { - return nil, err + return nil, fmt.Errorf(dockerVolumesConfigOption+" is false; cannot use Docker Volumes: %+q", driverConfig.Volumes) } if len(driverConfig.Volumes) > 0 { @@ -479,8 +466,7 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, // Binds are used to mount a host volume into the container. We mount a // local directory for storage and a shared alloc directory that can be // used to share data between different tasks in the same task group. - Binds: binds, - VolumesFrom: driverConfig.VolumesFrom, + Binds: binds, LogConfig: docker.LogConfig{ Type: driverConfig.Logging[0].Type, Config: driverConfig.Logging[0].Config, @@ -490,9 +476,6 @@ func (d *DockerDriver) createContainer(ctx *ExecContext, task *structs.Task, d.logger.Printf("[DEBUG] driver.docker: using %d bytes memory for %s", hostConfig.Memory, task.Name) d.logger.Printf("[DEBUG] driver.docker: using %d cpu shares for %s", hostConfig.CPUShares, task.Name) d.logger.Printf("[DEBUG] driver.docker: binding directories %#v for %s", hostConfig.Binds, task.Name) - if d.config.ReadBoolDefault(dockerVolumesConfigOption, false) { - d.logger.Printf("[DEBUG] driver.docker: binding Volumes-From: %#v for %s", hostConfig.VolumesFrom, task.Name) - } // set privileged mode hostPrivileged := d.config.ReadBoolDefault(dockerPrivilegedConfigOption, false) From 7d115a3fae073547445150ddb66289c23b7c580d Mon Sep 17 00:00:00 2001 From: Michael Schurter Date: Mon, 3 Oct 2016 16:35:16 -0700 Subject: [PATCH 8/8] Add comment and fix log line code style --- client/driver/docker.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/driver/docker.go b/client/driver/docker.go index 66e77416f5f..d4f21088dab 100644 --- a/client/driver/docker.go +++ b/client/driver/docker.go @@ -368,6 +368,7 @@ func (d *DockerDriver) Fingerprint(cfg *config.Config, node *structs.Node) (bool node.Attributes[dockerDriverAttr] = "1" node.Attributes["driver.docker.version"] = env.Get("Version") + // Advertise if this node supports Docker volumes (by default we do not) if d.config.ReadBoolDefault(dockerVolumesConfigOption, false) { node.Attributes["driver."+dockerVolumesConfigOption] = "1" } @@ -395,7 +396,7 @@ func (d *DockerDriver) containerBinds(driverConfig *DockerDriverConfig, alloc *a volumesEnabled := d.config.ReadBoolDefault(dockerVolumesConfigOption, false) if len(driverConfig.Volumes) > 0 && !volumesEnabled { - return nil, fmt.Errorf(dockerVolumesConfigOption+" is false; cannot use Docker Volumes: %+q", driverConfig.Volumes) + return nil, fmt.Errorf("%s is false; cannot use Docker Volumes: %+q", dockerVolumesConfigOption, driverConfig.Volumes) } if len(driverConfig.Volumes) > 0 {