Cloud Runに入門してみる

# 概要
先月、Google Cloud Platformに新サービスのCloud Runがリリースされましたね!
そんなわけで、早速Cloud RunにFlaskアプリケーションを乗せて動かしてみようと思います。

# Cloud Runとは
GCPの管理下の環境に、コンテナを乗せて動かすことができる**サーバーレス環境**です。
AWSの**Fargate**と似たような立ち位置っぽいです。

今までは、GKEはロードバランサーやサーバーなどのリソースは契約者側で管理する必要がありますが、これらの管理をGCPに任せる（**フルマネージド**）ことが出来るんですね。すごい。

GKEとGAEの良いとこどりをしたイメージな感じがします。

ちなみにCloud Run on GKEというのもあり、Cloud RunとGKEを組み合わせて使うこともできるみたいです。
複数のサービスを連携させるとなるとこちらの方が良いのでしょうか。後日試してみようかなと思います。

# 環境構築
[公式のクイックスタートガイド](https://cloud.google.com/run/docs/quickstarts)を見ながら進めていきます。

## gcloud betaコマンドをインストール
Cloud Runは**ベータ版**なので、`gcloud beta`コマンドが必要になります。

```shell

$ gcloud components install beta
$ gcloud components update
```

## コンテナ準備
### プロジェクトファイル作成
サンプルのプロジェクトを作成していきます。

```shell

$ mkdir helloworld-python
$ cd helloworld-python
```

```helloworld-python/app.py
import os

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    target = os.environ.get('TARGET', 'World')
    return 'Hello {}!\n'.format(target)

if __name__ == "__main__":
    app.run(debug=True,host='0.0.0.0',port=int(os.environ.get('PORT', 8080)))
```

アクセスされた時に、「Hello 〇〇」を表示するアプリができました。
〇〇は環境変数で指定した`TARGET`もしくは、worldが入ります。
ポートはデフォルトでは8080へのアクセスを受け付けるようになっていますが、環境変数の `PORT` でアプリが動くように指定しておきます。

### Dockerfileを準備
アプリが動くコンテナを用意するために、Dockerfileを準備しましょう。
hello-pythonディレクトリ配下に、Dockerfileを置きます。

```Dockerfile
# Use the official Python image.
# https://hub.docker.com/_/python
FROM python:3.7

# Copy local code to the container image.
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . .

# Install production dependencies.
RUN pip install Flask gunicorn

# Run the web service on container startup. Here we use the gunicorn
# webserver, with one worker process and 8 threads.
# For environments with multiple CPU cores, increase the number of workers
# to be equal to the cores available.
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 app:app
```

### ローカルでアプリを動かす
Dockerfileからコンテナを起動します。
コンテナをビルドし、ビルドしたコンテナの環境変数に`PORT=8000`を指定。
ゲスト側の8000番ポートと、コンテナ側の8000番ポートを紐づけて起動します。

```shell
$ docker build -t hello-python .
$ docker run -e PORT=8000 -p 8000:8000 hello-python
[2019-05-24 16:14:10 +0000] [1] [INFO] Starting gunicorn 19.9.0
[2019-05-24 16:14:10 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1)
[2019-05-24 16:14:10 +0000] [1] [INFO] Using worker: threads
[2019-05-24 16:14:10 +0000] [9] [INFO] Booting worker with pid: 9
```

`http://0.0.0.0:8000/` にアクセスしてみましょう。
![スクリーンショット 2019-05-25 1.16.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154121/304fdc72-6f49-6f86-2fe8-66dedfa96b86.png)
出ました。
ローカル環境での動作はOKです。

## コンテナをGCRへアップロード
Cloud Runにコンテナを配置するにあたって、 **GCR** (Google Container Registry)にコンテナをアップロードする必要があります。

### プロジェクト作成
まずはGCPプロジェクトの作成
![スクリーンショット 2019-05-25 1.21.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154121/ce54e448-f56f-462c-fa0b-c5eb8d1fc575.png)

### コンテナPush
今回は作成したGCPプロジェクトIDが`hellopython20-241616`だったので、下記のように入力してコンテナをGCRにPushします。

```shell
$ gcloud builds submit --tag gcr.io/hellopython20-241616/helloworld --project hellopython20-241616
```
こちらのコマンドは、DockerfileのビルドからPushまでを一貫して行ってくれるので、ビルドしたイメージを指定する必要はありません。

Pushが成功すると、GCRでコンテナが登録されているのが確認できます。
![スクリーンショット 2019-05-25 1.33.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154121/d3ecb376-ee2a-a0b2-d430-0040095c00c2.png)

これで、コンテナの登録まで完了です。

## Cloud Runへコンテナを配置
コンテナのアップロードまでできたので、あとはCloud Run上でコンテナを動かすのみです。

### Cloud Runサービスの作成
メニューから、Cloud Runを選択。
![スクリーンショット 2019-05-25 1.22.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154121/c97270f5-c0bf-f04f-f5ad-8f31789cfe21.png)

アイコンがかっこいいですね！速さを追求していそうな雰囲気。
今回はGKEではなく、通常のCloud Runを使います。
![スクリーンショット 2019-05-25 1.22.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154121/5be4fc8a-5adf-b033-67d1-2d34d832ec3f.png)

Create Serviceを選択。
![スクリーンショット 2019-05-25 1.22.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154121/1b046246-4fd2-95ab-5d57-0b25612f4d6a.png)

作成画面になったら、下記の入力をしましょう。

* コンテナイメージのURL: 「選択」から、先ほどGCRにアップしたコンテナイメージを選択
* サービス名: 任意
* ロケーション: 任意
* 未認証の呼び出しを許可: ブラウザからアクセスしたいので、チェックを入れます
![スクリーンショット 2019-05-25 1.37.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154121/87808dc1-e89b-12da-1303-980ffd3498f7.png)

また、詳細項目に環境変数を設定する部分があります。
**Cloud Runでは自動的に`PORT`という環境変数を埋め込んでくれ、コンテナの`PORT`で設定するポートとCloud Runのポートを繋いでくれる**んです。ですので、今回は特に環境変数を指定する必要はありません。
そのために、先ほど`PORT`の環境変数をアプリに埋め込んでいたんですね。

「作成」ボタンをクリック。

### 動作確認
すると、こんな風にコンテナを乗せた環境が作成されます。
![スクリーンショット 2019-05-25 1.40.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154121/7c487965-9e61-88f3-1688-0a78855fa513.png)

右上の`URL`をクリックすると。
![スクリーンショット 2019-05-25 1.41.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154121/8b2a125e-59ea-5636-34cf-d45cb1dd10f2.png)
アプリ画面が表示されました！
初回の起動ですが、4秒くらいで表示されました。
コンテナで動いているだけあって、初回の起動はGAEより体感的にも早いですね...!

# 所感
めっちゃ簡単でした。
環境変数もCloud RunのGUI上で設定できたりするので、かなり迷うことなく使える感じです。

とりあえずサクッとアプリをリリースしたい時には、かなり早くリリースまで持っていけます。
フルマネージドなのでロードバランサーとか、ネットワークとか気にする必要がないのが非常に嬉しいですね。
相当管理コスト下がりそう。

しかし、複数のサービスを組み合わせる時には、Cloud Run on GKEを使ったり、いくつもサービスを立ち上げる必要があったりしそうです。
これに関してはもう少し触ってみる必要があるかな...

まだ新しいのでベータ版となっていますが、正式版になったら既存のサービスを移し替えたいくらいでした。

## 参考文献
[Cloug Run Quickstarts](https://cloud.google.com/run/docs/quickstarts)