ECS のデプロイツール、サービスタイプを選択 + Dockerfile を用意するだけで ECS 上にアプリを展開できる。Amplify が Front-end のデプロイ & AaC (Architecture as Code) ツールだとしたら、こちらは Back-end の AaC ツールといえる。
ぱっと見 ↓ みたいな機能構成の理解でいいのかな。
- マイクロサービスアーキテクチャっぽく Application を複数 Service で構成
- Request-Driven Web Service (App Runner、制約多め)
- Load Balanced Web Service (ALB + ECS Fargate)
- Backend Service (endpoint のない ECS Fargate)
- Worker Service (ECS Fargate + Amazon SNS + Amazon SQS)
- Service の他に Job も登録できる
- いまは Scheduled Jobs (cron like な定期実行) だけ
- 構築した Application は dev, prod など各 Environment ごとに展開
- Application のデプロイについて CodePipeline で CI/CD を構成
- Source Stage: repo の push を hook に pipeline を起動
- Build Stage: repo から code を取得 => docker build し ecr へ push
- Deploy Stage: テストや主導承認やらして rolling update を実行
本番環境での利用は ↓ あたり読んでから選定。
- aurora serverless v2 に対応
- 初回 deploy 時に失敗すると rollback してエラーログを遡及できない問題について
--no-rollback
で対応可能になった - multi branch pipeline に対応したぽい
- app runner が vpc に対応
copilot は terraform, serverless, cdk なんかと比べると設定項目が少なく、あくまでも「 ECS のベストプラクティスな service 構成を手軽に作る 」ことに注力してるぽい。
この手のやつ、デザインされた範囲内の調整は気軽だが、そこを外れると辛い。amplify 同様に ↓ っぽく新規プロジェクト立ち上げ時のテンプレとして使い、どこかで見切って移行する前提の運用がよさそう。
- 素早く「よくある形」を構成する
- ツールの「カスタマイズ・調整の範囲」を見越した設計をする
- 規模が拡大したら潔く捨てる (体制、ツール、アーキテクト再選定する)
既に aws インフラ設計をまるっと頭でできるくらいなら、cdk で柔軟に組むほうが絶対楽。でもその頭がないうちは、こういうテンプレセットで「よくある形」を構成してくれることにありがたみを感じる。
とりあえず初回の立ち上げは miss ると時間溶けるので必ず service の count (タスク数) を 0 にして CREATE => ROLLBACK 落ちだけは回避しておくといい。
- CREATE からの ROLLBACK はキャンセルできず、ROLLBACK がマジで時間かかる
- が UPDATE については Web Console から早めにキャンセルできる & ROLLBACK も早い ので試行錯誤はここで
- aws/copilot-cli#3061
- aws/containers-roadmap#1247
- 初回の deploy でコケると log group が消えて
copilot svc logs
見れない- If initial deploy fails, log group deleted, so can't inspect why deploy failed #2811
- 先に plain な hello world Dockerfile deploy する
- ↑ で log group が維持される状態になってから検証してく
- 当然だけど、事前に開発環境のテスト通過や、ブランチ、コミットの整理しておく
- なんだかんだサクッとはいかないので、コード安定状態 & しっかり時間とってやること
あと *_IN_PROGRESS
で待たされているときは ecs の web console から task 数を 0 にしてキャンセルすればいい。
copilot svc deploy keep running due to task healthcheck failure #1580
Trouble Shooting - 色々な罠にハマった際のメモ
- ECS タスク起動失敗なので
copilot svc logs
や cloudwatch logs で error check して修正する - DB がないとか、疎通できてないのに migrate しようとして exit 1 になってたり
- ECS タスク定義からタスク数 0 にしてやると health check が入らず「アプリ起因の不具合でタスク起動しない」を回避できる
- aws/copilot-cli#1180 (comment)
- 構成に必要な policy が明文化されてない問題ある
- aws/copilot-cli#1345
- 基本アプリまるごと aws アカウントを分離して admin 権限で試したほうが良さそう
ALBのヘルスチェックでHealth checks failed with these codes [302]が出た場合の対処方法
Fargate での Amazon ECS タスクのヘルスチェックの失敗をトラブルシューティングするにはどうすればよいですか?
- うっかりで多いのは
/
path がログイン認証必要で 300 系で next-auth とか使ってて redirect されてるパターン- ↑ なら manifest.yml の healthcheck を 200 返すパスに変更しておけばいい
- 単純ミス (build 時の args 漏れとか) で普通に立ち上がってないとか、その辺もありえる
- port 3000 のとき alb target group の protocol が HTTPS になっていて落ちていた
- この辺理解浅いが、手動設定が必要とか ... ?
- 一旦
healthcheck.port
を設定したらうまくいったぽい? - aws/copilot-cli#3772
- 80 の default target group は落ちてるけど、rules で追加される正しい port の target group で healthcheck が通るみたい?
ECS だけかどうかは不明だが ENTRYPOINT
or CMD
で jest とかある程度時間かかるテスト系走らせると SIGKILL 137 で落ちる、そんなとこに仕込むなといえばそうなんだけど ... 。
- domain まわり、証明書の登録状況によって validation 通過しない問題ある
- aws/copilot-cli#3347
--import-cert-arns
で回避するか、作り直すかって感じか- 過去に利用した app name だとコケるらしい?
- ssm の parameter store から関連パラメータ消す
- aws/copilot-cli#2718
- ↑ おててで消すときは cloudformation を消せば、あとは parameter store だけ消せばええで、ってことらしい
- cloudformation の対象 stack sets から配下 instance を全消し
- ↑ 成功したら stack sets を消す
- ここまでで関連 resouce は全部消えてるはずなのであとは init からやり直しかな
- Check if secrets exist before deploying the workload #3246
copilot secret init
で登録してないやつを yml に書いてると起動しない- ダミー値でもいいから登録してから deploy してやる
- Dockerfile の entry point で migrate とかする場合は DATABASE_URL とか正常じゃないと当然コケる、DB は addon で載せてたりするはずなので、先にできるだけ外部連携しない状態で deploy してやったほうがいい
- addon の秘匿情報依存な container 構成 (addon で立てた redis の秘匿情報を parametor store から渡せる状態になってないと task の health check 通らないとか) のときは、ちょっとハックだけど一度 fail => retry するくらいまで待って addon の起動・接続情報確認して parametor store 書き換えでいける
Deploy your first application
Commands - init
AWS Copilot のご紹介
AWS Copilot によるコンテナアプリケーションの自動デプロイ
- docker container の deploy tool なので docker 起動してないと cli コマンド一部動かないので注意
- cli で定義した各 app, service などの meta データは ssm の parameter store に入ってる
- 初回
init
時に domain を割り当て or ACM 証明書を割り当てないと https 化が面倒なので注意- ACM 証明書を割り当てる (domain 使わない or 既存 domain 使うケース) => https://aws.github.io/copilot-cli/blogs/release-v118/#certificate-import
$ brew install aws/tap/copilot-cli
# Nginx の Dockerfile と index.html だけの sample repo を clone
#
$ git clone https://github.com/aws-samples/aws-copilot-sample-service example
$ cd example
# AWS_PROFILE 環境変数で app で利用する iam user の credential を流す
# ecr や pipeline で利用する環境は env 別に設定できないっぽいので
# app init の直前で指定、一度設定できればあとは大丈夫かは検証してない
#
$ export AWS_PROFILE=sandbox
# 初期化 & 対話で app の名称とタイプを設定
# copilot init でもいいが、このタイミングで --domain でドメイン指定しないと
# https 化されない & ドメイン指定できないっていう罠があるのでここでやっとく
# ドメイン名は route53 で作成 hostzone 登録してるものを指定
#
$ copilot app init --domain example.com
#
# Application name: xxx
#
# Which workload type best represents your architecture?
# > Request-Driven Web Service App Runner であげるやつ
# Load Balanced Web Service よくある ALB x ECS Fargate 構成
# Backend Service endpoint なしの ECS Fargate
# Worker Service SNS x SQS 購読する ECS Fargate
# Scheduled Job 定期実行させる ECS Fargate task
# service の追加
# copilot init だと app, env, svc を一度にやる感じっぽい
# ただ、何が起きてるか全然わからんし勝手に構築されると面倒なので
# いまのところ個別にやったほうがよさげ、 svc init は全 env に適用されるぽい
#
$ copilot svc init --name myapp
# test 環境 (env) 構築の設定 => aws profile の選択
#
$ copilot env init
#
# Environment name: test
# Credential source: [profile xxxx]
#
# Would you like to use the default configuration for a new environment?
# - A new VPC with 2 AZs, 2 public subnets and 2 private subnets
# - A new ECS Cluster
# - New IAM Roles to manage services and jobs in your environment
# [Use arrows to move, type to filter]
# > Yes, use default.
# Yes, but I'd like configure the default resources (CIDR ranges).
# No, I'd like to import existing resources (VPC, subnets).
#
# vpc 構成とか聞かれる、独自構成にしないなら default でよさそう
# 先に env だけでも deploy しておかないと secrets とか設定できない
#
$ copilot env deploy --name prod
# app 全体のデプロイ
# 個別デプロイは copilot svc deploy -n name -e env とか
#
$ copilot deploy
# fargate 上の container に入るなら
# 別途 ssm session manager plugin の install 必要
# https://go.aws/3qWnSbr
#
$ copilot svc exec -a my-app -e test -n frontend
# log は svc logs で見れる
# --follow は tail っぽくみる option
# log の出方は log stream として区切られてでる関係で
# limit 指定ちゃんとしてないといい感じに出てくれない
#
$ copilot svc logs --follow --limit 50
#
# サクッと調べるなら since で 1h とかのほうがいいかも
# ちゃんと見るなら cloudwatch > logs insights のほうがいい
#
$ copilot svc logs --since 1h
# 作成した app を削除してチュートリアルおしまい
# local の copilot/ 配下は .workspace ファイル以外残る
#
$ copilot app delete
認証情報に AWS Root アカウントのものは使えないらしいので IAM User 作って使えとのこと。
あとクロスアカウント利用する前に app と env でアカウントが内部的に別管理されていることに注意。
Support for cross-account access with copilot pipeline #2533
app 用の profile を指定したい場合は export AWS_PROFILE
などで環境変数を介して読ませる必要があるみたい。code pipeline や ecr ではこの app の profile を利用するっぽいので ...
- code pipeline を実際に動作させる prod の aws 環境の iam profile を
AWS_PROFILE
で読ませる - test, staging などを別の aws 環境の iam profile 指定して構成する
... のがいいか?
基本的には Dockerfile と manifest.yml で 1 service を ecs fargate にぶち上げるっていう作りみたい。裏側では manifest.yml に応じて CloudFormation を組んでるぽい。
Unit | Desc |
---|---|
Application | Service と Environment を包括する ... frontend と api という 2 つの service を持った app みたいな。 |
Environment | AWS リソースを dev, とか prod とかの環境毎に別ものとして展開してくれるやつ。 |
Service | 実行したい code とその周辺 infra をまとめた概念、web server を作りたいなら、express の Dockerfile + code に対して ALB, ECS Fargate を作成してくれる。Manifest で構成管理するぽい。 |
Job | 何らかの Event によって発火する、常駐しない短命の ECS Task 。こちらも Manifest で構成や実行スケジュールを管理する。 |
Pipeline | よくある GitHub なんかと連携する CI/CD の構成をしてくれる、AWS CodePipeline を裏側で動かしてるのかしら。 |
image:
build:
dockerfile: path/to/dockerfile
context: context/dir
target: build-stage # マルチステージビルドならここで stage 指定
service のメインとなる docker container は 1 つだが、Sidecar という形で補助 container を一緒に上げることもできるっぽい。この場合同じ unit (task 定義?) としてデプロイされるっぽく、volume mount も可能みたい。
- Service や Job に DynamoDB, S3, Aurora (Serverless) を追加できる
- 内部的には後述の Addon として追加されるよう
- Aurora Serverless 以外の RDS はまだ未サポートぽい ... 残念
# Aurora Serverless をぶちあげる
$ copilot storage init -t Aurora
$ copilot deploy --name servicename
# copilot/servicename/addons/mycluster
Mappings:
myclusterEnvScalingConfigurationMap:
# このへんお好みに
All:
"DBMinCapacity": 0.5 # AllowedValues: from 0.5 through 128
"DBMaxCapacity": 2 # AllowedValues: from 0.5 through 128
Resources:
# ...
nextjsclusterDBClusterParameterGroup:
# このへんお好みに
Properties:
Family: 'aurora-postgresql14'
nextjsclusterDBCluster:
# このへんお好みに (postgres 15 系は public の仕様がガラッとかわるので注意)
Properties:
Engine: 'aurora-postgresql'
EngineVersion: '14.4'
deploy 後は secrets に認証情報が入るっぽくて、これを自分で copilot secret init で parameter store に入れてつかえよということらしい ... でもほとんどのライブラリで DATABASE_URL
みたいな形式で読みたいから変換が必要で使えない 本当に aws さんってそういうとこあるよね 。
process.env.MYCLUSTER_SECRET // { host: xxx, username: xxx, password: xxx }
現状、回避策としては docker の build entrypoint 時点で MYCLUSTER_SECRET ばらして自前で DATABASE_URL をセットする ... とかしかなさそう。
Compose variable from other variables in manifest.yml #4790
construct DB URLs from DB Secrets #2483
# json なので jq 入れておく
RUN curl -o /usr/local/bin/jq -L https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 && chmod +x /usr/local/bin/jq
RUN chmod 777 entrypoint.sh
CMD [ "bash", "-c", "entrypoint.sh && npm start" ]
#!/bin/bash
# NOTE https://github.com/aws/copilot-cli/issues/4790
#
# copilot が生成する CLUSTER_SECRET が runtime 注入かつ json とかいう
# 意味不明仕様なので entrypoint で json to DATABASE_URL を生成している
# prisma は `.env` という名前のファイルしか解釈しないので要注意
# ref. https://www.prisma.io/docs/guides/development-environment/environment-variables
#
host=$(echo $MYCLUSTER_SECRET | jq -r '.host')
port=$(echo $MYCLUSTER_SECRET | jq -r '.port')
dbname=$(echo $MYCLUSTER_SECRET | jq -r '.dbname')
username=$(echo $MYCLUSTER_SECRET | jq -r '.username')
password=$(echo $MYCLUSTER_SECRET | jq -r '.password')
# 本当なら dockerfile で ENV したいが
# runtime 注入しかされないっぽいので entrypoint でうにょる
# next.js や prisma とかなら .env で回避したり、そうでなくても dotenv でなんとかなるか
# 当然、こいつの後続に db migrate とかを置く必要ある
#
echo DATABASE_URL="postgres://${username}:${password}@${host}:${port}/${dbname}?schema=public" >> .env
storage など、用意されているもの以外の依存リソース (S3 や DynamoDB や RDS など) を、Addon という形で構成できるぽい。
コマンドなどはないので自分で addons/
ディレクトリを追加して CloudFormation テンプレ (yml) をぶちこむぽい。特に親である svc の manifest に追記したりはしないみたい。
└ copilot
└ webhook # すでに init 済みの svc の下に
├ addons # こいつを生やす
│ └ mytable-ddb.yaml # ここに cfn yml 書く
└ manifest.yaml
CloudFormation については AWS CloudFormation > User Guide あたりを。
代替のケースでは生成と同時に secret に秘匿情報入れてもらって、parameter store から読み込む感じぽい。
# 作ったら svc 単位で deploy してやる感じ?
$ copilot svc deploy --name webhook
addon で生成した resource (rds とか) の接続情報を secrets 経由で渡さないとコケるような container (svc) は、deploy 前に 予め起動タスクを count: 0
で落として health check 通過させつつ addon deploy して、secrets に正しい接続情報入れてから再度 deploy する か、cloudformation template 側で 適切な parameter store を切ってそれを svc が読める状態で deploy させる ような工夫が必要。
↑ に EngineVersion: "6.2"
とか追加したら ok でした。
secrets:
REDIS_URL: /${COPILOT_APPLICATION_NAME}/${COPILOT_ENVIRONMENT_NAME}/quirrel/redis
Parameters:
App:
Type: String
Description: Your application's name.
Env:
Type: String
Description: The environment name your service, job, or workflow is being deployed to.
Name:
Type: String
Description: The name of the service, job, or workflow being deployed.
Resources:
# Subnet group to control where the Redis gets placed
RedisSubnetGroup:
Type: AWS::ElastiCache::SubnetGroup
Properties:
Description: Group of subnets to place Redis into
SubnetIds: !Split [ ',', { 'Fn::ImportValue': !Sub '${App}-${Env}-PrivateSubnets' } ]
# Security group to add the Redis cluster to the VPC,
# and to allow the Fargate containers to talk to Redis on port 6379
RedisSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: "Redis Security Group"
VpcId: { 'Fn::ImportValue': !Sub '${App}-${Env}-VpcId' }
# Enable ingress from other ECS services created within the environment.
RedisIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
Description: Ingress from Fargate containers
GroupId: !Ref 'RedisSecurityGroup'
IpProtocol: tcp
FromPort: 6379
ToPort: 6379
SourceSecurityGroupId: { 'Fn::ImportValue': !Sub '${App}-${Env}-EnvironmentSecurityGroup' }
# The cluster itself.
Redis:
Type: AWS::ElastiCache::CacheCluster
Properties:
Engine: redis
EngineVersion: "6.2"
CacheNodeType: cache.t3.small
NumCacheNodes: 1
CacheSubnetGroupName: !Ref 'RedisSubnetGroup'
VpcSecurityGroupIds:
- !GetAtt 'RedisSecurityGroup.GroupId'
# Redis endpoint stored in SSM so that other services can retrieve the endpoint.
RedisEndpointAddressParam:
Type: AWS::SSM::Parameter
Properties:
Name: !Sub '/${App}/${Env}/${Name}/redis' # Other services can retrieve the endpoint from this path.
Type: String
Value: !GetAtt 'Redis.RedisEndpoint.Address'
Outputs:
RedisEndpoint:
Description: The endpoint of the redis cluster
Value: !GetAtt 'Redis.RedisEndpoint.Address'
↑ を利用して、事前に copilot secret init
で DATABASE_PASSWORD をセット (DBName とか MasterUsername とかも編集したければやる) してから deploy でいけた。
あとは EngineVersion とか DBInstanceClass とか DBInstance 配下 Properties をチェックしてお好みで。
生成後に DATABASE_ENDPOINT が secure string じゃなくて string で parameter store に入ったり、db の識別子名が完全なランダムでひと目で判別できないのがちょっとあれだけど ... どうやって直すのかわからん。
あと parameter store に作った secure string の version 指定とか注意
#
# 最後の :1 の部分は secure string のバージョンなので
# 作り直したりしたら変更する必要ある
# ref. https://techblog.zozo.com/entry/pass_secrets_to_cloudformation
#
MasterUserPassword: !Sub "{{resolve:ssm-secure:/copilot/${App}/${Env}/secrets/DATABASE_PASSWORD:1}}"
# copilot/{service name}/manifest.yml の一部
variables:
LOG_LEVEL: debug
# 環境ごとの set (このケースだと prod のみ override 扱い)
environments:
production:
variables:
LOG_LEVEL: info
# shell の環境変数使うとか
image:
location: id.dkr.ecr.zone.amazonaws.com/project-name:${TAG}
biuld:
args:
NEXT_PUBLIC_FOO: bar # build 時の環境変数はここ
# Copilot の設定 (予約済み環境変数) を使うとか
secrets:
APP_SECRET: /copilot/${COPILOT_APPLICATION_NAME}/${COPILOT_ENVIRONMENT_NAME}/secrets/app_secret
Environments
ECR image tags should have different value for each environments. #2927
manifest.yml の任意の値を override したい場合 (例えば image.build.args とか) は environments を使う。
image:
build:
dockerfile: Dockerfile
args:
FOO: bar # test 以外では bar
environments:
test:
image:
build:
dockerfile: Dockerfile
args:
FOO: baz # test env では baz
- 基本
copilot secret init
で parameter store 作成 => 環境変数で流す - どの環境向けか、など自動でタグ付けされ secure string 扱い
- 作成した parameter は
manifest.yml > secrets
で key 指定すれば読み込めるDB_NAME: /.../.../db_user
みたいな定義でアプリ側で環境変数として参照可能
secret init
時点で存在する全 env 向けの parameter store を作成する- 裏を言うと env 毎に init できないことに注意
- ただし
--overwrite
を付けなければ「存在するやつは skip 」になるので、新規作成に限りなんとかなる- なんなら、enter だけ押すと生成処理も省略されてるっぽい?
# 前もって copilot storage init などで
# リソース作成 & 秘匿情報を AWS Secrets に作成し
# console から読み取り => メモっておく
#
# ↑ 秘匿情報を secret init で登録する
# 自動的に parameter store に secure string として
# 登録してくれる (/copilot/<app>/<env>/secrets/<secret> みたいな key)
#
$ copilot secret init
# あとは yml の environments とかで各環境向けに secrets 定義してやる
environments:
prod:
secrets:
DB_PASSWORD: /copilot/my-app/prod/secrets/db_password
dev:
secrets:
DB_PASSWORD: /copilot/my-app/dev/secrets/db_password
# まぁ ↑ くらい単純なら copilot の予約済み環境変数でやってもよき
secrets:
database_url: /copilot/${COPILOT_APPLICATION_NAME}/${COPILOT_ENVIRONMENT_NAME}/secrets/database_url
↑ の手順以外で作成した parameter store の secure string を読み込む場合は ...
- app と env をタグ付け
- copilot-application: copilot app 名
- copilot-environment: copilot env 名
- ↓ のように yml の secrets で parameter name を指定
secrets:
GITHUB_WEBHOOK_SECRET: GH_WEBHOOK_SECRET
- 現状、build 時の args で secrets を使うことはサポートされてない
- が、一応 pipeline 作って buildspec.yml の env セクションで読み込んで shell 変数を使うことはできる
- ので以下のように pipeline を介せば docker の build 時点で secrets を参照することは可能ぽい
以下 nextjs の NEXT_PUBLIC_
環境変数を build 時にセットしておき、inline 化する例。
業務でやったやつ (https://github.com/sousaku-co-ltd/acas/pull/3#discussion_r1212728409)
# Dockerfile
FROM node:16-buster
EXPOSE 80
WORKDIR /app
COPY ./ ./
RUN npm ci
# このへんに列挙
ARG NEXT_PUBLIC_SOME_ENV
# ここで NEXT_PUBLIC_ 接頭辞付きが inline 化される
RUN npm run build
CMD npm start
# buildspec.yml
env:
parameter-store:
NEXT_PUBLIC_SOME_ENV: /copilot/appname/envname/secrets/NEXT_PUBLIC_SOME_ENV
# manifest.yml
image:
build:
dockerfile: Dockerfile
context: .
args:
# buildspec.yml > env > parameter-store
NEXT_PUBLIC_SOME_ENV: ${NEXT_PUBLIC_SOME_ENV}
ちなみに NEXT_PUBLIC_
接頭辞がないやつは next が自動的に front に inline 化してくれない (多分 build 時の process.env に不要な shell 変数をのせないようにしてる) ので、env ファイルなどで別途吸わせる工夫が要る。
# .env.copilot
FRONT_ENV_WITHOUT_NEXT_PUBLIC=${FRONT_ENV_WITHOUT_NEXT_PUBLIC}
RUN apt-get update
RUN apt-get install gettext-base
ARG FRONT_ENV_WITHOUT_NEXT_PUBLIC
# 本番環境限定の .env を envsubst でテンプレートファイル (.env.copilot) をバラして生成
RUN cat .env.copilot | envsubst > .env.production
// next.config.js
const nextConfig = {
env: {
FRONT_ENV_WITHOUT_NEXT_PUBLIC: process.env.FRONT_ENV_WITHOUT_NEXT_PUBLIC,
},
}
module.exports = nextConfig
https://aws.github.io/copilot-cli/ja/docs/developing/domain/
ドメインは app init 時にしか設定できないっぽいので注意。
- aws/copilot-cli#3045
- aws/copilot-cli#1188 (comment)
- サブドメイン部分の alias は指定できそう?
https://aws.github.io/copilot-cli/ja/docs/developing/service-discovery/
service 間での連携 (別 service の検出) も可能。AWS 内部の private address と DNS による mapping で通信するっぽいので、VPC とか public の endpoint とか気にしなくていいみたい。
具体的には特別な環境変数 COPILOT_SERVICE_DISCOVERY_ENDPOINT
を利用して通信する。これは service 上で <env>.<app>.local
のように変換される。
service 上で http://<service>.test.myapp.local:8080
のような endpoint へ通信をすると、自動的に vpc 内で private ip address へ変換され myapp
app の test
env の <service>
service の :8080
port へ routing してくれるってワケ。
// この例では、ある service から同じ copilot の app 内で定義した
// api という service に対し、同一 vpc の service 検知 のための
// 特別な local endpoint (COPILOT_SERVICE_DISCOVERY_ENDPOINT) を
// 介して private network 内で通信している
//
endpoint := fmt.Sprintf(
"http://api.%s:8080/some-request",
os.Getenv("COPILOT_SERVICE_DISCOVERY_ENDPOINT"),
)
App Runner が VPC いけるようになるまでは Request Driven なんちゃらは触れなくていい気持ち 最近 VPC イケるようになったぽい。
- internet (IGW) からの public access を ALB or NLB で捌いて container にわたすやつ
http
の有効化で ALB が構成され 80, 443 listen =>image.prot
へ mappingnlb
有効化すると NLB が構成され tcp, udp の色んな port listen ができる
Problem create another loadbalancer #3013 で言われてるように load balancer は app の全 service が共有する こと。app 内で alb, nlb それぞれ 1 つずつしか持てないので、alb の path がかぶったり nlb の port / protocol がかぶったりは ng 。
http.path
によりパスで対応 svc を分割はできるが、複数の path: '/'
な svc は構成できないので注意。複数 port を internet 公開したいなら nlb でやるしかない。
- Dockerfile で port の
EXPOSE
必須ぽい image.port:
は 80 にしとくと ALB の health check サクッと通せる?- 3000 とかでも動作するんだけど、ALB の health check が HTTPS で 3000 に疎通確認して NG くらっていた (HTTP にしたら通った) ことがあった
とはいえ nlb にしなくても、手動で backend service に対して target group 生やして、alb に listener 登録すれば port アクセスもさせられるし、nlb と比べて柔軟な security group 設定できるので (固定 ip 制限とか) nlb にするメリットあんまり無い気がするけど ... 。
ref. VPC 上の private ECS サービスへ ALB Target Group から固定 IP のみアクセス許可する
container が api と gui を別 port で提供しているようなケースで ...
- HTTP/HTTPS で ALB 受け
- container の 1080 port へ流す (web gui)
- 同 container backend 通信向けに 1025 port も開放 (smtp)
... みたいなことできるぽい。
http:
path: '/'
image:
location: schickling/mailcatcher
port: 1080
# https://aws.github.io/copilot-cli/docs/developing/taskdef-overrides/
taskdef_overrides:
- path: "ContainerDefinitions[0].PortMappings[-].ContainerPort"
value: 1025
- path: "ContainerDefinitions[0].PortMappings[1].Protocol"
value: "tcp"
- v14 からの機能で NLB による tcp, udip の port listen が可能になった
- aws/copilot-cli#2297
- aws/copilot-cli#2918
- https://github.com/aws/copilot-cli/releases/tag/v1.14.0
NLB は ALB と違って security group とかつけられなかったり、アクセスログを終えなかったりするので、public access を直接捌くというより「捌いたあとの中継」とか「 HTTP 以外など ALB が対応してない protocol 」に使ったほうがいい。
/api
みたいなのをお外に出したいなら、素直に path でわけてプログラム側で対応し、alb を選択したほうが無難な気がする。
http: false
nlb:
port: 8080/tcp
- CI/CD を CodePipeline で構成できる
- 現状 db migration みたいなコマンドを実施する場所は提供されてない
- docker entrypoint か、中入って svc exec するか
- Post-deployment actions for pipeline #3007
- v1.16 で main ブランチを prod env へ ... という使い方に対応した
- slack 通知みたいなのは手動構成が必要
- pipeline 作って 1 度回す
- pipeline から通知管理 > sns topic 作成
- chatbot で slack client 作成し ↑ sns を購読する channel 作成
- CI を回すコンテナは docker v18 くらいで Dockerfile の書き方古いことに注意
COPY . .
みたいな複数ファイルコピーはCOPY . ./
みたいにすること
- 当然だけど env に対して deploy するので env init 最初にやっておくこと
- deploy したい svc or job は全て先に手動で deploy しておく必要があるので注意
- test_commands とか、どういう使い方するのかいまいちわからん
- いったんは dockerfile 内で全部回すことにした
- 多分この辺参考にする感じか https://aws.amazon.com/jp/blogs/containers/automatically-deploying-your-container-application-with-aws-copilot/
manifest.yml を local の docker-compose.yml と対応 させて、こっちの pipeline.ymlは local 開発時の provisioning script と対応 させる感じで構成すると良さそう。
# 設定ファイルの初期化
$ copilot pipeline init
# stages あたりで CI 構成
$ vi copilot/repo-branch/pipeline.yml
$ git add .
$ git commit -m "Adding pipeline artifacts"
$ git push
# 編集した yml に従い構成を AWS 上へ展開
# このとき github 連携を求められ aws console に飛ばされるが
# region が意味不明なとこになってて混乱する、aws profile の
# region に行けば「保留中」の接続があるので、そいつを更新してやる
#
$ copilot pipeline deploy
# pipeline の削除
$ copilot pipeline delete
# pipeline.yml
source:
provider: GitHub
properties:
branch: main # main へ push => CI が回る
repository: https://github.com/xxx/xxx
stages:
-
name: test
# make test コマンドと echo コマンドが
# test 環境で正常終了した場合のみ、次の
# prod 環境でのデプロイ stage へ進む ... という感じ?
test_commands:
- make test
- echo "woo! Tests passed"
-
name: prod
# デプロイ前に手動承認を挟めるぽい
requires_approval: true
- manifest.yml の branch を変更してから
copilot pipeline deploy
- ↑ やったあとに当該 branch で適当な空 commit 作って push (または再試行でも ok)
これで branch を変更できるので、最初は add-copilot-pipeline
みたいな pipeline 追加用開発ブランチで作業、push して pipeline を安定させてから、最後に main に変更するといい。
多分だけど、ドキュメントをざっと読んだ感じだとこう ... 。
copilot pipeline init
時に聞かれる pipeline name を${REPOSITORY}-${BRANCH}
形式にするcopilot/pipelines/${REPOSITORY}-${BRANCH}/manifest.yml
が生成される- あとは追跡ブランチ指定や、展開先 (env) 指定を yml でうにょれって感じか
最近 Docker Hub が匿名ユーザに対して pull 制限をかけた関係で docker login
でユーザログインしないとたまに制限に引っかかっておちちゃう。
# buildspec.yml
env:
# parameter store に適当に用意しておく
parameter-store:
DOCKER_USERNAME: DOCKER_USERNAME
DOCKER_PASSWORD: DOCKER_PASSWORD
phases:
install:
runtime-versions:
# ...
commands:
# ...
build:
commands:
# ...
post_build:
commands:
- docker login --username $DOCKER_USERNAME --password $DOCKER_PASSWORD
# ...
Publish/Subscribe - SNS と SQS を使った worker の queuing