Go Actionを利用する
Cloud Functionsでは、Go Language(以下、Go)コードを実行させられるアクションコンテナーを提供します。Go 1.1バージョンを基本提供し、独立した環境でコードを実行することができます。
予めコンパイルしてZip形式でアップロードしたり、Web上でコードを編集して実行することができます。
Actionを作成する
まず、以下のように、名前と場所を含む"Hello World"を出力する簡単なGo Actionであるhelloを作成します。
package main
import "log"
func Main(obj map[string]interface{}) map[string]interface{} {
name, ok := obj["name"].(string)
if !ok {
name = "world"
}
msg := make(map[string]interface{})
msg["message"] = "Hello, " + name + "!"
log.Printf("name=%s\n", name)
return msg
}
Goコードは、1つ以上のGoソースファイルを有することができます。Goソースで作ったActionの入口点はMain Packageにある関数です。Main関数の基本名はMainであるが、ユーザーの選択によて別名に変更することができます。しかし、名前の開始点は常に大文字で表記されます。そして、そのMain関数は、次の説明のように、特定の形式で作らなければなりません。
main
関数の形式
func Main(event map[string]interface{}) map[string]interface{}
GOコードは、複数の関数を含むことができるが、main
関数はプログラムの開始点として必ず宣言されなければなりません。
上記で作成したコードで'hello'という名前のActionを作ります。
対応可能な形式
実行環境においては、次のような形式に対応します。
- AMD64のアーキテクチャ用にコンパイルされたLinux ELFの実行ファイルの実行可能なバイナリー
- AMD64のアーキテクチャ用にコンパイルされたLinux ELFの実行ファイルを含み、最上位に
exec
名の実行ファイルを含むzipファイル - Goでコンパイルされた単一のソースファイル
- 最上位レベル(フォルダ)に実行バイナリーファイルを含まないzipファイルは、その後コンパイルされた実行されます。
GOOS=Linux
とGOARCH=amd64
で全てのGoに対応するプラットフォームで、正しい形式のバイナリーをクロスコンパイルすることができます。後述のように、事前コンパイル機能を利用して実行環境と同様のコンパイルを利用するほうがより安全です。
パッケージとvendor
を利用してActionを作成する
コードを作成していると、1つのアクションファイル以外の依存ファイルを一緒にパッケージングしなければならない場合があります。このような場合、関連するファイルを1つに圧縮してパッケージングし、圧縮されたファイルを利用してパッケージングされたActionを作成することができます。
zip形式でActionを作る際、以下の3つの形式で作ることができます。
main
パッケージ内に全ての機能を実現した場合main
パッケージ以外に一部のパッケージを分離して構成した場合- 機能の実現のために、外部の従属性を有する部分を含む形式で実現した場合(include third party dependencies)
全ての機能が基本パッケージにある場合、全てのソースファイルをzipファイルの最上位レベルに配置します。
パッケージフォルダを利用する
一部の機能がメイン関数の実行部分と異なるパッケージに属するとしたら、hello/
のように、パッケージ名に注意してフォルダをパッケージングする必要があります。以下は、このようにパッケージングされた形式の例です。
golang-main-package/
- src/
- main.go
- hello/
- hello.go
- hello_test.go
テストを実行し、エラーなく編集したい場合には、src
フォルダを利用する必要があります。基本パッケージの内容は、src/
の下に位置させ、hello
パッケージのソースコードはhello/
フォルダに位置させます。
利用するためには、必ず下位パッケージをimport "hello"
のように呼び出します。それは、もしローカル開発環境でコンパイルする場合、ユーザーのGOPATH
にsrc
の上位ディレクトリーを設定しなければならないことを意味します。もし、ユーザーがVSCodeのようなエディタを利用する場合、go.inferGopath
オプションを有効化する必要があります。
ソースを送る際、最上位ディレクトリーでないsrc
フォルダの内容を以下のように圧縮する必要があります。
cd src
zip -r ../hello.zip *
cd ..
上記の例題ファイルは、以下の通りです。
src/main.go
package main
import (
"fmt"
"hello"
)
// Main forwading to Hello
func Main(args map[string]interface{}) map[string]interface{} {
fmt.Println("Main")
return hello.Hello(args)
}
src/hello/hello.go
package hello
import (
"fmt"
)
// Hello receive an event in format
// { "name": "Mike"}
// and returns a greeting in format
// { "greetings": "Hello, Mike"}
func Hello(args map[string]interface{}) map[string]interface{} {
res := make(map[string]interface{})
greetings := "world"
name, ok := args["name"].(string)
if ok {
greetings = name
}
res["golang-main-package"] = "Hello, " + greetings
fmt.Printf("Hello, %s\n", greetings)
return res
}
src/hello/hello_test.go
package hello
import (
"encoding/json"
"fmt"
)
func ExampleHello() {
var input = make(map[string]interface{})
input["name"] = "Mike"
output := Hello(input)
json, _ := json.Marshal(output)
fmt.Printf("%s", json)
// Output:
// Hello, Mike
// {"golang-main-package":"Hello, Mike"}
}
func ExampleHello_noName() {
var input = make(map[string]interface{})
output := Hello(input)
json, _ := json.Marshal(output)
fmt.Printf("%s", json)
// Output:
// Hello, world
// {"golang-main-package":"Hello, world"}
}
vendor
フォルダを利用する
別のサードパーティーライブラリーを利用しなければならない場合、ランタイムはコンパイルする際、インターネットを介してそのライブラリーをダウンロードしません。vendor
フォルダの構造を利用してダウンロードをし、配置しなければなりません。ここでは、dep
ツールを利用する方法について説明します。
vendor
フォルダは、src
フォルダとパッケージフォルダ、そしてvendor
フォルダを含む必要があり、最上位フォルダで動作しません。もし、main
パッケージに含まれたファイルを利用するためには、最上位フォルダでないmain
で明示された下位フォルダに配置しなければなりません。
例えば、ファイルsrc/hello/hello.go
で以下のパッケージをimportする場合,
import "github.com/sirupsen/logrus"
vendor
フォルダを作るためには、次の手順を行います。
depツールをインストールしてください。
src/hello
フォルダに入って下さい。(src
フォルダではありません。)cd ./src/hello
DEPPROJECTROOT=$(realpath $PWD/../..) dep init
を実行します。
このツールは、使われたライブラリーを探索/検知し、2つのマニフェストファイルGopkg.lock
、 Gopkg.toml
を作ります。既にマニフェストファイルがある場合には、dep ensure
を実行すると、vendor
フォルダが作られ、従属のファイルがダウンロードされます。
構造をまとめてみると、以下の通りです。
golang-hello-vendor
- src/
- hello.go
- hello/
- Gopkg.lock
- Gopkg.toml
- hello.go
- vendor/
- github.com/...
- golang.org/...
上記の例題ファイルは、以下の通りです。
hello.go
package main
import (
"fmt"
"hello"
)
// Main forwading to Hello
func Hello(args map[string]interface{}) map[string]interface{} {
fmt.Println("Entering Hello")
return hello.Hello(args)
}
hello/hello.go
package hello
import (
"os"
"github.com/sirupsen/logrus"
)
var log = logrus.New()
// Hello receive an event in format
// { "name": "Mike"}
// and returns a greeting in format
// { "greetings": "Hello, Mike"}
func Hello(args map[string]interface{}) map[string]interface{} {
log.Out = os.Stdout
res := make(map[string]interface{})
greetings := "world"
name, ok := args["name"].(string)
if ok {
greetings = name
}
res["golang-hello-vendor"] = "Hello, " + greetings
log.WithFields(logrus.Fields{"greetings": greetings}).Info("Hello")
return res
}
バージョン管理システムにおいて、vendor
フォルダを再度作成することができるため、別途保存する必要がありません。マニフェストファイルだけを保存してください。しかし、コンパイルされた状態でActionを作るためには、vendor
フォルダを含む必要があります。
もし、main
関数でサードパーティーライブラリーを利用したい場合には、最上位にあるmainパッケージのファイルをmain
フォルダ内に移動し、vendor
フォルダを作る必要があります。最上位フォルダは認識することができません。
基本パラメータを設定する
毎回Actionを実行する度にパラメータを転送する代わりに、特定のパラメータに基本値を指定することができます。上記で作成したhelloアクションのplace
パラメータに基本値を登録してみます。
Action実行時にパラメータを転送する
Actionの実行の際、入力でパラメータを転送することができます。Main関数に転送されるパラメータは、JSON object形式で転送されます。
パラメータは、Actionの実行の際に直接入力するか、JSON形式のファイルを作成して転送することができます。ファイルを通じてパラメータを転送する場合には、以下のようなJSON形式のファイルを作成する必要があります。
関連情報へ
下のガイドから関連情報をご確認いただけます。