AWS Codeサービス群を利用してCI/CDのための構成を構築してみた

AWSが公開している[AWS 初心者向けハンズオン](https://aws.amazon.com/jp/events/aws-event-resource/hands-on/)では、AWSアカウントの作り方から始まりサーバレスアーキテクチャで翻訳Web APIを構築したり、CloudFormationでWebシステムを構築したり、と様々なAWSサービスを利用したハンズオンが掲載されており、実際に手を動かして知識を深めることができます。

今回はその中から[AWS Code サービス群を活用して、CI/CD のための構成を構築しよう！](https://pages.awscloud.com/JAPAN-event-OE-Hands-on-for-Beginners-cicd-2022-reg-event.html?trk=aws_introduction_page)を実際に構築し、挙動を確認していきます。

# アーキテクチャ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/be50f36f-97b3-0bcc-de86-289b5ac0a863.png)

# 利用しているAWSサービス
**AWS CodeCommit**
* フルマネージド型のソース管理サービス
* 既存のGitツールともシームレスに連携できる

**AWS CodeBuild**
* フルマネージド型のビルドサービス
* ソースコードのコンパイル、テスト実行、デプロイ可能なソフトウェアパッケージの作成が可能
※フルマネージドなのでビルド用のサーバの管理が不要となる

**AWS CodeDeploy**
* EC2, Lambda、オンプレ環境などに対してデプロイを行う
* AutoScalingする攻勢に対しても、連動して自動でデプロイする
* インプレース、canary、ブルー/グリーンデプロイなど、複数のデプロイタイプをサポート

**AWS CodePipeline**
* 上の３つのサービスを統合する
* ソースコードの変更をトリガにビルド、デプロイといった一連の流れを自動的に実行する

**AWS Cloud9**
2024/12/17時点でCloud9は新規利用が制限されているため利用ができません。
代わりにAWS管理コンソール上から利用できるCloudShellを利用してCodeCommitへのgitコマンド発行を行います。

# 構築(ポイントとなる箇所のみ)
## s3(静的Webサイトホスティング用)
s3はデフォルトで静的Webサイトホスティングが無効となっているため、有効に設定します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/304c31e5-6715-7bb4-79b3-9e234dc7def8.png)

ブラウザからS3バケット内のリソースへのアクセスを許可するための「バケットポリシー」を設定します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/ca0e978b-7726-ac62-5c8f-7ab704c92fbd.png)
ポリシーの生成には「ポリシージェネレータ」を使用すると、GUIで簡単にポリシーを作成することができます。

## s3(CodeBuild用)
CodeBuildでビルドした際の成果物であるアーティファクトを格納するためのs3バケットを作成する。

## CodeBuild
ビルド結果のアーティファクトをCodeDeployに渡す必要があるため、CodeBuildに設定しているロールに対して「AWSCodeDeployDeployerAccess」ポリシーをアタッチします。

ビルド用の設定はyamlファイルで記述してCodeCommitのリポジトリのトップに配置しておきます。
```
version: 0.2
phases:
  build:
    commands:
      - aws deploy push --application-name h4b-app --s3-location s3://codepipeline-artifact-20241218/artifact.zip --source src
artifacts:
  files:
    - '**/*'
  base-directory: src
```

## CodeDeploy
デプロイ対象のEC2インスタンスの設定などを「アプリケーション」という単位で設定します。
設定もyamlファイルで記述し、CodeCommitに登録します。
```
version: 0.0
os: linux
files:
  - source: index.html 
    destination: /var/www/html/
```

## CodeCommit
CloudShellからCodeCommitに対してgitコマンドを発行するために、CloudShell上で接続設定を行います。
接続には[AWS CLI 認証情報ヘルパー](https://docs.aws.amazon.com/ja_jp/codecommit/latest/userguide/setting-up-https-unixes.html)を利用します。
認証情報ヘルパーを利用した接続は以下の通りとなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/0e57e8a3-0f7d-9223-33f0-dbcb56dd462f.png)

CloudShellからはファイルのアップロードもできるため、gitリポジトリに静的Webサイトホスティングで使用するindex.htmlファイルをアップロードし、CodeCommitにgit pushします。

## CodePipeline(EC2へのデプロイ用)
CodeCommitに変更が生じたときにCI/CDを自動的に動かすように設定します。
変更の検知はCloudWatchを使用（デフォルト）します。
CodePipelineの作成ではソース、ビルド、デプロイでそれぞれ何を使うのかを選択できますので、
上で作成したものを設定します。

## EC2
CodeDeployを利用するためにはデプロイ先のEC2に対して[CodeDeployエージェント](https://docs.aws.amazon.com/ja_jp/codedeploy/latest/userguide/codedeploy-agent-operations-install.html)をインストールする必要がある。
EC2インスタンスを起動し、EC2 Instance Connectで接続した後に上のURLの手順に従ってCodeDeployエージェントをインストールする。

動作確認のためにhttpdサーバをインストールし、起動しておきます。
```
yum install httpd -y
systemctl start httpd.service
systemctl enable httpd.service
```

# 動作確認
## s3へのデプロイを行うCodePipeline
s3のバケットに登録したindex.htmlを静的ウェブサイトホスティングのURLから開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/581b7fa0-15ac-9dc5-4ffc-48ea79a80516.png)

Cloud Shellでindex.htmlの内容を修正。修正後はCodeCommitにgit pushを実行します。
※CodePipelineの機能により、CodeCommitへのpushを検知してs3にファイルがデプロイされる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/bf3ad357-49f0-d219-124a-2316b74ab56d.png)

再度s3の画面を開くと文字列が変更されていることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/78a2284f-8f02-0962-9269-7931dd4a3511.png)

## EC2へのデプロイを行うCodePipeline
1. index.htmlを更新してCodeCommitにgit push
1. CloudWatchが更新を検知
1. CodeBuildがリポジトリからファイルを取得してビルド
1. CodeDeployがアーティファクトをEC2にデプロイ
1. EC2上でhttpdサーバが動作しているので、更新されたindex.htmlが表示

という流れを確認したいと思います。
実際は1と5のみ手動で実施し、2～4は自動で動くことになります。

まずindex.htmlの文字列を以下のように修正します。
```
<html>
        <body>
            Good Morning Auto CodePipeline World!!!
        </body>
</html>
```
CodeCommitにgit pushします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/28204d88-d05e-30fb-245c-3e1ef55c4903.png)

CodePipelineを見ると2～4の処理が走って、成功していることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/f9b7f885-dbc1-c939-34c5-241b92c5e141.png)

EC2のパブリックIPアドレスを確認すると更新後のindex.htmlが表示されていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3956392/1d4da6bb-918a-d4c9-324c-18fbeed289a9.png)

# 感想
AWS Codeサービス群を使ったCI/CDの構築を実施してみました。
ビルド対象がhtmlファイル1つだけだったのでビルドやデプロイのコードは非常に簡素なものでしたが、簡単な設定でCodePipelineの自動化がサーバレスに実施できることが確認できました。
より複雑なビルド構成についても[リファレンス](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-spec-ref.html)を参考にしつつ確認していけたらと思います。
それでは今回はこの辺で。