なにこれ
社内勉強会でdockerの概論的なものとマルチステージビルドについてのお話をしました。
単純にマルチステージビルドするサンプルだけだと、ちょっと内容としては寂しかったので、せっかくだから精神でCloud Runにイメージをデプロイして走らせてみます。
利用するプロジェクト
構成
$ tree -L 1
.
├── LICENSE
├── Makefile // docker-compose周りのビルド処理
├── README.md
├── app // 雑な静的ページのプロジェクトディレクトリ
├── docker-compose.yml
└── server // 雑なAPIサーバーのプロジェクトディレクトリ
静的ページ
.
├── Dockerfile
├── babel.config.js
├── nginx
│ └── default.conf // nginx定義ファイル(本番用)
├── package-lock.json
├── package.json
├── src // ソースディレクトリ
├── vue.config.js
└── yarn.lock
- 現状Cloud Runのポートが
8080
で固定されているのでnginx側で8080ポートを使うようにdefault.conf
を再定義 - productionSourceMapはfalse
-
.env
を作成してAPIサーバーのOriginを指定 - サンプル自体は基礎から学ぶ Vue.jsの応用。いい本だからみんな買おう。
Dockerfileは以下のような形
# --- local ---
FROM node:8.15.0-alpine as build-vue
WORKDIR /app
COPY . .
RUN apk update && \
npm install -g npm && \
npm install -g yarn && \
yarn install && \
yarn run build
# --- production ---
FROM nginx:1.15.12-alpine as production-vue
COPY --from=build-vue /app/dist /usr/share/nginx/html
COPY --from=build-vue /app/nginx/default.conf /etc/nginx/conf.d/default.conf
EXPOSE 8080
CMD ["nginx", "-g", "daemon off;"]
- ローカルではnodeのalpineで開発し、本番はnginxのalpineにbuildしたものを入れる
- 現状だとnginxとCloud Runの相性がちょっと良くないので
default.conf
も上書き
APIサーバー
.
├── Dockerfile
├── Makefile // go用各種ビルド処理
├── go.mod
├── go.sum
├── list.json // 最強のクソ雑要素
└── main.go
- ビルド周りの設定は全てMakefileで定義
- realizeでホットリロード
- 入力データを
list.json
に任せる雑設計
Dockerfileは以下のような形
# --- local ---
FROM golang:1.12-alpine as build-go
WORKDIR /go/server
COPY . .
RUN apk add --no-cache git make && \
go get github.com/oxequa/realize && \
make build
# --- production ---
FROM alpine as production-go
WORKDIR /app
COPY --from=build-go /go/server/bin/server .
COPY --from=build-go /go/server/list.json .
RUN addgroup go \
&& adduser -D -G go go \
&& chown -R go:go /app/server
EXPOSE 8080
CMD ["./server"]
- ローカルではgolangのalpineで開発、本番はただのalpineにバイナリファイルを上げる
- ビルド周りはMakefileで定義
-
list.json
で入力を定義しちゃっているのでこれも追加
docker-compose
フロントエンドとバックエンドを同じプロジェクトで管理するという取り回しにくい構成になっているので、docker-compoes側をちょっとひねります。
version: '3.5'
services:
vue-app:
stdin_open: true
tty: true
build:
context: ./app # フロント側のディレクトリ(Dockerfileのあるとこ)を渡してあげる
target: build-vue # ローカルステージをターゲットに(as で指定した名前)
command: yarn run serve
volumes:
- ./app:/app # ホットリロードかけたいからbuild contextと同じ所を指定
ports:
- 39000:8080 # ポートは適当。被んなければいいっしょ精神
depends_on:
- go-app
go-app:
build:
context: ./server # バックエンド側のディレクトリ(Dockerfileのあるとこ)を渡してあげる
target: build-go # ローカルステージ。名前もっと考えればよかった
command: realize start --run
volumes:
- ./server:/go/server # ホットリロードかけたいからvolumeを指定
ports:
- 38080:8080 # ポートは適当。8080ついてればいいっしょ精神
重要な点としては
-
build:
でDockerfileと連携を取る-
context
にDockerfileのあるディレクトリを指定する -
target
に、DockerfileでFrom <image名> as <stage名>
のas以下の値を入れる
-
- volumesを指定してあげる
- これがないと
docker-compose up
した後にホストマシンでコードを書き換えてもリロードされない - イメージに直にsshして値を書き換えるとホットリロードしてくれるけど・・・
- これがないと
- 8080を叩くようにポートを指定
- 現状Cloud Runのポートは8080
- これのせいでnginxもdefault.confの書き換えが必要
Cloud Runにデプロイ
先にサービスの一覧を確認します。
$ gcloud beta run services list
WARNING: No target platform specified. This will be a required flag in a future version of the gcloud command-line tool. Pass the `--platform` flag or set the [run/platform] property to satisfy this warning.
Available platforms:
- gke: Cloud Run on Google Kubernetes Engine. Use with the `--cluster` and `--cluster-location` flags or set the [run/cluster] and [run/cluster_location] properties to specify a cluster in a given zone.
- managed: Fully managed version of Cloud Run. Use with the `--region` flag or set the [run/region] property to specify a Cloud Run region.
Listed 0 items.
Listed 0 items.
なので現状何もサービスが動いていないことが確認できます。
デプロイ処理
例えば静的ページを以下のイメージ名でビルドした場合を考えます。
docker build -t gcr.io/sugoi-cloud-run-test/super-sugoi-sample-app app/
まず最初にGoogle Cloud Buildにイメージをアップロードします。
# 静的ページ側
$ gcloud builds submit --project sugoi-cloud-run-test --tag gcr.io/sugoi-cloud-run-test/super-sugoi-sample-app app/.
# API側
$ gcloud builds submit --project sugoi-cloud-run-test --tag gcr.io/sugoi-cloud-run-test/super-sugoi-sample-server server/.
イメージが上がったら、デプロイを実行します。
$ gcloud beta run deploy super-sugoi-sample-app --image gcr.io/sugoi-cloud-run-test/super-sugoi-sample-app:latest --region asia-northeast1
実行するとWARNINGとかがモチャモチャ出た後、未認証の呼び出しを許可するかどうかを聞かれるので、y
を入れておきます。
WARNING: No target platform specified. This will be a required flag in a future version of the gcloud command-line tool. Pass the `--platform` flag or set the [run/platform] property to satisfy this warning.
Available platforms:
- gke: Cloud Run on Google Kubernetes Engine. Use with the `--cluster` and `--cluster-location` flags or set the [run/cluster] and [run/cluster_location] properties to specify a cluster in a given zone.
- managed: Fully managed version of Cloud Run. Use with the `--region` flag or set the [run/region] property to specify a Cloud Run region.
Allow unauthenticated invocations to [super-sugoi-sample-app]
(y/N)? y
Deploying container to Cloud Run service [super-sugoi-sample-app] in project [sugoi-cloud-run-test] region [asia-northeast1]
✓ Deploying new service... Done.
✓ Creating Revision...
✓ Routing traffic...
✓ Setting IAM Policy...
Done.
Service [super-sugoi-sample-app] revision [super-sugoi-sample-app-***] has been deployed and is serving traffic at https://super-sugoi-sample-app-***.a.run.app
ここまで行った段階で、もう一度listコマンドを試します。
$ gcloud beta run services list --region asia-northeast1
SERVICE REGION LATEST REVISION SERVING REVISION LAST DEPLOYED BY LAST DEPLOYED AT
✔ super-sugoi-sample-app asia-northeast1 super-sugoi-sample-app-*** super-sugoi-sample-app-*** *** 2019-08-07T03:54:55.770Z
✔ super-sugoi-sample-server asia-northeast1 super-sugoi-sample-server-*** super-sugoi-sample-server-*** *** 2019-08-07T03:59:15.436Z
ちゃんと入っているのでデプロイOKです。
デプロイコマンドの詳細については、公式も確認してください
FYI: https://cloud.google.com/sdk/gcloud/reference/beta/run/deploy
動作確認
デプロイできたので動作確認をします。
デプロイコマンド実行時にserving traffic at ~
出てきたURLにアクセスしてみます。
API側
$ curl https://super-sugoi-sample-server-***.a.run.app/monsters | jq .
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 147 100 147 0 0 1732 0 --:--:-- --:--:-- --:--:-- 1750
[
{
"id": 1,
"name": "スライム",
"max": 10,
"hp": 10
},
{
"id": 2,
"name": "ゴブリン",
"max": 50,
"hp": 50
},
{
"id": 3,
"name": "ドラゴン",
"max": 500,
"hp": 500
}
]
フロント側
$ open https://super-sugoi-sample-app-***.a.run.app/
初期データが入っているので、ちゃんとAPI側を呼んだ結果が取れているのがわかりますね。
お片付け
遊んだものはちゃんと片付けましょう。
$ gcloud beta run services delete super-sugoi-sample-service --region asia-northeast1
$ gcloud beta run services delete super-sugoi-sample-app --region asia-northeast1
まとめ
簡単な静的ページとAPIサーバーをCloud Runにデプロイして挙動を試しました。
beta版ということで、8080ポート縛りなどがあるので、最初nginxのデプロイで困りましたし(docker run -p 8080:80 sugoi-sample-app:latest
は動くのになんでや!ってなりました)、こちらの設計で言えばフロントとサーバーを同じプロジェクトに突っ込んで一つのdocker-composeで管理するというのも初めての体験だったので、ホットリロード動かない問題の原因とかbuild contextをどう置くかなど、色々学びができました(CI/CD考えると取り回しが悪いのでこのパターンは二度とやらないでしょうね)。
それでも、料金体系と開発の楽さを考えるとかなり可能性を感じます。
これからもちょくちょく使っていこうと思います。