はじめに
GoogleからDockerコンテナをサーバレスで実行できるCloudRunが公開されたので触ってみようと思ったところかなり使いやすくて、自分でサービスを立ち上げたので、その時の備忘録を記載していこうと思います。
今回はNodeJSの公式イメージを元にNodeJS + Expressでアプリケーションを作成し、Dockerコンテナを作成してCloudRunに乗せるまでを記載します。
また、今回はNodeJSのアプリケーションの説明を目的とはしていませんので、そこについては触れません。
対象読者
以下のような方が対象となるかもしれません。
- インフラわからないけどアプリを公開してみたい
- てっとり早く公開したい
- サーバレスを経験してみたい
- 新しいサービス触ってみたい
ご自身でサーバを立ち上げて、webサーバ等のミドルウェアを構築したい方は以下の記事が参考になるかもしれません。
CloudRunについて
CloudRunとはGoogle Cloud Next'19で発表されたDockerコンテナをサーバレス環境で実行できるサービスです。
HTTPでリクエストを受ける事が可能なステートレスコンテナを実行できます。
Knativeから作成されており、開発者はCloudRunを使用してフルマネージド型でコンテナを実行するか、GKEクラスタ上にデプロイする事が可能です。
CloudRunによる管理の場合は、開発者がインフラを意識せずに利用ができ、トラフィックに応じてスケールアップやスケールダウンも自動的に実行してくれます。なのでスケーリング構成のことを心配する必要はありません。
詳しい内容は公式ドキュメントを読んでください
CloudRunの公式ドキュメント
料金について
Cloud Run の課金対象は使用したリソース(100 ミリ秒単位、1,000 ミリ秒単位以下切り捨て)に限られるため、過剰にプロビジョニングしたリソースに料金を支払う必要はありません。
無料枠も用意されているので、過度なアクセスが来ない限りは無料で利用することができます。
無料枠としては、以下の通りになっています。
CPU | Memory | Requests |
---|---|---|
180,000 vCPU 秒/月 | 360,000GB/月 | 200 万回リクエスト数/月 |
詳しくは以下のドキュメントをご覧ください
CloudRunの料金
最速でアプリをデプロイするまで
前置きが長くなってしまいましたが、早速アプリをCloudRunで公開してみようと思います。
事前準備
CloudRunを利用するために以下の事前準備を行いましょう。
1. GCPアカウントを作成
作りましょう。
2. GCPのプロジェクトを作成
リソース管理ページから以下の画像の赤枠のリンクからプロジェクトを新規に作成しましょう。
3. プロジェクトに対して課金を有効にする
こちらのページから課金を有効にしましょう。
4. CloudRunAPIを有効にする
こちらから"有効にする"を押してAPIを有効にしましょう。
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!"を表示するだけの以下のコードを書きましょう。
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に記載しましょう。
{
"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を作成して中身に以下のように記述しましょう。
FROM node:12-slim
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install --only=production
COPY . ./
CMD [ "npm", "start" ]
このDockerfileを元にコンテナを起動させるといらないものまでコンテナ側に渡してしまうことになるので、.dockerignoreも用意しておきましょう。
Dockerfile
README.md
node_modules
Step2: コンテナをBuildし、GCRにuploadする
-
Cloud Build APIをあらかじめ有効にしておきましょう。
-
GCPで作成したプロジェクトのプロジェクトIDを控えておいてください。
-
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}はStep2で控えておいたプロジェクトIDに置き換えてください。
- また、helloworldをStep2で変更していた場合はその名前に変更してください。
$ 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!と表示されていれば無事に公開できています。
お疲れ様です!
どうでしょう?
そんなにステップもなく簡単にデプロイできたのではないでしょうか?
表題の通り5分でリリースできましたね!(事前準備をなくせば)
(Appendix) デプロイの自動化
ここまでで一旦デプロイが完了し、アプリケーションにリクエストすることができますが、
デプロイするために毎回毎回上記の処理をするのは少し面倒ではあるので、
ここからはおまけとして、
githubのmasterブランチにpushされたタイミングで自動的にデプロイされるような仕組みを組み立てたいと思います。
全体の構成
流れとしては
- githubのmasterにpushされたのをトリガーにCloud Buildを実行
- Cloud BuildでDockerイメージのビルドを実行し、GCRにpush
- GCRからCloudRunにデプロイ
の3ステップを自動化させることになります。
それではやっていきましょう。
事前準備
デプロイの自動化を行うために事前準備が必要なので、
以下の通りに準備を進めていきましょう。
APIの有効化
以下二つのAPIを有効化しておきましょう。
サービスアカウントの権限設定
IAMの管理から{ProjectID}@cloudbuild.gserviceaccount.com)に
以下の権限を追加してください。
- Cloud Run 管理者
- Cloud Run サービスエージェント
- ストレージオブジェクト 閲覧者
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に以下にのように記載します。
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の内容が順番に実行されていきます。
今回は3つステップが存在していてそれぞれ以下のような役割を実行します。
- Dockerfileを元にDockerイメージをビルド
- DockerイメージをGCRにpush
- 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 .
の場合には以下のように記載します。
steps:
- name: 'gcr.io/cloud-builders/docker'
- args:
- 'build'
- '-t'
- 'hoge'
- '.'
最後にidフィールドですが、
そのstepの識別子として利用するのでわかりやすい名称をつけてあげると良いかと思います。
CloudBuildのトリガーを作成
cloudbuild.ymlまで作成し終えたらCloudBuildにトリガーを作成します。
CloudBuildのトリガーページを開いて以下画像のトリガーを追加を選択します。
次のページでgithubを選択して同意するにチェックをいれた状態で続行を押します。
少しの間認証が完了するのを待ち、以下の画面が出たら、今回のアプリケーションを管理しているgithubのレポジトリを選択し、続行を押します。
そうすると以下の画面が出るので、どのブランチへのpushをトリガーにするかやcloudbuild.yamlの場所を決定していきます。
masterブランチへのpushをトリガーにする かつ アプリケーションルートにcloudbuild.yamlをおいている場合には以下の設定にすれば大丈夫です。
ここまでできたら保存を押して設定は完了です。
githubのmasterブランチにpush
ここまでであらかたの設定は完了しているので、正しく動作しているかを確認するためにmasterブランチにpushしてみてください。
正しくCloudRunにデプロイされていれば成功になります。
お疲れ様でした!