Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add network_aliases for docker driver #1980

Merged
merged 1 commit into from
Dec 19, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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