[ GCP ] Cloud RunでPythonアプリ(Flask)をデプロイ・クリーンアップしてみる
普段からDockerを使用していて、呼び出し時のみ起動するサーバレスコンテナに興味が湧いたので、お手軽にDockerコンテナをデプロイできるGoogleの「Cloud Run」とそれに関連するサービスを調査してみました。
Cloud Runとは?
CloudRunはGCPの環境にDockerコンテナをデプロイして動かすことができる「サーバレスコンテナ」のサービスです。
コンテナを秒単位で本番環境にデプロイでき、トラフィックに応じてほぼ瞬時にゼロから自動的にスケールされるため、インフラストラクチャの管理は一切不要なサービスです。
開発〜デプロイのサイクルを迅速にできるので、開発も捗りそうです。
またDockerで使えるプログラムなら任意で選択して使用できるので、OS、ミドルウェア、プログラミング言語等の選択肢が豊富なのも特徴です。
コンテナのベースイメージは、以下で説明する「Container Registry」から使用するようになります。イメージ作成、アップロードに使う「Cloud Build」も合わせて紹介します。
Cloud Buildとは?
Dockerのイメージビルド、テスト、デプロイなどをする際、カスタムワークフローを定義し、自動化できるツール。
設定すれば、gitのプッシュ等をトリガーにして運転させることもできるようです。
Container Registryとは?
Google Cloud上に非公開の安全なDockerイメージストレージを提供します。
セキュアなHTTPSエンドポイントを使用してContainer Registryにアクセスできるので、あらゆるシステム、VMインスタンス、所有のハードウェア(PCなど)からイメージをプッシュ/プル/管理するのに役立てられます。
機会があれば「docker login」コマンド等でもつないでみたいです。
料金
Cloud Runの料金
こちらは従量課金制で、
- コードが実行されている間(使用時間)
のみ料金が発生します。使用時間は最も近い100ミリ秒単位で発生します。
また以下で説明する
- コンテナイメージ作成で使用する「Cloud Build」
- イメージ保管・管理のために使用する「Container Registry」
も料金に関連します。
Cloud Buildの料金
利用するインスタンスマシンの種類にもよりますが、このサービスの最小グレード「n1-standard-1」であれば、無料枠1日120分がもらえて以下のようになります。
- ビルド処理時間: 1日 120分まで: 無料(n1-standard-1利用時)
- 以降1分ごと: $0.003/分(n1-standard-1での料金) (上位インスタンス2種類も選択でき、時間料金もそれに応じて変化するようです)
のようです。
Container Registryの料金
Dockerイメージの保管のためにGCPのオブジェクト保管庫「Cloud Storage」を使用します。その際
- ストレージ保持
- 下り(外向き、ダウンロード)ネットワーク
- 脆弱性スキャン機能
に対して課金されます。
お試しの場合は後片付けをしっかりしておきましょう。
※GCP登録後なら無料クレジットを使用することができますので、お試しに最適です
それでは、Dockerコンテナをデプロイしていこうと思います。
前提
- Google Cloud Platformのアカウント、プロジェクト
- Google Cloud SDK: 298.0.0(公式サイトに従いインストール、gcloud auth login済み)
- Docker: 19.03.12(aptコマンドでインストール)
デプロイの下準備
作業ディレクトリを作って移動
$ mkdir test1
$ cd test1
app.pyを作成
URLにパスなしでアクセスすると「Hello,World!」の文字列を返すだけの最小構成で作成します。
import os
fom flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
target = os.environ.get("TARGET", "World")
return "Hello, {}!\n".format(target)
if __name__=="__main__":
app.run(debug=False, threaded=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
Dockerfileの作成
Dockerfileで「python:3.7-slim」という名前のDockerイメージをベースに、さっき書いたFlaskアプリケーションを起動するコンテナのもとを作成しておきます。
FROM python:3.7-slim
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . ./
RUN pip install Flask gunicorn
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 app:app
.dockerignoreの定義
Dockerイメージビルドの対象外にするファイルを指定しておきます。
Dockerfile
README.md
*.pyc
*.pyo
*.pyd
__pycache__
ローカルでコンテナを試してみる
$ docker build -t hello-world . //除外ファイルを除外してカレントディレクトリのファイルからイメージを作成(Dockerfileや*.pyc、__pycache__を含めないようにできる)
$ docker run -e PORT=8080 -p 8080:8080 hello-world
$ curl http://localhost:8080/
Hello, World!
これと同じものをCloud Runにデプロイしてみます。
イメージのビルド、Cloud Registryにアップロード
gcloudのコマンド「gcloud builds submit」をベースに使用することで、Dockerイメージのビルド〜アップロードを一発で完了できます。
以下の2パターンをお好みで使い分けることができます。
[ パターンA ]Dockerfileによるビルド
以下のコマンドはコマンドでイメージのビルド、Container Registryへのプッシュまで一貫して実行してくれる優れものです。
$ gcloud builds submit --tag gcr.io/[project_id]/helloworld
helloworldの部分が「Dockerイメージ名」になります。
[ パターンB ]ビルド構成ファイルによるビルド(Cloud Buildの使用)
上記のように直接Dockerfileを指定もできる他に、以下の構成ファイルを使ってContainer RegistryにDockerイメージをビルドすることもできます。
Dockerfile、app.py、.dockerignoreが配置されているディレクトリに、追加で「cloudbuild.yaml」を作成していきます。
- cloudbuild.yaml
steps:
- name: 'gcr.io/cloud-builders/docker'
args: [ 'build', '-t', 'gcr.io/[project_id]/helloworld', '.' ]
images:
- 'gcr.io/[project_id]/helloworld'
上記の設定であれば、Cloud Buildで
- 「docker」コマンドを使用
- 引数にargs配列内の値を渡してビルド実行
- 出力イメージはimagesブロックの「gcr.io/[project_id]/helloworld」
ができます。
ビルド構成ファイルの「images」ブロックには、Cloud BuildがContainer Registryにプッシュする1つ以上のDockerイメージを指定することができます(ここでは1つしかイメージ指定してないですが、配列で複数指定もできます)。
Dockerイメージを作成せずにタスクだけ実行するビルド(テスト目的など)があるかもしれませんが、ビルドしてもContainer Registryにプッシュしなければ、このビルドで作成されたイメージはビルド完了時に破棄されるようです。
逆に、指定されたイメージがビルド時に生成されない(失敗したなどの)場合、ビルドは失敗します。
設定ファイルの作成ができたら、以下のコマンドで設定ファイルを指定し、イメージのビルドを開始できます。
$ gcloud builds submit --config cloudbuild.yaml
※オプション–configのデフォルト名は「cloudbuild.yaml」ですが、任意の名前にもできるようです。
GCPプロジェクトIDの調べ方
以下のコマンド
$ gcloud config get-value project
で調べられます。
コマンドラインからデプロイする
Cloud Runへのデプロイします。
コマンド実行。
$ gcloud run deploy --image gcr.io/[project_id]/helloworld --platform managed
GCPのコンテナのデフォルトポートは8080ですが、--portオプションで指定もできます(1〜65535の範囲で指定できます)。
特に指定しないなら--port=defaultを指定しましょう。
※特にポート指定しなければ8080番で開放されます。
コマンドを叩くと、ターミナル上で対話が始まります。
- ここでサービス名を聞かれるので希望するサービス名を入力します(helloworld)。
- GCPでclodu run apiを有効にしていない場合、再試行を提案されるので「y」を入力。
- デプロイしたいリージョン(データセンターの地域)の指定に答える
(--regionオプションで指定しておくことも可能)。 - 未認証の呼び出し(誰からでもHTTPリクエストを受け付けるように立ち上げていいか)を許可するよう求められるので「y」を入力(これも一応オプションで指定しておける模様)。
デプロイをしばらく待ち、完了。
URLが表示されるので、ブラウザでこのURLにアクセスしてみて、「Hello, World!」が見えたら成功です。
あとかたづけ
プロジェクト自体削除するか、Container Registryのイメージを削除する
(レジストリの保存で課金されることがあるため)。
Registry上のイメージを消してもサービスは続行しており、リクエストは課金対象になるので、サービスの停止もしておきましょう。
デプロイ〜クリーンアップまで、あっという間でした!
一から自前で用意する手間をかけずコンテナのデプロイを、しかもいま話題のサーバレスで体験できるのでおすすめです。