話題のAWS App Runnerをハンズオン！


# App Runnerとは？
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550573/a8c469f6-976a-1b77-aa66-b95a18f6df84.png" width=600">

>App Runnerはコンテナネイティブのフルマネージドサービスです。オーケストレーターの設定、ビルドパイプラインの準備、ロードバランサーの調整、 TLS 証明書のローテートなどは必要ありません。そしてもちろん、管理すべきサーバもありません。

ソースコード、コンテナを用意すれば、ロードバランサー、オートスケーリングなどなどをAWSがフルマネージドにやってくれて、簡単にAWSに展開できる話題のサービス！

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">📣 新サービス <a href="https://twitter.com/hashtag/AWSAppRunner?src=hash&amp;ref_src=twsrc%5Etfw">#AWSAppRunner</a> のローンチです！🚀<br><br>＼数クリックでソースコードやコンテナイメージをデプロイ！／<br><br>AWS Fargate より高い抽象度、あるいは AWS Lambda のようなスレッドではなくプロセスそのものを実行したかった方にぜひお試しいただきたいサービスです！1/n<a href="https://t.co/LPFNOP7CBT">https://t.co/LPFNOP7CBT</a></p>&mdash; Tori Hara 🚀 (@toricls) <a href="https://twitter.com/toricls/status/1394795120013103106?ref_src=twsrc%5Etfw">May 18, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 料金
###### Asia Pacific (Tokyo) Region
$0.009 / GB時間
$0.081 / vCPU

###### Add-ons

|    |  料金  |
| ---- | ---- |
|  自動デプロイ  |  $1 / 1アプリケーション（月） |
|  ビルド |  $0.005 / ビルド料金（分） |

https://aws.amazon.com/jp/apprunner/pricing/

## 注意事項
本投稿は2021-05-22時点の情報になり、サービスのアップデート次第で内容が変わる可能性があります。

# ハンズオン 🚀
ワークショップを参考にコンテナをデプロイしてみます！

https://www.apprunnerworkshop.com/github/

## アプリケーションの用意
###### ディレクトリ作成

```terminal
$ mkdir apprunner-example
```

###### ディレクトリ配下に下記３つのファイルを作成

```javascript:index.js
const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`);
});
```

```json:package.json
{
  "name": "apprunner_example",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "dependencies": {
    "express": "^4.17.1"
  },
  "devDependencies": {},
  "author": "",
  "license": "ISC"
}
```

```dockerfile:Dockerfile
FROM node:14

# Create app directory
WORKDIR /usr/src/app

# Install app dependencies
COPY package*.json ./

RUN npm install

# Bundle app source
COPY . .

EXPOSE 3000
CMD [ "node", "index.js" ]
```

```terminal
~/apprunner-example$ ls
Dockerfile   index.js     package.json
```

## ECRのセットアップ
DockerベースのサービスをApp Runnerにデプロイするには、DockerイメージをECRにプッシュする必要があります。

##### リポジトリ作成
- プライベート
- リポジトリ名 => simple-express-repository
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550573/24b8c8c9-511b-555a-f5a9-fcbca8aa1252.png" width=600">


##### リポジトリにイメージプッシュ
プッシュコマンドを参考に先ほど用意したアプリケーションのイメージをECRにプッシュします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550573/f4ba759a-0f53-c093-d6eb-9cabcec4e86f.png" width=600">

```terminal
$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 1234567890.dkr.ecr.ap-northeast-1.amazonaws.com

$ docker build -t simple-express-repository .

$ docker tag simple-express-repository:latest 1234567890.dkr.ecr.ap-northeast-1.amazonaws.com/simple-express-repository:latest

$ docker push 1234567890.dkr.ecr.ap-northeast-1.amazonaws.com/simple-express-repository:latest
```

## IAMロールの作成
App RunnerがECRプライベートリポジトリにアクセスする際に必要なロールを作成します。
`AppRunnerECRAccessRole`という名前で作成します。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:DescribeImages",
                "ecr:GetAuthorizationToken",
                "ecr:BatchCheckLayerAvailability"
            ],
            "Resource": "*"
        }
    ]
}
```

信頼関係

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "build.apprunner.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```
## デプロイ :rocket:
おまちかねのApp Runnerの出番です！
[App Runner](https://ap-northeast-1.console.aws.amazon.com/apprunner/home?region=ap-northeast-1#/welcome)コンソールに移動しサービスの作成をします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550573/ba62a845-14ba-7dc1-a3c7-933a56d29b17.png" width=600">

- リポジトリタイプ => コンテナレジストリ

- プロバイダー => Amazon ECR
- コンテナイメージのURI => 先ほどECRにプッシュしたイメージ
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550573/55f054a5-dd63-c9a3-e787-ddaad09b5c0e.png" width=600">

- ワークショップのハンズオンだとデプロイトリガーを`手動`にしていますが、今回は`自動`で行ってみます。

- サービスロールを先ほど作成したロールを選択
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550573/2df0dac0-fa7a-1b94-d808-4f62d486bad2.png" width=600">

- サービス名 => simple-express-docker

- ポート => アプリケーションで設定した3000ポートを指定

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550573/99b20e79-f00e-c87f-8080-0bff15844590.png" width=600">

次のページで設定を確認しデプロイし、ステータスが`Running`になれば完了です！（数分かかりました。）
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550573/a2cceab0-2acf-135d-3407-4c23b5df8ae8.png" width=600">

デフォルトドメインにアクセスしてみると、
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550573/467718da-fa82-261d-1eb1-15c6a8d691dd.png" width=600">

おーー！めちゃくちゃ簡単！！！！

## 自動デプロイ動作確認

デプロイトリガーを`自動`とすることでApp Runnerがレジストリを監視してくれ、イメージプッシュごとに新しいバージョンをデプロイしてくれるようです！

index.jsの文字列を変更しECRにプッシュしてみます。

```javascript:index.js
const express = require('express');
const app = express();
const port = 3000;

app.get('/', (req, res) => {
  // res.send('Hello World!');
  res.send('Hello App Runner!');
});

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`);
});
```

プッシュ後すぐにデプロイが始まりました！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550573/e92f191d-6e93-c4e0-615e-df16cb035d05.png" width=600">

デプロイ完了後にデフォルトドメインにアクセスしてみると、
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550573/72dea782-dea4-8182-67ad-16107555ac5f.png" width=600">



## まとめ
数分でコンテナベースアプリケーションをデプロイ出来ました！
App Runnerには、AWSの運用とセキュリティのベストプラクティスが組み込まれており、開発者がアプリケーション開発に集中できる素晴らしいサービスだと思いました。

実践で使えそうな場面では積極的に使ってみようと思います！


## 参考
[AWS App Runner Workshop](https://www.apprunnerworkshop.com/github/)