无法使用 CDK 从私有 AWS ECR 存储库中提取 Docker 映像

问题描述 投票:0回答:1

我正在尝试使用 AWS CDK 将 Docker 映像启动为 Fargate 任务。图像已上传到私人存储库,但我在提取图像时遇到问题。

按照这篇 AWS 文章中的说明,我尝试了多种方法来确保任务可以访问私有存储库,但我无法解决问题。这包括使用 VPC 终端节点并打开必要的端口。

我正在使用具有三个私有子网的现有 VPC。否则,AWS 账户配置为“空白”。 ECS存储库与VPC位于同一区域,并且CDK应用程序配置为与VPC和存储库相同的区域和帐户。

下面是我的代码:

import { Stack, StackProps } from "aws-cdk-lib";
import {
    aws_ecs as ecs,
    aws_iam as iam,
    aws_ecs_patterns as ecsPatterns,
    aws_ecr as ecr,
    aws_ec2 as ec2,
} from "aws-cdk-lib";
import {
    Vpc,
} from "aws-cdk-lib/aws-ec2";
import { Construct } from "constructs";

export class MattermostStack extends Stack {
    constructor(scope: Construct, id: string, props?: StackProps) {
        super(scope, id, props);

        // Use existing VPC
        const vpc = Vpc.fromLookup(this, 'MyVPC', {
            tags: {
                Name: 'my-VPC',
            },
        })

        // Create VPC endpoint for ECR
        const ecrVpcEndpoint = vpc.addInterfaceEndpoint('EcrEndpoint', {
            service: ec2.InterfaceVpcEndpointAwsService.ECR,
            privateDnsEnabled: true, // Set to false if you want public DNS names for the endpoint
            subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, // Specify the subnets where you want the endpoint
        });

        // Create task execution role
        const ecsTaskExecutionRole = new iam.Role(this, "ecsTaskExecutionRole", {
            assumedBy: new iam.ServicePrincipal("ecs-tasks.amazonaws.com"),
        });

        ecsTaskExecutionRole.addManagedPolicy(
            iam.ManagedPolicy.fromAwsManagedPolicyName(
                "service-role/AmazonECSTaskExecutionRolePolicy"
            )
        );

        // Define your cluster, Fargate ECS task and service
        const ecsCluster = new ecs.Cluster(this, 'EcsCluster', { vpc: vpc });

        const fargateService = new ecs.FargateService(this, 'FargateService', {
            cluster: ecsCluster,
            taskDefinition: new ecs.FargateTaskDefinition(this, 'MattermostTaskDefinition', {
                taskRole: ecsTaskExecutionRole
            }),
            assignPublicIp: false, // Set to true if you want tasks to have public IP addresses
        });

        // Get image
        const containerImage = ecs.ContainerImage.fromEcrRepository(ecr.Repository.fromRepositoryName(this, 'mattermost', 'mattermost-team-edition'));

        // Add container to the task definition
        const container = fargateService.taskDefinition.addContainer('MattermostContainer', {
            image: containerImage,
            memoryLimitMiB: 512, // Adjust as needed
            cpu: 256, // Adjust as needed
            environment: {
                MM_SQLSETTINGS_DRIVERNAME: 'postgres',
                // replace username/pass with secret (also see dbStack commented lines)
                MM_SQLSETTINGS_DATASOURCE: 'postgres://xxxxxxxx:[email protected]:5500/mattermost?sslmode=disable&connect_timeout=10',
            },
            portMappings: [{ containerPort: 8065 }],
            logging: new ecs.AwsLogDriver({ streamPrefix: 'MatterLogTest', mode: ecs.AwsLogDriverMode.NON_BLOCKING }),
        });

        // Connect your service to the VPC endpoint
        fargateService.connections.allowTo(ecrVpcEndpoint, ec2.Port.allTraffic(), 'Allow access to ECR');

        // Allow inbound HTTPS access
        fargateService.connections.allowFromAnyIpv4(ec2.Port.tcp(443), 'Allow inbound HTTPS traffic');

        // Allow HTTPS access through port 443 at the task definition level
        container.addPortMappings({
            containerPort: 443,
            protocol: ecs.Protocol.TCP,
        })

        // Allow inbound HTTPS access through port 443 at the security group level
        const securityGroup = fargateService.connections.securityGroups[0]; // Assuming there is at least one security group
        securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(443), 'Allow HTTPS inbound traffic');

    }
}

不幸的是,在部署堆栈时,我在任务级别收到此错误:

CannotPullContainerError: pull image manifest has been retried 5 time(s): failed to resolve ref xxxxxxx.dkr.ecr.eu-central-1.amazonaws.com/mattermost-team-edition:latest: failed to do request: Head "https://xxxxxxx.dkr.ecr.eu-central-1.amazonaws.com/v2/mattermost-team-edition/manifests/latest": dial tcp 3.121.166.70:443: i/o timeout

谁能告诉我我的 CDK 堆栈配置有什么问题吗?

amazon-web-services docker aws-cdk amazon-vpc aws-fargate
1个回答
0
投票

我能够通过在失败的集群/任务上运行此运行手册并仔细研究发现的所有问题来解决这个问题。

我改变了一些东西以使其正常工作:

  1. 使用 console/json 预定义“ecsTaskExecutionRole”IAM 角色和所有所需的权限。我添加了以下策略:“AmazonECSTaskExecutionRolePolicy”、“CloudWatchLogsFullAccess”和一个名为“PrivateECRAuthenticationPolicy”的自定义策略,其中包含按照此页面进行私有注册表身份验证所需的 IAM 权限。我在 CDK 代码中引用这个现有角色,而不是在那里创建新角色。
  2. 我添加了其他端点:ECR Docker VPC 端点和 S3 网关端点

最终的 CDK 堆栈现在如下所示:

    // Use existing VPC
    const vpc = Vpc.fromLookup(this, 'MyVPC', {
        tags: {
            Name: 'MyVPC',
        },
    })

    // Create VPC endpoint for ECR
    const ecrVpcEndpoint = vpc.addInterfaceEndpoint('EcrEndpoint', {
        service: ec2.InterfaceVpcEndpointAwsService.ECR,
        privateDnsEnabled: true, // Set to false if you want public DNS names for the endpoint
        subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, // Specify the subnets where you want the endpoint
    });

    // Create VPC endpoint for ECR docker
    const ecrDkrVpcEndpoint = vpc.addInterfaceEndpoint('EcrDkrEndpoint', {
        service: ec2.InterfaceVpcEndpointAwsService.ECR_DOCKER,
        privateDnsEnabled: true, // Set to false if you want public DNS names for the endpoint
        subnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }, // Specify the subnets where you want the endpoint
    });

    // Create a Gateway endpoint for S3
    const s3GatewayEndpoint = vpc.addGatewayEndpoint('S3GatewayEndpoint', {
        service: ec2.GatewayVpcEndpointAwsService.S3,
    });

    // Get existing role
    const ecsTaskExecutionRole = iam.Role.fromRoleArn(this, 'ecsTaskExecutionRole', 'arn:aws:iam::805442828467:role/ecsTaskExecutionRole');

    // Define your cluster, Fargate ECS task and service
    const ecsCluster = new ecs.Cluster(this, 'EcsCluster', { vpc: vpc });

    const fargateService = new ecs.FargateService(this, 'FargateService', {
        cluster: ecsCluster,
        taskDefinition: new ecs.FargateTaskDefinition(this, 'MattermostTaskDefinition', {
            taskRole: ecsTaskExecutionRole
        }),
        assignPublicIp: false, // Set to true if you want tasks to have public IP addresses
        vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED }
    });

    // Add a container to the task definition
    const containerImage = ecs.ContainerImage.fromEcrRepository(ecr.Repository.fromRepositoryName(this, 'mattermost', 'mattermost-team-edition'));

    // Add container to the task definition
    const container = fargateService.taskDefinition.addContainer('MattermostContainer', {
        image: containerImage,
        memoryLimitMiB: 512, // Adjust as needed
        cpu: 256, // Adjust as needed
        environment: {
            MM_SQLSETTINGS_DRIVERNAME: 'postgres',
            // replace username/pass with secret (also see dbStack commented lines) -> remember setting up IAM role: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_execution_IAM_role.html
            MM_SQLSETTINGS_DATASOURCE: 'postgres://xxxxx:[email protected]:5500/mattermost?sslmode=disable&connect_timeout=10',
        },
        portMappings: [{ containerPort: 8065 }],
    });

    // Connect service to the VPC endpoints
    fargateService.connections.allowTo(ecrVpcEndpoint, ec2.Port.allTraffic(), 'Allow access to ECR');
    fargateService.connections.allowTo(ecrDkrVpcEndpoint, ec2.Port.allTraffic(), 'Allow access to ECR docker');

    // Allow inbound HTTPS access
    fargateService.connections.allowFromAnyIpv4(ec2.Port.tcp(443), 'Allow inbound HTTPS traffic');

    // Allow HTTPS access through port 443 at the task definition level
    container.addPortMappings({
        containerPort: 443,
        protocol: ecs.Protocol.TCP,
    })

    // Allow inbound HTTPS access through port 443 at the security group level
    const securityGroup = fargateService.connections.securityGroups[0]; // Assuming there is at least one security group
    securityGroup.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(443), 'Allow HTTPS inbound traffic');
© www.soinside.com 2019 - 2024. All rights reserved.