使用 Amazon CDK 创建 Amazon ECS 资源 - Amazon Elastic Container Service
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

使用 Amazon CDK 创建 Amazon ECS 资源

Amazon Cloud Development Kit (Amazon CDK) 是一个基础设施即代码 (IAC) 框架,可以让您使用所选编程语言来定义 Amazon 云基础设施。要定义您自己的云基础设施,请首先编写一个包含一个或多个堆栈的应用程序(使用 CDK 支持的一种语言)。然后,将其合成为 Amazon CloudFormation 模板并将您的资源部署到 Amazon Web Services 账户。按照本主题中的步骤,使用 Amazon Elastic Container Service (Amazon ECS) 和 Fargate 上的 Amazon CDK 部署容器化 Web 服务器。

CDK 中包含的 Amazon 构造库提供可用于对 Amazon Web Services 提供的资源进行建模的模块。对于常用的服务,该库提供具有智能默认值和最佳实践的精选构造。其中一个模块(特别是 aws-ecs-patterns)提供高级抽象,让您只需几行代码即可定义容器化服务和所有必要的支持资源。

本主题使用 ApplicationLoadBalancedFargateService 构造。此构造会在应用程序负载均衡器后面的 Fargate 上部署 Amazon ECS 服务。aws-ecs-patterns 模块还包括使用网络负载平衡器并在 Amazon EC2 上运行的构造。

在开始此任务之前,请设置您的 Amazon CDK 开发环境,并通过运行以下命令安装 Amazon CDK。有关如何设置 Amazon CDK 开发环境的说明,请参阅 Amazon CDK 入门 - 先决条件

npm install -g aws-cdk
注意

这些说明假设您在使用 Amazon CDK v2。

步骤 1:设置您的 Amazon CDK 项目

为您的新 Amazon CDK 应用程序创建目录并初始化项目。

TypeScript
mkdir hello-ecs cd hello-ecs cdk init --language typescript
JavaScript
mkdir hello-ecs cd hello-ecs cdk init --language javascript
Python
mkdir hello-ecs cd hello-ecs cdk init --language python

项目启动后,请激活项目的虚拟环境并安装 Amazon CDK 的基线依赖关系。

source .venv/bin/activate python -m pip install -r requirements.txt
Java
mkdir hello-ecs cd hello-ecs cdk init --language java

将此 Maven 项目导入到 Java IDE 中。例如,在 Eclipse 中,使用 File(文件)> Import(导入)> Maven > Existing Maven Projects(现有 Maven 项目)。

C#
mkdir hello-ecs cd hello-ecs cdk init --language csharp
Go
mkdir hello-ecs cd hello-ecs cdk init --language go
注意

Amazon CDK 应用程序模板使用项目目录的名称来生成源文件和类的名称。在此示例中,该目录名为 hello-ecs。如果您使用其他项目目录名称,则您的应用将与这些说明不匹配。

Amazon CDK v2 在名为 aws-cdk-lib 的单个程序包中包含适用于所有 Amazon Web Services 的稳定构造。当您初始化该项目时,此程序包作为依赖项进行安装。使用某些编程语言时,会在您首次构建项目时安装该程序包。本主题介绍如何使用 Amazon ECS 模式构造,它为使用 Amazon ECS 提供高级抽象。此模块依赖 Amazon ECS 构造和其他构造来预置您的 Amazon ECS 应用程序所需的资源。

将这些库导入 CDK 应用程序时使用的名称可能略有不同,具体取决于您使用的编程语言。下面提供了每种受支持的 CDK 编程语言中使用的名称,以方便参考。

TypeScript
aws-cdk-lib/aws-ecs aws-cdk-lib/aws-ecs-patterns
JavaScript
aws-cdk-lib/aws-ecs aws-cdk-lib/aws-ecs-patterns
Python
aws_cdk.aws_ecs aws_cdk.aws_ecs_patterns
Java
software.amazon.awscdk.services.ecs software.amazon.awscdk.services.ecs.patterns
C#
Amazon.CDK.AWS.ECS Amazon.CDK.AWS.ECS.Patterns
Go
github.com/aws/aws-cdk-go/awscdk/v2/awsecs github.com/aws/aws-cdk-go/awscdk/v2/awsecspatterns

步骤 2:使用 Amazon CDK 在 Fargate 上定义容器化 Web 服务器

使用 DockerHub 中的容器映像 amazon-ecs-sample。此映像包含在 Amazon Linux 2 上运行的 PHP Web 应用。

在您创建的 Amazon CDK 项目中,编辑包含堆栈定义的文件,使其类似于以下示例之一。

注意

堆栈是一个部署单元。所有资源都必须位于一个堆栈中,并且一个堆栈中的所有资源都是同时部署的。如果某资源无法部署,则会回滚已部署的任何其他资源。一个 Amazon CDK 应用可以包含多个堆栈,一个堆栈中的资源可以引用另一个堆栈中的资源。

TypeScript

更新 lib/hello-ecs-stack.ts,使其类似于以下内容。

import * as cdk from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as ecs from 'aws-cdk-lib/aws-ecs'; import * as ecsp from 'aws-cdk-lib/aws-ecs-patterns'; export class HelloEcsStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); new ecsp.ApplicationLoadBalancedFargateService(this, 'MyWebServer', { taskImageOptions: { image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), }, publicLoadBalancer: true }); } }
JavaScript

更新 lib/hello-ecs-stack.js,使其类似于以下内容。

const cdk = require('aws-cdk-lib'); const { Construct } = require('constructs'); const ecs = require('aws-cdk-lib/aws-ecs'); const ecsp = require('aws-cdk-lib/aws-ecs-patterns'); class HelloEcsStack extends cdk.Stack { constructor(scope = Construct, id = string, props = cdk.StackProps) { super(scope, id, props); new ecsp.ApplicationLoadBalancedFargateService(this, 'MyWebServer', { taskImageOptions: { image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), }, publicLoadBalancer: true }); } } module.exports = { HelloEcsStack }
Python

更新 hello-ecs/hello_ecs_stack.py,使其类似于以下内容。

import aws_cdk as cdk from constructs import Construct import aws_cdk.aws_ecs as ecs import aws_cdk.aws_ecs_patterns as ecsp class HelloEcsStack(cdk.Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) ecsp.ApplicationLoadBalancedFargateService(self, "MyWebServer", task_image_options=ecsp.ApplicationLoadBalancedTaskImageOptions( image=ecs.ContainerImage.from_registry("amazon/amazon-ecs-sample")), public_load_balancer=True )
Java

更新 src/main/java/com.myorg/HelloEcsStack.java,使其类似于以下内容。

package com.myorg; import software.constructs.Construct; import software.amazon.awscdk.Stack; import software.amazon.awscdk.StackProps; import software.amazon.awscdk.services.ecs.ContainerImage; import software.amazon.awscdk.services.ecs.patterns.ApplicationLoadBalancedFargateService; import software.amazon.awscdk.services.ecs.patterns.ApplicationLoadBalancedTaskImageOptions; public class HelloEcsStack extends Stack { public HelloEcsStack(final Construct scope, final String id) { this(scope, id, null); } public HelloEcsStack(final Construct scope, final String id, final StackProps props) { super(scope, id, props); ApplicationLoadBalancedFargateService.Builder.create(this, "MyWebServer") .taskImageOptions(ApplicationLoadBalancedTaskImageOptions.builder() .image(ContainerImage.fromRegistry("amazon/amazon-ecs-sample")) .build()) .publicLoadBalancer(true) .build(); } }
C#

更新 src/HelloEcs/HelloEcsStack.cs,使其类似于以下内容。

using Amazon.CDK; using Constructs; using Amazon.CDK.AWS.ECS; using Amazon.CDK.AWS.ECS.Patterns; namespace HelloEcs { public class HelloEcsStack : Stack { internal HelloEcsStack(Construct scope, string id, IStackProps props = null) : base(scope, id, props) { new ApplicationLoadBalancedFargateService(this, "MyWebServer", new ApplicationLoadBalancedFargateServiceProps { TaskImageOptions = new ApplicationLoadBalancedTaskImageOptions { Image = ContainerImage.FromRegistry("amazon/amazon-ecs-sample") }, PublicLoadBalancer = true }); } } }
Go

更新 hello-ecs.go,使其类似于以下内容。

package main import ( "github.com/aws/aws-cdk-go/awscdk/v2" // "github.com/aws/aws-cdk-go/awscdk/v2/awssqs" "github.com/aws/aws-cdk-go/awscdk/v2/awsecs" "github.com/aws/aws-cdk-go/awscdk/v2/awsecspatterns" "github.com/aws/constructs-go/constructs/v10" "github.com/aws/jsii-runtime-go" ) type HelloEcsStackProps struct { awscdk.StackProps } func NewHelloEcsStack(scope constructs.Construct, id string, props *HelloEcsStackProps) awscdk.Stack { var sprops awscdk.StackProps if props != nil { sprops = props.StackProps } stack := awscdk.NewStack(scope, &id, &sprops) // The code that defines your stack goes here // example resource // queue := awssqs.NewQueue(stack, jsii.String("HelloEcsQueue"), &awssqs.QueueProps{ // VisibilityTimeout: awscdk.Duration_Seconds(jsii.Number(300)), // }) res := awsecspatterns.NewApplicationLoadBalancedFargateService(stack, jsii.String("MyWebServer"), &awsecspatterns.ApplicationLoadBalancedFargateServiceProps{ TaskImageOptions: &awsecspatterns.ApplicationLoadBalancedTaskImageOptions{ Image: awsecs.ContainerImage_FromRegistry(jsii.String("amazon/amazon-ecs-sample"), &awsecs.RepositoryImageProps{}), }, }, ) awscdk.NewCfnOutput(stack, jsii.String("LoadBalancerDNS"), &awscdk.CfnOutputProps{Value: res.LoadBalancer().LoadBalancerDnsName()}) return stack } func main() { defer jsii.Close() app := awscdk.NewApp(nil) NewHelloEcsStack(app, "HelloEcsStack", &HelloEcsStackProps{ awscdk.StackProps{ Env: env(), }, }) app.Synth(nil) } // env determines the AWS environment (account+region) in which our stack is to // be deployed. For more information see: https://docs.aws.amazon.com/cdk/latest/guide/environments.html func env() *awscdk.Environment { // If unspecified, this stack will be "environment-agnostic". // Account/Region-dependent features and context lookups will not work, but a // single synthesized template can be deployed anywhere. //--------------------------------------------------------------------------- return nil // Uncomment if you know exactly what account and region you want to deploy // the stack to. This is the recommendation for production stacks. //--------------------------------------------------------------------------- // return &awscdk.Environment{ // Account: jsii.String("123456789012"), // Region: jsii.String("us-east-1"), // } // Uncomment to specialize this stack for the AWS Account and Region that are // implied by the current CLI configuration. This is recommended for dev // stacks. //--------------------------------------------------------------------------- // return &awscdk.Environment{ // Account: jsii.String(os.Getenv("CDK_DEFAULT_ACCOUNT")), // Region: jsii.String(os.Getenv("CDK_DEFAULT_REGION")), // } }

前面的简短片段包括以下内容:

  • 服务的逻辑名称:MyWebServer

  • 从 DockerHub 获取的容器映像:amazon/amazon-ecs-sample

  • 其他相关信息,例如负载均衡器有公有地址并且可以从互联网访问这一事实。

Amazon CDK 将创建部署 Web 服务器所需的所有资源,包括以下资源。此示例中省略了这些资源。

  • Amazon ECS 集群

  • Amazon VPC 和 Amazon EC2 实例

  • 自动扩缩组

  • 应用程序负载均衡器

  • IAM 角色和策略

一些自动预置的资源由堆栈中定义的所有 Amazon ECS 服务共享。

保存源文件,然后在应用程序的主目录中运行 cdk synth 命令。Amazon CDK 运行应用程序并从中合成一个 Amazon CloudFormation 模板,然后显示该模板。该模板是一个约 600 行的 YAML 文件。此处显示了文件的开头。您的模板可能与此示例有所不同。

Resources: MyWebServerLB3B5FD3AB: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: LoadBalancerAttributes: - Key: deletion_protection.enabled Value: "false" Scheme: internet-facing SecurityGroups: - Fn::GetAtt: - MyWebServerLBSecurityGroup01B285AA - GroupId Subnets: - Ref: EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1Subnet3C273B99 - Ref: EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2Subnet95FF715A Type: application DependsOn: - EcsDefaultClusterMnL3mNNYNVpcPublicSubnet1DefaultRouteFF4E2178 - EcsDefaultClusterMnL3mNNYNVpcPublicSubnet2DefaultRouteB1375520 Metadata: aws:cdk:path: HelloEcsStack/MyWebServer/LB/Resource MyWebServerLBSecurityGroup01B285AA: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Automatically created Security Group for ELB HelloEcsStackMyWebServerLB06757F57 SecurityGroupIngress: - CidrIp: 0.0.0.0/0 Description: Allow from anyone on port 80 FromPort: 80 IpProtocol: tcp ToPort: 80 VpcId: Ref: EcsDefaultClusterMnL3mNNYNVpc7788A521 Metadata: aws:cdk:path: HelloEcsStack/MyWebServer/LB/SecurityGroup/Resource # and so on for another few hundred lines

要在您的 Amazon Web Services 账户 中部署服务,请在应用程序的主目录中运行 cdk deploy 命令。将要求您批准 Amazon CDK 生成的 IAM policy。

部署需要几分钟,在此期间,Amazon CDK 将创建多个资源。部署输出的最后几行包括负载均衡器的公共主机名和新 Web 服务器的 URL。它们如下所示。

Outputs: HelloEcsStack.MyWebServerLoadBalancerDNSXXXXXXX = Hello-MyWeb-ZZZZZZZZZZZZZ-ZZZZZZZZZZ.us-west-2.elb.amazonaws.com HelloEcsStack.MyWebServerServiceURLYYYYYYYY = http://Hello-MyWeb-ZZZZZZZZZZZZZ-ZZZZZZZZZZ.us-west-2.elb.amazonaws.com

步骤 3:测试 Web 服务器

从部署输出复制 URL 并将其粘贴到 Web 浏览器。将显示来自 Web 服务器的以下欢迎消息。

Amazon ECS 示例应用程序的屏幕截图。输出显示“Your application is now running on Amazon ECS”(您的应用程序现在正在 Amazon ECS 上运行)。

步骤 4:清除

完成 Web 服务器的使用后,通过在应用程序的主目录中运行 cdk destroy 命令,使用 CDK 结束服务。这样做可以防止您在未来产生任何意外费用。

后续步骤

要了解有关如何使用 Amazon CDK 开发 Amazon 基础设施的更多信息,请参阅《Amazon CDK 开发人员指南》。

有关使用所选语言编写 Amazon CDK 应用程序的信息,请参阅以下内容:

TypeScript

在 TypeScript 中使用 Amazon CDK

JavaScript

在 JavaScript 中使用 Amazon CDK

Python

在 Python 中使用 Amazon CDK

Java

在 Java 中使用 Amazon CDK

C#

在 C# 中使用 Amazon CDK

Go

在 Go 中使用 Amazon CDK

有关本主题中使用的 Amazon 构造库模块的更多信息,请参阅以下 Amazon CDK API 参考概述。