Go
    • PDF

    Go

    • PDF

    Article Summary

    Classic/VPC環境で利用できます。

    Go(Go Language)形式のアクションを作成して様々な方法で活用する方法と、そのユースケースを紹介します。

    アクション作成

    Goコードは、1つ以上の Goソースファイルを持つことができます。Goソースで作成した Actionのエントリーポイントは、Main Packageにある関数です。Main関数のデフォルト名は Mainですが、ユーザーの選択により他の名前に変更できます。ただし、名前の先頭は常に大文字で表記されます。また、この Main関数は以下の説明のような形で作成する必要があります。

    func Main(event map[string]interface{}) map[string]interface{}
    

    Goで作成したコードは複数の関数を含めますが、main関数はプログラムのエントリーポイントとして宣言される必要があります。この点を考慮して名前と場所を含めて「Hello World」を出力する Go形式の簡単なサンプルコードの「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
    }
    

    上記で作成したコードを使用してコンソールで「hello」という名前のアクションを作成する手順は、次の通りです。

    compute-15-2-701.png

    サポート可能な形態

    実行環境でサポート可能な形態は、次の通りです。

    • AMD64アーキテクチャ用にコンパイルされた Linux ELF実行ファイルの実行可能なバイナリ
    • AMD64アーキテクチャ用にコンパイルされた Linux ELF実行ファイルが含まれていて、最上位に execという名前の実行ファイルが含まれている zipファイル
    • Goでコンパイルされた単一ソースファイル
    • 最上位レベル(フォルダ)に実行バイナリファイルを含まない zipファイルは、その後にコンパイルされて実行
    参考

    GOOS=LinuxGOARCH=amd64ですべての Goをサポートするプラットフォームで、有効な形式のバイナリをクロスコンパイルできます。事前コンパイル機能を使用して実行環境と同じコンパイラを使用した方がより安全です。

    Go Modulesを使ってアクションを作成

    go1.19バージョンで外部ライブラリを使うためには、Go Modulesを使います。Go Modulesを使用しない場合、ソースコードを直接含める必要があります。
    以下は、go modを使ってアクションで下記のパッケージを取得する方法のステップバイステップガイドです。この方法はインターネット通信が可能である必要があり、VPC環境の場合は NAT G/Wの設定が必要です。NAT G/Wに関する詳細は、NAT Gatewayご利用ガイドをご参照ください。

    import "github.com/rs/zerolog"
    
    1. 新しいモジュールの初期化

    次のコマンドを実行して新しいモジュールを初期化します。このコマンドを実行すると、go.modファイルが作成されます。

    go mod init <module>
    
    1. main.goの作成

    下記のサンプルコードを参照して main.goを作成します。

    package main
    
    import (
    	"github.com/rs/zerolog"
    	"github.com/rs/zerolog/log"
    )
    
    func init() {
    	zerolog.TimeFieldFormat = ""
    }
    
    func Main(obj map[string]interface{}) map[string]interface{} {
    	name, ok := obj["name"].(string)
    	if !ok {
    		name = "world"
    	}
    	log.Debug().Str("name", name).Msg("Hello")
    	msg := make(map[string]interface{})
    	msg["module-main"] = "Hello, " + name + "!"
    	return msg
    }
    
    1. 依存関係のインポート

    以下のコマンドを実行して go.modファイルを更新し、go.sumファイルを作成します。

    go get github.com/rs/zerolog@v1.19.0
    
    1. アクションパッケージングとアップロード

    以下のコマンドを実行してパッケージを圧縮し、アップロードしてアクションを作成します。

    zip -r action.zip go.mod go.sum main.go
    

    パッケージと vendorを使ってアクションを作成

    コードを作成していると、1つのアクションファイル以外に依存ファイルを一緒にパッケージングする必要がある場合があります。このような場合、関連するファイルを1つのファイルに圧縮してパッケージ化し、圧縮されたファイルを利用してアクションを作成できます。

    zipファイルを利用してアクションを作成する場合、可能な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"のようにインポートする必要があります。これは、ローカル開発環境でコンパイルする場合、ユーザーの GOPATHsrcの上位ディレクトリを設定する必要があることを意味します。 ユーザーが 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フォルダを使用する

    他の3rd-partyライブラリを使用する場合、ランタイムはコンパイルする際にインターネットを通じてそのライブラリをダウンロードするのではなく、vendorフォルダ構造を使用してダウンロードして配置する必要があります。ここでは、depツールを使用する方法について説明します。
    vendorフォルダに srcフォルダ、パッケージフォルダ、vendorフォルダが含まれている必要があります。最上位フォルダでは動作しません。mainパッケージに含まれたファイルを使用するには、最上位フォルダではなく mainと明示された下位フォルダに配置します。例えば、ファイル src/hello/hello.goで以下のようなパッケージを importする必要があるとします。

    import "github.com/sirupsen/logrus"
    

    このような場合、vendorフォルダを作成するには、以下の手順に従ってください。

    1. depツールをインストールします。

    2. src/helloフォルダに移動します。

      cd ./src/hello
      
      • srcフォルダではなく src/helloであることにご注意ください。
    3. DEPPROJECTROOT=$(realpath $PWD/../..) dep initを実行します。

      • このツールは、使用されたライブラリを探索・検知して2つのマニフェストファイルGopkg.lockGopkg.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フォルダを再度作成できるので、別途保存する必要はありません。マニフェストファイルだけ保存すればいいですが、コンパイルされた状態でアクションを作成するには、vendorフォルダを含める必要があります。
    main関数で3rd-partyライブラリを使用する場合、最上位にある mainパッケージのファイルを mainフォルダに移動させて vendorフォルダを作成する必要があります。


    この記事は役に立ちましたか?

    What's Next
    Changing your password will log you out immediately. Use the new password to log back in.
    First name must have atleast 2 characters. Numbers and special characters are not allowed.
    Last name must have atleast 1 characters. Numbers and special characters are not allowed.
    Enter a valid email
    Enter a valid password
    Your profile has been successfully updated.