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時間)
CodeCommitGitHub、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
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が出ますが無視で大丈夫です。
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利用の方法を参考までに記載しておきます。
ローカルPCにsession-manager-pluginをインストールします。
https://s3.amazonaws.com/session-manager-downloads/plugin/latest/windows/SessionManagerPluginSetup.exeECS Execを有効化します
aws ecs update-service --cluster sbcntr-stg-backend-cluster --service sbcntr-stg-backend-service --enable-execute-command
タスク定義にタスクロールを追加します。(ポリシーはAmazonSSMFullAccessをつけましたが、ssmmessages関連だけでもよさそうです)
タスク定義ファイル(taskdef.json)からreadonlyRootFilesystemを外します。(ECS Execサポート外のため)
ssmmessagesエンドポイントを作成します。(プライベートサブネットに起動するコンテナであるため)
コマンド実行後にタスクを再実行するために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を利用するまでの手順としては問題なさそうなので参考になると思いましたので、おまけで残しておきます。
お問合せはお気軽に
SHIFTについて(コーポレートサイト)
SHIFTのサービスについて(サービスサイト)
SHIFTの導入事例
お役立ち資料はこちら
SHIFTの採用情報はこちら
PHOTO:UnsplashのAaron McLean