AWSアカウントをまたいでECSにアプリケーションをデプロイする 〜ECRへのPushをCodePipelineのソースとして〜
ECSに乗せるアプリケーションができた!開発環境での確認はOKだ!さぁ本番リリースだ! あっ、でも開発環境と本番環境でAWSアカウントは分けるんだった。。どうしよう。。
みなさんそんな経験はないでしょうか。 本日はそんな課題に対する1つの解決策を紹介したいと思います。
今回の構成
以下のような構成を構築します。
GitリポジトリにはCodeCommitを利用し、devブランチへPushされた場合は開発アカウントに、masterブランチへPushされた場合は本番アカウントにそれぞれデプロイします。
本番アカウントのECSにデプロイするまでのフローは以下のようになります。
- Gitリポジトリを開発アカウントに作成
- GitリポジトリのdevブランチへのPushされた場合は、開発アカウント上のCodePipeline(dev-pipeline)を実行し開発アカウントのECSにデプロイ
- 開発アカウントでの動作確認後、masterブランチへマージ
- masterブランチへのマージをトリガーに開発アカウント上のCodePipeline(dev-to-prd-pipeline)を実行
- 開発アカウントのCodeBuildでDockerイメージを作成
- 本番アカウントのECRにDockerイメージをPush
- 本番アカウントのECRへのPushをトリガーに本番アカウントのCodePipeline(prd-pipeline)を実行
- 本番アカウントのECRからDockerイメージを取得し本番アカウントのECSにデプロイ
本記事では2以外の部分を構築していきます。こちらの部分については弊社のハンズオンなどを参考に構築していただければと思います。
それでは早速構築していきましょう!
開発アカウントでの作業①
Gitリポジトリ、CodePipelineの構築
CloudFormationで以下のリソースを作成します。パラメータのprdAccountId
には、本番アカウントを設定します。
- CodeCommit(コンテナ化するアプリケーションのリポジトリ:sample-app-codecommit)
- CodePipeline
- SourceAction(sample-app-codecommitのmasterブランチをトリガーとする)
- CodeBuild(sample-app-build-projectをビルドプロジェクトとする)
本番アカウントECRへのPushはビルドプロジェクトのsample-app-build-project
にて行ないます。
sample-app-build-project
の設定はポイントは以下の通りです。
ビルドプロジェクト(Buildspec)
開発アカウントから本番アカウントのECRにイメージをPushするため、開発アカウントから本番アカウントのECRにログインします。 ログインする際にはAssumeRoleで本番アカウントのロールにスイッチします。 ※スイッチロールせずイメージをPushしても本番アカウントのCodePipelineが起動しないため
version: 0.2 env: variables: DOCKER_BUILDKIT: "1" phases: pre_build: commands: - echo Logging in to Amazon ECR... - aws --version - export AWS_CONFIG_FILE=config - $(aws ecr get-login --registry-ids ${REGISTRY_IDS} --no-include-email --profile prd-account-role) - REPOSITORY_URI=${REGISTRY_IDS}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${IMAGE_NAME} - IMAGE_TAG=${CODEBUILD_RESOLVED_SOURCE_VERSION} build: commands: - echo Build started on `date` - echo Building the Docker image... - docker build -t $REPOSITORY_URI:latest . - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG post_build: commands: - echo Build completed on `date` - echo Pushing the Docker images... - docker push $REPOSITORY_URI:$IMAGE_TAG - docker push $REPOSITORY_URI:latest
ビルドプロジェクト(Environment)
以下の環境変数をビルドプロジェクトに設定します。
- AWS_ACCOUNT_ID:開発アカウントID
- IMAGE_NAME:Dockerイメージ名
- CONTAINER_NAME:ECSにデプロイするコンテナ名
- REGISTRY_IDS:本番アカウントID
本番アカウントでの作業
ECS環境の構築
CloudFormationでECS環境を構築します。
完了後、CloudFormationの出力タブより作成されたALBのURLをクリックします。
nginxのデフォルトの画面が表示されればOKです。
CodePipelineの構築
CloudFormationで本番アカウントのCodePipelineを構築します。
- CodePipeline
- SourceAction(sample-app-ecrへのPutImageをトリガーとする)
- CodeBuild(sample-app-build-prd-projectをビルドプロジェクトとする)
- Deploy2Service(本番アカウントのECSへデプロイする)
ビルドプロジェクトsample-app-build-prd-project
の設定はポイントは以下の通りです。
ビルドプロジェクト(Buildspec)
ECSへデプロイするためにimagedefinitions.json
を作成します。
version: 0.2 phases: build: commands: - REPOSITORY_URI=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com/${IMAGE_NAME} - IMAGE_TAG=latest - echo "[{\"name\":\"${CONTAINER_NAME}\",\"imageUri\":\"${REPOSITORY_URI}:${IMAGE_TAG}\"}]" - echo "[{\"name\":\"${CONTAINER_NAME}\",\"imageUri\":\"${REPOSITORY_URI}:${IMAGE_TAG}\"}]" > imagedefinitions.json artifacts: files: imagedefinitions.json
ビルドプロジェクト(Environment)
以下の環境変数をビルドプロジェクトに設定します。
- AWS_ACCOUNT_ID:本番アカウントID
- IMAGE_NAME:Dockerイメージ名
- CONTAINER_NAME:ECSにデプロイするコンテナ名
AssumeRoleの作成
開発アカウントが本番アカウントにスイッチするためのロールを作成します。
上記記事の「アカウントAでロール (Role-A) を作る」を参考にロールを作成します。ロール名はprd-account-role
とし、AmazonEC2ContainerRegistryFullAccess
ポリシーをアタッチします。
開発アカウントでの作業②
CodeCommitへソースコードをプッシュする
サンプルアプリケーションおよびProfile情報を定義した以下の3ファイルをsample-app-codecommitへPushします。configのXXXXXXXXXXXX
の部分は本番アカウントIDに変換してください。
package main import ( "fmt" "log" "net/http" ) func main() { http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "healthy!!!!") }) log.Fatal(http.ListenAndServe(":80", nil)) }
FROM golang:alpine ADD . /go/src/ EXPOSE 80 CMD ["/usr/local/go/bin/go", "run", "/go/src/server.go"]
[profile prd-account-role] role_arn = arn:aws:iam::XXXXXXXXXXXX:role/prd-account-role credential_source=EcsContainer
しばらくすると開発アカウントのCodePipeline、本番アカウントのCodePipelineが順に実行されます。
最後に先ほどはnginxのデフォルトの画面が表示されたURLをもうリロードしてみましょう。
アプリケーションが変わっていることが確認できました!!
最後に
AWSアカウントをまたいでECSにアプリケーションをデプロイしてみました。アカウントをまたぐリリースは「CodeCommitの共有」や「S3の共有」などいくつかの方式で実現することはですが、どの方法もIAM周りで考慮しなければならない箇所が多く設定がやや複雑になります。それに比べ今回紹介したCodeBuildとECRでアカウントをまたぐ場合は割とシンプルな構成になります。
CodeCommit、ECSの構成でアカウントをまたいでリリースしたい方はぜひ試してみてください。 ちなみにGitHubを使うとアカウントまたぎの苦しみはないのでこちらもおすすめです。