My External Storage

Jan 17, 2019 - 5 minute read - Comments - gcp go

BetaリリースされたGoのGoogle Cloud Functionsを試す #gcp #golangjp

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用の関数を定義する。

HTTPをトリガーにして実行するHTTP Functionsの場合

HTTPアクセスをトリガーにして実行されるFunctionsを定義する場合は、http.HandlerFuncインターフェースを満たす関数を用意しておけば良い。

イベントをトリガーにして実行する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を有効化しておく。

また、ローカルのgcloudコマンドも以下のコマンドで最新にしておく。 なお、最新にしてもgcloud functions deploy --helpruntimeオプションにgo111の記述はなかったが、ちゃんと使うことができた。

$ gcloud components update
$ gcloud components install beta

あとは、作成したローカルのGoの関数定義があるディレクトリでgcloud functions deployコマンドを実行すれば良い。 以下のコマンド実行結果はHTTPをトリガーとするhelloという名前のCloud FunctionsをFという名前のGoの関数をエントリポイントとして公開したときのログ。 デプロイ完了までそこそこかかるので少し待つ必要があった。

$ 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コマンドを実行してみる。

$ 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で確認できるようだ。 fmtlogを仕込んだ先程のFunctionsを実行したあとログを確認すると、両方ともログが残っていた。

実行ログ

イベントについて

Goで作成するCloud FunctionsもCloud Functionsがサポートするイベントを受け取ることができる。
aws-lambda-goは公式から構造体が提供されているが、2019/01/17時点でGCPから各イベント情報を格納する構造体はパッケージとして公開されていなそうだ。 受け取れるイベント情報の構造は以下のガイドで確認できる。

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

その他

go1.11ベースで動くので当然go modulesもサポートされている。また、ドキュメントではinit()関数やsync.Onceを利用した実行時の初期化についても触れられていた。

終わりに

軽くさわってみたが、gcloudコマンドの認証さえちゃんとできていれば直ぐ試せた。 とくにAPIゲートウェイなどの公開設定をしなくてもすぐHTTPリクエストの処理ができるのもよい。イベント処理を行う構造体のパッケージも提供されると無用なコピペ定義しなくても済みそうだ。

なお、Cloud Functionsは呼び出し200万回まで無料(正確には別に実行時間などの条件もある)なので誰でも試すことが出来る。Goの関数一つで試せるのでぜひ触ってみるといいと思う。

参考

関連記事