見出し画像

AWSコンテナCI/CD実装ハンズオン【ECS、Fargate】


こんにちは。SHIFTのITソリューション部の當眞です。
AWSを専門に主に上流(要件定義、基本設計)工程を担当しています。

インフラエンジニアはコンテナが必修科目になってくると考えていますので、コンテナ関連の記事をどんどん書いていこうと思っています。

はじめに


  • AWSエンジニアでコンテナ未経験なので、AWSコンテナの使用感を最速でつかみたい

  • AWSでのコンテナのCI/CD利用イメージを最小の労力で簡単に身につけたい

といった方向けにサンプルのCDKコードで簡単にコンテナCI/CD環境を作る手順をまとめています。
AWSでのコンテナの概要を理解したい方は以下の記事もおすすめです。

本記事ではAWSコンテナ設計・構築[本格]入門の5-2章のハンズオンが最短でできる構成にしています。
AWSコンテナ設計・構築[本格]入門 の5-2章の内容を読んだ方がより理解は深まると思うのですが、
読む時間が無く、最短で構築してコンテナのCI/CD実装と運用の体験をしたい方向けにまとめました。

※AWSコンテナ設計・構築[本格]入門は良書なのでおすすめです。時間があればぜひ読んでみてください。
AWSコンテナ設計・構築[本格]入門

ハンズオン内容


本記事の構成は以下の通りです。

  • 【前提】:ECS周りのリソースが作成されていること(3時間)
    以下のハンズオンを実施し、ECSなどのリソースが作成されていることが前提になります。
    AWSコンテナ構築・運用ハンズオン【ECS、Fargate】
    https://note.shiftinc.jp/n/n16cdcc2df8bf

  • 構築:サンプルのCDKコードでCI/CD環境を作る手順(1時間)
    CodeCommit GitHub、CodeBuild、CodePipeline作成の手順が1時間以内でできるようにまとめています。
    ※CodeCommitはサービス終了が発表されましたので、GitHubでハンズオン作成しています。

  • 運用:CI/CDのリリースを体験(5分)
    CI/CD環境構築完了後、サンプルアプリの変更及び、再リリースを体験できる手順です。

CDKコードによって設定はほとんど自動で完了しますので、 コンテナ初心者の方でも、つまずくことなく設定できると思います。
構築した設定内容をマネコンで確認することも良い勉強になるかと思います。

CI/CD関連のサービスは無料枠で利用が可能です。
しかし、前提のコンテナ構築に利用したサービスは有料になります。
できればCI/CDハンズオンまで一日でやり切れると良いと思います。

※ハンズオンはWindowsのPCで動作確認できています。
※CDKのバージョンは2.101.0で実施しましたが、CDKは後方互換ありのため、最新Verでも問題なく動作するものと思います。

【前提】コンテナリソースを作る手順(3時間)


まずはCI/CD実装の前提となるコンテナ関連のリソースを構築します。 以下のブログの通りに対応することでCI/CD実装に必要なリソースが整います。


本ハンズオンを中断する場合は以下の対応を実施すれば課金を最小限に抑えられます。

  • RDS停止(1週間後に自動起動するので注意)

  • ECS、CodeDeploy、ELB、EndpointについてCDKのコード(ecs-stack.ts)からコメントアウトして削除

CI/CD実装(2時間)


本ハンズオンでは以下の作業を通してCI/CDパイプラインを構築し、パイプライン実行までを体験できる内容にしています。

  • GitHub準備

  • CI/CD実行用ファイル作成

  • ベースイメージのECR保管

  • CodeBuild、CodePipeline構築

  • CI/CDリリース体験

  • 後片付け

順を追って手順を示します。

GitHub準備

書籍ではCodeCommitを利用していましたが、CodeCommitのサービス終了の発表があったため、GitHubに切り替えてハンズオンを作成しました。

GitHubリポジトリ作成

以下などを参考にGitHubのアカウントを登録しておきます。

ページの右上隅を選択し、「新しいリポジトリ」をクリックします。

リポジトリ名は「sbcntr-backend」で作成します。
AWSアカウントID情報を含むファイルをプッシュしますので、プライベートリポジトリで作成します。

上記以外はデフォルトで問題ありません。

GitHubへのリソース配置

クライアントPC上で「container-demo」配下に「container-cicd」というディレクトリを作成します。

そのディレクトリで以下のコマンドを順次実行します。

  • GitClone実施

git clone https://github.com/uma-arai/sbcntr-backend.git
cd ./sbcntr-backend
git remote -v
  • GitHubリポジトリへ切り替え、プッシュ

git remote set-url origin https://github.com/<Githubユーザー名>/sbcntr-backend
git remote -v
git push

ここで認証情報が求められるため、GitHubの認証情報を入力します。

作成したGitHubのsbcntr-backendリポジトリにコードが格納されます。

CI/CD実行用ファイル作成

CodeBuildとCodeDeploy実行に必要なファイルを作成し、作成したGithubにアップロードします。

CodeBuild用ファイル(buildspec.yml、Dockerfile)追加

以下からbuildspec.yml、Dockerfileをダウンロードします。

https://github.com/toma1110/container-basic/tree/main/contents

※本書のbuildspec.ymlに記載されていたDockerのruntime-versionsの「docker: 19」は古いため、CodeBuildがエラーになります。
runtime-versionsの指定を外すことで正常起動するようになります。
※DockerFile.txtというファイル名でダウンロードされてしまった場合、拡張子の「.txt」を削除します

Dockerfileの内容を以下の通り変換します

  • [aws_account_id]→AWSのアカウントID

container-cicd\sbcntr-backendディレクトリの直下にbuildspec.yml、Dockerfileを配置します。

  • CodeBuild用ファイルをGitHubに追加

cd ./sbcntr-backend
git add buildspec.yml Dockerfile
git commit -m 'ci: add buildspec'
git push

LFをCRLFに変換するというwarningが出ますが無視で大丈夫です。

warning: in the working copy of 'Dockerfile', LF will be replaced by CRLF the next time Git touches it

CodeDeploy用ファイル(appspec.yaml、taskdef.json)追加

以下からappspec.yaml、taskdef.jsonをダウンロードします。
https://github.com/toma1110/container-basic/tree/main/contents

taskdef.jsonの内容を以下の通り変換します。

  • [aws_account_id]→AWSのアカウントID

  • [mysql_secret_alias]→シークレットARNの末尾(sbcntr/mysql-XXXXXXX)

  • [BackendDef]→ECSのバックエンドのタスク定義名(sbcntr-stg-stack-ecs-backenddef-XXXXXXXXX)

container-cicd\sbcntr-backendディレクトリの直下にappspec.yaml、taskdef.jsonを配置します。

  • CodeBuild用ファイルをGithubに追加

cd ./sbcntr-backend
git add appspec.yaml taskdef.json
git commit -m 'ci: add appspec'
git push

CodeBuild、CodePipeline構築

Connection作成

CodePipelineがGitHubに接続するための接続設定(Connection)はCDK対応していないため、手動で作成します。

  • CodePipelineの「設定」>「接続」を選択し、「接続を作成」を選択

  • 以下の通り入力し、「GitHubに接続する」を選択
    プロバイダー:GitHub
    接続名:sbcntr-connection

  • GitHubのページに飛ぶので認証情報を入力後に「sbcntr-backend」のリポジトリを選択し「Save」を選択

  • 「新しいアプリをインストールする」を選択し、ステータスが利用可能となったことを確認します。

CDKコード実行

container-basic/lib/resource/codepipeline.tsの内容を以下の通り変換します(TODO と記載の箇所の修正)

  • GitHubユーザー名→先ほど作成したGitHubのユーザー名

  • connectionArn→先ほど作成したConnectionのARN(arn:aws:codeconnections:ap-northeast-1:[AWSアカウントID]:connection/XXXXXXX)

  • CodeBuild、CodePipelineの構築

cdk deploy CICDStack

※本コードによって作成されるAWS構成はAWSコンテナ設計・構築[本格]入門 の5章をご確認頂ければと思います。

ベースイメージのECR保管

本手順は「Too Many Requests」対策です。詳細は以下を参照してください。

Dockerでは本事象がよく起こるので、本記事でも対応します。今回は「ECR にイメージを集約する」方式で対策します。

ベースイメージをECRへ格納

Cloud9で以下のコマンドを実行します。

  •  ベースイメージの取得

docker image pull golang:1.16.8-alpine3.13
docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"
  • 取得したイメージをECRへ格納

AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text)
aws ecr --region ap-northeast-1 get-login-password | docker login --username AWS --password-stdin https://${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/sbcntr-base
docker image tag golang:1.16.8-alpine3.13 ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/sbcntr-base:golang1.16.8-alpne3.13
docker image push ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/sbcntr-base:golang1.16.8-alpne3.13

CI/CDのリリースを体験


CI/CD実行前の動作確認

作成されたELBのsbcntr-stg-alb-frontendの方のDNS名をコピーします。(以下のようなURLです)
ブラウザで「Hello world」という画面が表示されることを確認できます。

http://sbcntr-stg-alb-frontend-XXXXXXXXXX.ap-northeast-1.elb.amazonaws.com/

コード修正

sbcntr-backendのhandler\helloworld_handler.goを修正します。
22行目
変更前: Data: "Hello world",
変更後: Data: "Hello world for CI/CD pipeline",

CI/CD実行

  • 変更後のコードをGitHubに格納

cd ./sbcntr-backend
git add .
git commit -m 'ci: modify  Hello World'
git push

GitへのPushを契機にCI/CDが実行されます。
進捗はAWSマネジメントコンソール(CodePipeline)で確認できます。
失敗の場合はエラー内容も確認できます。

CI/CD実行後の動作確認

パイプラインが正常終了したらブラウザで「Hello world for CI/CD pipeline」という画面が表示されることを確認できます。
http://sbcntr-stg-alb-frontend-XXXXXXXXXX.ap-northeast-1.elb.amazonaws.com/

これでCI/CDハンズオンは完了です!

後片付け


  • cdk destroy CICDStack

  • 「sbcntr-stg-stack-cicd~」と先頭につくバケットを空にして削除

  • CodePipelineのConnection削除

  • GitHubリポジトリ削除

  • 最後に、以下ページの後片付けも行います
    AWSコンテナ構築・運用ハンズオン【ECS、Fargate】
    https://note.shiftinc.jp/n/n16cdcc2df8bf

これで後片付け完了です。お疲れさまでした。

おまけ:コンテナが起動しなかったら。。ECS Execを利用する


CodeDeploy実行後にコンテナ起動せず、タイムアウトしましたが、原因はタスク定義誤りでした。

もし解決できていなかったらECS Execを利用してサービス起動しない原因を確認しようと思っていましたので、 ECS Exec利用の方法を参考までに記載しておきます。

aws ecs update-service  --cluster sbcntr-stg-backend-cluster --service sbcntr-stg-backend-service --enable-execute-command
  • タスク定義にタスクロールを追加します。(ポリシーはAmazonSSMFullAccessをつけましたが、ssmmessages関連だけでもよさそうです)

※以下の権限エラーの解消
The service couldn't be updated because a valid taskRoleArn is not being used. Specify a valid task role in your task definition and try again.  

  • タスク定義ファイル(taskdef.json)からreadonlyRootFilesystemを外します。(ECS Execサポート外のため)

  • ssmmessagesエンドポイントを作成します。(プライベートサブネットに起動するコンテナであるため)

※以下のネットワークエラーの解消
An error occurred (TargetNotConnectedException) when calling the ExecuteCommand operation:

  • コマンド実行後にタスクを再実行するためにECSサービス「sbcntr-stg-backend-service」を手動更新します。(以下2点)

    • 「新しいデプロイの強制」をチェックする

    • 「デプロイオプション」で作成したCodeDeployを選択する

  • コンテナ上で/bin/bashを実行します。

aws ecs execute-command --cluster sbcntr-stg-backend-cluster --task <タスクのID>(44bd2227e8a847538bb187b42363f223) --container app --interactive --command "/bin/bash"

ここでコンテナに/bin/bashがないというエラーになりました。
コンテナに/bash追加しても同様だったので、私はここでECS Execの利用を断念しました。

コンテナのbashが利用できない問題であってECSExecを利用するまでの手順としては問題なさそうなので参考になると思いましたので、おまけで残しておきます。


執筆者プロフィール(當眞 尚平)
AWSエンジニアです。インフラ案件上流(要件定義)から下流(運用)までこなします。
得意分野:IaC(Terraform、CDK)AWS認定:SAP、SAA、DVA、SOA、DOP、MLS、DAS、SCS、ANS直近の目標:DevOpsエンジニアになる
SHIFTでやっていること:IaC、CI/CD、AWSセキュリティ実装

お問合せはお気軽に

SHIFTについて(コーポレートサイト)

SHIFTのサービスについて(サービスサイト)

SHIFTの導入事例

お役立ち資料はこちら

SHIFTの採用情報はこちら

PHOTO:UnsplashAaron McLean