- Newest
- Most votes
- Most comments
Eventually resolved, the problem was here:
alb := awselasticloadbalancingv2.NewApplicationLoadBalancer(infraStack, jsii.String("LoadBalancer"), &awselasticloadbalancingv2.ApplicationLoadBalancerProps{
Vpc: vpc,
InternetFacing: jsii.Bool(true),
LoadBalancerName: jsii.String(props.Branch + "-alb"),
})
albSecurityGroup := awsec2.NewSecurityGroup(infraStack, jsii.String("LoadBalancerSecurityGroup"), &awsec2.SecurityGroupProps{
Vpc: vpc,
AllowAllOutbound: jsii.Bool(true),
Description: jsii.String("Security group for Load Balancer"),
})
Root cause: The albSecurityGroup had to be added to the alb.
answered a year ago
The code got truncated, here's the rest
Logging: awsecs.LogDrivers_AwsLogs(&awsecs.AwsLogDriverProps{
StreamPrefix: jsii.String("/ecs/route66"),
LogGroup: logGroup,
}),
HealthCheck: &awsecs.HealthCheck{
Command: jsii.Strings("CMD-SHELL", "true"),
Interval: awscdk.Duration_Seconds(jsii.Number(30)),
Timeout: awscdk.Duration_Seconds(jsii.Number(15)),
StartPeriod: awscdk.Duration_Seconds(jsii.Number(15)),
Retries: jsii.Number(3),
},
})
props.Listener.AddTargets(jsii.String("ECS"), &awselasticloadbalancingv2.AddApplicationTargetsProps{
Port: containerPort,
Targets: &[]awselasticloadbalancingv2.IApplicationLoadBalancerTarget{service},
HealthCheck: &awselasticloadbalancingv2.HealthCheck{
Path: jsii.String("/"),
HealthyHttpCodes: jsii.String("200,300"),
Interval: awscdk.Duration_Seconds(jsii.Number(10)),
Timeout: awscdk.Duration_Seconds(jsii.Number(5)),
},
SlowStart: awscdk.Duration_Seconds(jsii.Number(60)),
DeregistrationDelay: awscdk.Duration_Seconds(jsii.Number(30)),
TargetGroupName: jsii.String(props.MonostackProps.Branch + "-" + containerName),
})
return &ContainerInfo{
Cluster: cluster,
Service: service,
AutoScalingGroup: asg,
TaskDefinition: taskDefinition,
}
}
func ecsActivation(stack awscdk.Stack, previewContainer *ContainerInfo) (awslambda.Function, *awscodepipeline.StageOptions) {
activationLambda := awslambda.NewFunction(stack, jsii.String("ActivationLambda"), &awslambda.FunctionProps{
Runtime: awslambda.Runtime_PYTHON_3_12(),
Handler: jsii.String("index.handler"),
Code: awslambda.Code_FromInline(jsii.String(`
import boto3
import os
ecs = boto3.client('ecs')
autoscaling = boto3.client('autoscaling')
codepipeline = boto3.client('codepipeline')
def handler(event, context):
job_id = event['CodePipeline.job']['id']
cluster_name = os.environ['CLUSTER_NAME']
service_name = os.environ['SERVICE_NAME']
asg_name = os.environ['ASG_NAME']
action = event['CodePipeline.job']['data']['actionConfiguration']['configuration']['UserParameters'] # Get action from event data
if action == 'activate':
desired_count = 1
desired_capacity = 1
else: # action == 'deactivate'
desired_count = 0
desired_capacity = 0
ecs_params = {
'cluster': cluster_name,
'service': service_name,
'desiredCount': desired_count,
}
asg_params = {
'AutoScalingGroupName': asg_name,
'DesiredCapacity': desired_capacity,
'MinSize': desired_capacity,
}
try:
autoscaling.update_auto_scaling_group(**asg_params)
print(f'Auto Scaling Group set to desired capacity: {desired_capacity}')
except Exception as e:
print(f'Error updating Auto Scaling Group: {e}')
codepipeline.put_job_failure_result(jobId=job_id, failureDetails={'message': str(e), 'type': 'ConfigurationError', 'externalExecutionId': context.aws_request_id})
return
try:
ecs.update_service(**ecs_params)
print(f'Staging service set to desired count: {desired_count}')
codepipeline.put_job_success_result(jobId=job_id)
return {
'statusCode': 200,
'body': f'Staging service set to desired count: {desired_count}'
}
except Exception as e:
print(f'Error updating staging service: {e}')
codepipeline.put_job_failure_result(jobId=job_id, failureDetails={'message': str(e), 'type': 'ConfigurationError', 'externalExecutionId': context.aws_request_id})
raise e
`)),
MemorySize: jsii.Number(128),
Timeout: awscdk.Duration_Seconds(jsii.Number(30)),
Environment: &map[string]*string{
"CLUSTER_NAME": jsii.String(*previewContainer.Cluster.ClusterName()),
"SERVICE_NAME": jsii.String(*previewContainer.Service.ServiceName()),
"ASG_NAME": jsii.String(*previewContainer.AutoScalingGroup.AutoScalingGroupName()),
},
})
activationLambda.AddToRolePolicy(awsiam.NewPolicyStatement(&awsiam.PolicyStatementProps{
Actions: jsii.Strings("ecs:UpdateService"),
Resources: jsii.Strings(*previewContainer.Service.ServiceArn()), // Modify with your actual ARN
}))
activationLambda.AddToRolePolicy(awsiam.NewPolicyStatement(&awsiam.PolicyStatementProps{
Actions: jsii.Strings("autoscaling:UpdateAutoScalingGroup"),
Resources: jsii.Strings(*previewContainer.AutoScalingGroup.AutoScalingGroupArn()), // ARN
}))
return activationLambda, &awscodepipeline.StageOptions{
StageName: jsii.String("ActivatePreview"),
Actions: &[]awscodepipeline.IAction{
awscodepipelineactions.NewLambdaInvokeAction(&awscodepipelineactions.LambdaInvokeActionProps{
ActionName: jsii.String("ActivatePreviewAction"),
Lambda: activationLambda,
UserParametersString: jsii.String("activate"),
}),
},
}
}
func ecsDeploymentSteps(codePipeline awscodepipeline.Pipeline, dockerOutput awscodepipeline.Artifact, targetContainer *ContainerInfo, previewContainer *ContainerInfo, activationLambda awslambda.Function) {
// Deploy staging container in a separate stage so it runs independently
_ = codePipeline.AddStage(&awscodepipeline.StageOptions{
StageName: jsii.String("DeployPreview"),
Actions: &[]awscodepipeline.IAction{
awscodepipelineactions.NewEcsDeployAction(&awscodepipelineactions.EcsDeployActionProps{
ActionName: jsii.String("DeployPreview"),
Service: previewContainer.Service,
DeploymentTimeout: awscdk.Duration_Minutes(jsii.Number(15)),
Role: codePipeline.Role(),
ImageFile: awscodepipeline.ArtifactPath_ArtifactPath(dockerOutput.ArtifactName(), jsii.String("imagedefinitions-preview.json")),
}),
},
})
// Deploy main container after manual approval in a separate stage
_ = codePipeline.AddStage(&awscodepipeline.StageOptions{
StageName: jsii.String("Approval"),
Actions: &[]awscodepipeline.IAction{
awscodepipelineactions.NewManualApprovalAction(&awscodepipelineactions.ManualApprovalActionProps{
ActionName: jsii.String("ManualApproval"),
}),
},
})
_ = codePipeline.AddStage(&awscodepipeline.StageOptions{
StageName: jsii.String("DeployTarget"),
Actions: &[]awscodepipeline.IAction{
awscodepipelineactions.NewEcsDeployAction(&awscodepipelineactions.EcsDeployActionProps{
ActionName: jsii.String("DeployTarget"),
Service: targetContainer.Service,
DeploymentTimeout: awscdk.Duration_Minutes(jsii.Number(15)),
Role: codePipeline.Role(),
ImageFile: awscodepipeline.ArtifactPath_ArtifactPath(dockerOutput.ArtifactName(), jsii.String("imagedefinitions-target.json")),
}),
},
})
_ = codePipeline.AddStage(&awscodepipeline.StageOptions{
StageName: jsii.String("DeactivatePreview"),
Actions: &[]awscodepipeline.IAction{
awscodepipelineactions.NewLambdaInvokeAction(&awscodepipelineactions.LambdaInvokeActionProps{
ActionName: jsii.String("DeactivatePreviewAction"),
Lambda: activationLambda,
UserParametersString: jsii.String("deactivate"),
}),
},
})
}
answered 2 years ago
The issue you're experiencing with the HOST network mode failing health checks is likely due to a few factors:
-
Security Group Configuration: When using HOST mode, the container uses the EC2 instance's network interface directly. Make sure the EC2 instance's security group allows inbound traffic from the Application Load Balancer (ALB) on the container port.
-
Health Check Configuration: Ensure that the health check path and port in your ALB target group settings match the container's exposed endpoint.
-
Container Port Mapping: In HOST mode, the HostPort should match the ContainerPort. Make sure your task definition correctly maps these ports.
-
EC2 Instance Networking: Verify that the EC2 instances are in public subnets if you need internet access without a NAT gateway.
To resolve these issues:
-
Modify the host security group (hostSg) to allow inbound traffic from the ALB security group on the container port:
hostSg.AddIngressRule( props.AlbSg, awsec2.Port_Tcp(containerPort), jsii.String("Allow traffic from ALB to Host"), nil, )
-
Ensure your ALB target group's health check settings are correct for your application.
-
In the task definition, make sure the HostPort matches the ContainerPort:
PortMappings: &[]*awsecs.PortMapping{{ ContainerPort: containerPort, Protocol: awsecs.Protocol_TCP, HostPort: containerPort, }},
-
Configure your Auto Scaling Group to launch instances in public subnets:
VpcSubnets: &awsec2.SubnetSelection{ SubnetType: awsec2.SubnetType_PUBLIC, },
By making these adjustments, you should be able to get the HOST network mode working properly with your ECS tasks while maintaining internet access without requiring a NAT gateway.
Sources
Host mode - Amazon Elastic Container Service
Map Amazon ECS container ports to the EC2 instance network interface - Amazon Elastic Container Service
Amazon ECS task networking options for the EC2 launch type - Amazon Elastic Container Service
Choosing a network mode - Amazon Elastic Container Service
Relevant content
asked 3 years ago
- AWS OFFICIALUpdated a year ago

This is a poor answer by the AI Agent -- all four of the suggested changes are already implemented correctly in the code.