CodePipelineを使ってCloudFormationをDeployするCICD環境を作ってみた
こんにちは、吉田です。
今回はCodePipelineでCloudFormationを実行する環境をさっくり作ってみたのでブログに書いてみました。
はじめに
今回作成する構成は以下のとおりです。
CodeCommitにコードをPushすること(厳密にはmainブランチへ変更が入ること)をトリガーにCICDが動き、
CloudFormationがDeployを行うことを想定しています。

各サービスの基本概念の説明は行わないため、気になる方は以下記事を参考にしてください。
CodePipeline で CodeCommit/CodeBuild/CodeDeploy を繋げてデリバリプロセスを自動化してみた #reinvent
それでは始めていきます。
CodeCommit作成・設定
行うのは次のとおりです。
- Repository の作成
- ファイルをアップロード
Repository の作成
作成はとてもシンプルです。Repositoryの名前を決めて、以下のとおりに作成します。
ここでは Sandbox-Repository という名前にしています。

作成するのはこれだけです。
ファイルをアップロード
CodeCommitには以下の3通りでアクセスできます。
- HTTPS
- HTTPS(GRC)
- SSH
特に深い理由はありませんが、今回は HTTPS を試してみようと思います。
Commitの接続準備
[IAMユーザ] > [該当作業ユーザを選択] > [セキュリティ認証情報] の画面より、Gitの認証情報を作成します。

出てきたものはすぐに使うのでファイルを控えておきます。
その後Gitの認証情報を用いてCloneを行います。
% git clone https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/Sandbox-Repository
Cloning into 'Sandbox-Repository'...
Username for 'https://git-codecommit.ap-northeast-1.amazonaws.com': {user name}
Password for 'https://{user name}@git-codecommit.ap-northeast-1.amazonaws.com': {password}
warning: You appear to have cloned an empty repository.
% cd Sandbox-Repository
% git status
On branch main
No commits yet
nothing to commit (create/copy files and use "git add" to track)
mainブランチと出てきたので接続はできていることが確認できました。
適当に README を作ってPushしてみます。
% echo "# Sandbox用" > README.md
% git add README.md
% git commit -m "initial commit"
[main (root-commit) 3caa059] initial commit
1 file changed, 1 insertion(+)
create mode 100644 README.md
% git push origin main
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 227 bytes | 227.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Validating objects: 100%
To https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/Sandbox-Repository
* [new branch] main -> main
GUIから確認すると次のとおり、できていることが確認できました。

CodeBuild作成・テスト実行
事前準備
以下二つのファイルを作り、該当 CodeCommit にPushしておきます。
ymlは必須ですが、pythonファイルは必要に応じて作成すれば良いと思います。
buildspec.yml
version: 0.2
phases:
pre_build:
commands:
- python3 buildspecs/test.py
build:
commands:
- echo "Build completed"
artifacts:
files:
- ec2.yml
適切な例が思いつかなかったためこのような内容ですが、ここで静的解析などを行うと良いかもしれませんね。
buildspecs/test.py
print("OK")
exit(0)
CodeBuild 作成
以下のとおりに作成していきます。
要点は次のとおり、他の点については基本的にデフォルト値を確認しつつ調整すれば良いかと思います。
- 上記で作成したCodeCommitを指定する
- buildspec.ymlとファイルパスを合わせる



CodeBuildのテスト実行
画像の開始を押して実行してみます。

ログを見ると以下のとおりになっており、CodeBuildが正常に動作していることを確認できました。
〜割愛〜
[Container] Entering phase PRE_BUILD
[Container] Running command python3 buildspecs/test.py
OK
[Container] Phase complete: PRE_BUILD State: SUCCEEDED
[Container] Phase context status code: Message:
[Container] Entering phase BUILD
[Container] Running command echo "Build completed"
Build comple
〜割愛〜
[Container] Report auto-discover file discovery took 0.009708 seconds
[Container] Phase complete: UPLOAD_ARTIFACTS State: SUCCEEDED
[Container] Phase context status code: Message:
CodePipeline作成
CodeCommit、CodeBuildと続くとCodeDeployを思いがちですが、
CloudFormationでファイルをDeployする場合はCodeDeployが不要のため、
CodePipelineを作成します。
事前準備
デプロイステージで用いるIAMを作成しておきます。
本記事ではデモンストレーション目的でAdmin権限を使用していますが、
本番環境ではCloudFormationの実行に必要な最小限の権限(cloudformation:*、iam:PassRole、ec2:*など)に限定することを推奨します。

また次の内容のCloudFormation用Yamlファイルを該当CodeCommitにPushしておきます。
AWSTemplateFormatVersion: '2010-09-09'
Resources:
SSHSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow SSH
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: t2.micro
ImageId: '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64}}'
SecurityGroups:
- !Ref SSHSecurityGroup
Tags:
- Key: Name
Value: Sandbox-App
CodePipeline の作成
DeploymentからCloudformationを選ぶこともできますが、CodeCommitが次ページのソースプロバイダーの選択肢になかったため、
今回はカスタムパイプラインを構築していきます。

参考:CodeCommitが存在せず、次ページに進めない

パイプラインの設定は次のとおりにします。

ソースステージは次のように設定します。
ここでのサービスロールは CodeCommit を指定できるため、mainブランチを見るように設定します。

ビルドステージは次のように設定します。
デフォルトではコマンドになっていますが、その他のビルドプロバイダーで先ほど作成したCodeBuildを指定します。

今回はテストステージは特に何も作っていないためスキップ、
デプロイステージは次のように設定します。

テスト実行
初回Deploy
そして実行するとエラーが起きました。

一見すると s3:ListBucket に対するアクセス権限が足りていないようにも見えますが、
CodeBuildの時に出力アティファクトを出していないためですね。
CodeBuildの設定にあるアーティファクトを追加し、次のように修正してみます。

成功しました。
いまさらですが、こうやって成功なら緑色で表示してくれるUIが良いですよね。

今回作成予定だったEC2もできているようです。
画像ではまだ保留中でしたが、この後しっかり起動に成功していることを確認しました。

CloudFormationのファイルを修正して、リソースの修正を行う
今回作ったリソースの一部を変更してみます。
先ほど作った ec2.yml ファイルに記載のInstanceTypeを t2.micro -> t3a.micro へ変更してPushしてみます。
Pushすると、自動でPipelineが動き、無事にEC2のインスタンスが上がりました。
Push後にPipelineが自動的に動き始めるのを見るとなかなかの感動体験を得られます。

まとめ
今回はPipelineでCICD実行環境を作ってみました。
基本GUIで済むのでさっくり作る時は向いていそうですが、
CloudFormationでインスタンスタイプを変更すると、デフォルト設定ではインスタンスが置き換わる可能性があるため、
AMIからの起動に落とし込んでおくなど、今回紹介したやり方+αなやり方が必要そうに感じました。
参考記事
- CodeCommit入門 – Code三兄弟を知る
- CodePipeline で CodeCommit/CodeBuild/CodeDeploy を繋げてデリバリプロセスを自動化してみた
- GitHub/CodeBuild/CodePipelineを利用してCloudFormationのCI/CDパイプラインを構築する
- CodePipelineを使用して別アカウントにCloudFormationスタックをデプロイしてみた
- CodePipeline のパイプライン作成時に既存のロールを選択しているにもかかわらず、iam:CreateRole の権限が必要な理由を教えてください
- CloudFormation で使用するサービスロールの作成方法を教えてください
- CodePipelineでCloudFormationを利用してECSをデプロイ
- CodePipeline を使用した継続的デリバリー(AWS公式)
- チュートリアル: AWS CloudFormation デプロイアクションの変数を使用するパイプラインを作成する(AWS公式)




