当你利用 CloudFormation 在 YAML 模板中定义你的基础设施时,将 Docker 容器部署到 AWS弹性容器服务(ECS)是直接和自动化的。在这里,我们将通过一个简单的例子,我们将设置在 AWS 中运行一个 NGINX 容器并通过互联网访问它所需的一切。
我们选择运行 NGINX 官方的 Docker 镜像,因为它将允许我们浏览到 80 端口并查看响应,以证明容器正在运行。为了让这个部署到 ECS 中,我们需要以下构件。
ECS 任务可以根据您的要求,以 2 种模式运行。
在这个例子中,我们将使用 Fargate 发射类型,因为它是最快速的入门方式。✔
为了使这个例子尽可能的简单,我们将假设你已经有了下面的设置。
我们将使用 YAML 风味的 CloudFormation,并逐个建立一个堆栈,直到我们有一个 NGINX容器运行,我们可以通过互联网访问。
我推荐 IntelliJ IDEA 来编辑 CloudFormation 模板,因为它有一个插件,可以提供语法验证。
首先创建一个文件 ecs.yml,并添加以下定义。
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
SubnetID:
Type: String
Resources:
Cluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: deployment-example-cluster
LogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: deployment-example-log-group
ExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: deployment-example-role
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
ContainerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: ContainerSecurityGroup
GroupDescription: Security group for NGINX container
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
我们的模板只需要一个参数,SubnetID,来指定将 ECS 任务部署到哪个子网。在正常的生产设置中,你会希望部署到多个子网的可用性区,以实现高可用性。
AWS::ECS::Cluster
资源除了名称外,不需要其他配置。
ECS 任务将把应用日志记录到这个日志组。
这是 ECS 任务在执行过程中要承担的角色。因此,它需要所提供的承担角色策略文档,允许ECS 任务承担这个角色。
它还附加了 AmazonECSTaskExecutionRolePolicy,其中包含了 logs:CreateLogStream 和 logs:PutLogEvents 等动作。
安全组定义了哪些网络流量将被允许访问 ECS 任务。在我们的例子中,我们只需要访问 80 端口,即默认的 NGINX 端口。
让我们使用以下 AWS CLI 命令应用此模板,创建一个 CloudFormation 堆栈来供应上述资源。记住要用自己的子网来代替
$ aws cloudformation create-stack --stack-name example-deployment --template-body file://./ecs.yml --capabilities CAPABILITY_NAMED_IAM --parameters 'ParameterKey=SubnetID,ParameterValue='
最终,如果您在 AWS 控制台中导航到 CloudFormation > Stacks > example-deployment > Resources,您会看到以下资源已经创建。
将以下定义添加到 ecs.yml CloudFormation 模板的末尾。
//previous template code
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: deployment-example-task
Cpu: 256
Memory: 512
NetworkMode: awsvpc
ExecutionRoleArn: !Ref ExecutionRole
ContainerDefinitions:
- Name: deployment-example-container
Image: nginx:1.17.7
PortMappings:
- ContainerPort: 80
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-region: !Ref AWS::Region
awslogs-group: !Ref LogGroup
awslogs-stream-prefix: ecs
RequiresCompatibilities:
- EC2
- FARGATE
Service:
Type: AWS::ECS::Service
Properties:
ServiceName: deployment-example-service
Cluster: !Ref Cluster
TaskDefinition: !Ref TaskDefinition
DesiredCount: 1
LaunchType: FARGATE
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
Subnets:
- !Ref SubnetID
SecurityGroups:
- !GetAtt ContainerSecurityGroup.GroupId
我们正在定义一个 AWS::ECS::TaskDefinition
,其重要属性如下。
awsvpc
,这是 Fargate 启动类型所需要的。这个网络模式意味着我们的任务将拥有和 EC2 实例一样的网络能力,比如它自己的 IP 地址。我们正在定义一个AWS::ECS::
服务,其属性如下。
现在让我们用 update-stack 命令更新 CloudFormation 栈。
$ aws cloudformation update-stack --stack-name example-deployment --template-body file://./ecs.yml --capabilities CAPABILITY_NAMED_IAM --parameters 'ParameterKey=SubnetID,ParameterValue='
稍等片刻,然后您可以看到我们的 CloudFormation 堆栈中又创建了一些资源。
前往 ECS > 服务,我们来看看有什么创造。
你会看到 deployment-example-cluster,它重要有 1 个服务和 1 个正在运行的任务。
单击群集,然后单击_“任务”_选项卡。
这里可以看到我们使用的是我们在 CloudFormation 中定义的任务定义,任务状态为运行,启动类型为 Fargate。
点击任务 id 查看更多详情。这里是详情页的网络部分。
你可以看到这里我们已经得到了任务的公共 IP 地址。去试试在浏览器中打这个 IP。
看来我们得到了一个 NGINX!
要清理的话,只需运行 delete-stack 命令即可。
$ aws cloudformation delete-stack --stack-name example-deployment
希望你已经看到,在 ECS 中运行 Docker 容器是很直接的,而且 AWS 提供了大量的配置选项,可以让事情完全按照你的意愿工作。
使用 CloudFormation,可以直接进行增量更改,是管理 ECS 集群的好选择。