過去にCloud Functions/Cloud Scheduler/Cloud Pub Subを使って、Google Compute Engineインスタンスの起動停止の自動化を行う
という記事を書きましたが、背景としては実装した方が楽しいよねとか、Goを使ってみたいという欲がありました。業務でも個人的にも書いたことがなかったので、勉強がてらにCloud Functions×Goで作ってみました。GCPで使うサービスも前回はGUIで作成をしていきましたが、GCP上のサービスはCLIで作成していき、最後の起動部分は画面で確認します。
完成品はGitHubに公開しました。辛辣な意見などもらえると気持ち良いです。
前提条件
GoでGoogle Cloud Functionsの実装していく
自前で書いたコードの全貌としてはこちらです。
package src import ( "context" "encoding/json" "google.golang.org/api/compute/v1" "log" "os" ) var projectId = os.Getenv("GCP_PROJECT") type Message struct { Data []byte `json:"data"` } type PayLoad struct { Switch string `json:"switch"` Target string `json:"target"` Zone string `json:"zone"` } func InstanceSwitcher(ctx context.Context, msg Message) error { var payLoad PayLoad err := json.Unmarshal(msg.Data, &payLoad) if err != nil { log.Println("[ERROR][%T][MSG]: %v", err, err) return nil } service, err := compute.NewService(ctx) is := compute.NewInstancesService(service) insList, err := is.List(projectId, payLoad.Zone).Do() log.Printf("instance:list: %v", insList) log.Printf("[ProjectId:%s][Switch:%s][Target:%s][Zone:%s]", projectId, payLoad.Switch, payLoad.Target, payLoad.Zone) switch payLoad.Switch { case "start": log.Println("instance start") _, err = is.Start(projectId, payLoad.Zone, payLoad.Target).Do() case "stop": log.Printf("instance stop") _, err = is.Stop(projectId, payLoad.Zone, payLoad.Target).Do() } if err != nil { log.Printf("[ERROR][%T][MSG]: %v", err , err) return nil } return nil }
Pub/Subのトピックを作成する
メッセージを投げる際の役割を担ってくれるPub/Subトピックを作成しておきます。
❯❯❯ gcloud pubsub topics create insSwitch
Google Cloud Functionsをデプロイする
❯❯❯ gcloud functions deploy InstanceSwitcher --runtime go111 --trigger-topic insSwitch
これだけでサクッと作成してくれるかと思っていましたが、エラーに苛まれました。 以下が実際に出力されたエラーです。
Deploying function (may take a while - up to 2 minutes)...failed. ERROR: (gcloud.functions.deploy) OperationError: code=3, message=Build failed: /tmp/sgb/gopath/src/serverlessapp/vendor/src/main.go:6:2: cannot find package "google.golang.org/api/compute/v1" in any of: /tmp/sgb/gopath/src/serverlessapp/vendor/google.golang.org/api/compute/v1 (vendor tree) /go/src/google.golang.org/api/compute/v1 (from $GOROOT) /tmp/sgb/gopath/src/google.golang.org/api/compute/v1 (from $GOPATH)
調査したところ公式にしっかり書いてあることに気付きました。
Go の Cloud Functions では、go.mod ファイルを含む Go モジュール、または vendor ディレクトリのいずれかによって、すべての依存関係を指定する必要があります。詳しくは、Go での依存関係の指定をご覧ください。
正直かなりの時間を費やしましたが、以下のドキュメントにある通りgo env GOPATH
で作業ディレクトリを見てgo.mod
を作成しました。私は内側にいたので以下を実行しました。
❯❯❯ go mod init ❯❯❯ go mod tidy
Google Cloud Functionsを再度デプロイする
❯❯❯ gcloud functions deploy InstanceSwitcher --runtime go111 --trigger-topic insSwitch Deploying function (may take a while - up to 2 minutes)...done. availableMemoryMb: 256 entryPoint: InstanceSwitcher eventTrigger: eventType: google.pubsub.topic.publish failurePolicy: {} ・・・以降略
これでGoogle Cloud Functionsのデプロイが成功しました。
Google Cloud Functionsの動作確認
Pub/Subから来るメッセージを想定して、実際に動いているか確認します。
❯❯❯ gcloud pubsub topics publish insSwitch --message '{"switch":"switchTest", "target":"targetTest", "zone":"zoneTest"}' #成功していると以下が返ってきます messageIds: - 'XXXXXXXXX'
Google Cloud Functionsのログを確認します。ログに出力されているので問題なく動いていますね!
❯❯❯ gcloud functions logs read --limit 2 LEVEL NAME EXECUTION_ID TIME_UTC LOG InstanceSwitcher XXXXXXXXXXXXXXX 2019-08-09 09:58:56.680 2019/08/09 09:58:56 [ProjectId:xxxxxxxxxxx][Switch:switchTest][Target:targetTest][Zone:zoneTest] D InstanceSwitcher XXXXXXXXXXXXXXX 2019-08-09 09:58:56.681 Function execution took 1197 ms, finished with status: 'ok'
Cloud Schedulerを作成する
Pub/Subトピックを中間してGoogle Cloud Functionsをキックし、停止と起動をおこなうCloud Schedulerを作成します。
※一部自身の環境に合わせることに注意してください
GCE停止用
❯❯❯ gcloud --project [PROJECT_ID] scheduler jobs create pubsub [PUBSUB_NAME] \ --time-zone "[TIME_ZONE]" \ --schedule "[CRON_TIMER]" \ --topic [TOPIC_NAME \ --message-body '{"switch":"stop", "target":"[TARGET_INSTANCE_NAME], "zone":"[ZONE]"}'
GCE起動用
❯❯❯ gcloud --project [PROJECT_ID] scheduler jobs create pubsub [PUBSUB_NAME] \ --time-zone "[TIME_ZONE]" \ --schedule "[CRON_TIMER]" \ --topic [TOPIC_NAME \ --message-body '{"switch":"start", "target":"[TARGET_INSTANCE_NAME], "zone":"[ZONE]"}'
GCEの起動と停止を確認する
GCEが起動している前提はありますが、作成した起動用のCloud Schedulerと停止用のCloud Schedulerを画面から実行します。
Cloud Schedulerを実行し停止の確認 少し時間をおいてから以下の通り、インスタンスが停止してくれました!期待通り動作していますね!
Cloud Schedulerを実行し起動の確認 こちらも少し時間をおいてからインスタンスが起動するのが確認出来ました!
まとめ
Google FunctionsからのGCEへ対しての操作をGo初心者でも実装することが出来た。Goインストール後の作業場はどうするべきか、GoからGCEを操作するためにはどうするべきなのかなど環境面も含めて結構時間がかかってしまいました。またまだGoの深淵には程遠いですが、今まで触れてこなかった言語に触れる事で改めてモノ作りの楽しさを実感。GCP上のサービスはまだまだたくさんあるのでGoとのセットでこれに留まらず更に研鑽していきます。余談ですがGopherがとっても可愛かったのでTシャツを購入しました。
参考URL
Google Cloud Functionsをコマンドラインからデプロイする - Qiita
Cloud FunctionsでGo言語を使ってCloud Pub/Subから値を取得する - Qiita
godoc.org/google.golang.org/api/compute/v1
https://cloud.google.com/compute/docs/reference/rest/v1/
The Go Blog - Using Go Modules / Go Modulesを使う(和訳) - Qiita