Upgrade to Pro — share decks privately, control downloads, hide ads and more …

1年間本番運用してわかった、スタートアップこそAWS Copilot CLIを使うべきNつの理由

1年間本番運用してわかった、スタートアップこそAWS Copilot CLIを使うべきNつの理由

AWS Startup Community Conference 2022 の登壇資料です。

kokuyouwind

August 26, 2022
Tweet

More Decks by kokuyouwind

Other Decks in Programming

Transcript

  1. $ whoami 黒曜 / @kokuyouwind 名古屋在住 Leaner Technologies Inc. 所属

    Rails エンジニア Next.js とか AWS 周りも触ってる
  2. AWS Copilot CLI の向き・不向き 新規でのWeb アプリ構築に最も向いている ベストプラクティスに沿った構成が⼀気通貫で作れる 既存環境の移⾏にも使えるが、やや旨みが減る DNS ・VPC

    周りは既存のものを使い回すほうが楽 ⽤途や現状構成によってはCopilot が適さない可能性 厳密なBlue/Green デプロイはできない マルチAWS アカウントの構成によっては使いづらい
  3. copilot init の功罪 copilot init では複数のCopilot リソースがまとめて作られる Copilot の特徴的な概念が隠蔽されてしまい理解しづらい 細かいオプションが制御できない

    ドメイン名の紐付け 環境を構築するAWS アカウントの指定 Copilot リソースごとの init サブコマンドを使うとよい copilot app init, copilot svc init など
  4. Copilot のリソース構成 Application: MyApp Test Production Stage WebAPI Worker (Environment)

    (Service) Container Container Container Container Container Container
  5. Copilot リソース: Application Application: MyApp Test Production Stage WebAPI Worker

    (Environment) (Service) Container Container Container Container Container Container 1 つのWeb アプリケーションを表現 https://aws.github.io/copilot-cli/ja/docs/concepts/applications/
  6. Copilot リソース: Environment Application: MyApp Test Production Stage WebAPI Worker

    (Environment) (Service) Container Container Container Container Container Container 1 つのWeb アプリケーションを表現 サービスの 動作環境を表現 https://aws.github.io/copilot-cli/ja/docs/concepts/environments/
  7. Copilot リソース: Service Application: MyApp Test Production Stage WebAPI Worker

    (Environment) (Service) Container Container Container Container Container Container サービスの 動作環境を表現 サービスの 動作環境を表現 1 つのWeb アプリケーションを表現 コンテナで動く サービスを表現 https://aws.github.io/copilot-cli/ja/docs/concepts/services/
  8. Env, Service と実際のコンテナの関係 Application: MyApp Test Production Stage WebAPI Worker

    (Environment) (Service) Container Container Container Container Container Container Env × Service ごとにコンテナが作られる ( これはCopilot 管理リソースではない)
  9. $ copilot deploy --env test Application: MyApp Test Production Stage

    WebAPI Worker (Environment) (Service) Container Container Container Container Container Container この2 箇所が デプロイ対象になる
  10. Copilot リソース: Pipeline Application: MyApp Test Prod Stage WebAPI Worker

    (Environment) (Service) Container Container Container Container Container Container DevPipeline (Pipeline) ProdPipeline develop ブランチ main ブランチ Test Env にデプロイ Stage Env にデプロイ E2E テストが通ったら Production にデプロイ
  11. AWS Copilot CLI の概要: まとめ Copilot では独⾃の単位でリソースを管理する Application: Web アプリケーション全体を表現

    Environment: テスト・本番などの環境を表現 Service: API サーバ・Worker などのサービスを表現 Pipeline: デプロイパイプラインを表現 Environment × Service ごとにコンテナなどが作られる Environment 単位でデプロイされる Pipeline からは複数のEnvironment を順に更新できる
  12. Copilot リソース: Application Application: MyApp Test Production Stage WebAPI Worker

    (Environment) (Service) Container Container Container Container Container Container https://aws.github.io/copilot-cli/ja/docs/concepts/applications/
  13. Application の詳細 copilot app init で Application を作成できる Parameter Store

    上にメタデータが格納される ローカルに copilot/.workspace が作られる このコマンド実⾏時のAWS Profile が Copilot CLI 利⽤時の中央アカウントを規定する 以降のコマンド実⾏時は同じProfile 指定が必要 ECR やCodePipeline など、環境横断のAWS リソースは このAWS アカウントに作成される
  14. Application の⽣成 ❯ copilot app init Use existing application: No

    Application name: copilot-test ✔ Created the infrastructure to manage services and jobs under application copilot-test. ✔ The directory copilot will hold service manifests for application copilot-test. ❯ copilot app ls copilot-test 1 2 3 4 5 6 7 8 9 10 11 12 13 14
  15. ドメインの紐付け copilot app init --domain 'leaner.jp' api.test.copilot-test.leaner.jp のように、 [svcName].[envName].[appName].[domain] を紐付ける

    Route 53 に上記ドメインのホストゾーンが必要 leaner.jp のホストゾーンに copilot-test.leaner.jp に向ける NS レコードが追加される copilot-test.leaner.jp のホストゾーンが作成される
  16. Copilot リソース: Environment Application: MyApp Test Production Stage WebAPI Worker

    (Service) Container Container Container Container Container Container https://aws.github.io/copilot-cli/ja/docs/concepts/environments/
  17. Environment の詳細 copilot env init で Environment を作成できる 環境を作るAWS アカウントを指定できる

    VPC とSubnet が作成される ( 既存のリソースを使うこともできる) [envName].[appName].[domain] の Route 53 ホストゾーンが作られる Environment のメタ情報が中央アカウントの Parameter Store に格納される
  18. Environment の⽣成 (1) ❯ copilot env init Environment name: test

    Which credentials would you like to use to create test? [Use arrows to move, type to filter, ? for more help] > Enter temporary credentials [profile default] [profile env-test] 1 2 3 4 5 6 7 8 9
  19. Environment の⽣成 (2) ❯ copilot env init Environment name: test

    Credential source: [profile env-test] 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, AZs). No, I'd like to import existing resources (VPC, subnets). 1 2 3 4 5 6 7 8 9 10 11 12 13 14
  20. Environment の⽣成 (3) ❯ copilot env init Environment name: test

    Credential source: [profile env-test] Default environment configuration? Yes, use default. ✔ Linked account xxxxxxxxx and region ap-northeast-1 to application copilot-test. ✔ Proposing infrastructure changes for the copilot-test-test environment. - Creating the infrastructure for the copilot-test-test environment. [create complete] [105.3s] - An IAM Role for AWS CloudFormation to manage resources [create complete] [36.1s] - An ECS cluster to group your services [create complete] [8.7s] - An IAM Role to describe resources in your environment [create complete] [37.7s] - A security group to allow your containers to talk to each other [create complete] [6.0s] - An Internet Gateway to connect to the public internet [create complete] [18.0s] - Private subnet 1 for resources with no internet access [create complete] [6.0s] - Private subnet 2 for resources with no internet access [create complete] [6.0s] - A custom route table that directs network traffic for the public subnets [create complete] [15.1s] - Public subnet 1 for resources that can access the internet [create complete] [6.0s] - Public subnet 2 for resources that can access the internet [create complete] [6.0s] - A private DNS namespace for discovering services within the environment [create complete] [49.2s] - A Virtual Private Cloud to control networking of your AWS resources [create complete] [12.6s] ✔ Created environment test in region ap-northeast-1 under application copilot-test. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
  21. Copilot リソース: Service Application: MyApp Test Production Stage WebAPI Worker

    (Environment) (Service) Container Container Container Container Container Container https://aws.github.io/copilot-cli/ja/docs/concepts/services/
  22. Service の詳細 copilot svc init で Service を作成できる Service のタイプなどを対話的に⼊⼒する

    ( 今回はLoad Balanced Web Service を選択) copilot/[svcName]/manifest.yml ファイルが作られる Service ⽤のECR Repo とメタデータParameter Store が 中央アカウントに作られる ALB がEnvironment に紐付いて作られる 別途デプロイしない限りコンテナは起動しない
  23. Service の⽣成(1) ❯ copilot svc init Note: It's best to

    run this command in the root of your workspace. Which service type best represents your service's architecture? [Use arrows to move, type to filter, ? for more help] Request-Driven Web Service (App Runner) > Load Balanced Web Service (Internet to ECS on Fargate) Backend Service (ECS on Fargate) Worker Service (Events to SQS to ECS on Fargate) 1 2 3 4 5 6 7 8 9 10
  24. Service の⽣成(2) ❯ copilot svc init Note: It's best to

    run this command in the root of your workspace. Service type: Load Balanced Web Service Service name: api Which Dockerfile would you like to use for api? [Use arrows to move, type to filter, ? for more help] > docker/Dockerfile Enter custom path for your Dockerfile Use an existing image instead 1 2 3 4 5 6 7 8 9 10 11
  25. Service の⽣成(3) ❯ copilot svc init Note: It's best to

    run this command in the root of your workspace. Service type: Load Balanced Web Service Service name: api Dockerfile: docker/Dockerfile parse EXPOSE: no EXPOSE statements in Dockerfile docker/Dockerfile Port: 80 ✔ Wrote the manifest for service api at copilot/api/manifest.yml Your manifest contains configurations like your container size and port (:80). ✔ Created ECR repositories for service api. 1 2 3 4 5 6 7 8 9 10 11
  26. copilot/api/manifest.yml name: api type: Load Balanced Web Service http: path:

    '/' image: build: docker/Dockerfile port: 80 cpu: 256 memory: 512 platform: linux/x86_64 count: 1 exec: true 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  27. ここまでの構成 Application Environment Service 中央アカウント Test 環境⽤ アカウント Metadata リポジトリ内

    ファイル Metadata Metadata manifest.yml .workspace ECR Repo Route 53 HostZone Route 53 HostZone ALB VPC
  28. Copilot リソース: Pipeline Application: MyApp Test Prod Stage WebAPI Worker

    (Environment) (Service) Container Container Container Container Container Container DevPipeline (Pipeline) ProdPipeline develop ブランチ main ブランチ Test Env にデプロイ Stage Env にデプロイ E2E テストが通ったら Production にデプロイ
  29. Pipeline の詳細 copilot pipeline init で設定ファイルを作成 copilot/pipelines/[pipelineName] 以下に manifest.yml と

    buildspec.yml が作られる この時点ではAWS リソースは作られない copilot pipeline deploy で AWS リソースを作成 manifest.yml を元に CodePipeline と関連リソースが 中央アカウントに作られる
  30. Pipeline の初期化 (1) ❯ copilot pipeline init Only one git

    remote detected. Your pipeline will follow '[email protected]:leaner-co-jp/copilot-test'. Your pipeline will follow branch 'develop'. Pipeline name: copilot-test-pipeline Which environment would you like to add to your pipeline? [Use arrows to move, type to filter, ? for more help] > test [No additional environments] 1 2 3 4 5 6 7 8 9 10 11 12
  31. Pipeline の初期化 (2) ❯ copilot pipeline init Only one git

    remote detected. Your pipeline will follow '[email protected]:leaner-co-jp/copilot-test'. Your pipeline will follow branch 'develop'. Pipeline name: copilot-test-pipeline 1st stage: test ✔ Wrote the pipeline manifest for copilot-test at 'copilot/pipelines/copilot-test-pipeline/manifest.yml' The manifest contains configurations for your pipeline. Update the file to add stages, change the tracked branch, add test commands or manual approval actions. ✔ Wrote the buildspec for the pipeline's build stage at 'copilot/pipelines/copilot-test-pipeline/buildspec.yml' The buildspec contains the commands to push your container images, and generate CloudFormation templates. Update the "build" phase to unit test your services before pushing the images. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
  32. copilot/pipelines/.../manifest.yml name: copilot-test-pipeline version: 1 source: provider: GitHub properties: branch:

    develop repository: https://github.com/leaner-co-jp/copilot-test stages: name: test # Optional: flag for manual approval action before deployment. # requires_approval: true # Optional: use test commands to validate this stage of your build. # test_commands: [echo 'running tests', make test] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  33. Pipeline の作成 (1) ❯ copilot pipeline deploy Only found one

    pipeline; defaulting to: copilot-test-pipeline ✔ Successfully added pipeline resources to your application: copilot-test ⠋ Creating a new pipeline: copilot-test-pipelineACTION REQUIRED! Go to https://console.aws.amazon.com/codesuite/settings/connections to update the status of connection copilot-leane-leaner-purchasing- from PENDING to AVAILABLE. ⠸ Creating a new pipeline: copilot-test-pipeline 1 2 3 4 5 6 7 8 9
  34. Pipeline の作成 (3) ❯ copilot pipeline deploy Only found one

    pipeline; defaulting to: copilot-test-pipeline ✔ Successfully added pipeline resources to your application: copilot-test ⠋ Creating a new pipeline: copilot-test-pipelineACTION REQUIRED! Go to https://console.aws.amazon.com/codesuite/settings/connections to update the status of connection copilot-leane-leaner-purchasing- from PENDING to AVAILABLE. ✔ Successfully created a new pipeline: copilot-test-pipeline 1 2 3 4 5 6 7 8 9
  35. ここまでの構成 Application Environment Service Pipeline 中央アカウント Test 環境⽤ アカウント Metadata

    リポジトリ内 ファイル Metadata Metadata manifest.yml manifest.yml buildspec.yml .workspace CodePipeline ECR Repo Route 53 HostZone Route 53 HostZone ALB VPC CodeBuild
  36. CodePipeline からのデプロイ CodeBuild で docker build を⾏い、ECR Repo にpush する

    複数環境にデプロイする場合でもDocker イメージは サービスごとに共通 各Service のCloudFormation Stack をCreateOrUpdate する ECS Service や関連リソースの他、 ALB Listener Rule や Target Group なども作られる 更新はローリングアップデートで⾏われる
  37. ここまでの構成 Application Environment Service Pipeline 中央アカウント Test 環境⽤ アカウント Metadata

    リポジトリ内 ファイル Metadata Metadata manifest.yml manifest.yml buildspec.yml .workspace CodePipeline ECR Repo Route 53 HostZone Route 53 HostZone ECS Service ALB VPC CodeBuild
  38. 最終的な構成 Application Environment Service Pipeline 中央アカウント Test 環境⽤ アカウント Metadata

    リポジトリ内 ファイル Metadata Metadata manifest.yml manifest.yml buildspec.yml .workspace CodePipeline ECR Repo Route 53 HostZone Route 53 HostZone ECS Service ALB VPC CodeBuild
  39. 各Copilot リソースの詳細: まとめ (1) application init 時のAWS Profile 指定が重要 メタデータのParameterStore

    やCodePipeline, ECR などがこのアカウントに作られる 以降のcopilot コマンド実⾏時もこのProfile を指定する environment init 時にAWS アカウントを指定することで 環境ごとのAWS アカウント分割が簡単に⾏える service init 時には copilot/[serviceName]/manifest.yml に サービスマニフェストが⽣成される 環境ごとのデプロイは別途⾏う必要がある
  40. 各Copilot リソースの詳細: まとめ (2) pipeline init 時にはファイルだけ作成され、 AWS リソースは作られない pipeline

    deploy で CodePipeline などが実際に作成される init コマンド実⾏結果がParameter Store, CloudFormation, ローカルファイルの最⼤3 箇所に反映される copilot コマンドを経由せずに削除すると 不整合になる可能性があるため注意
  41. 😆 Copilot CLI の便利な点 ベストプラクティスに沿った構成を簡単に作れる 直感的な単位でリソースを管理できる デフォルトでセキュリティ設定が担保される Manifest ファイルで簡易的なIaC が⾏える

    定期実⾏ジョブもService として⼀元管理できる copilot svc exec で簡単にコンテナ内作業が⾏える Addon で追加のAWS リソースを管理できる
  42. AWS サービスを組み合わせた標準Web アプリ構成 Route 53 での環境ごとのDNS ホストゾーン分割 ALB でのHTTP リクエスト受付・ECS

    へのルーティング ECS Fargate でのサービス起動・ローリングアップデート CodePipeline でのソース変更検知と⾃動デプロイ 環境ごとのAWS アカウント分割 Multi-AZ 構成 ベストプラクティスに沿った構成を簡単に作れる
  43. 直感的な単位でリソースを管理できる Application: MyApp Test Prod Stage WebAPI Worker (Environment) (Service)

    Container Container Container Container Container Container DevPipeline (Pipeline) ProdPipeline develop ブランチ main ブランチ Test Env にデプロイ Stage Env にデプロイ E2E テストが通ったら Production にデプロイ
  44. Manifest ファイルで簡易的なIaC が⾏える http: path: '/' healthcheck: path: '/health' healthy_threshold:

    3 unhealthy_threshold: 2 interval: 10s timeout: 5s grace_period: 300s deregistration_delay: 10s network: vpc: placement: 'private' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Service Manifest でALB のHealth Check 設定や ネットワーク配置設定(private 化) などが指定できる
  45. 定期実⾏ジョブもService として⼀元管理できる name: daily-batch type: Scheduled Job on: # JST

    9:00 -> UTC 0:00 schedule: "0 0 * * *" retries: 0 timeout: 1h image: build: context: . dockerfile: ./docker/Dockerfile command: "bundle exec rake app:daily_batch" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 Service Type: Scheduled Job でスケジュール実⾏できる (AWS 上では Step Function + ECS OneShot Task で実⾏される)
  46. copilot svc exec で簡単にコンテナ内作業が⾏える ❯ copilot svc exec Into which

    service would you like to execute? [Use arrows to move, type to filter, ? for more help] api (staging) api (production) > api (develop) Service: api Execute `/bin/sh` in container api in task 03020538d7b1482790d362faa1979d9a. Starting session with SessionId: ecs-execute-command-00e6b3ab703b08eb1 # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 サービスと環境を選んで、そのコンテナ内でコマンド実⾏できる ( 内部的にはSessonManager で接続する)
  47. Addon で追加のAWS リソースを管理できる Resources: FireLensPolicy: Type: AWS::IAM::ManagedPolicy Properties: PolicyDocument: Version:

    2012-10-17 Statement: - Effect: Allow Action: - logs:CreateLogStream - logs:CreateLogGroup - logs:DescribeLogStreams - logs:PutLogEvents Resource: - "arn:aws:logs:*:*:log-group:/ecs/logs/copilot-test" - "arn:aws:logs:*:*:log-group:/ecs/logs/copilot-test:log-stream:*" 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 copilot/[svcName]/addons/[addonName].yml に CloudFormation YAML で任意のAWS リソースを追加できる https://aws.github.io/copilot-cli/ja/docs/developing/addons/modeling/
  48. 🤔 Copilot CLI の癖のある点 Copilot リソースの単位で何が作られるかを知らないと、 トラブルシューティングが⾮常に難しい ドメイン紐付けが Application init

    時にしかできない 意識しないとデフォルトAWS アカウントに⾊々作られてしまう ルートドメインのホストゾーンとApplication ⽤のホストゾーンを 別のAWS アカウントに分けることができない サービスごとにDocker Build やECR Repo Push が⾏われるため 同じビルド設定で複数サービス・ジョブが必要だと⾮効率 デプロイがCloudFormation 更新で⾏われるため、 ローリングアップデート固定でBlue-Green Deploy できない
  49. Copilot CLI Tips (1) 既存環境移⾏時はドメイン紐付けを動作環境⽤と割り切って、 全く別のドメインを紐付けて置くと動作確認が楽 問題なければALB Listener Rule に既存ドメイン設定⼊れた上で

    hosts 弄って既存ドメインでの挙動を改めて確認する それも良ければ既存DNS レコード弄ってCopilot ALB に向ける healthcheck 周りの設定を⼊れるとデプロイが速くなる healthy_threshold, interval, deregistration_delay あたり platform をlinux/arm64 にする場合はCodeBuild 環境もarm に変更する ここを直さないとビルドに失敗するか、 イメージ形式が合わずECS Task の起動に失敗する
  50. Copilot CLI Tips (2) サービス初回デプロイでデプロイ失敗した場合は、 ECS Service 含むCloudFormation Stack の削除が必要

    イメージとECS Task でplatform 不⼀致のときなどに発⽣ CREATE_FAILED になるので以降のCreateOrUpdate が必ず失敗 ⼀度作成に成功していれば、以降はRollback になるので⼤丈夫 vpc.placement をprivate にするとセキュリティ的には安⼼だが、 NAT Gateway が作られるのでコストは⾼くなる コストを抑えたいなら本番環境のみ設定を⼊れるのがおすすめ Dockerfile のFROM イメージはECR Public Repository にするとよい DockerHub だと上限引っかかることがよくある
  51. 😆 Copilot CLI の便利な点( 再掲) ベストプラクティスに沿った構成を簡単に作れる 直感的な単位でリソースを管理できる copilot svc exec

    で簡単にコンテナ内作業が⾏える Manifest ファイルで簡易的なIaC が⾏える 定期実⾏ジョブもService として⼀元管理できる デフォルトでセキュリティ設定が担保される Addon で追加のAWS リソースを管理できる
  52. まとめ 少なくとも 7 個 のおすすめポイントがある( 多分もっとある) 癖はあるが、リソース管理単位が直感的で扱いやすい スタートアップ規模なら制限要件も特に気にならないはず AWS マルチアカウント構成は最初に考えておくとよい

    ルートホストゾーンを含むCopilot ⽤の中央アカウントと、 App × Env ごとのアカウントを作るのがおすすめ ルートホストゾーンのあるアカウントの共有が厳しい場合は、 Copilot 割当を冗⻑なドメインにしてしまうのも⼿ ( api.develop.myapp.copilot-myapp.leaner.jp など)