亚马逊AWS官方博客

使用 Copilot 部署你的应用

Amazon Elastic Container Service 是一项高度可扩展的快速容器管理服务,可让您在集群上轻松运行、停止和管理容器。容器是在任务定义中定义的,您可以使用该任务定义运行单个任务或服务中的任务。为了让客户更易于部署他们的容器业务,我们将分享一款新的命令行工具:Copilot。


AWS Copilot 适用于现有 ECS 用户和新 ECS 用户。使用 Copilot 可以从应用程序及其生命周期的角度进行管理,而非简单地基础设施管理。Copilot 在默认情况下就可以完成适用于生产环境的现代应用部署,这写逻辑是基于 ECS 工程师和客户的经验设计的。
除了部署到 ECS, 你还可以使用 Copilot 部署一个基于 App Runner 或 Fargate 的服务,你可以在服务类型中自由选择。

安装 Copilot

你可以执行以下的命令安装 Copilot

curl -Lo /usr/local/bin/copilot https://github.com/aws/copilot-cli/releases/latest/download/copilot-darwin && chmod +x /usr/local/bin/copilot && copilot --help

另外,使用 Copilot 前请确认已经安装 AWS CLI 并配置了相应的凭证。
Copilot 需要使用 Docker 来构建应用程序。所以请确认已经安装 Docker。

Copilot 概念介绍

在 Copilot help 界面可以看到,Copilot 有三个主要概念呢。

分别是:

Application – 在集群中,可能同时运行这多个业务系统。Application 这个概念正是如此。一个 Application 由一个或多个 Service 组成。你可以通过copilot app show查看应用的组成。

Environment – Environment 对应的是开发,测试,生产等环境。在初始化 Environment 时,可以选择现有VPC,或创建一个新的VPC。Copilot 可以根据你指定的 CIDR范围创建 VPC, Subnet, Security Group 和 Internet Gateway.

Service – Service 指的是一个长时间运行容器。一个 Application 由一个或多个 Service 组成。Copilot 有多种 Service 类型,分别对应不同的使用场景,也对应基础设施的类型,ECS 或者 Farget 或者 App Runner.

Service 类型

Copilot 中重要的概念部分就是 Service。Copilot Service 分为三种,四个类型:

  • 面向互联网的服务 Internet-facing services
    • 需求驱动的 Web 服务 Request-Driven Web Service – 此类服务运行在 AWS App Runner 上,是一种灵活弹性的方案。可根据传入流量自动缩放实例,并在没有流量时缩容到基础实例。对于请求量突然增加或请求量减少的HTTP服务,此选项更具成本效 益。
    • 负载均衡的 Web 服务 Load Balanced Web Service – 此类服务运行在 ECS Fargate 上,以 ALB 作为流量入口。此选项适用于具有稳定请求量的HTTP服务,此类服务需要依赖于 VPC 进行进阶配置。
  • 后端服务 Backend Service – 同样运行在 ECS Farget 上的服务,区别是没有访问入口。如果您想要一个不能从外部访问的服务,只能被内部调用的服务,那么 Backend Service 非常合适。
  • 工作服务 Worker Service – Worker Service 使用“发布/订阅”架构实现服务对服务的异步通信。应用程序可以讲事件发送到 SNS,然后由 Worker Service 异步处理。Worker Service 由两部分构成。
    • 一个或多个 Amazon SQS 消息队列用于处理发布到SNS的通知,以及死信队列用于处理故障。
    • 运行在 ECS Fargate 上的服务,具有轮询SQS队列和异步处理消息的权限。

使用 Copilot 部署实例应用

我们先从一个简单单体应用开始

(1)克隆代码仓库

git clone https://github.com/aws-samples/aws-copilot-sample-service

可以看到整个文件夹主要由三部分构成

  • Dockerfile – 用于构建 Service
  • index.html – 用于应用显示
  • copilot/front-end/manifest.yml – 用于打包、发布和配置 Service

(2)通过 Copilot 部署Service

copilot init

copilot 会通过可交互命令行,向我们询问四个问题:

  • “What would you like to name your application” – 给你的 Application 起一个名字,这里可以是一个新的名字,也可以选择一个已有 Application, 这样就可以把创建的Service注册到应用之下。这里我们输入 colipot-app.
  • “Which service type best represents your service’s architecture?” – 根据需要选择对应的 Service 类型,这里我门选择 Load Balanced Web Service.
  • “What do you want to name this Load Balanced Web Service?” – 给你的 Service 起一个名字,你可以输入 front-end.
  • “Which Dockerfile would you like to use for front-end?” – 指定 Service 的 Dockerfile,这里我们选择默认的 ./Dockerfile.

然后我们稍等几分钟,等待部署的完成。
一旦部署完成,控制台会出现部署应用的访问地址。
至此,一个应用就轻松的被 Copilot 部署成功。

(3)删除 Service

copilot app delete

Copilot 会删除包括 ECS, ECR 在内的所有资源。

部署一个完整的应用

上一节提到一个 Application 可以由多个 Service 组成,这里我们部署一个三层架构的 Application, 架构如下:


这一次我们使用 Load Balanced Web Service 和 Backend Service 构建一个完整的 Application。
首先我们先克隆代码仓库:

git clone https://github.com/aws-containers/ecsdemo-frontend
git clone https://github.com/aws-containers/ecsdemo-nodejs
git clone https://github.com/aws-containers/ecsdemo-crystal

部署 Frontend

(1)初始化 Service

cd ecsdemo-frontend
copilot init

参考以下内容进行交互式配置

    • Application name: colipot-workshop
    • Service Type: Load Balanced Web Service
    • What do you want to name this Load Balanced Web Service: ecsdemo-frontend
    • Dockerfile: ./Dockerfile

在此之后,当询问你是否部署一个 Test 环境时,选择 No,因为我们还要进行一些配置

(2)预配置 crystal 和 nodejs 服务的访问地址
这些 服务地址是在后续步骤中创建的,这里我们提前配置用于服务发现。

cat << EOF >> copilot/ecsdemo-frontend/manifest.yml
variables:
    CRYSTAL_URL: "http://ecsdemo-crystal.prod.colipot-workshop.local:3000/crystal"
    NODEJS_URL: "http://ecsdemo-nodejs.prod.colipot-workshop.local:3000"
EOF
git rev-parse --short=7 HEAD > code_hash.txt

(3)初始化环境

copilot env init --name prod --profile default --default-config

(4)部署服务

copilot svc deploy

这时已经可以看到服务被成功部署,并返回访问 URL。你可以用下面的命令获取 URL。

copilot svc show -n ecsdemo-frontend --json | jq -r .routes[].url

部署 Node.js Backend API

(1)初始化 Service

cd ../ecsdemo-nodejs
git rev-parse --short=7 HEAD > code_hash.txt
copilot init

参考以下内容进行交互式配置

    • Application: colipot-workshop
    • Service Type: Load Balanced Web Service
    • What do you want to name this Load Balanced Web Service: ecsdemo-nodejs
    • Dockerfile: ./Dockerfile

(2)部署 Service

copilot deploy

部署 Crystal Backend API

(1)初始化 Service

cd ../ecsdemo-crystal
git rev-parse --short=7 HEAD > code_hash.txt
copilot init

参考以下内容进行交互式配置

    • Application: colipot-workshop
    • Service Type: Load Balanced Web Service
    • What do you want to name this Load Balanced Web Service: ecsdemo-crystal
    • Dockerfile: ./Dockerfile

(2)部署 Service

copilot deploy

更新服务

这是一个可以不断请求后端服务,显示后端服务IP的应用。在我们完成部署后,可以看到页面成功显示,但每次返回的都是相同的后端服务。
这是因为我们只部署了一个 ecsdemo-nodejs 和 csdemo-crystal 服务,我们需要更新服务来扩容。

更新 ecsdemo-nodejs

cd ../csdemo-nodejs
mkdir -p copilot/ecsdemo-nodejs/
cat << EOF >> copilot/ecsdemo-frontend/manifest.yml
name: ecsdemo-nodejs
type: Backend Service
image:
  build: ./Dockerfile
  port: 3000
count: 3
EOF
copilot svc deploy

更新 csdemo-crystal

cd ../csdemo-crystal
mkdir -p copilot/ecsdemo-crystal/
cat << EOF >> copilot/ecsdemo-frontend/manifest.yml
name: ecsdemo-crystal
type: Backend Service
image:
  build: ./Dockerfile
  port: 3000
count: 3
EOF
copilot svc deploy

几分钟后,可以看到部署成功,再次打开前端页面,可以看到流量分配到不同的多个后端服务上。

创建 pipeline

在创建完 Service 后我们是可以对他进行后续的会更新和修改的。但从刚才的例子看,这个更新的流程还是有些繁琐。
Copilot 是支持使 Pipeline 流水线发布应用的。接下来我们一起创建一个 Frontend 的 Pipeline。

(1)创建 CodeCommit

首先我们创建一个 CodeCommit 托管代码

repo_https_url=$(aws codecommit create-repository \
  --repository-name "ecsdemo-frontend" \
  --repository-description "ECSWorkshop frontend application" | jq -r '.repositoryMetadata.cloneUrlHttp')

并配置 CodeCommit 凭证

# Configure git client to use the aws cli credential helper
git config --global credential.helper '!aws codecommit credential-helper $@'
git config --global credential.UseHttpPath true

# Add the new repo as a remote
git remote add cc $repo_https_url

# Push the changes
git push cc HEAD

(2)创建 Pipeline

cd ../ecsdemo-frontend
copilot pipeline init

在之后的可交互配置中:
选择已有环境:prod
代码仓库选择刚才创建的CodeCommit,类似于:git-codecommit..xxxxxxx

(3)运行 Pipeline

这时我们就可以触发这个 Pipeline:
首先我们提交代码,并更新 Pipeline

git add copilot
git commit -m "Adding copilot pipeline configuration"
git push cc
copilot pipeline update

可以通过下面的命令查看 Pipeline 的运行情况:

copilot pipeline update

我们可以更新一些代码,来查看 Pipeline 的运行情况。
我们更新app/views/application/index.html.erb中第9行的代码,在行首加上[Pipeline Deployed!],类似这样:

[Pipeline Deployed!] Rails frontend: Hello! from <%= @az %> running <%= @code_hash %>

然后我们更新代码至 CodeCommit:

git rev-parse --short=7 HEAD > code_hash.txt
git add app/views/application/index.html.erb code_hash.txt
git commit -m "Updating code hash and updating frontend"
git push cc

稍等几分钟后就可以完成构建,在这期间你可以通过 CodePipeline 或以下命令查看 Pipeline 运行情况:

git rev-parse --short=7 HEAD > code_hash.txt
git add app/views/application/index.html.erb code_hash.txt
git commit -m "Updating code hash and updating frontend"
git push cc

几分钟后,新版本部署完成,你可以访问URL,查看新的界面,就类似这样:

总结

Copilot 非常适合用于管理一些轻量级的工作负载。可以用极短的时间帮助客户构建一个高可用的微服务架构。

本篇作者

王逸飞

亚马逊云科技解决方案架构师,负责基于亚马逊云科技的云计算方案的咨询与架构设计,同时致力于亚马逊云科技云服务知识体系的传播与普及。在微服务,容器等领域拥有多年经验。