From 7ec96852c527ba5fb964643ffe0edeac7d9eb897 Mon Sep 17 00:00:00 2001 From: Chien-Han Lin Date: Sun, 12 Sep 2021 21:33:54 -0700 Subject: [PATCH] Introduce a new environment variable ECS_EXCLUDE_IPV6_PORTBINDING --- README.md | 3 ++- agent/api/ecsclient/client.go | 20 +++++++++++++------- agent/api/ecsclient/client_test.go | 7 ++++--- agent/config/config.go | 3 +++ agent/config/config_test.go | 2 ++ agent/config/config_unix.go | 1 + agent/config/config_unix_test.go | 1 + agent/config/config_windows.go | 1 + agent/config/config_windows_test.go | 1 + agent/config/types.go | 5 +++++ 10 files changed, 33 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index ebedc73916a..71e4f9c2f5b 100644 --- a/README.md +++ b/README.md @@ -194,7 +194,8 @@ additional details on each available environment variable. | `ECS_ENABLE_AWSLOGS_EXECUTIONROLE_OVERRIDE` | `true` | Whether to enable awslogs log driver to authenticate via credentials of task execution IAM role. Needs to be true if you want to use awslogs log driver in a task that has task execution IAM role specified. When using the ecs-init RPM with version equal or later than V1.16.0-1, this env is set to true by default. | `false` | `false` | | `ECS_FSX_WINDOWS_FILE_SERVER_SUPPORTED` | `true` | Whether FSx for Windows File Server volume type is supported on the container instance. This variable is only supported on agent versions 1.47.0 and later. | `false` | `true` | | `ECS_ENABLE_RUNTIME_STATS` | `true` | Determines if [pprof](https://pkg.go.dev/net/http/pprof) is enabled for the agent. If enabled, the different profiles can be accessed through the agent's introspection port (e.g. `curl http://localhost:51678/debug/pprof/heap > heap.pprof`). In addition, agent's [runtime stats](https://pkg.go.dev/runtime#ReadMemStats) are logged to `/var/log/ecs/runtime-stats.log` file. | `false` | `false` | - +| `ECS_EXCLUDE_IPV6_PORTBINDING` | `true` | Determines if agent should exclude IPv6 port binding using default network mode. If enabled, IPv6 port binding will be filtered out, and the response of DescribeTasks API call will not show tasks' IPv6 port bindings, but it is still included in Task metadata endpoint. | `true` | `true` | + ### Persistence When you run the Amazon ECS Container Agent in production, its `datadir` should be persisted between runs of the Docker diff --git a/agent/api/ecsclient/client.go b/agent/api/ecsclient/client.go index 39e8e21fdea..4fe7e061d3c 100644 --- a/agent/api/ecsclient/client.go +++ b/agent/api/ecsclient/client.go @@ -413,7 +413,7 @@ func (client *APIECSClient) SubmitTaskStateChange(change api.TaskStateChange) er containerEvents := make([]*ecs.ContainerStateChange, len(change.Containers)) for i, containerEvent := range change.Containers { - containerEvents[i] = client.buildContainerStateChangePayload(containerEvent) + containerEvents[i] = client.buildContainerStateChangePayload(containerEvent, client.config.ShouldExcludeIPv6PortBinding.Enabled()) } req.Containers = containerEvents @@ -454,7 +454,7 @@ func (client *APIECSClient) buildManagedAgentStateChangePayload(change api.Manag } } -func (client *APIECSClient) buildContainerStateChangePayload(change api.ContainerStateChange) *ecs.ContainerStateChange { +func (client *APIECSClient) buildContainerStateChangePayload(change api.ContainerStateChange, shouldExcludeIPv6PortBinding bool) *ecs.ContainerStateChange { statechange := &ecs.ContainerStateChange{ ContainerName: aws.String(change.ContainerName), } @@ -487,19 +487,25 @@ func (client *APIECSClient) buildContainerStateChangePayload(change api.Containe exitCode := int64(aws.IntValue(change.ExitCode)) statechange.ExitCode = aws.Int64(exitCode) } - networkBindings := make([]*ecs.NetworkBinding, len(change.PortBindings)) - for i, binding := range change.PortBindings { + + networkBindings := []*ecs.NetworkBinding{} + for _, binding := range change.PortBindings { + if binding.BindIP == "::" && shouldExcludeIPv6PortBinding { + seelog.Debugf("Exclude IPv6 port binding %v for container %s in task %s", binding, change.ContainerName, change.TaskArn) + continue + } + hostPort := int64(binding.HostPort) containerPort := int64(binding.ContainerPort) bindIP := binding.BindIP protocol := binding.Protocol.String() - networkBindings[i] = &ecs.NetworkBinding{ + networkBindings = append(networkBindings, &ecs.NetworkBinding{ BindIP: aws.String(bindIP), ContainerPort: aws.Int64(containerPort), HostPort: aws.Int64(hostPort), Protocol: aws.String(protocol), - } + }) } statechange.NetworkBindings = networkBindings @@ -507,7 +513,7 @@ func (client *APIECSClient) buildContainerStateChangePayload(change api.Containe } func (client *APIECSClient) SubmitContainerStateChange(change api.ContainerStateChange) error { - pl := client.buildContainerStateChangePayload(change) + pl := client.buildContainerStateChangePayload(change, client.config.ShouldExcludeIPv6PortBinding.Enabled()) if pl == nil { return nil } diff --git a/agent/api/ecsclient/client_test.go b/agent/api/ecsclient/client_test.go index 532251eb651..12201241a23 100644 --- a/agent/api/ecsclient/client_test.go +++ b/agent/api/ecsclient/client_test.go @@ -84,9 +84,10 @@ func NewMockClient(ctrl *gomock.Controller, return NewMockClientWithConfig(ctrl, ec2Metadata, additionalAttributes, &config.Config{ - Cluster: configuredCluster, - AWSRegion: "us-east-1", - InstanceAttributes: additionalAttributes, + Cluster: configuredCluster, + AWSRegion: "us-east-1", + InstanceAttributes: additionalAttributes, + ShouldExcludeIPv6PortBinding: config.BooleanDefaultTrue{Value: config.ExplicitlyEnabled}, }) } diff --git a/agent/config/config.go b/agent/config/config.go index bf6f38a1785..9ea42df06d3 100644 --- a/agent/config/config.go +++ b/agent/config/config.go @@ -591,6 +591,7 @@ func environmentConfig() (Config, error) { FSxWindowsFileServerCapable: parseFSxWindowsFileServerCapability(), External: parseBooleanDefaultFalseConfig("ECS_EXTERNAL"), EnableRuntimeStats: parseBooleanDefaultFalseConfig("ECS_ENABLE_RUNTIME_STATS"), + ShouldExcludeIPv6PortBinding: parseBooleanDefaultTrueConfig("ECS_EXCLUDE_IPV6_PORTBINDING"), }, err } @@ -623,6 +624,7 @@ func (cfg *Config) String() string { "ContainerCreateTimeout: %v, "+ "DependentContainersPullUpfront: %v, "+ "TaskCPUMemLimit: %v, "+ + "ShouldExcludeIPv6PortBinding: %v, "+ "%s", cfg.Cluster, cfg.AWSRegion, @@ -640,6 +642,7 @@ func (cfg *Config) String() string { cfg.ContainerCreateTimeout, cfg.DependentContainersPullUpfront, cfg.TaskCPUMemLimit, + cfg.ShouldExcludeIPv6PortBinding, cfg.platformString(), ) } diff --git a/agent/config/config_test.go b/agent/config/config_test.go index 929020e7af2..03bc0a88990 100644 --- a/agent/config/config_test.go +++ b/agent/config/config_test.go @@ -157,6 +157,7 @@ func TestEnvironmentConfig(t *testing.T) { defer setTestEnv("ECS_CGROUP_CPU_PERIOD", "") defer setTestEnv("ECS_PULL_DEPENDENT_CONTAINERS_UPFRONT", "true")() defer setTestEnv("ECS_ENABLE_RUNTIME_STATS", "true")() + defer setTestEnv("ECS_EXCLUDE_IPV6_PORTBINDING", "true")() additionalLocalRoutesJSON := `["1.2.3.4/22","5.6.7.8/32"]` setTestEnv("ECS_AWSVPC_ADDITIONAL_LOCAL_ROUTES", additionalLocalRoutesJSON) setTestEnv("ECS_ENABLE_CONTAINER_METADATA", "true") @@ -214,6 +215,7 @@ func TestEnvironmentConfig(t *testing.T) { assert.Equal(t, []string{"efsAuth"}, conf.VolumePluginCapabilities) assert.True(t, conf.DependentContainersPullUpfront.Enabled(), "Wrong value for DependentContainersPullUpfront") assert.True(t, conf.EnableRuntimeStats.Enabled(), "Wrong value for EnableRuntimeStats") + assert.True(t, conf.ShouldExcludeIPv6PortBinding.Enabled(), "Wrong value for ShouldExcludeIPv6PortBinding") } func TestTrimWhitespaceWhenCreating(t *testing.T) { diff --git a/agent/config/config_unix.go b/agent/config/config_unix.go index 6692b8770d2..64b93348c2d 100644 --- a/agent/config/config_unix.go +++ b/agent/config/config_unix.go @@ -97,6 +97,7 @@ func DefaultConfig() Config { FSxWindowsFileServerCapable: false, RuntimeStatsLogFile: defaultRuntimeStatsLogFile, EnableRuntimeStats: BooleanDefaultFalse{Value: NotSet}, + ShouldExcludeIPv6PortBinding: BooleanDefaultTrue{Value: ExplicitlyEnabled}, } } diff --git a/agent/config/config_unix_test.go b/agent/config/config_unix_test.go index e073b82d5e5..7aafeade8d6 100644 --- a/agent/config/config_unix_test.go +++ b/agent/config/config_unix_test.go @@ -72,6 +72,7 @@ func TestConfigDefault(t *testing.T) { assert.False(t, cfg.DependentContainersPullUpfront.Enabled(), "Default DependentContainersPullUpfront set incorrectly") assert.False(t, cfg.PollMetrics.Enabled(), "ECS_POLL_METRICS default should be false") assert.False(t, cfg.EnableRuntimeStats.Enabled(), "Default EnableRuntimeStats set incorrectly") + assert.True(t, cfg.ShouldExcludeIPv6PortBinding.Enabled(), "Default ShouldExcludeIPv6PortBinding set incorrectly") } // TestConfigFromFile tests the configuration can be read from file diff --git a/agent/config/config_windows.go b/agent/config/config_windows.go index 16c99caf09d..8fb530fa196 100644 --- a/agent/config/config_windows.go +++ b/agent/config/config_windows.go @@ -136,6 +136,7 @@ func DefaultConfig() Config { CNIPluginsPath: filepath.Join(ecsBinaryDir, defaultCNIPluginDirName), RuntimeStatsLogFile: filepath.Join(ecsRoot, defaultRuntimeStatsLogFile), EnableRuntimeStats: BooleanDefaultFalse{Value: NotSet}, + ShouldExcludeIPv6PortBinding: BooleanDefaultTrue{Value: ExplicitlyEnabled}, } } diff --git a/agent/config/config_windows_test.go b/agent/config/config_windows_test.go index 45f403c9c03..0a133c8c9d0 100644 --- a/agent/config/config_windows_test.go +++ b/agent/config/config_windows_test.go @@ -69,6 +69,7 @@ func TestConfigDefault(t *testing.T) { assert.Equal(t, DefaultImagePullTimeout, cfg.ImagePullTimeout, "Default ImagePullTimeout set incorrectly") assert.False(t, cfg.DependentContainersPullUpfront.Enabled(), "Default DependentContainersPullUpfront set incorrectly") assert.False(t, cfg.EnableRuntimeStats.Enabled(), "Default EnableRuntimeStats set incorrectly") + assert.True(t, cfg.ShouldExcludeIPv6PortBinding.Enabled(), "Default ShouldExcludeIPv6PortBinding set incorrectly") } func TestConfigIAMTaskRolesReserves80(t *testing.T) { diff --git a/agent/config/types.go b/agent/config/types.go index d2b5c46d662..d0eafd2f9b1 100644 --- a/agent/config/types.go +++ b/agent/config/types.go @@ -349,4 +349,9 @@ type Config struct { // EnableRuntimeStats specifies if pprof should be enabled through the agent introspection port. By default, this configuration // is set to false and can be overridden by means of the ECS_ENABLE_RUNTIME_STATS environment variable. EnableRuntimeStats BooleanDefaultFalse + + // ShouldExcludeIPv6PortBinding specifies whether agent should exclude IPv6 port bindings reported from docker. This configuration + // is set to true by default, and can be overridden by the ECS_EXCLUDE_IPV6_PORTBINDING environment variable. This is a workaround + // for docker's bug as detailed in https://github.com/aws/amazon-ecs-agent/issues/2870. + ShouldExcludeIPv6PortBinding BooleanDefaultTrue }