1923

都内と業界の隅っこで生活しているエンジニアのノート

Azure Functions カスタム コンテナーで Golang を使う

Azure Functions のカスタム ハンドラーが GA です。カスタム ハンドラーを使うと Golang でもで関数アプリを実装することができます。

ですが・・・今回は、Azure Functions カスタム コンテナーです。Azure Functions Core Tools 使って function app と Dockerfile を作成し、Golang で作ったアプリを簡単に動かすことができますので試してみます。

Azure Functions Core Tools (試したのは 3.0.3160 )でプロジェクトを作成します。

func init go-func-app1 --worker-runtime custom --docker

関数と同じ名前のサブフォルダー(Hello)を作成して、構成ファイル function.json を追加します。シンプルなHTTPトリガーです。

{
  "bindings": [
    {
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "get"
      ],
      "authLevel": "anonymous"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }
  ]
}

関数を実装します。 /Hello にHTTPリクエストが来たら JSONを返すだけのコードです。

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "os"
)

func main() {
    customHandlerPort, exists := os.LookupEnv("FUNCTIONS_CUSTOMHANDLER_PORT")
    if exists {
        fmt.Println("FUNCTIONS_CUSTOMHANDLER_PORT: " + customHandlerPort)
    }
    mux := http.NewServeMux()
    mux.HandleFunc("/Hello", helloHandler)
    fmt.Println("Go server Listening...on FUNCTIONS_CUSTOMHANDLER_PORT:", customHandlerPort)
    log.Fatal(http.ListenAndServe(":"+customHandlerPort, mux))
}
type InvokeResponse struct {
    Outputs     map[string]interface{}
    Logs        []string
    ReturnValue interface{}
}
type user struct {
    Name string
    Address  string
}
func helloHandler(w http.ResponseWriter, r *http.Request) {
    outputs := make(map[string]interface{})
    resData := make(map[string]interface{})
    resData["body"] = user{
        Name: "Taka",
        Address:  "Tokyo",
    }
    outputs["res"] = resData
    invokeResponse := InvokeResponse{outputs, nil, nil}
    responseJson, _ := json.Marshal(invokeResponse)
    w.Header().Set("Content-Type", "application/json")
    w.Write(responseJson)
}

ファイル構成はこんな感じです。

f:id:taka1923:20201210223411p:plain

host.jsonのdefaultExecutablePathにビルドで作成される main を指定します。

 "defaultExecutablePath": "main",

Dockerfile に Go のビルドとコピーなどを追加して準備は終わりです。

FROM golang:latest
COPY . /go/app
WORKDIR /go/app
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .

FROM mcr.microsoft.com/azure-functions/dotnet:3.0-appservice
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
    AzureFunctionsJobHost__Logging__Console__IsEnabled=true

COPY --from=0 /go/app/ /home/site/wwwroot

ビルドしてローカルで確認してみます。

docker build -t go-func-app1:latest .
docker run -p 8080:80 -it go-func-app1:latest .

f:id:taka1923:20201210223433p:plain

あとは、 Azure Container Registrなどに Push して functions に設定すれば完了です。

f:id:taka1923:20201210223252p:plain