この記事について
AWS & Game Advent Calendar 2020 23日目の記事になります。
AWSでコンテナを動かす場合真っ先に候補に上がるサービスはECSかと思います。
とても便利なサービスなのは間違いありませんが、いざ使うとなると考慮する点がたくさんあります。
- ネットワーク(VPC)設計
- ECSのクラスタ/サービス/タスク定義の作成
- デプロイフローの確立
- ロギング
上記はあくまで一例ですが、基本どのプロジェクトでECSを使う場合でも、タスクが起動するVPCの設計から始まり、デプロイされたタスクが出力するログをどのように集約/管理するのかまでは共通で考える必要があるのではないかと思います。
その一方で、ECSが一般的に広く使われるようになっていて、ある種の「利用する上でのベストプラクティス」的なものが生まれつつあるように思います。
都度1から構築しても良いですが、できればベストプラクティスに沿ってもっと簡単に構築できるようになれば便利ですよね。
そんな願いを叶えてくれるツールが2020/11/23にGAしています。「AWS Copilot」と言います。
AWS Copilot is 何?
- Amazon ECS CLI の後継に当たるものです
- AWSのECSチームのエンジニアやユーザーが作り上げてきたベストプラクティスに基いてデフォルトでモダンかつプロダクションレディなインフラを構築できます
AWS Copilot のご紹介
https://aws.amazon.com/jp/blogs/news/introducing-aws-copilot/
実際に使ってみる
インストール
GitHubから最新のバイナリファイルを落としてきます
$ curl -Lo /usr/local/bin/copilot https://github.com/aws/copilot-cli/releases/download/v0.1.0/copilot-darwin-v0.1.0 && chmod +x /usr/local/bin/copilot
$ copilot --help
👩✈️ Launch and manage applications on Amazon ECS and AWS Fargate.
Commands
Getting Started 🌱
init Create a new ECS application.
docs Open the copilot docs.
Develop ✨
app Commands for applications.
Applications are a collection of services and environments.
env Commands for environments.
Environments are deployment stages shared between services.
svc Commands for services.
Services are long-running Amazon ECS services.
Release 🚀
pipeline Commands for pipelines.
Continuous delivery pipelines to release services.
deploy Deploy your service.
Settings ⚙️
version Print the version number.
completion Output shell completion code.
Flags
-h, --help help for copilot
-v, --version version for copilot
Examples
Displays the help menu for the "init" command.
`$ copilot init --help`
サンプルアプリケーションのClone
$ git clone https://github.com/aws-samples/amazon-ecs-cli-sample-app.git aws-copilot-example
Credentialの設定
aws configure
でプロファイルを作成してAWS_PROFILE
として環境変数に設定しておきます。
$ aws configure --profile copilot-example
$ export AWS_PROFILE=copilot-example
アプリケーションのセットアップ
GitからCloneしたディレクトリに移動してでセットアップを行っていきます。
copilot init
を実行して対話式で情報の入力をしていくことでAWS上に必要なリソースを構築することができます。
$ cd aws-copilot-example
$ copilot init
Note: It's best to run this command in the root of your Git repository.
Welcome to the Copilot CLI! We're going to walk you through some questions
to help you get set up with an application on ECS. An application is a collection of
containerized services that operate together.
What would you like to name your application? [? for help] copilot-example-app
Application name: copilot-example-app
Which service type best represents your service's architecture? [Use arrows to move, type to filter, ? for more help]
> Load Balanced Web Service
Backend Service
Application name: copilot-example-app
Service type: Load Balanced Web Service
What do you want to name this Load Balanced Web Service? [? for help] copilot-example-service
Application name: copilot-example-app
Service type: Load Balanced Web Service
Service name: copilot-example-service
Which Dockerfile would you like to use for copilot-example-service? [Use arrows to move, type to filter, ? for more help]
> ./Dockerfile
Application name: copilot-example-app
Service type: Load Balanced Web Service
Service name: copilot-example-service
Dockerfile: ./Dockerfile
no EXPOSE statements in Dockerfile ./Dockerfile
Which port do you want customer traffic sent to? [? for help] (80) 80
Application name: copilot-example-app
Service type: Load Balanced Web Service
Service name: copilot-example-service
Dockerfile: ./Dockerfile
no EXPOSE statements in Dockerfile ./Dockerfile
Port: 80
Ok great, we'll set up a Load Balanced Web Service named copilot-example-service in application copilot-example-app listening on port 80.
✔ Created the infrastructure to manage services under application copilot-example-app.
✔ Manifest file for service copilot-example-service already exists at copilot/copilot-example-service/manifest.yml, skipping writing it.
Your manifest contains configurations like your container size and port (:80).
✔ Created ECR repositories for service copilot-example-service.
All right, you're all set for local development.
Would you like to deploy a test environment? [? for help] (y/N) y
All right, you're all set for local development.
Deploy: Yes
All right, you're all set for local development.
Deploy: Yes
✔ Created the infrastructure for the test environment.
- Virtual private cloud on 2 availability zones to hold your services [Complete]
- Virtual private cloud on 2 availability zones to hold your services [Complete]
- Internet gateway to connect the network to the internet [Complete]
- Public subnets for internet facing services [Complete]
- Private subnets for services that can't be reached from the internet [Complete]
- Routing tables for services to talk with each other [Complete]
- ECS Cluster to hold your services [Complete]
- Application load balancer to distribute traffic [Complete]
✔ Linked account XXXXXXXXXXXX and region ap-northeast-1 to application copilot-example-app.
✔ Created environment test in region ap-northeast-1 under application copilot-example-app.
Sending build context to Docker daemon 88.06kB
Step 1/2 : FROM nginx
---> ae2feff98a0c
Step 2/2 : COPY index.html /usr/share/nginx/html
---> Using cache
---> ad1b08cb2bb0
Successfully built ad1b08cb2bb0
Successfully tagged XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/copilot-example-app/copilot-example-service:cee7709
Login Succeeded
The push refers to repository [XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/copilot-example-app/copilot-example-service]
2e8160029ff7: Pushed
4eaf0ea085df: Pushed
2c7498eef94a: Pushed
7d2b207c2679: Pushed
5c4e5adc71a8: Pushed
87c8a1d8f54f: Pushed
cee7709: digest: sha256:fe7757f53a6d9a90c57cafd32578e5b5290430cf0a06067ba92b0031fb00c873 size: 1570
✔ Deployed copilot-example-service, you can access it at http://{ELB_ENDPOINT}
実行が完了するとテスト環境が作成されELBのエンドポイントのURLが返ってきました。アクセスしてみましょう。
表示できましたね。今回はサンプルアプリケーションですが、実際の開発でこの画面を表示させるまでに構築する必要のあるAWSリソースは結構多いです。
コマンドの実行自体は10分程度で完了するので短時間で必要なものを揃えられるというのはとても魅力的です。
ちなみに裏ではCloudFormationのスタックが実行されています。
論理ID | タイプ |
---|---|
AdministrationRole | AWS::IAM::Role |
ExecutionRole | AWS::IAM::Role |
CloudformationExecutionRole | AWS::IAM::Role |
Cluster | AWS::ECS::Cluster |
DefaultHTTPTargetGroup | AWS::ElasticLoadBalancingV2::TargetGroup |
DefaultPublicRoute | AWS::EC2::Route |
EnableLongARNFormatAction | Custom::EnableLongARNFormatFunction |
EnableLongARNFormatFunction | AWS::Lambda::Function |
EnvironmentManagerRole | AWS::IAM::Role |
EnvironmentSecurityGroup | AWS::EC2::SecurityGroup |
EnvironmentSecurityGroupIngressFromPublicALB | AWS::EC2::SecurityGroupIngress |
EnvironmentSecurityGroupIngressFromSelf | AWS::EC2::SecurityGroupIngress |
HTTPListener | AWS::ElasticLoadBalancingV2::Listener |
InternetGateway | AWS::EC2::InternetGateway |
InternetGatewayAttachment | AWS::EC2::VPCGatewayAttachment |
PrivateSubnet1 | AWS::EC2::Subnet |
PrivateSubnet2 | AWS::EC2::Subnet |
PublicLoadBalancer | AWS::ElasticLoadBalancingV2::LoadBalancer |
PublicLoadBalancerSecurityGroup | AWS::EC2::SecurityGroup |
PublicRouteTable | AWS::EC2::RouteTable |
PublicSubnet1 | AWS::EC2::Subnet |
PublicSubnet1RouteTableAssociation | AWS::EC2::SubnetRouteTableAssociation |
PublicSubnet2 | AWS::EC2::Subnet |
PublicSubnet2RouteTableAssociation | AWS::EC2::SubnetRouteTableAssociation |
ServiceDiscoveryNamespace | AWS::ServiceDiscovery::PrivateDnsNamespace |
VPC | AWS::EC2::VPC |
ECRRepocopilotDASHexampleDASHservice | AWS::ECR::Repository |
KMSKey | AWS::KMS::Key |
PipelineBuiltArtifactBucket | AWS::S3::Bucket |
PipelineBuiltArtifactBucketPolicy | AWS::S3::BucketPolicy |
CustomResourceRole | AWS::IAM::Role |
DiscoveryService | AWS::ServiceDiscovery::Service |
ExecutionRole | AWS::IAM::Role |
HTTPListenerRule | AWS::ElasticLoadBalancingV2::ListenerRule |
HTTPRulePriorityAction | Custom::RulePriorityFunction |
HTTPWaitHandle | AWS::CloudFormation::WaitConditionHandle |
LogGroup | AWS::Logs::LogGroup |
RulePriorityFunction | AWS::Lambda::Function |
Service | AWS::ECS::Service |
TargetGroup | AWS::ElasticLoadBalancingV2::TargetGroup |
TaskDefinition | AWS::ECS::TaskDefinition |
TaskRole | AWS::IAM::Role |
WaitUntilListenerRuleIsCreated | AWS::CloudFormation::WaitCondition |
これだけのリソースが構築されていました。
今のところは起動タイプがFargateのみになっていて、EC2で起動したい場合は手動で作成する必要がありそうなので
copilotをECS環境構築のスターターキットとして利用し、細かな要件や設定は自分達で追加していくといった使い方が1番しっくり来ますね。
アプリケーションに対してのcopilotからの操作
copilot app show
でcopilotで構築したアプリケーション/環境/サービスの情報を参照できます。
$ copilot app show
About
Name copilot-example-app
URI
Environments
Name AccountID Region
test XXXXXXXXXXXX ap-northeast-1
Services
Name Type
copilot-example-service Load Balanced Web Service
起動したタスクから出力されるログはCloudWatchlogsに保存されるようになっています。
マネジメントコンソールから見てもいいですがcopilot svc logs
でログの閲覧が可能です。
$ copilot svc logs
Showing logs of service copilot-example-service deployed in environment test
copilot-example-service/0 10.0.1.45 - - [24/Dec/2020:18:03:01 +0000] "GET / HTTP/1.1" 200 3165 "-" "ELB-HealthChecker/2.0" "-"
copilot-example-service/0 10.0.1.45 - - [24/Dec/2020:18:03:12 +0000] "GET / HTTP/1.1" 200 3165 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" "XXX.XXX.XXX.XXX"
copilot-example-service/0 10.0.1.45 - - [24/Dec/2020:18:03:12 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" "XXX.XXX.XXX.XXX"
現在はテスト環境しかないので本番環境を作成してみましょう。
新たにprod
という環境を作成して先ほど作成したcopilot-example-service
をデプロイします。
$ copilot env init --name prod
$ copilot svc deploy --name copilot-example-service --env prod
デプロイが完了するとテスト環境を作成したときと同じくELBのエンドポイント経由でECSにアクセスできるようになります。
アプリケーションの情報とログを見てみましょう。
$ copilot app show
About
Name copilot-example-app
URI
Environments
Name AccountID Region
test XXXXXXXXXXXX ap-northeast-1
prod XXXXXXXXXXXX ap-northeast-1
Services
Name Type
copilot-example-service Load Balanced Web Service
$ copilot svc logs copilot-example-service --env prod
Showing logs of service copilot-example-service deployed in environment prod
copilot-example-service/7 10.0.0.206 - - [24/Dec/2020:18:20:25 +0000] "GET / HTTP/1.1" 200 3165 "-" "ELB-HealthChecker/2.0" "-"
copilot-example-service/7 10.0.0.206 - - [24/Dec/2020:18:20:30 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" "XXX.XXX.XXX.XXX"
copilot-example-service/7 10.0.0.206 - - [24/Dec/2020:18:20:30 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" "XXX.XXX.XXX.XXX"
正常にアクセスが来ていますね、問題なさそうです。
copilot app show
だと若干情報が少なめですがcopilot svc status
でサービスのステータスを確認できます。
$ copilot svc status copilot-example-service --env prod
Showing status of service copilot-example-service deployed in environment prod
Service Status
ACTIVE 1 / 1 running tasks (0 pending)
Last Deployment
Updated At 6 minutes ago
Task Definition arn:aws:ecs:ap-northeast-1:XXXXXXXXXXXX:task-definition/copilot-example-app-prod-copilot-example-service:1
Task Status
ID Image Digest Last Status Health Status Started At Stopped At
7788f7bc fe7757f5 RUNNING UNKNOWN 7 minutes ago -
Alarms
Name Health Last Updated Reason
一通り動作を確認できました。費用がかかるのでお掃除しましょう。copilot app delete
を実行します。
$ copilot app delete
Are you sure you want to delete application copilot-example-app? Yes
✔ Deleted service copilot-example-service from environment test.
✔ Deleted service copilot-example-service from environment prod.
✔ Deleted service copilot-example-service resources from application copilot-example-app.
✔ Deleted service copilot-example-service from application copilot-example-app.
✔ Deleted environment test from application copilot-example-app.
✔ Deleted environment prod from application copilot-example-app.
✔ Cleaned up deployment resources.
✔ Deleted application resources.
✔ Deleted application configuration.
✔ Deleted local .workspace file.
お掃除できました、CloudFormationで管理されているのでそこから削除すれば不要なものは残らず綺麗になりますね。
まとめ
copilotを利用することでベストプラクティスに沿ったECS環境をお手軽に構築できました。
今回の記事ではご紹介していませんが、デプロイに利用するCodePipelineなどのCode系サービスもcopilotから構築して
GitへのPushをトリガーに自動デプロイするフローを整えることが可能ですのでまたの機会に試してみたいと思います。
まだGAされたばかりなので今後もさらに便利なアップデートが行われていくに違いありません。
私自身も定期的にcopilotのアップデートをウォッチしていきたいと思います。