学園祭の露店アプリのインフラをAWSで作成した話

この記事は、【 可茂IT塾 Advent Calendar 2024 】の17日目の記事です。
## はじめに
クラスメイトと文化祭の露店の運用を効率化するアプリを作成しました。私はサーマーインターンでバックエンド・インフラを勉強したこともあり、インフラを担当することになりました。初めて使うAWSのサービスやネットワーク設定、セキュリティ対策に苦戦しましたが、その分多くの学びを得ることができました。本記事では、開発過程や学んだことを振り返り、習得した知識を共有したいと思います。


## アーキテクチャ
今回作成したアプリのアーキテクチャは以下のようになっています。フロントエンドはNext.js, バックエンドはGoを使って開発しました。また、デプロイには以下のツールを採用しました。
- フロント：Vercel
- バックエンド：aws AppRunner

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/05a0bd59-83c7-efd9-445d-91b78a7c13b7.png)

具体的には以下の手順でインフラを構築しました。
- **AppRunnerへのコンテナのデプロイ**
- **RDS（MySQL）の作成**
- **AppRunnerからRDSに接続できるようにする**
- **AppRunnerにシークレットでDB関連の環境変数を渡す**
- **GitHubActionsでECRにDockerイメージを自動プッシュするようにする**

## AppRunnerへのコンテナのデプロイ

### 1. Dockerを用いたGo環境のDockerイメージの作成

以下の記事を参考にDockerfileとdocker-compose.ymlを作成して、Goの開発環境を構築しました。

https://zenn.dev/yuki_tu/articles/bcb926b0ebae47

**[dockerfileの内容]**
```dockerfile
# 開発環境(dev)
FROM golang:1.23-alpine AS dev
WORKDIR /app

RUN apk add --no-cache curl \
    && go install github.com/cosmtrek/air@v1.49.0

# go.modとgo.sumを個別にコピーしてキャッシュを有効化
COPY go.mod ./
COPY go.sum ./
RUN go mod download

COPY . ./

# dev環境ではホットリロードを使って実行
CMD ["air"]

# ビルド環境(build)
FROM golang:1.23-alpine AS build
WORKDIR /app

# go.modとgo.sumを個別にコピーしてキャッシュを効率化
COPY go.mod ./
COPY go.sum ./
RUN go mod download

COPY . ./

RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o main

# デプロイ環境(deploy)
FROM alpine:3.19 AS deploy
WORKDIR /root/

# ビルド済みバイナリをコピー
COPY --from=build /app/main .
# COPY --from=build /app/.env .

CMD ["./main"]

```
### 2. 作成したイメージをECRにプッシュ
AWS ECRの「プッシュコマンド」の手順に従い、DockerイメージをECRにプッシュしました。この作業は後にGitHub Actionsで自動化しました。

**[プッシュコマンドの手順]**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984024/de53686d-da2a-fdf9-b977-411d27d445a9.png)

### 3. AppRunnerへのデプロイ

ECRにプッシュしたイメージを使用してAppRunnerをデプロイしました。デプロイ方法を手動デプロイにすることでコストを抑えました。

**[エラーと解決]**
AppRunnerにデプロイした際、以下のエラーが発生しました。

```
10-10-2024 11:14:26 PM exec /bin/sh: exec format error
```

[公式サイト](https://repost.aws/questions/QUFkj5Ih-QTwqWOrCyH3m8LQ/does-apprunner-support-arm64-images)を確認したところ、原因はM1 MacでビルドしたイメージがARMアーキテクチャに依存していたためでした。

**解決策:**
Dockerfile内の--platform=linux/x86_64を追加することで解決しました。

## RDS（MySQL）の作成
### 1. VPCの設定
[動画](https://www.youtube.com/watch?v=2_FxLp9xgmo&t=2287s)を参考にしながら、VPCを作成し、以下の設定を行いました。
- サブネットとルートテーブルの作成
- セキュリティグループの追加

### 2. RDSのMySQLデータベースの作成
[公式サイトのチュートリアル](https://aws.amazon.com/jp/getting-started/hands-on/create-mysql-db/)を参考にRDSのMySQLデータベースを作成しました。

初めはVPCによる通信制限が原因でローカル環境からの接続確認ができず、苦労しました。以下の2点を調整することで接続が可能になりました。
（後にインターネットからの接続は削除し、AppRunnerからの接続のみにルーティングし直します。）

- ルートテーブルでインターネットからの通信を許可
- セキュリティグループのインバウンドルールに自分のPCのグローバルIPを追加

詳しい手順は以下の記事にまとめています。

https://qiita.com/hirune/items/f56fa3b3fe92dc5e183c



## AppRunnerからRDSに接続できるようにする

以下の手順でAppRunnerからRDSに接続できるようにしました。

1. ルートテーブルのルートからパブリック0.0.0.0/0を削除する前にローカルでMySQLにアクセスして、利用するDBを作成しておく。（DB作成手順は[こちら](https://qiita.com/aki_number16/items/1e1ee12aa98893e54677)を参考にしました)
2. ルートテーブルのルートからパブリックである0.0.0.0/0を削除
3. セキュリティグループのインバウンドルールでAppRunnerのセキュリティグループを許可
4. AppRunnerにVPCコネクタを設定

## AppRunnerにシークレットでDB関連の環境変数を渡す
AWS AppRunnerでのセキュリティ対策として、DB接続情報などの環境変数をシークレットとして安全に渡す設定を行いました。この方法により、コード内に直接書き込む必要がなくなり、情報漏洩のリスクを軽減できます。

**[手順概要]**
1. Secrets Manager に環境変数として渡したい情報を登録
2. AppRunnerの環境変数設定でシークレットを参照
3. アプリケーションで環境変数を読み取る設定を追加

詳細な手順については、以下の記事で解説しています。ぜひご参照ください。

https://qiita.com/hirune/items/19e71abf6322f7f049dc

## GitHubActionsでECRにDockerイメージを自動プッシュするようにする
コード変更時にDockerイメージをビルドし、AWS ECRへ自動アップロードするための仕組みをGitHub Actionsで構築しました。この自動化により、手作業でのビルドやプッシュの手間を省き、デプロイフロー全体を効率化することができました。

**[概要]**
- **AWS認証情報の設定:** 
GitHub ActionsからAWSを操作するために、一時的な認証情報を使用したIAMロールを設定
- **ECRへのアップロード:**
docker/build-push-actionを用いて、Dockerイメージをビルドし、プッシュするワークフローを構築
- **自動トリガー:**
mainブランチへのプッシュをトリガーに、自動でECRへ最新イメージをプッシュ

これらの具体的な手順やコードについては、以下の記事に詳しく記載しています。ぜひご覧ください。

https://qiita.com/hirune/items/68cbff5aaea1c40502a8

## 当日のハプニング
開発中にチームメンバーが私のAWSアカウントに不正アクセスし、アカウントが一時的にロックされる問題が発生しました。パスワードがチームの共有チャンネルに投稿されていたのが根本的原因でした。この経験を通じて、セキュリティ意識の重要性を痛感しました。今後はチーム全体でセキュリティ意識を高め、アカウント情報を厳重に管理したいと思います。

詳しいエラー内容や解決手順については以下の記事に記載しています。

https://qiita.com/hirune/items/0f3018c1d88e87939ac5

それ以外はハプニングなく、正常に動作しました🎉

## 最後に
今回のプロジェクトを通じて、AWSやネットワーク構築の基本を学ぶことができました。エラー対応に苦戦する日々でしたが、無事完成したときの達成感は格別でした。来年も露店アプリの開発は続く予定です。来年はTerraformやCloudFormationなどのIaC（Infrastructure as Code）ツールを活用し、さらに効率的で再現性の高いインフラ構築を目指したいと思います。