Go ランタイム Cloud Functions の開発環境を考える
はじめに
Cloud Functions 便利だけど構成とかってどうするのがいいんだろうか?を考えてみた記事となります。
デプロイなどの動作確認は行なっていますが、実際の運用などは行なってはいません。あくまで参考程度に見ていただければと思います。あしからず...
実行環境
uname -a
Darwin MacBook-Pro-7.local 22.6.0 Darwin Kernel Version 22.6.0: Wed Jul 5 22:22:52 PDT 2023; root:xnu-8796.141.3~6/RELEASE_ARM64_T8103 arm64
go version
go version go1.21.1 darwin/arm64
docker version
Client:
Cloud integration: v1.0.35-desktop+001
Version: 24.0.5
API version: 1.43
Go version: go1.20.6
Git commit: ced0996
Built: Fri Jul 21 20:32:30 2023
OS/Arch: darwin/arm64
Context: desktop-linux
Server: Docker Desktop 4.22.1 (118664)
Engine:
Version: 24.0.5
API version: 1.43 (minimum version 1.12)
Go version: go1.20.6
Git commit: a61e2b4
Built: Fri Jul 21 20:35:38 2023
OS/Arch: linux/arm64
Experimental: false
containerd:
Version: 1.6.21
GitCommit: 3dce8eb055cbb6872793272b4f20ed16117344f8
runc:
Version: 1.1.7
GitCommit: v1.1.7-0-g860f061
docker-init:
Version: 0.19.0
GitCommit: de40ad0
gcloud version
Google Cloud SDK 437.0.1
bq 2.0.93
core 2023.06.30
gcloud-crc32c 1.0.0
gsutil 5.24
構成
ディレクトリ構成は以下となります。
.
├── LICENSE
├── Makefile # タスクランナー
├── README.md
├── e2e
│ ├── bar_test.go # bar エンドポイントへのE2Eテスト
│ └── foo_test.go # foo エンドポイントへのE2Eテスト
├── functions
│ ├── bar
│ │ ├── bar.go # クラウド環境に対するエントリーポイント
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── local
│ │ └── main.go # ローカル環境に対するエントリーポイント
│ └── foo
│ ├── foo.go # クラウド環境に対するエントリーポイント
│ ├── go.mod
│ ├── go.sum
│ └── local
│ └── main.go # ローカル環境に対するエントリーポイント
├── go.mod
├── go.sum
├── go.work
├── go.work.sum
├── local
│ └── main.go # ローカル環境でのルートエントリーポイント
└── script
├── add.sh # 新たに Cloud Functions を追加するためのスクリプト
├── deploy.sh # Cloud Functions をデプロイするためのスクリプト
└── destory.sh # Cloud Functions をデストロイするためのスクリプト
ポイント: go.work を活用したモノレポ構成
go.work を活用したモノレポ構成となっています。
(Cloud Functions ごとに go.mod が必要みたいなので... go.mod なしでデプロイできる方法があれば知りたいです。)
go.work を設定すれば VSCode でルートディレクトリで作業し続けることができます。
(go.work がないと警告が出た気がします。)
ポイント: functions-framework-go を活用したローカルでの開発
ローカル環境で動作確認を実施するために functions-framework-go というライブラリを活用します。
このライブラリを使ったローカル用のサーバーは Docker で起動するように設定しています。
Dockerfile
また起動には air というライブラリを利用することで半(?)ホットリロードになるようにしています。
完全なホットリロードにしたいですが、現状はエントリーポイントの main.go を更新することでしかリロードされないです...
ポイント: ローカル環境向けの proxy サーバー実装
functions-framework-go を使うと Cloud Functions ごとにサーバーが立ち上がります。
これだとポート番号を Cloud Functions ごとに使い分ける必要があり使いづらかったので proxy を使うことにしました。
docker compose にて各 Cloud Functions を管理しdockerネットワーク内に閉じ込めます。
compose.yaml
それぞれの Cloud Functions はポート番号 8080 で起動させておき隠蔽します。
そして proxy サーバーから service 名で接続するように設定します。
proxy のコードも極力新しい Cloud Functions を追加してもコードを変更しないように実装しています。
proxy server main.go
環境変数でエントリーポイントとなる関数名(?)を追加して proxy を設定しています。
なぜこんなことをしたかったかというとクラウド環境にデプロイしたときに払い出されるエンドポイントとの差異を無くしたかったからです。
こうしておくことでパスを切り替えるだけで接続することができます。
E2Eテストのエンドポイントを環境変数で切り替えて実施できるようになります。
E2Eテスト
Cloud Functions を追加する
以下のゴリ押しスクリプトを組んで追加できるようにしてみました。go.work の使い方とかも多少はわかるかもしれません...(解説省略してすみません。)
add.sh
M1 Mac でしか動作確認を実施していないのでご了承ください。
おわりに
Cloud Functions は手軽にデプロイして動作確認できますが、なんだかんだローカル環境での動作確認もしたいかと思います。モノレポ構成でいい感じに考えることができたのではないでしょうか。
共通化して利用するための pkg を root において各 module から参照する方法とかもあるので時間があったら追記します。(replace 使ってごにょごにょする)
今回考えた構成は以下のリポジトリに置いておきます。ご参考まで。
Discussion