CloudRunならたった5分でwebアプリをリリースできる！(自動デプロイも)

# はじめに
GoogleからDockerコンテナをサーバレスで実行できるCloudRunが公開されたので触ってみようと思ったところかなり使いやすくて、自分でサービスを立ち上げたので、その時の備忘録を記載していこうと思います。

今回はNodeJSの公式イメージを元にNodeJS + Expressでアプリケーションを作成し、Dockerコンテナを作成してCloudRunに乗せるまでを記載します。
また、今回はNodeJSのアプリケーションの説明を目的とはしていませんので、そこについては触れません。

# 対象読者
以下のような方が対象となるかもしれません。

* インフラわからないけどアプリを公開してみたい
* てっとり早く公開したい
* サーバレスを経験してみたい
* 新しいサービス触ってみたい

ご自身でサーバを立ち上げて、webサーバ等のミドルウェアを構築したい方は以下の記事が参考になるかもしれません。

* [GCPで永久無料枠を利用してサービスを立ち上げたときにしたことの備忘録](https://qiita.com/riku-shiru/items/a870edd9dc0b132e092c)

# CloudRunについて
CloudRunとはGoogle Cloud Next'19で発表されたDockerコンテナをサーバレス環境で実行できるサービスです。
HTTPでリクエストを受ける事が可能なステートレスコンテナを実行できます｡

Knativeから作成されており､開発者はCloudRunを使用してフルマネージド型でコンテナを実行するか、GKEクラスタ上にデプロイする事が可能です｡
CloudRunによる管理の場合は、開発者がインフラを意識せずに利用ができ、トラフィックに応じてスケールアップやスケールダウンも自動的に実行してくれます。なのでスケーリング構成のことを心配する必要はありません。

詳しい内容は公式ドキュメントを読んでください
[CloudRunの公式ドキュメント](https://cloud.google.com/run/?hl=ja)

## 料金について
Cloud Run の課金対象は使用したリソース（100 ミリ秒単位、1,000 ミリ秒単位以下切り捨て）に限られるため、過剰にプロビジョニングしたリソースに料金を支払う必要はありません。

無料枠も用意されているので、過度なアクセスが来ない限りは無料で利用することができます。
無料枠としては、以下の通りになっています。

|CPU |Memory  | Requests  |
|---|---|---|
|180,000 vCPU 秒/月  | 360,000GB/月 | 200 万回リクエスト数/月  |

詳しくは以下のドキュメントをご覧ください
[CloudRunの料金](https://cloud.google.com/run/pricing?hl=ja)

# 最速でアプリをデプロイするまで
前置きが長くなってしまいましたが、早速アプリをCloudRunで公開してみようと思います。
## 事前準備
CloudRunを利用するために以下の事前準備を行いましょう。
### 1. GCPアカウントを作成
作りましょう。
### 2. GCPのプロジェクトを作成
[リソース管理](https://console.cloud.google.com/cloud-resource-manager?_ga=2.59284459.-755609582.1558849277)ページから以下の画像の赤枠のリンクからプロジェクトを新規に作成しましょう。
<img width="578" alt="スクリーンショット 2019-09-16 3.33.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255007/cbdd8955-b23d-50b7-5998-5db6a7bee423.png">

### 3. プロジェクトに対して課金を有効にする
[こちらのページ](https://cloud.google.com/billing/docs/how-to/modify-project)から課金を有効にしましょう。

### 4. CloudRunAPIを有効にする
[こちら](http://console.cloud.google.com/apis/library/run.googleapis.com?_ga=2.163590393.-755609582.1558849277)から"有効にする"を押してAPIを有効にしましょう。
<img width="892" alt="スクリーンショット 2019-09-16 3.41.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255007/567a4c34-9609-209b-b6e8-eb7e69a183e3.png">

### 5. Cloud SDKをインストール
以下のページ の手順にしたがってCloud SDKをインストールしましょう。
https://cloud.google.com/sdk/docs/

### 6. gcloud betaをインストール
以下のコマンドを実行し、gcloud betaをインストールする。

```
$gcloud components install beta
```

### 7. componentsをupdate
以下のコマンドを実行し、componentsをアップデートする。

```
$gcloud components update
```

### 8.  platformとregionをset
platformとregionを設定しておきましょう。
regionですが、現在cloudrunを実行できるregionは以下から選べます。

* asia-northeast1 (Tokyo)
* europe-west1 (Belgium)
* us-central1 (Iowa)
* us-east1 (South Carolina)

```
gcloud config set run/platform managed
gcloud config set run/region {REGION}
```

### 9. アプリケーションを用意しておく
今回はNodeJSで簡単なアプリを作って動かしてみたいと思います。
(nodeの実行環境は用意しておいてください。)

適当な作業ディレクトリに移動して以下のコマンドを実行します。

```
$ mkdir test-app && cd test-app
$ touch index.js
```
そして好きなエディタでindex.jsを開いて"Hello World!"を表示するだけの以下のコードを書きましょう。

``` index.js
const express = require('express');
const app = express();

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

const port = process.env.PORT || 8080;
app.listen(port, () => {
  console.log('Listening on port', port);
});
```

最後にpackage.jsonを作成しましょう。

```npm init```して```npm install express```を実行する か
以下のコードをpackage.jsonに記載しましょう。

```package.json
{
  "name": "test-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1"
  }
}
```

ここまでで事前準備は完了です！
ではデプロイしましょう。

## Step1: Dockerfileを用意
事前準備通りに準備した場合は以下のようなDockerfileで上手く行くかと思います。
test-appディレクトリ直下にDockerfileを作成して中身に以下のように記述しましょう。

```Dockerfile
FROM node:12-slim

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install --only=production

COPY . ./

CMD [ "npm", "start" ]
```

このDockerfileを元にコンテナを起動させるといらないものまでコンテナ側に渡してしまうことになるので、.dockerignoreも用意しておきましょう。

```shell:.dockerignore
Dockerfile
README.md
node_modules
```

## Step2: コンテナをBuildし、GCRにuploadする

1. [Cloud Build API](https://console.cloud.google.com/apis/library/cloudbuild.googleapis.com?project=cloudruntest-253018)をあらかじめ有効にしておきましょう。

2. **GCPで作成したプロジェクトのプロジェクトIDを控えておいてください。**

3. Dockerfileを配置したディレクトリで以下のコマンドを実行し、コンテナをBuildします。
成功するとGCR(Google Container Registry)にアップロードされます。
 - ${PROJECT_ID}にはGCPのプロジェクトIDを記載してください。
 - helloworldの部分も適宜変えてください。

```
$ gcloud builds submit --project ${PROJECT_ID} --tag gcr.io/${PROJECT_ID}/helloworld
```

成功すると以下のようにSUCCESSと標示されると思います。

```
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

ID                                    CREATE_TIME                DURATION  SOURCE                                                                                         IMAGES                                           STATUS
26*****0f-4**1-4**2-a**c-9*******ad  2019-09-15T20:23:30+00:00  35S       gs://clo****************ld/source/15*****7.36-270*******************a37.tgz  gcr.io/clo*************18/helloworld (+1 more)  SUCCESS
```

## Step3: CloudRunにデプロイ
実際にCloudRunにデプロイしましょう。

* 以下のコマンドを実行してください。
  - ${PROJECT-ID}はStep２で控えておいたプロジェクトIDに置き換えてください。
  - また、helloworldをStep２で変更していた場合はその名前に変更してください。

```
$ gcloud beta run deploy --image gcr.io/${PROJECT-ID}/helloworld --platform managed
```

* 上記コマンドを実行するとサービス名を聞かれるので、任意のサービス名を入力しましょう。

```
Service name (helloworld): ~サービス名~
```

* あとは聞かれた質問に答えましょう
    * regionを聞かれた場合は、事前準備で選択したregionを記載しましょう
    * allow unauthenticated invocationsを聞かれた場合は、y/Nのどちらかで回答しましょう。 
        * 今回作成するアプリケーションは認証なく呼べていいものなので"y"でよいかと思います。

* デプロイが完了するとURLが表示されるのでアクセスしてみてください
    * Hello World!と表示されていれば無事に公開できています。
<img width="417" alt="スクリーンショット 2019-09-16 5.42.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255007/3fe419db-5bb0-be83-8797-90b4ab8c81e8.png">


お疲れ様です！
どうでしょう？
そんなにステップもなく簡単にデプロイできたのではないでしょうか？

表題の通り5分でリリースできましたね！（事前準備をなくせば）

# (Appendix) デプロイの自動化
ここまでで一旦デプロイが完了し、アプリケーションにリクエストすることができますが、
デプロイするために毎回毎回上記の処理をするのは少し面倒ではあるので、
ここからはおまけとして、
githubのmasterブランチにpushされたタイミングで自動的にデプロイされるような仕組みを組み立てたいと思います。

## 全体の構成
イメージとしては以下のような構成図になります。
<img width="820" alt="スクリーンショット 2019-09-16 17.38.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255007/2029120d-472d-b385-fbcd-bf4b890f3464.png">


流れとしては
1. githubのmasterにpushされたのをトリガーにCloud Buildを実行
2. Cloud BuildでDockerイメージのビルドを実行し、GCRにpush
3. GCRからCloudRunにデプロイ

の３ステップを自動化させることになります。
それではやっていきましょう。

## 事前準備
デプロイの自動化を行うために事前準備が必要なので、
以下の通りに準備を進めていきましょう。
### APIの有効化
以下二つのAPIを有効化しておきましょう。
* [Cloud Run API](https://console.cloud.google.com/apis/library/run.googleapis.com)の有効化
* [Cloud Resource Manager API](https://console.cloud.google.com/apis/library/cloudresourcemanager.googleapis.com)の有効化

### サービスアカウントの権限設定
[IAMの管理](https://console.cloud.google.com/iam-admin/iam)から{ProjectID}@cloudbuild.gserviceaccount.com)に
以下の権限を追加してください。

* Cloud Run 管理者
* Cloud Run サービスエージェント 
* ストレージオブジェクト 閲覧者

以下のような状態になっていれば大丈夫です。
<img width="673" alt="スクリーンショット 2019-09-16 19.45.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255007/ed27864f-2a96-d8bb-d9d9-7d78568b6aec.png">


## cloudbuild.ymlを作成
### cloudbuild.ymlとは
cloudbuild.yamlはCloud Buildが公式にサポートするデフォルト設定ファイルです。
このファイルを利用してトリガーを作成してDockerイメージをビルドします。
今回はDockerfile + cloudbuild.ymlの組み合わせでCI/CDを行います。


cloudbuild.yamlの主な役割は、Dockerfileを実行し、ビルドしたイメージをGCRにPushして、CloudRunにデプロイを行います。

### cloudbuild.ymlの作成
それではcloudbuild.yamlを　アプリケーションのあるディレクトリのいずれかに作成しましょう。
今回の例ではアプリケーションルートにおいた例を記載します。

```
~ test-appディレクトリに移動 ~

$ touch cloudbuild.yaml
```

そしてcloudbuild.yamlに以下にのように記載します。

```cloudbuild.yaml
steps:
  - name: 'gcr.io/cloud-builders/docker'
    id: 'build-docker-image-from-dockerfile'
    args: 
      - 'build'
      - '-t'
      - 'gcr.io/$PROJECT_ID/${_SERVICE_NAME}:$SHORT_SHA'
      - '.'
  - name: 'gcr.io/cloud-builders/docker'
    id: 'push-docker-image-to-gcr'
    args: 
      - 'push'
      - 'gcr.io/$PROJECT_ID/${_SERVICE_NAME}'
  - name: 'gcr.io/cloud-builders/gcloud'
    id: 'deploy-cloud-run'
    args: 
      - 'beta'
      - 'run'
      - 'deploy'
      - '${_SERVICE_NAME}'
      - '--image'
      - 'gcr.io/$PROJECT_ID/${_SERVICE_NAME}:$SHORT_SHA'
      - '--platform'
      - 'managed'
      - '--region'
      - 'us-central1'
substitutions:
  _REGION: us-central1
  _SERVICE_NAME: helloworld
```

内容を説明するとstepsの内容が順番に実行されていきます。
今回は３つステップが存在していてそれぞれ以下のような役割を実行します。

1. Dockerfileを元にDockerイメージをビルド
2. DockerイメージをGCRにpush
3. GCRからDockerイメージをCloud Runへデプロイ



また、cloudbuild.yamlに記載するフィールドを少し解説すると
stepのnameフィールドは、クラウド ビルダーを指定するために使用します。

例えば
gcloudを実行したい場合には
- name: 'gcr.io/cloud-builders/gcloud'

dockerを実行したい場合には
- name: 'gcr.io/cloud-builders/docker'
と記載します。

また、argsフィールドには上記のnameフィールドに記載したコマンドに続くコマンドを","区切りで記載します。
例えば、
```docker build -t hoge .```の場合には以下のように記載します。

```yml

steps:
  - name: 'gcr.io/cloud-builders/docker'
  - args:
      - 'build'
      - '-t'
      - 'hoge'
      - '.'
```

最後にidフィールドですが、
そのstepの識別子として利用するのでわかりやすい名称をつけてあげると良いかと思います。


## CloudBuildのトリガーを作成
cloudbuild.ymlまで作成し終えたらCloudBuildにトリガーを作成します。
[CloudBuildのトリガー](https://console.cloud.google.com/cloud-build/triggers)ページを開いて以下画像のトリガーを追加を選択します。
<img width="705" alt="スクリーンショット 2019-09-16 20.21.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255007/eeae6290-1ae7-6542-15f2-29e05cc2427b.png">

次のページでgithubを選択して同意するにチェックをいれた状態で続行を押します。
<img width="606" alt="スクリーンショット 2019-09-16 20.23.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255007/0882400b-816f-8720-0d94-4f8d685caf72.png">

少しの間認証が完了するのを待ち、以下の画面が出たら、今回のアプリケーションを管理しているgithubのレポジトリを選択し、続行を押します。
<img width="741" alt="スクリーンショット 2019-09-16 20.24.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255007/79234e6e-00ea-8bba-cb54-dddc96661456.png">

そうすると以下の画面が出るので、どのブランチへのpushをトリガーにするかやcloudbuild.yamlの場所を決定していきます。
masterブランチへのpushをトリガーにする　かつ　アプリケーションルートにcloudbuild.yamlをおいている場合には以下の設定にすれば大丈夫です。
<img width="497" alt="スクリーンショット 2019-09-16 20.29.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255007/ff76c878-d6d3-2d18-1ac4-5398f402377d.png">

ここまでできたら保存を押して設定は完了です。


## githubのmasterブランチにpush

ここまでであらかたの設定は完了しているので、正しく動作しているかを確認するためにmasterブランチにpushしてみてください。
正しくCloudRunにデプロイされていれば成功になります。

お疲れ様でした!




### 参考文献
[GCPのCloud Buildを使おう](https://developers.cyberagent.co.jp/blog/archives/17034/)