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 support for Custom Network and Network Alias settings #3793

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ additional details on each available environment variable.
| `ECS_DYNAMIC_HOST_PORT_RANGE` | `100-200` | This specifies the dynamic host port range that the agent uses to assign host ports from, for container ports mapping. If there are no available ports in the range for containers, including customer containers and Service Connect Agent containers (if Service Connect is enabled), service deployments would fail. | Defined by `/proc/sys/net/ipv4/ip_local_port_range` | `49152-65535` |
| `ECS_TASK_PIDS_LIMIT` | `100` | Specifies the per-task pids limit cgroup setting for each task launched on the container instance. This setting maps to the pids.max cgroup setting at the ECS task level. See https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html#pid. If unset, pids will be unlimited. Min value is 1 and max value is 4194304 (4*1024*1024) | `unset` | Not Supported on Windows |
| `ECS_EBSTA_SUPPORTED` | `true` | Whether to use the container instance with EBS Task Attach support. This variable is set properly by ecs-init. Its value indicates if correct environment to support EBS volumes by instance has been set up or not. ECS only schedules EBSTA tasks if this feature is supported by the platform type. Check [EBS Volume considerations](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ebs-volumes.html#ebs-volume-considerations) for other EBS support details | `true` | Not Supported on Windows |
|`ECS_OVERRIDE_BRIDGE_NETWORK_NAME` | `ecs` | This value specifies a docker network name used for cotnainers scheduled with a bridge type | `` | `` |
jsuchenia marked this conversation as resolved.
Show resolved Hide resolved
|`ECS_ADD_CONTAINER_NAME_AS_NETWORK_ALIAS` | `true` | This value tell ECS agent to assign a container name as docker network alias name - it can be used only in a custom docker networks, so only when `ECS_OVERRIDE_BRIDGE_NETWORK_NAME` is non-empty | `true` | `true` |

Additionally, the following environment variable(s) can be used to configure the behavior of the ecs-init service. When using ECS-Init, all env variables, including the ECS Agent variables above, are read from path `/etc/ecs/ecs.config`:
| Environment Variable Name | Example Value(s) | Description | Default value |
Expand Down
2 changes: 2 additions & 0 deletions agent/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,8 @@ func environmentConfig() (Config, error) {
WarmPoolsSupport: parseBooleanDefaultFalseConfig("ECS_WARM_POOLS_CHECK"),
DynamicHostPortRange: parseDynamicHostPortRange("ECS_DYNAMIC_HOST_PORT_RANGE"),
TaskPidsLimit: parseTaskPidsLimit(),
OverrideBridgeNetworkName: os.Getenv("ECS_OVERRIDE_BRIDGE_NETWORK_NAME"),
AddContainerNameAsNetworkAlias: parseBooleanDefaultTrueConfig("ECS_ADD_CONTAINER_NAME_AS_NETWORK_ALIAS"),
}, err
}

Expand Down
5 changes: 5 additions & 0 deletions agent/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,4 +394,9 @@ type Config struct {

// NodeUnstageTimeout is the amount of time to wait for unstaging an EBS TA volume
NodeUnstageTimeout time.Duration
// OverrideBridgeNetworkName is a custom bridge name used for docker container - it has to be created before an agent start
OverrideBridgeNetworkName string `trim:"true"`

// AddContainerNameAsNetworkAlias specifies whether container name should be added as network alias
AddContainerNameAsNetworkAlias BooleanDefaultTrue
}
17 changes: 16 additions & 1 deletion agent/dockerclient/dockerapi/docker_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ const (
dockerContainerDieEvent = "die"
// dockerContainerEventExitCodeAttribute is the attribute name to get exit code from Docker event attribute.
dockerContainerEventExitCodeAttribute = "exitCode"
// NetworkAliasDockerLabel is a nanme of docker label to set a network alias value
NetworkAliasDockerLabel = "com.amazonaws.ecs.network-alias"
)

// Timelimits for docker operations enforced above docker
Expand Down Expand Up @@ -715,7 +717,20 @@ func (dg *dockerGoClient) createContainer(ctx context.Context,
return DockerContainerMetadata{Error: CannotGetDockerClientError{version: dg.version, err: err}}
}

dockerContainer, err := client.ContainerCreate(ctx, config, hostConfig, &network.NetworkingConfig{}, nil, name)
networkConfig := network.NetworkingConfig{
EndpointsConfig: make(map[string]*network.EndpointSettings),
}

if config.Labels != nil { // This can happen only in tests
networkAliasName, networkAliasExists := config.Labels[NetworkAliasDockerLabel]
if networkAliasExists && hostConfig.NetworkMode.IsUserDefined() {
networkConfig.EndpointsConfig[hostConfig.NetworkMode.UserDefined()] = &network.EndpointSettings{
Aliases: []string{networkAliasName},
}
}
}

dockerContainer, err := client.ContainerCreate(ctx, config, hostConfig, &networkConfig, nil, name)
if err != nil {
return DockerContainerMetadata{Error: CannotCreateContainerError{err}}
}
Expand Down
10 changes: 7 additions & 3 deletions agent/dockerclient/dockerapi/docker_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -574,8 +574,10 @@ func TestCreateContainerTimeout(t *testing.T) {
wait := &sync.WaitGroup{}
wait.Add(1)
hostConfig := &dockercontainer.HostConfig{Resources: dockercontainer.Resources{Memory: 100}}
mockDockerSDK.EXPECT().ContainerCreate(gomock.Any(), &dockercontainer.Config{}, hostConfig,
&network.NetworkingConfig{}, gomock.Any(), "containerName").Do(func(u, v, w, x, y, z interface{}) {
networkConfig := &network.NetworkingConfig{EndpointsConfig: make(map[string]*network.EndpointSettings)}

mockDockerSDK.EXPECT().ContainerCreate(gomock.Any(), &dockercontainer.Config{}, hostConfig, networkConfig,
gomock.Any(), "containerName").Do(func(u, v, w, x, y, z interface{}) {
wait.Wait()
}).MaxTimes(1).Return(dockercontainer.CreateResponse{}, errors.New("test error"))
ctx, cancel := context.WithCancel(context.TODO())
Expand All @@ -592,6 +594,8 @@ func TestCreateContainer(t *testing.T) {

name := "containerName"
hostConfig := &dockercontainer.HostConfig{Resources: dockercontainer.Resources{Memory: 100}}
dockerContainerConfig := &dockercontainer.Config{}

gomock.InOrder(
mockDockerSDK.EXPECT().ContainerCreate(gomock.Any(), gomock.Any(), hostConfig, gomock.Any(), gomock.Any(), name).
Do(func(u, v, actualHostConfig, x, y, actualName interface{}) {
Expand All @@ -609,7 +613,7 @@ func TestCreateContainer(t *testing.T) {
)
ctx, cancel := context.WithCancel(context.TODO())
defer cancel()
metadata := client.CreateContainer(ctx, nil, hostConfig, name, defaultTestConfig().ContainerCreateTimeout)
metadata := client.CreateContainer(ctx, dockerContainerConfig, hostConfig, name, defaultTestConfig().ContainerCreateTimeout)
assert.NoError(t, metadata.Error)
assert.Equal(t, "id", metadata.DockerID)
assert.Nil(t, metadata.ExitCode, "Expected a created container to not have an exit code")
Expand Down
12 changes: 12 additions & 0 deletions agent/engine/docker_task_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -2016,6 +2016,18 @@ func (engine *DockerTaskEngine) createContainer(task *apitask.Task, container *a
config.Labels[labelTaskDefinitionVersion] = task.Version
config.Labels[labelCluster] = engine.cfg.Cluster

if task.IsNetworkModeBridge() && engine.cfg.OverrideBridgeNetworkName != "" {
logger.Info("Assigning docker container to a custom network", logger.Fields{
field.TaskID: task.GetID(),
field.Container: container.Name,
"network": engine.cfg.OverrideBridgeNetworkName,
})
hostConfig.NetworkMode = dockercontainer.NetworkMode(engine.cfg.OverrideBridgeNetworkName)
if engine.cfg.AddContainerNameAsNetworkAlias.Enabled() {
config.Labels[dockerapi.NetworkAliasDockerLabel] = container.Name
}
}

if dockerContainerName == "" {
// only alphanumeric and hyphen characters are allowed
reInvalidChars := regexp.MustCompile("[^A-Za-z0-9-]+")
Expand Down