typescript - اجرای AWS cdk deploy --all باعث ایجاد سرویس ECS نمیشود


تازه وارد به CDK و نسبتاً تازه وارد به AWS

مسئله

من این آموزش را دنبال میکنم که شامل ایجاد یک API خصوصی مبتنی بر Fargate است و دسترسی به آن از طریق یک نمونه EC2 که به طور عمومی در دسترس است، در اینترنت عمومی میباشد.

من در حال مرور هستم و به طور حداقلی مشکلات مختلف را اصلاح میکنم که همه چیز را راهاندازی میکند. زمان ساخت با این فرا میرسد:

npm run build
cdk bootstrap
cdk synth FargateVpclinkStack
cdk deploy --all

که منجر به استقرار این شد:

من بیرون میروم تا غذا بخورم و برمیگردم، و هنوز دارم به موارد زیر نگاه میکنم:

[███████████████████████████████████████████████████████▊··] (52/54)

4:19:40 PM | CREATE_IN_PROGRESS   | AWS::CloudFormation::Stack                 | FargateVpclinkStack
4:23:17 PM | CREATE_IN_PROGRESS   | AWS::ECS::Service                          | bookService/Service

پس از انتظار طولانی کافی، شکلگیری ابر به عقب بازگردانده شد

10:43:36 PM | CREATE_FAILED        | AWS::ECS::Service                          | bookService/Service
Resource timed out waiting for completion (RequestToken: f8b1d082-1ff3-5a84-938a-95a0ea2f0960)
10:43:45 PM | ROLLBACK_IN_PROGRESS | AWS::CloudFormation::Stack                 | FargateVpclinkStack
The following resource(s) failed to create: [bookService05FB6DBB]. Rollback requested by user.

FrgateVpclinkStack failed: Error: The stack named FargateVpclinkStack failed creation, it may need to be manually deleted from the AWS console: ROLLBACK_COMPLETE
The stack named FargateVpclinkStack failed creation, it may need to be manually deleted from the AWS console: ROLLBACK_COMPLETE

من فرض میکنم این بدان معناست که سرویس ECS bookService/Service نتوانست مستقر شود و بنابراین کل FrgateVpclinkStack بازگردانده شد. من کنجکاوم بدانم چرا این اتفاق افتاده و چگونه میتوان آن را برطرف کرد.

کد

این همان TypeScript است که توسط cdk برای ایجاد قالب cloud formation برای FrgateVpclinkStack استفاده میشود، که در آموزش با نام fargate-vpclink-stack.ts نامیده شده است

import * as cdk from "@aws-cdk/core";
import * as elbv2 from "@aws-cdk/aws-elasticloadbalancingv2";
import * as ec2 from "@aws-cdk/aws-ec2";
import * as ecs from "@aws-cdk/aws-ecs";
import * as ecr from "@aws-cdk/aws-ecr";
import * as iam from "@aws-cdk/aws-iam";
import * as logs from "@aws-cdk/aws-logs";
import * as apig from "@aws-cdk/aws-apigatewayv2";
import * as servicediscovery from "@aws-cdk/aws-servicediscovery";

export class FargateVpclinkStack extends cdk.Stack {
  
  //Export Vpclink and ALB Listener
  public readonly httpVpcLink: cdk.CfnResource;
  public readonly httpApiListener: elbv2.ApplicationListener;

  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // VPC
    const vpc = new ec2.Vpc(this, "ProducerVPC");

    // ECS Cluster
    const cluster = new ecs.Cluster(this, "Fargate Cluster", {
      vpc: vpc,
    });

    // Cloud Map Namespace
    const dnsNamespace = new servicediscovery.PrivateDnsNamespace(
      this,
      "DnsNamespace",
      {
        name: "http-api.local",
        vpc: vpc,
        description: "Private DnsNamespace for Microservices",
      }
    );

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

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

    // Task Definitions
    const bookServiceTaskDefinition = new ecs.FargateTaskDefinition(
      this,
      "bookServiceTaskDef",
      {
        memoryLimitMiB: 512,
        cpu: 256,
        taskRole: taskrole,
      }
    );

    const authorServiceTaskDefinition = new ecs.FargateTaskDefinition(
      this,
      "authorServiceTaskDef",
      {
        memoryLimitMiB: 512,
        cpu: 256,
        taskRole: taskrole,
      }
    );

    // Log Groups
    const bookServiceLogGroup = new logs.LogGroup(this, "bookServiceLogGroup", {
      logGroupName: "/ecs/BookService",
      removalPolicy: cdk.RemovalPolicy.DESTROY,
    });

    const authorServiceLogGroup = new logs.LogGroup(
      this,
      "authorServiceLogGroup",
      {
        logGroupName: "/ecs/AuthorService",
        removalPolicy: cdk.RemovalPolicy.DESTROY,
      }
    );

    const bookServiceLogDriver = new ecs.AwsLogDriver({
      logGroup: bookServiceLogGroup,
      streamPrefix: "BookService",
    });

    const authorServiceLogDriver = new ecs.AwsLogDriver({
      logGroup: authorServiceLogGroup,
      streamPrefix: "AuthorService",
    });

    // Amazon ECR Repositories
    const bookservicerepo = ecr.Repository.fromRepositoryName(
      this,
      "bookservice",
      "book-service"
    );

    const authorservicerepo = ecr.Repository.fromRepositoryName(
      this,
      "authorservice",
      "author-service"
    );

    // Task Containers
    const bookServiceContainer = bookServiceTaskDefinition.addContainer(
      "bookServiceContainer",
      {
        image: ecs.ContainerImage.fromEcrRepository(bookservicerepo),
        logging: bookServiceLogDriver,
      }
    );

    const authorServiceContainer = authorServiceTaskDefinition.addContainer(
      "authorServiceContainer",
      {
        image: ecs.ContainerImage.fromEcrRepository(authorservicerepo),
        logging: authorServiceLogDriver,
      }
    );

    bookServiceContainer.addPortMappings({
      containerPort: 80,
    });

    authorServiceContainer.addPortMappings({
      containerPort: 80,
    });

    //Security Groups
    const bookServiceSecGrp = new ec2.SecurityGroup(
      this,
      "bookServiceSecurityGroup",
      {
        allowAllOutbound: true,
        securityGroupName: "bookServiceSecurityGroup",
        vpc: vpc,
      }
    );

    bookServiceSecGrp.connections.allowFromAnyIpv4(ec2.Port.tcp(80));

    const authorServiceSecGrp = new ec2.SecurityGroup(
      this,
      "authorServiceSecurityGroup",
      {
        allowAllOutbound: true,
        securityGroupName: "authorServiceSecurityGroup",
        vpc: vpc,
      }
    );

    authorServiceSecGrp.connections.allowFromAnyIpv4(ec2.Port.tcp(80));

    // Fargate Services
    const bookService = new ecs.FargateService(this, "bookService", {
      cluster: cluster,
      taskDefinition: bookServiceTaskDefinition,
      assignPublicIp: false,
      desiredCount: 2,
      securityGroup: bookServiceSecGrp,
      cloudMapOptions: {
        name: "bookService",
        cloudMapNamespace: dnsNamespace,
      },
    });

    const authorService = new ecs.FargateService(this, "authorService", {
      cluster: cluster,
      taskDefinition: authorServiceTaskDefinition,
      assignPublicIp: false,
      desiredCount: 2,
      securityGroup: authorServiceSecGrp,
      cloudMapOptions: {
        name: "authorService",
        cloudMapNamespace: dnsNamespace,
      },
    });

    // ALB
    const httpApiInternalALB = new elbv2.ApplicationLoadBalancer(
      this,
      "httpapiInternalALB",
      {
        vpc: vpc,
        internetFacing: false,
      }
    );

    // ALB Listener
    this.httpApiListener = httpApiInternalALB.addListener("httpapiListener", {
      port: 80,
      // Default Target Group
      defaultAction: elbv2.ListenerAction.fixedResponse(200),
    });

    // Target Groups
    const bookServiceTargetGroup = this.httpApiListener.addTargets(
      "bookServiceTargetGroup",
      {
        port: 80,
        priority: 1,
        healthCheck: {
          path: "/api/books/health",
          interval: cdk.Duration.seconds(30),
          timeout: cdk.Duration.seconds(3),
        },
        targets: [bookService],
        pathPattern: "/api/books*",
      }
    );

    const authorServiceTargetGroup = this.httpApiListener.addTargets(
      "authorServiceTargetGroup",
      {
        port: 80,
        priority: 2,
        healthCheck: {
          path: "/api/authors/health",
          interval: cdk.Duration.seconds(30),
          timeout: cdk.Duration.seconds(3),
        },
        targets: [authorService],
        pathPattern: "/api/authors*",
      }
    );

    //VPC Link
    this.httpVpcLink = new cdk.CfnResource(this, "HttpVpcLink", {
      type: "AWS::ApiGatewayV2::VpcLink",
      properties: {
        Name: "http-api-vpclink",
        SubnetIds: vpc.privateSubnets.map((m) => m.subnetId),
      },
    });
  }
}

تمام این کارها در cloud 9 انجام میشود، با cdk نسخه 1.105.0 (build 4813992). فایل package.json من شامل موارد زیر است:

{
  "name": "cdk",
  "version": "0.1.0",
  "bin": {
    "cdk": "bin/cdk.js"
  },
  "scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "test": "jest",
    "cdk": "cdk"
  },
  "devDependencies": {
    "@aws-cdk/assert": "1.101.0",
    "@aws-cdk/aws-apigatewayv2": "1.101.0",
    "@aws-cdk/core": "1.101.0",
    "@aws-cdk/aws-ec2": "1.101.0",
    "@aws-cdk/aws-ecr": "1.101.0",
    "@aws-cdk/aws-ecs": "1.101.0",
    "@aws-cdk/aws-elasticloadbalancingv2": "1.101.0",
    "@aws-cdk/aws-iam": "1.101.0",
    "@aws-cdk/aws-logs": "1.101.0",
    "@aws-cdk/aws-servicediscovery": "1.101.0",
    "@types/jest": "^26.0.10",
    "@types/node": "10.17.27",
    "jest": "^26.4.2",
    "ts-jest": "^26.2.0",
    "aws-cdk": "1.101.0",
    "ts-node": "^9.0.0",
    "typescript": "~3.9.7"
  },
  "dependencies": {
    "@aws-cdk/core": "1.101.0",
    "source-map-support": "^0.5.16"
  }
}

تمام کدهای کل آموزش را میتوان در این لینک گیتهاب پیدا کرد

پاسخ شماره ۱

تایماوت به دلیل یک ECR با نام نادرست بود که bookService تلاش میکرد به آن دسترسی پیدا کند. برای کلیتر کردن این پاسخ، اگر تایماوت رخ دهد، ممکن است بهتر باشد که ثبت کنید کدام منابع تایماوت شدهاند و تمام عناصر تشکیلدهنده را بررسی کنید.