Skip to content

Commit

Permalink
Add network_aliases for docker driver
Browse files Browse the repository at this point in the history
  • Loading branch information
dmexe committed Nov 16, 2016
1 parent 1c4575f commit 49416eb
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 11 deletions.
23 changes: 20 additions & 3 deletions client/driver/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ type DockerDriverConfig struct {
Args []string `mapstructure:"args"` // The arguments to the Command/Entrypoint
IpcMode string `mapstructure:"ipc_mode"` // The IPC mode of the container - host and none
NetworkMode string `mapstructure:"network_mode"` // The network mode of the container - host, nat and none
NetworkAliases []string `mapstructure:"network_aliases"` // The network-scoped alias for the container
PidMode string `mapstructure:"pid_mode"` // The PID mode of the container - host and none
UTSMode string `mapstructure:"uts_mode"` // The UTS mode of the container - host and none
UsernsMode string `mapstructure:"userns_mode"` // The User namespace mode of the container - host and none
Expand Down Expand Up @@ -154,6 +155,7 @@ func NewDockerDriverConfig(task *structs.Task, env *env.TaskEnvironment) (*Docke
dconf.Command = env.ReplaceEnv(dconf.Command)
dconf.IpcMode = env.ReplaceEnv(dconf.IpcMode)
dconf.NetworkMode = env.ReplaceEnv(dconf.NetworkMode)
dconf.NetworkAliases = env.ParseAndReplace(dconf.NetworkAliases)
dconf.PidMode = env.ReplaceEnv(dconf.PidMode)
dconf.UTSMode = env.ReplaceEnv(dconf.UTSMode)
dconf.Hostname = env.ReplaceEnv(dconf.Hostname)
Expand Down Expand Up @@ -261,6 +263,9 @@ func (d *DockerDriver) Validate(config map[string]interface{}) error {
"network_mode": &fields.FieldSchema{
Type: fields.TypeString,
},
"network_aliases": &fields.FieldSchema{
Type: fields.TypeArray,
},
"pid_mode": &fields.FieldSchema{
Type: fields.TypeString,
},
Expand Down Expand Up @@ -818,10 +823,22 @@ func (d *DockerDriver) createContainerConfig(ctx *ExecContext, task *structs.Tas
containerName := fmt.Sprintf("%s-%s", task.Name, ctx.AllocID)
d.logger.Printf("[DEBUG] driver.docker: setting container name to: %s", containerName)

networkingConfig := &docker.NetworkingConfig{
EndpointsConfig: make(map[string]*docker.EndpointConfig),
}

if len(driverConfig.NetworkAliases) > 0 {
networkingConfig.EndpointsConfig[hostConfig.NetworkMode] = &docker.EndpointConfig{
Aliases: driverConfig.NetworkAliases,
}
d.logger.Printf("[DEBUG] driver.docker: applied network aliases on the container: [%s]%+v", hostConfig.NetworkMode, driverConfig.NetworkAliases)
}

return docker.CreateContainerOptions{
Name: containerName,
Config: config,
HostConfig: hostConfig,
Name: containerName,
Config: config,
HostConfig: hostConfig,
NetworkingConfig: networkingConfig,
}, nil
}

Expand Down
69 changes: 61 additions & 8 deletions client/driver/docker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,11 @@ func dockerTask() (*structs.Task, int, int) {
// If there is a problem during setup this function will abort or skip the test
// and indicate the reason.
func dockerSetup(t *testing.T, task *structs.Task) (*docker.Client, DriverHandle, func()) {
if !testutil.DockerIsConnected(t) {
t.SkipNow()
}

client, err := docker.NewClientFromEnv()
if err != nil {
t.Fatalf("Failed to initialize client: %s\nStack\n%s", err, debug.Stack())
}
client := newTestDockerClient(t)
return dockerSetupWithClient(t, task, client)
}

func dockerSetupWithClient(t *testing.T, task *structs.Task, client *docker.Client) (*docker.Client, DriverHandle, func()) {
driverCtx, execCtx := testDriverContexts(task)
driverCtx.config.Options = map[string]string{"docker.cleanup.image": "false"}
driver := NewDockerDriver(driverCtx)
Expand All @@ -119,6 +115,18 @@ func dockerSetup(t *testing.T, task *structs.Task) (*docker.Client, DriverHandle
return client, handle, cleanup
}

func newTestDockerClient(t *testing.T) *docker.Client {
if !testutil.DockerIsConnected(t) {
t.SkipNow()
}

client, err := docker.NewClientFromEnv()
if err != nil {
t.Fatalf("Failed to initialize client: %s\nStack\n%s", err, debug.Stack())
}
return client
}

// This test should always pass, even if docker daemon is not available
func TestDockerDriver_Fingerprint(t *testing.T) {
driverCtx, execCtx := testDriverContexts(&structs.Task{Name: "foo", Resources: basicResources})
Expand Down Expand Up @@ -589,6 +597,51 @@ func TestDockerDriver_NetworkMode_Host(t *testing.T) {
}
}

func TestDockerDriver_NetworkAliases_Bridge(t *testing.T) {
// Because go-dockerclient doesn't provide api for query network aliases, just check that
// a container can be created with a 'network_aliases' property

// Create network, network-scoped alias is supported only for containers in user defined networks
client := newTestDockerClient(t)
networkOpts := docker.CreateNetworkOptions{Name: "foobar", Driver: "bridge"}
network, err := client.CreateNetwork(networkOpts)
if err != nil {
t.Fatalf("err: %v", err)
}
defer client.RemoveNetwork(network.ID)

expected := []string{"foobar"}
task := &structs.Task{
Name: "nc-demo",
Config: map[string]interface{}{
"image": "busybox",
"load": []string{"busybox.tar"},
"command": "/bin/nc",
"args": []string{"-l", "127.0.0.1", "-p", "0"},
"network_mode": network.Name,
"network_aliases": expected,
},
Resources: &structs.Resources{
MemoryMB: 256,
CPU: 512,
},
LogConfig: &structs.LogConfig{
MaxFiles: 10,
MaxFileSizeMB: 10,
},
}

client, handle, cleanup := dockerSetupWithClient(t, task, client)
defer cleanup()

waitForExist(t, client, handle.(*DockerHandle))

_, err = client.InspectContainer(handle.(*DockerHandle).ContainerID())
if err != nil {
t.Fatalf("err: %v", err)
}
}

func TestDockerDriver_Labels(t *testing.T) {
task, _, _ := dockerTask()
task.Config["labels"] = []map[string]string{
Expand Down
15 changes: 15 additions & 0 deletions website/source/docs/drivers/docker.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,21 @@ The `docker` driver supports the following configuration in the job spec:
pre-docker 1.9 are `default`, `bridge`, `host`, `none`, or `container:name`.
See below for more details.

* `network_aliases` - (Optional) A list of network-scoped aliases, provide a way for a
container to be discovered by an alternate name by any other container within
the scope of a particular network. Network-scoped alias is supported only for
containers in user defined networks

```hcl
config {
network_mode = "overlay"
network_aliases = [
"${NOMAD_TASK_NAME}",
"${NOMAD_TASK_NAME}-${NOMAD_ALLOC_INDEX}"
]
}
```

* `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 49416eb

Please sign in to comment.