You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

寻求用Python CDK在ECS Fargate运行单容器的最简示例及镜像拉取故障解决

问题:ECS Fargate容器镜像拉取失败及修复方案

需求背景

  • 运行单个容器,选用AWS ECS而非EKS集群
  • 容器无需HTTP入站暴露,但需具备出站互联网访问能力
  • 仅需单实例运行,基于健康检查实现故障自动重启

遇到的错误

镜像拉取失败,错误信息如下:

CannotPullContainerError: ref pull has been retried 5 time(s): failed to copy: httpReadSeeker: failed open: failed to do request: Get "https://prod-eu-central-1-starport-layer-bucket.s3.eu-central-1.amazonaws.com/..."

原代码实现

class MyStack(Stack):
    def __init__(self, scope: Construct, id: str, props, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        repository = props["ecr-repository"]

        vpc = aws_ec2.Vpc(self, "VPC", vpc_name="vpc", max_azs=2, nat_gateways=0)

        vpc.add_interface_endpoint(
            "S3Endpoint",
            service=aws_ec2.InterfaceVpcEndpointAwsService.S3,
            private_dns_enabled=False,
        )
        vpc.add_interface_endpoint(
            "EcrDockerEndpoint",
            service=aws_ec2.InterfaceVpcEndpointAwsService.ECR_DOCKER,
        )
        vpc.add_interface_endpoint(
            "EcrEndpoint", service=aws_ec2.InterfaceVpcEndpointAwsService.ECR
        )
        vpc.add_interface_endpoint(
            "CloudWatchLogsEndpoint",
            service=aws_ec2.InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS,
        )

        cluster = aws_ecs.Cluster(
            self, "EcsCluster", cluster_name="ecs-cluster", vpc=vpc
        )

        execution_role = iam.Role(
            self,
            "ecs-devops-execution-role",
            assumed_by=iam.ServicePrincipal("ecs-tasks.amazonaws.com"),
            role_name="ecs-devops-execution-role",
        )
        execution_role.add_to_policy(
            iam.PolicyStatement(
                effect=iam.Effect.ALLOW,
                resources=["*"],
                actions=[
                    "ecr:GetAuthorizationToken",
                    "ecr:BatchCheckLayerAvailability",
                    "ecr:GetDownloadUrlForLayer",
                    "ecr:BatchGetImage",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents",
                ],
            )
        )

        task_definition = aws_ecs.FargateTaskDefinition(
            self,
            "EcsFargateTaskDefinition",
            family="EcsFargateFamily",
            execution_role=execution_role,
        )

        image = aws_ecs.ContainerImage.from_ecr_repository(
            repository=repository, tag="1.0.0"
        )

        container = task_definition.add_container(
            "app",
            image=image,
            environment=dict(
                WEBSOCKET_CHANNELS="channel-name", WEBSOCKET_TIMEOUT_DURATION="PT15M"
            ),
        )

        log_group = aws_logs.LogGroup(
            self,
            "ecs-devops-service-logs-groups",
            log_group_name="ecs-devops-service-logs",
        )

        container.add_port_mappings(aws_ecs.PortMapping(container_port=8080))

        service = aws_ecs_patterns.ApplicationLoadBalancedFargateService(
            self,
            "EcsFargateService",
            service_name="fargate-service",
            cluster=cluster,
            desired_count=1,
            task_definition=task_definition,
        )

        service.target_group.configure_health_check(path="/actuator/health")

        self.output_props = props.copy()

修复后的代码

class ComputeStack(Stack):
    def __init__(self, scope: Construct, id: str, props, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        repository = props["ecr-repository"]
        secret = props["sm-secret"]

        vpc = aws_ec2.Vpc(self, "VPC", vpc_name="vpc", max_azs=2, nat_gateways=0)

        cluster = aws_ecs.Cluster(
            self, "EcsCluster", cluster_name="ecs-cluster", vpc=vpc
        )

        task_definition = aws_ecs.FargateTaskDefinition(
            self,
            "EcsFargateTaskDefinition",
            memory_limit_mib=2048,
            family="EcsFargateFamily",
        )

        image = aws_ecs.ContainerImage.from_ecr_repository(
            repository=repository, tag="1.0.0"
        )

        container = task_definition.add_container(
            "app",
            image=image,
            logging=aws_ecs.LogDrivers.aws_logs(stream_prefix="ecs-fargate"),
            memory_limit_mib=2048,
            environment=dict(
                WEBSOCKET_CHANNELS="channel-name",
                WEBSOCKET_TIMEOUT_DURATION="PT15M",
            ),
        )

        container.add_port_mappings(aws_ecs.PortMapping(container_port=8080))

        service = aws_ecs_patterns.ApplicationLoadBalancedFargateService(
            self,
            "EcsFargateService",
            service_name="fargate-service",
            cluster=cluster,
            desired_count=1,
            assign_public_ip=True,
            task_definition=task_definition,
        )

        service.target_group.configure_health_check(path="/actuator/health")

        self.output_props = props.copy()

关键修复说明

  • 启用assign_public_ip=True,让Fargate任务通过公网直接访问ECR镜像存储和S3层桶,无需依赖VPC接口端点
  • 移除手动创建的执行角色:CDK会自动生成具备镜像拉取、日志推送所需权限的执行角色,避免权限配置冗余
  • 明确配置任务和容器的内存限制(2048MiB),避免因资源不足导致的运行异常
  • 直接绑定CloudWatch Logs驱动,无需手动创建LogGroup,简化日志配置流程

非常感谢@gshpychka的帮助!


内容的提问来源于stack exchange,提问作者user3105453

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 03:54:58