AWS App Runner と ECS それぞれで同じアプリをデプロイして比較してみる


こんにちは、Masuyama です。

[別な記事](https://zenn.dev/tmasuyama1114/articles/60c1309d0fb1a8)では、AWS App Runner を使って手軽にコンテナ式アプリをデプロイできることを学びました。
その時は確かに少ないステップでデプロイできることは分かっていただけたと思うのですが、別なサービス (ECS とか) でデプロイする時との違いが分かりにくかったかもしれません。

そこで、App Runner と ECS の**それぞれで同じコンテナアプリをデプロイ**し、App Runner がどれだけ簡単かを分かっていただこうかと思います。
前回は Workshop に従いましたが、今回は Python の軽量 Web フレームワークの一つである **Flask** を App Runner でデプロイしてみましょう。

---

# 0. 前準備 (共通手順)

App Runner 版、ECS 版のどちらでも共通となる **コンテナイメージの準備** だけは共通手順として実施します。

## 0-1. ECR 作成

コンテナイメージをプッシュするためのリポジトリを先に用意しておきます。

[リポジトリを作成] を選択します。
![](https://storage.googleapis.com/zenn-user-upload/ef6866434ccbcda045447a0d.png)

リポジトリ名は今回は **app-runner-flask-ecr** と設定します。
![](https://storage.googleapis.com/zenn-user-upload/529e28bed248c96bcf0b5146.png)

リポジトリを作成できたら [プッシュコマンドを表示] を選択し、画面に表示される指示に従いローカル端末からイメージのビルド、プッシュコマンドを確認しておきます。
![](https://storage.googleapis.com/zenn-user-upload/e6e868f24bea7282171033bb.png)

次の手順でサクッと Flask アプリコードを準備し、コンテナイメージを作成したらプッシュコマンドでイメージをリポジトリに上げていきます。

---

## 0-2. コンテナイメージ作成

続いて ECR にプッシュするためのコンテナイメージを作成しましょう。

**apprunner-flask** という名前のディレクトリを用意し、その中に以下の 2 つのファイルを用意します。

- app.py
- requirements.txt

それぞれのコードの中身はこのように記述します。

```app.py
FROM python:3.8

# 以降の RUN, CMD で使われる作業ディレクトリ
WORKDIR /app

# カレントディレクトリにある情報をコンテナ内の ｢/app｣ にコピー
ADD . /app

# requirements.txt に従いパッケージをインストール
RUN pip install --trusted-host pypi.python.org -r requirements.txt

# 待受ポート指定
EXPOSE 5000

# コンテナが起動時に実行するコマンド
CMD ["python", "app.py"]
```

```requirements.txt
Flask
```

ここまで準備できたら、ECR にリポジトリを作成した時に確認したプッシュコマンドを apprunner-flask ディレクトリ内で実行していきます。
![](https://storage.googleapis.com/zenn-user-upload/5264e062e9907f573f900b06.png)

プッシュまで終わったら、リポジトリにイメージが上がっていることを確認しておきましょう。
![](https://storage.googleapis.com/zenn-user-upload/d30d6be534f5aa50d477caa8.png)

なお、プッシュする前にローカルでコンテナを起動させて動作確認をする場合は以下のコマンドを実行します。

```
$ docker run -d -p 5000:5000 app-runner-flask-ecr
```

その後、ブラウザで **localhost:5000** にアクセスすると app.py 内で指定した文字が表示されているはずです。
![](https://storage.googleapis.com/zenn-user-upload/9e37561b7f370e970ebbf6d1.png)

---

# 1. App Runner 版

ではイメージを用意できたので、まずは App Runner でイメージから Flask アプリをデプロイしてみます。

## 1-1. サービス作成

細かい手順は [別な記事](https://zenn.dev/tmasuyama1114/articles/60c1309d0fb1a8)で紹介もしているので一部割愛しますが、App Runner ではサービスを作成するという手順だけで済んでしまいます。

なお、サービス作成時に指定する待ち受けポートは Dockerfile 内で指定した通り **5000** と設定しましょう。
![](https://storage.googleapis.com/zenn-user-upload/b70e7b1b65fdc5bbf5aaf45c.png)

※Dockerfile より抜粋

```
...
EXPOSE 5000
...
```

設定するところといったらこれぐらいです。早い。

さて、少し待ってデプロイが完了したら表示されるデフォルトドメインにアクセスしてみましょう。
Hello ~ が表示されていれば成功です。

![](https://storage.googleapis.com/zenn-user-upload/98b6c03e64fe993421d32eb4.png)

![](https://storage.googleapis.com/zenn-user-upload/6ba957c7aaea296ef514131f.png)

---

# 2. ECS (Fargate) 版

次に、これまでコンテナアプリのデプロイに多く使われてきた ECS (Fargate) で Flask アプリをデプロイする手順を試してみましょう。
基本的にはできるだけデフォルト設定で簡単に済ませる方針です。

## 2-1. クラスター作成

ECS のコンソールから [クラスター]->[クラスターの作成] を選択します。
![](https://storage.googleapis.com/zenn-user-upload/d55d326ea17bd89cf3c37c7a.png)

次にクラスターテンプレートを選択していきます。
今回はサクッと Fargate を使いたいので [ネットワーキングのみ] を選択します。
![](https://storage.googleapis.com/zenn-user-upload/edbd1169bc6ae8da68007394.png)

次はクラスターの設定です。
新しく VPC を作成するよう選択し、VPC とサブネットの CIDR を設定していきます。
![](https://storage.googleapis.com/zenn-user-upload/c754e45560d00d76f25af4d8.png)

---

## 2-2. ECS タスク定義作成

クラスターの作成が完了するまでの間、タスク定義も作成していきます。

ECS の管理画面から[タスク定義]→[新しいタスク定義の作成]を選択します。
![](https://storage.googleapis.com/zenn-user-upload/1eba5e1b92cb0a9223ba461c.png)

起動タイプは前述の通り **Fargate** を選択します。
EC2 管理までマネージドになるのは素敵ですね。
![](https://storage.googleapis.com/zenn-user-upload/ff15b87557e33e0b3fb6747e.png)

さらに実行ロールやタスク定義名を設定しつつ、、、
![](https://storage.googleapis.com/zenn-user-upload/f9148a1d384c847af5fc1640.png)

タスクサイズも適当に、とりあえず最小要件で設定しつつ、、、
![](https://storage.googleapis.com/zenn-user-upload/3bb54090839a531cb1e92882.png)

[コンテナの定義]->[コンテナの追加] から、先ほど ECR にアップロードしたイメージを指定します。
![](https://storage.googleapis.com/zenn-user-upload/36462d43f5c06493cf9ad590.png)

ここでも待受ポートは Dockerfile で指定した通り、5000 と設定するのを忘れないようにしましょう。
![](https://storage.googleapis.com/zenn-user-upload/c603db6d65c44017821403f3.png)

App Runner は 1 手順のみでデプロイできたので、ECS は既に工程が多いようにみえてきました…。

---

## 2-3. ECS サービス作成

さて、そろそろ先ほどのクラスターが作成完了しているはずなので、ここからサービスを立ち上げます。

クラスターの画面から [デプロイ] を選択し、サービス名などを適当に設定して進みます。
![](https://storage.googleapis.com/zenn-user-upload/f4c5d2d0c7199ae5342cd98a.png)

![](https://storage.googleapis.com/zenn-user-upload/d132215452ab9db4f671f5e7.png)

デプロイが始まり、しばらく待つとデプロイ完了です。
![](https://storage.googleapis.com/zenn-user-upload/5169d1b6a624743f18adafbb.png)

ではデプロイした Flask アプリにアクセスしてみます。
作成したクラスターの [タスク]->[ネットワーキング]->[パブリック IP] から Flask コンテナの IP を確認できるので、これにブラウザでアクセスします。
![](https://storage.googleapis.com/zenn-user-upload/5c50a2ed3329419b1db75fc4.png)

ポートマッピングで指定した :5000 を付けるのを忘れないようにしましょう。
無事にアクセスできましたね。
![](https://storage.googleapis.com/zenn-user-upload/1c59cf623e79babda4d7c1b2.png)

---

# おわりに

さて、いかがでしたでしょうか。
App Runner を簡単に見せたいという気持ちは少なからずあったかもしれませんが、それでも手順の数でいうと以下のように差があることが分かっていただけたかと思います。
(ECR へのイメージプッシュは共通手順のため除く)

1. App Runner の場合
   1. サービス作成
2. ECS (Fargate) の場合
   1. クラスター作成
   2. タスク定義作成
   3. サービス作成

最小構成のデプロイでこの差でしたが、Auto Scaling 等、もう少し設定を付加するとなればもっと違ってくるはずです。
(ECS だと CloudWatch アラーム + Auto Scaling の設定が必要です。)
App Runner はサービス作成時に、一緒にぽちぽちっとするだけで Auto Scaling まで気軽に設定できるので楽ちんです。

(参考：サービス作成時 or 作成後に赤枠内で設定するだけ)
![](https://storage.googleapis.com/zenn-user-upload/78536daef088a5874ac966df.png)

また、ECR 上に新しいイメージがプッシュされた時にも、App Runner では CI/CD 構成を自分で用意せずとも設定項目一つで自動デプロイまで出来ちゃいます。

もちろん細かく要件に合わせた設定にするにはまだまだ ECS や k8s が適任かもしれませんが、少なくとも小〜中規模開発においては、まさに **「開発に集中」** を実現できるサービスだと実感しました。