簡體   English   中英

使用 AWS CDK 創建數據庫實例后如何運行 Fargate 任務?

[英]How to run Fargate task after database instance is created with AWS CDK?

我有一個 AWS CDK 堆棧,它從 docker 容器創建一個 Fargate 任務(使用ApplicationLoadBalancedFargateService )。 容器是連接到數據庫的 Web 應用程序。 當我部署 CDK 堆棧時,創建一個數據庫實例需要 7 分鍾。 但是,Fargate 任務啟動得更快,因此該任務因無法連接到數據庫而停止(因為尚未創建)。 然后它嘗試再次啟動任務,失敗並停止。 這樣重復四次,直到創建數據庫。

問題:有沒有辦法在 CDK 代碼中將 Fargate 任務的啟動延遲到數據庫創建完成?

這是 CDK 代碼,我使用的是aws-cdk庫的 2.30.0 版本。

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';

import * as ecr from 'aws-cdk-lib/aws-ecr';
import * as ec2 from "aws-cdk-lib/aws-ec2";
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as ecsp from 'aws-cdk-lib/aws-ecs-patterns';
import * as secretManager from "aws-cdk-lib/aws-secretsmanager";
import { Credentials, DatabaseInstance, DatabaseInstanceEngine, DatabaseSecret, PostgresEngineVersion } from 'aws-cdk-lib/aws-rds';
import { SecurityGroup } from 'aws-cdk-lib/aws-ec2';

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

    const stackPrefix = 'PgRails'

    const vpc = new ec2.Vpc(this, `${stackPrefix}VPC`, {
      maxAzs: 3,
      subnetConfiguration: [
        {
          name: 'Public',
          subnetType: ec2.SubnetType.PUBLIC,
          cidrMask: 28,
        },
        {
          name: 'Private',
          subnetType: ec2.SubnetType.PRIVATE_WITH_NAT,
          cidrMask: 24,
        },
        {
          name: 'Isolated',
          subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
          cidrMask: 28,
        },
      ],
    });


    // Security groups
    // ------------

    // Fargate security group
    const fargateSecurityGroup = new SecurityGroup(this, `${stackPrefix}FargateSecurityGroup`, { vpc })

    // Database security group
    const databaseSecurityGroup = new SecurityGroup(this, `${stackPrefix}DatabaseSecurityGroup`, {
      vpc,
      allowAllOutbound: false
    });

    databaseSecurityGroup.addIngressRule(
      fargateSecurityGroup,
      ec2.Port.tcp(5432),
      'Permit the database to accept requests from the fargate service'
    );


    // Database
    // -----------

    const databaseSecret = new DatabaseSecret(this, `${stackPrefix}DatabaseSecret`, {
      username: 'postgres',
    });

    new DatabaseInstance(this, `${stackPrefix}DatabaseInstance`, {
      vpc,
      securityGroups: [databaseSecurityGroup],
      engine: DatabaseInstanceEngine.postgres({
        version: PostgresEngineVersion.VER_14_2,
      }),
      removalPolicy: cdk.RemovalPolicy.DESTROY, // CHANGE TO .SNAPSHOT FOR PRODUCTION !!!!!!!!!!!!!!!!!!!!!!
      credentials: Credentials.fromSecret(databaseSecret),
      instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE3, ec2.InstanceSize.MICRO),
      vpcSubnets: {
        subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
      },
      backupRetention: cdk.Duration.days(7),
      allocatedStorage: 10,
      maxAllocatedStorage: 30,
      databaseName: 'rails_postgres_production',
    });


    // Fargate service
    // ------------

    const repo = ecr.Repository.fromRepositoryName(this, 'pg_rails_docker', 'pg_rails_docker');
    const image =  ecs.ContainerImage.fromEcrRepository(repo, 'latest');
    const cluster = new ecs.Cluster(this, "DataCluster", { vpc });
    const mySecret = secretManager.Secret.fromSecretNameV2(this, 'MySecret', 'MySecret');

    const webLogging = new ecs.AwsLogDriver({
      streamPrefix: "my_pg_rails",
    })

    const webTaskDefinition = new ecs.FargateTaskDefinition(this, `${stackPrefix}FargateTask`, {
      cpu: 256,
      memoryLimitMiB: 512,
      runtimePlatform: {
        operatingSystemFamily: ecs.OperatingSystemFamily.LINUX,
        cpuArchitecture: ecs.CpuArchitecture.ARM64
      },
    });

    webTaskDefinition.addContainer(`${stackPrefix}Container`, {
      image: image,
      portMappings: [{ containerPort: 80 }],
      secrets: {
        RDS_HOSTNAME: ecs.Secret.fromSecretsManager(databaseSecret, 'host'),
        RDS_PORT: ecs.Secret.fromSecretsManager(databaseSecret, 'port'),
        RDS_USERNAME: ecs.Secret.fromSecretsManager(databaseSecret, 'username'),
        RDS_PASSWORD: ecs.Secret.fromSecretsManager(databaseSecret, 'password'),
        TRIST: ecs.Secret.fromSecretsManager(mySecret, 'TRIST')
      },
      logging: webLogging,
    });

    new ecsp.ApplicationLoadBalancedFargateService(this, `${stackPrefix}WebServer`, {
      cluster: cluster,
      taskDefinition: webTaskDefinition,
      securityGroups: [fargateSecurityGroup],
      publicLoadBalancer: true
    });
  }
}

如果你想在fargate之前運行數據庫,你應該做一些事情讓fargate依賴於數據庫。 就我而言,我只是在下面做一個技巧。

首先,將數據庫聲明為 const

const database = new DatabaseInstance(this, `${stackPrefix}DatabaseInstance`, {
...

然后,在定義 Fargate 服務時在某處調用數據庫變量。

例子:

webTaskDefinition.addContainer(`${stackPrefix}Container`, {
      image: image,
      portMappings: [{ containerPort: 80 }],
      secrets: {
        ...
        TRICK: database.endpoint // or something like this, Idk exactly grammar

      },
      logging: webLogging,
    });

希望它可以幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM