Google Cloud FunctionsでついにGoがサポートされた(まだベータリリースだが)。
さっそくさわってみたメモ。
TL;DR
- Go1.11でCloud Functionsを書くことができるようになった
- Cloud Functionsの定義は主に2種類
gcloud functions deploy ${ファンクション名} --runtime go111 --entry-point ${関数名} ${Functions実行時のトリガー}
でデプロイできる
- HTTP Functions
http.HandlerFunc
インターフェースを満たす関数- Functions以外の設定をせずに外部公開されてエンドポイントが与えられる
- Background Functions
- 第一引数が
context.Context
、第二引数が任意のstruct
な関数 - 特定のGCP上のイベントをトリガーにして起動する
- イベントの情報は第二引数の構造体に含まれるが、公式から構造体はまだ公開されていない
- 公式ガイドのサンプルコードを見るとよい
- 第一引数が
GoのFunctionsを作成する
まず以下のドキュメントを参考にGoのGunctions用の関数を定義する。
- The Go Runtime | Documentation | Cloud Functions
HTTPをトリガーにして実行するHTTP Functionsの場合
HTTPアクセスをトリガーにして実行されるFunctionsを定義する場合は、http.HandlerFunc
インターフェースを満たす関数を用意しておけば良い。
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
イベントをトリガーにして実行するBackground Functionsの場合
Cloud Storageなどで発生したイベントをトリガーに起動するFunctionsを定義することもできる。
type GCSEvent struct {
// 省略
}
// HelloGCSInfo はGCSのイベントをトリガーに起動するBackground Functions用の関数
func HelloGCSInfo(ctx context.Context, e GCSEvent) error {
// Do anything...
}
今回はリリース記事に記載されていたHTTP Functionsを少し改良した以下のソースコードを利用する。パッケージ名はmain
でなければ良い。
package functions
import (
"fmt"
"log"
"net/http"
)
// F is sample functions
func F(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
fmt.Println("Hello by fmt pkg")
log.Println("Hello by log pkg")
w.Write([]byte(r.Header.Get("X-Forwarded-For")))
}
Functionsをデプロイする
まずはgcloud
コマンドで選択中のプロジェクトのCloud FunctionsのAPIを有効化しておく。
- Cloud Functions API | IAM Library
また、ローカルのgcloud
コマンドも以下のコマンドで最新にしておく。
なお、最新にしてもgcloud functions deploy --help
のruntime
オプションにgo111
の記述はなかったが、ちゃんと使うことができた。
$ gcloud components update
$ gcloud components install beta
あとは、作成したローカルのGoの関数定義があるディレクトリでgcloud functions deploy
コマンドを実行すれば良い。
以下のコマンド実行結果はHTTPをトリガーとするhello
という名前のCloud FunctionsをF
という名前のGoの関数をエントリポイントとして公開したときのログ。
デプロイ完了までそこそこかかるので少し待つ必要があった。
```bash` $ gcloud functions deploy hello –runtime go111 –entry-point F –trigger-http –region asia-northeast1 Deploying function (may take a while - up to 2 minutes)…done. availableMemoryMb: 256 entryPoint: F httpsTrigger: url: https://asia-northeast1-MYPROJECT_NAME.cloudfunctions.net/hello labels: deployment-tool: cli-gcloud name: projects/MYPROJECT_NAME/locations/asia-northeast1/functions/hello runtime: go111 serviceAccountEmail: MUPROJECT_NAME@appspot.gserviceaccount.com sourceUploadUrl: https://storage.googleapis.com/g…. status: ACTIVE timeout: 60s updateTime: ‘2019-01-16T23:11:50Z’ versionId: ‘1’
デプロイ後の実行結果ログの`httpsTrigger`という項目がHTTPのエントリポイントなので、そのアドレスに対して`curl`コマンドを実行してみる。
```bash`
$ curl -i https://asia-northeast1-MYPROJECT_NAME.cloudfunctions.net/hello
HTTP/2 200
content-type: text/plain; charset=utf-8
function-execution-id: pzhl9rayoaq6
x-cloud-trace-context: f7bc8c67d13641651434d8b3dc2b2444;o=1
date: Wed, 16 Jan 2019 23:14:58 GMT
server: Google Frontend
content-length: 14
alt-svc: quic=":443"; ma=2592000; v="44,43,39,35"
XXX.XXX.XXX.82%
先ほどのGoの関数がちゃんと実行された!!
Cloud Functions実行時のログについて
とくに記載はなかったような気がするが、標準出力に出ていればStackdriverで確認できるようだ。
fmt
とlog
を仕込んだ先程のFunctionsを実行したあとログを確認すると、両方ともログが残っていた。
- Stacdriver Logging
イベントについて
Goで作成するCloud FunctionsもCloud Functionsがサポートするイベントを受け取ることができる。
aws-lambda-goは公式から構造体が提供されているが、2019/01/17時点でGCPから各イベント情報を格納する構造体はパッケージとして公開されていなそうだ。
受け取れるイベント情報の構造は以下のガイドで確認できる。
- Calling Cloud Functions
2019/01/17現在日本語のガイドには記載がないが、英語のガイドを確認するとGoのサンプルコードがあるので、そこから構造体定義を確認すれば良い。
下記はガイドに記載されているCloud Firestoreのイベント用の構造体。
// FirestoreEvent is the payload of a Firestore event.
type FirestoreEvent struct {
OldValue FirestoreValue `json:"oldValue"`
Value FirestoreValue `json:"value"`
UpdateMask struct {
FieldPaths []string `json:"fieldPaths"`
} `json:"updateMask"`
}
Background Functions
実行時に受け取るcontext
の中からメタデータを取得するcloud.google.com/go/functions/metadata
パッケージは提供されている。
- GoDoc cloud.google.com/go/functions/metadata
import "cloud.google.com/go/functions/metadata"
// ...
meta, err := metadata.FromContext(ctx)
if err != nil {
return fmt.Errorf("metadata.FromContext: %v", err)
}
log.Printf("Event ID: %v\n", meta.EventID)
// ...
その他
go1.11ベースで動くので当然go modulesもサポートされている。また、ドキュメントではinit()
関数やsync.Once
を利用した実行時の初期化についても触れられていた。
- Specifying dependencies
- One-time initialization
終わりに
軽くさわってみたが、gcloud
コマンドの認証さえちゃんとできていれば直ぐ試せた。
とくにAPIゲートウェイなどの公開設定をしなくてもすぐHTTPリクエストの処理ができるのもよい。イベント処理を行う構造体のパッケージも提供されると無用なコピペ定義しなくても済みそうだ。
なお、Cloud Functionsは呼び出し200万回まで無料(正確には別に実行時間などの条件もある)なので誰でも試すことが出来る。Goの関数一つで試せるのでぜひ触ってみるといいと思う。
- Pricing | Documentation | Cloud Functions
参考
- The Go Runtime | Documentation | Cloud Functions
- Get Go-ing with Cloud Functions: Go 1.11 is now a supported language | Google Cloud Blog
- GoDoc cloud.google.com/go/functions/metadata