繁体   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