AWS App Runnerを学ぶためtDiaryをデプロイしてみる

「[AWS App Runner Advent Calendar 2022](https://qiita.com/advent-calendar/2022/aws-app-runner)」の5日目の記事です。

# はじめに

App Runnerの学習目的で、[tDiary](https://tdiary.org/)をデプロイしてみました。実運用を想定したものではありませんが、VPC内のリソースに接続するサンプルとして、参考になれば幸いです。

大まかな流れは下記の通りです。

1. App Runnerサービス以外のリソースを作成する
2. tDiaryのDockerイメージをビルドしてECRにpushする
3. App Runnerサービスを作成する
4. サービスのデフォルトドメインにアクセスする
5. tdiary.confを編集して再デプロイする
6. デフォルトドメインに再度アクセスする
7. 日記を書く
8. 作成したリソースを削除する

読者の方にも手軽に試していただけるよう、[CloudFormationテンプレートを用意しました](https://github.com/iwamot/tdiary-on-aws-app-runner-example)。ただし、内容を充分ご確認の上、自己責任でお願いします。

# 1. App Runnerサービス以外のリソースを作成する

まず、[infrastructure.json](https://github.com/iwamot/tdiary-on-aws-app-runner-example/blob/master/infrastructure.json)を使ってCloudFormationスタックを作成します。リージョンは、後述のリソースが作れるところなら、どこでも構いません。

スタック名は、あとで使う関係で「tdiary-infrastructure-stack」をお勧めします。

スタックのパラメータとして、Redisのポートと、VPCのIPv4 CIDRブロックが指定できます。デフォルト値はそれぞれ「6379」と「172.33.0.0/16」です。必要に応じてご変更ください。他の設定項目は、デフォルトのままでOKです。

![infrastructureスタック作成画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35988/7068240a-5532-e679-53a0-c1ceb8277331.png)

実行してしばらく待つと、以下のリソースが作成されます。

## VPC関連リソース

* VPC
* サブネット
* ルートテーブル（サブネットに関連付ける）

## ECR関連リソース

* プライベートリポジトリ

## App Runner関連リソース

* IAMロール（ECRへのアクセスロール）
* VPCコネクタ
* セキュリティグループ（VPCコネクタに関連付ける）

## ElastiCache関連リソース

* Redisクラスター（日記データのキャッシュを保存する）
* セキュリティグループ（Redisクラスターに関連付ける）
* サブネットグループ

# 2. tDiaryのDockerイメージをビルドしてECRにpushする

次に、下記の要領でtDiaryのDockerイメージをビルドします。`<>` で囲まれた部分は、適宜お読み替えください。

```
$ git clone https://github.com/iwamot/tdiary-core.git
$ cd tdiary-core

// Basic認証用の .htpasswd ファイルを作成
$ htpasswd -cd data/.htpasswd <username>

$ docker build -t tdiary .
```

ちなみに[iwamot/tdiary-core](https://github.com/iwamot/tdiary-core)は、公式の[tdiary/tdiary-core](https://github.com/tdiary/tdiary-core)をforkして下記の変更を加えたものです。

- キャッシュの保存先をファイルからRedisに変更する
- Redisの接続情報を環境変数で渡せるようにする
- `YAML.load`で発生するエラーを`YAML.unsafe_load`で回避する (https://github.com/tdiary/tdiary-cache-redis/issues/5)

具体的な差分は下記コミットの通りです。

https://github.com/iwamot/tdiary-core/commit/1d31a81df1d6f7e054ddb922a94b545c97ee05fc

イメージがビルドできたら、ECRリポジトリにpushします。

```
$ aws ecr get-login-password --region <region> | docker login --username AWS --password-stdin <account>.dkr.ecr.<region>.amazonaws.com
$ docker tag tdiary:latest <account>.dkr.ecr.<region>.amazonaws.com/tdiary:latest
$ docker push <account>.dkr.ecr.<region>.amazonaws.com/tdiary:latest
```

# 3. App Runnerサービスを作成する

続いて、[service.json](https://github.com/iwamot/tdiary-on-aws-app-runner-example/blob/master/service.json)を使ってCloudFormationスタックを作成します。スタックに含まれるリソースはApp Runnerサービスのみです。

スタック名は「tdiary-service-stack」が分かりやすいと思います。が、何でも構いません。

パラメータとして、手順1で作ったスタック名を指定します。デフォルト値は「tdiary-infrastructure-stack」です。他の設定項目は、デフォルトのままでOKです。

![serviceスタック作成画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35988/749285a4-033a-1836-683e-b65de459032b.png)

# 4. サービスのデフォルトドメインにアクセスする

App Runnerサービスの作成が完了したら、デフォルトドメインにアクセスします。すると、tDiaryの初期画面が開きます。

![tDiary初期画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35988/2fb22288-195f-6749-b2d4-19a9759e2e86.png)

さっそく日記のタイトルを変えたくなりますが、急いで「サイトの情報」で変更してはいけません。コンテナ内のtdiary.confに反映されるだけで、コンテナが変わったら巻き戻ってしまうためです。

# 5. tdiary.confを編集して再デプロイする

日記のタイトルを永続的に変えるには、tdiary.confを編集し、Dockerイメージを再ビルドします。

```
$ cp tdiary.conf.beginner tdiary.conf

// tdiary.conf の @html_title を編集

$ diff tdiary.conf.beginner tdiary.conf
88c88
< @html_title = %Q[【日記のタイトル】(→<a href="#{@update}?conf=default">サイトの情報</a>で変更しましょう)]
---
> @html_title = "tDiary on AWS App Runner"

$ docker build -t tdiary .
```

ビルドできたら、ECRに再pushします。

```
$ docker tag tdiary:latest <account>.dkr.ecr.<region>.amazonaws.com/tdiary:latest
$ docker push <account>.dkr.ecr.<region>.amazonaws.com/tdiary:latest
```

pushするだけで自動デプロイされます。

# 6. デフォルトドメインに再度アクセスする

デプロイ完了後、デフォルトドメインに再度アクセスすると、日記のタイトルが変わっています。

![タイトル変更後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35988/3fb1c350-e180-5399-506a-f4c9f7226f04.png)

# 7. 日記を書く

せっかくなので、日記を書いてみましょう。右上の「追記」リンクから投稿フォームに遷移できます。Basic認証を求められたら、手順2で指定したユーザ名とパスワードを入力します。

![投稿画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35988/168feb44-0d96-50ab-aa5e-fdfa09a95e2f.png)

![投稿後画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35988/c933082a-a113-702c-7676-b693ac497b32.png)

見た目では分かりませんが、キャッシュデータがRedisに保存されています。興味のある方は、EC2インスタンスを立てるなどして、保存されたデータを見てみるとよいでしょう。

# 8. 作成したリソースを削除する

ひととおり遊んだら、リソースを下記の順で削除します。

1. tdiary-service-stackを削除する
2. pushしたイメージをECRから削除する
3. tdiary-infrastructure-stackを削除する
4. 必要に応じて、CloudWatchログを削除する

以上で、App Runnerのいくつかの機能が試せました。特に下記がポイントです。

- ECRプライベートリポジトリからの自動デプロイ
- VPCリソースへのアクセス

# 最後に

App Runnerに触ったのは初めてですが、VPCリソースへの接続を含め、あっさりと実現できました。自由度が低いぶん、学習コストが少ない印象です。

一方、環境変数にシークレットを指定できない点や、WAFを適用できない点など、物足りなさも感じました。とはいえロードマップには載っているので、今後の改善に期待します。

https://github.com/aws/apprunner-roadmap/projects/1