【ハンズオン】CodeBuild＋CodeDeployを使って簡単Webサーバを構築しよう（Sphinx）

いつも記事を読んでいただきありがとうございます！
モブエンジニア（[@mob-engineer](https://qiita.com/mob_engineer))です！

業務内でCodeBuild⇒CodeDeployのパイプライン構築のキャッチアップに少し難儀していましたので、自身のスキル向上を兼ねてハンズオン記事をまとめてみたいと思います。

初見の方でもサクッと読めるように平易な表現で執筆しておりますので、お気軽に読んでいただければ幸いです。

# 目次
- 対象読者
- 完成イメージ
- ハンズオン
    - その０：事前準備
    - その１：IAMロール・S3設定
    - その２：EC2構築（RHEL10）
    - その３：Code Build設定
    - その４：Code Deploy設定
    - その５：実行結果
- 所感

## 対象読者

次のような課題を抱えている方に本記事を活用いただければ幸いです。

- AWSパイプラインに対して苦手意識を持っている方
- パイプライン周りのスキルを強化したい方
- ハンズオンを通じてパイプラインの理解を深めたい方


## 完成イメージ

完成イメージとして次のような形を考えています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/baa535e8-dade-4826-8adb-8a74456917ae.png)

- GitHub：フロント（Spihinx）コード管理
- Code Build：ビルド（Sphinx生成）
- Code Deploy：デプロイ（生成物をEC2へ展開）
- S3：Build生成物を格納

## ハンズオン

### その０：事前準備

サンプルコードについては次のGitHubに作成しています。
サンプルコードを自身のGitHubへForkしてください。

https://github.com/MASAKIOKUDA-eng/sphinx-aws-demo/blob/main/buildspec.yml

### その１：IAMロール・S3設定

最初にS3を作成しましょう。

- 検索ボックスに**S3**と入力します
- 検索結果のうち**S3**をクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/cb4189f1-8d9e-49b3-b91a-9859300c29a8.png)

- 画面中央の**バケットを作成**ボタンをクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/fa6d4708-29a4-41cf-a13d-648f4c9b51d2.png)

- バケット名に任意の名前を入力します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/869b3bbd-0647-4eb4-93f9-a9fc88420393.png)

- 最下部へスクロールし**バケットを作成**ボタンをクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/ad1d0207-0769-4358-b664-0daa718c3fb5.png)

- 作成したバケットが表示されていることを確認します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/a0bc5610-f6f2-486f-b3cc-8dbfcb1c20d5.png)

これでS3バケットの作成は完了しました。
次にIAMロールを作成します。

- 検索ボックスに**IAM**と入力します
- 検索結果のうち**IAM**をクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/c08bddee-31ae-4faa-a1a8-6a4e042591b8.png)

- 左側ペインの**ポリシー**をクリックします
- 画面右側の**ポリシーの作成**をクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/2f0bc9d7-050a-4d85-89cd-9f8379e5ceeb.png)

- ポリシー作成画面から以下ポリシーを作成します

**AWSCodePipelineServiceRole**

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketAcl",
                "s3:GetBucketLocation",
                "s3:GetObject",
                "s3:GetObjectAcl",
                "s3:GetObjectVersion",
                "s3:ListBucket",
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::your-codepipeline-artifacts-bucket",
                "arn:aws:s3:::your-codepipeline-artifacts-bucket/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "codebuild:BatchGetBuilds",
                "codebuild:StartBuild"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "codedeploy:CreateDeployment",
                "codedeploy:GetApplication",
                "codedeploy:GetApplicationRevision",
                "codedeploy:GetDeployment",
                "codedeploy:GetDeploymentConfig",
                "codedeploy:RegisterApplicationRevision"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "codestar-connections:UseConnection"
            ],
            "Resource": "*"
        }
    ]
}
```

**AWSCodeBuildServiceRole**

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Resource": "*",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::your-codepipeline-artifacts-bucket",
                "arn:aws:s3:::your-codepipeline-artifacts-bucket/*"
            ]
        }
    ]
}
```

- 作成後、ロールを作成します。

**EC2InstanceRole**
（EC2インスタンス用）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/7e6a7c8e-9dac-4fe6-b358-f37f7385da8a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/eb88d9b1-6a61-4bc4-acb5-90ba61f42f04.png)

**AWSCodePipelineServiceRole**
（Code Pipeline用）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/29e958cd-75a3-480a-bb9d-dcf71032a4f8.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/f2ede921-508e-41b3-8c0a-a3ea10fe6d66.png)

**AWSCodeBuildServiceRole**
（Code Build用）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/645e76fb-dfb2-4e35-b014-7dabe1d78cb0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/9102cdb7-7da9-403c-ae60-070707cfc62a.png)

**AWSCodeDeployServiceRole**
（Code Deploy用）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/2313253d-17a4-4866-846b-2ebb57bcfc87.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/f12cba70-31af-4fff-9fb6-a318c58126b9.png)

### その２：EC2構築（RHEL10）

EC2を構築する前にあらかじめセキュリティグループを作成します。

- 検索ボックスに**EC2**と入力します
- 検索結果より**EC2**をクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/2417ed71-34b5-4d08-8588-c842ab427308.png)

- 左側ペインより**セキュリティグループ**をクリックします
- 画面右側の**セキュリティグループを作成**ボタンをクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/e40a68de-63b4-4b0c-adb3-fa8f9efe6b91.png)

- セキュリティグループ作成画面が表示されるため任意の値を入れておきます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/c44c1cc0-d1b4-40a6-9404-135bf376aeef.png)

- インバウンド・アウトバウンドを次の通り設定します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/7c3e0d86-c174-41c0-bb92-cc3364109681.png)

- 左側ペインより**インスタンス**をクリックします
- 右側上部の**インスタンスの作成**をクリックします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/cada5e46-87a7-4ccc-b3af-1de1d1aed737.png)

:::note info
EC2作成に関してはセキュリティグループ以外デフォルトのため割愛いたします
:::

- 起動完了後、WebSVサーバへTeraterm接続します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/05dfed1a-b305-4711-862f-2de73b374cb1.png)

- 接続後、以下コマンドを実行します

```shell
sudo yum update -y
sudo yum install -y ruby wget httpd
cd /home/ec2-user
wget https://aws-codedeploy-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/latest/codedeploy-agent.noarch.rpm
sudo yum install -y ./codedeploy-agent.noarch.rpm
sudo systemctl start codedeploy-agent
sudo systemctl status codedeploy-agent
sudo systemctl start httpd
sudo systemctl enable httpd
sudo systemctl status httpd
```

- 設定後、EC2InstanceRoleを割り当ててください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/fd34034b-41c5-4128-9e62-a6331eb4dd49.png)


### その３：Code Build設定

次のような設定を行ってください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/3c1c1a63-5433-4d0e-8dd5-cedcd8d59f4f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/7e7dee0b-1da5-4249-b41d-51422bff8c86.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/ad4790a0-c195-4a30-b018-ec9b31fbafce.png)

### その４：Code Deploy設定

- Code Deploy用のアプリケーションを次の通り作成してください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/5023d873-1ec1-42b1-bf1b-b6c4ae4bd6cc.png)

- デプロイグループを次のように作成します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/7c517489-241b-4a1a-9131-4925af0bb3a4.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/f74ad357-1ccd-40fa-b543-8288e093540a.png)


### その5：実行結果

パイプラインを作成し実行してみました。
実行したところ、以下エラーが表示されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/af2c6c32-421b-44c4-9b20-69fa62ec762e.png)

ポリシーの権限不足判明したため、以下ポリシーを**AWSCodePipelineServiceRole**に追加しました。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetBucketAcl",
                "s3:GetBucketLocation",
                "s3:GetBucketVersioning",
                "s3:GetObject",
                "s3:GetObjectAcl",
                "s3:GetObjectVersion",
                "s3:ListBucket",
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::codepipeline-ap-northeast-1-71a30834a9be-4ec0-a2b9-981224e19677",
                "arn:aws:s3:::codepipeline-ap-northeast-1-71a30834a9be-4ec0-a2b9-981224e19677/*"
            ]
        }
    ]
}
```

実行したところ、Deploy時にEC2の権限不足エラーが出たため
以下インラインポリシーをEC2InstanceRoleに追加しました。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::sphinx-handson-20250526",
                "arn:aws:s3:::sphinx-handson-20250526/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "codedeploy:CreateDeployment",
                "codedeploy:GetApplication",
                "codedeploy:GetDeployment",
                "codedeploy:GetDeploymentConfig",
                "codedeploy:ListApplications",
                "codedeploy:ListDeployments"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeInstances",
                "ec2:DescribeInstanceStatus"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "tag:GetResources"
            ],
            "Resource": "*"
        }
    ]
}
```

改めて実行したところエラーが解消しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/ee0ec0b9-d8a7-45d4-99c9-42d8c162c5f7.png)

ホストへアクセスしてみましょう！！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3846878/f7c63fad-5382-4cd3-99b4-fda6a6714d18.png)

無事アクセスできました。
とりあえず、今回のゴールは実現できました。

## 所感

個人的にCode Deployエラーの対処に時間がかかりましたが、
数をこなせばそこまで労せず実施できるといった印象を持ちました。

そのうえで、今回実装したケースは最小構成ですので、他サービスと組み合わせることで拡張性高く運用を行えると感じました。

パイプライン周りについてはまだまだキャッチアップしないといけないと感じていましたので、
引き続きアウトプット活動を行っていきたいと思います。

最後まで、記事をお読みいただきありがとうございました。