- 追加された行はこの色です。
- 削除された行はこの色です。
#author("2020-07-12T12:22:46+00:00","","")
#mynavi(Azureメモ)
#setlinebreak(on);
* 概要 [#daae4a2b]
#html(<div class="pl10">)
Azure Functions で Goはサポートされていない。( [[Azure Functions でサポートされている言語:https://docs.microsoft.com/ja-jp/azure/azure-functions/supported-languages]] )
・・が、[[カスタム ハンドラー:https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-custom-handlers]]を使用する事によって、サポート外の言語でも Azure Functions として利用する事ができる。
ここでは、Blobにファイルがアップロードされたタイミングで起動する Functions を Goで開発する方法について記載する。
#html(</div>)
* 目次 [#ncbd6030]
#contents
- 関連
-- [[Azureメモ]]
-- [[Go言語]]
-- [[AWS SDK for Go を使ってみる]]
-- [[GoでWebAPIサーバを書いてみる]]
-- [[GoからInfluxDBにアクセスする]]
- 参考
-- [[Azure Functions でサポートされている言語:https://docs.microsoft.com/ja-jp/azure/azure-functions/supported-languages]]
-- [[Azure Functions 開発者ガイド:https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-reference]]
-- [[Azure Functions でのトリガーとバインドの概念:https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-triggers-bindings]]
-- [[Azure Functions のカスタム ハンドラー:https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-custom-handlers]]
-- [[Azure Functions 2.x 以降の host.json のリファレンス:https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-host-json]]
-- [[Go を使用して BLOB をアップロード、ダウンロード、および一覧表示する:https://docs.microsoft.com/ja-jp/azure/storage/blobs/storage-quickstart-blobs-go?tabs=linux]]
-- https://github.com/Azure/azure-sdk-for-go
-- https://github.com/azure/azure-storage-blob-go/
-- https://github.com/Azure-Samples/functions-custom-handlers
-- http://json.schemastore.org/function
* 概要 [#daae4a2b]
#html(<div class="pl10">)
Azure Functions で Goはサポートされていない。( [[Azure Functions でサポートされている言語:https://docs.microsoft.com/ja-jp/azure/azure-functions/supported-languages]] )
・・が、[[カスタム ハンドラー:https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-custom-handlers]]を使用する事によって、サポート外の言語でも Azure Functions として利用する事ができる。
ここでは、カスタムハンドラーを使用して Go で実装した Azure Functions を動作させる方法について記載する。
#html(</div>)
* カスタムハンドラーの仕組み [#o7a63c51]
#html(<div class="pl10">)
カスタムハンドラーは軽量のWebサーバとして動作するもので、Functions Host と Web通信する事により動作する。
※ https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-custom-handlers#overview
#html(<div class="ib" style="vertical-align: middle">)
| &br;トリガー&br;&br;|
#html(</div>)
#html(<div class="ib pt06 pl08 pr08" style="vertical-align: top">ーー リクエスト ーー><br /><ーー レスポンス ーー</div>)
#html(<div class="ib" style="vertical-align: top">)
| &br;Functions Host&br;&br; |
#html(</div>)
#html(<div class="ib pt06 pl08 pr08" style="vertical-align: top">ーー Webリクエスト ーー><br /><ーー Webレスポンス ーー</div>)
#html(<div class="ib" style="vertical-align: top">)
| &br;カスタムハンドラー&br;&br; |h
#html(</div>)
つまり、Webサーバがかける言語であれば何でも動く。
#html(</div>)
* 構築するFunctionsの仕様 [#d37ba3b6]
* ファイル構成 [#v3aa9669]
#html(<div class="pl10">)
以下の処理を行う関数を作成する。
以下の通り構成する。
#TODO
- Blobストレージの画像ファイルが追加/変更された際にトリガーされる
- 追加/変更されたファイルのサムネイルを作成し、同じBlobストレージに格納する
#html(<div class="ib border pr10 pl10">)
+ host.json
+ 関数名
┗ function.json
+ Webサーバ(スクリプト,実行可能ファイルなど)
#html(</div>)
#html(</div>)
* 準備 [#kcd153f3]
#html(<div class="pl10">)
ローカルでの Azure Storage の開発とテスト用にAzurite エミュレーターをインストールしておく。
https://docs.microsoft.com/ja-jp/azure/storage/common/storage-use-azurite
インストール&起動
#myterm2(){{
npm install -g azurite
azurite --silent --location ./azurite --debug ./azurite/debug.log
}}
#html(</div>)
* host.json の作成 [#ne85a6dd]
#html(<div class="pl10">)
参考
[[https://github.com/Azure-Samples/functions-custom-handlers/blob/master/go/host.json]]
[[Azure Functions 2.x 以降の host.json のリファレンス:https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-host-json]]
・defaultExecutablePath で今回 Go で作成するWebサーバの実行可能ファイルのPATHを指定する。
・ローカル開発用の拡張機能バンドル(extensionBundle)を利用すれば、拡張機能バンドルを別途インストールしなくても良い。
#mycode2(){{
{
"version": "2.0",
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[1.*, 2.0.0)"
},
"httpWorker": {
"description": {
"defaultExecutablePath": "MyGoCustomHandlers.exe"
}
}
}
}}
** Azure functions が実行される Functions Host 上に既にランタイムがある場合 [#p8d355df]
#html(<div class="pl10">)
スクリプトのPATH を defaultWorkerPath で指定する。
注) nodejs は Azure functions のサポート対象言語なので、そもそもカスタムハンドラを使用する必要はない。
#mycode2(){{
{
"version": "2.0",
"httpWorker": {
"description": {
"defaultExecutablePath": "node",
"defaultWorkerPath": "server.js"
}
}
}
}}
#html(</div>)
#html(</div>)
* function.json の作成 [#e1fbd895]
#html(<div class="pl10">)
参考: http://json.schemastore.org/function
https://github.com/Azure-Samples/functions-custom-handlers/tree/master/go/BlobTrigger
以下、Blob トリガーにより起動される Functions の例
#mycode2(){{
{
"bindings" : [ {
"type" : "blobTrigger",
"direction" : "in",
"name" : "triggerBlob",
"path" : "test-input-container/{name}",
"dataType" : "binary",
"connection" : "AzureWebJobsStorage"
},
{
"type" : "blob",
"direction" : "out",
"name" : "$return",
"path" : "test-output-container/{name}",
"dataType" : "binary",
"connection" : "AzureWebJobsStorage"
} ]
}
}}
#html(</div>)
* local.settings.json の作成 [#j11026b0]
#html(<div class="pl10">)
#mycode2(){{
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "YOUR_STORAGE_CONNECTION_STRING"
}
}
}}
ローカルのストレージエミュレータに接続する場合は以下の通り設定する。
#mycode2(){{
:
"AzureWebJobsStorage": "UseDevelopmentStorage=true"
:
}}
#html(</div>)
* 処理の作成 [#l0ee6194]
#html(<div class="pl10">)
以下、test-input-container にアップロードされたファイルを base64エンコードしたものを test-output-container に出力する例。
#mycode2(){{
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"os"
)
type ReturnValue struct {
Data string
}
type InvokeResponse struct {
Outputs map[string]interface{}
Logs []string
ReturnValue interface{}
}
type InvokeRequest struct {
Data map[string]interface{}
Metadata map[string]interface{}
}
func blobTriggerHandler(w http.ResponseWriter, r *http.Request) {
var invokeReq InvokeRequest
d := json.NewDecoder(r.Body)
decodeErr := d.Decode(&invokeReq)
if decodeErr != nil {
http.Error(w, decodeErr.Error(), http.StatusBadRequest)
return
}
fmt.Println("The JSON data is:invokeReq metadata......")
fmt.Println(invokeReq.Metadata)
// データはBASE64エンコードされいる
returnValue := invokeReq.Data["triggerBlob"]
invokeResponse := InvokeResponse{Logs: []string{"test log1", "test log2"}, ReturnValue: returnValue}
js, err := json.Marshal(invokeResponse)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.Write(js)
}
func main() {
httpInvokerPort, exists := os.LookupEnv("FUNCTIONS_HTTPWORKER_PORT")
if exists {
fmt.Println("FUNCTIONS_HTTPWORKER_PORT: " + httpInvokerPort)
}
mux := http.NewServeMux()
mux.HandleFunc("/BlobTrigger", blobTriggerHandler)
log.Println("Go server Listening...on httpInvokerPort:", httpInvokerPort)
log.Fatal(http.ListenAndServe(":"+httpInvokerPort, mux))
}
}}
レスポンスとして以下を返却する。
| ペイロードのキー | データ型 | 解説 |h
| Outputs | JSON | function.json ファイルの bindings 配列によって定義される応答値。|
| Logs | array | Functions の呼び出しログとして表示するメッセージ。 |
| ReturnValue | string | レスポンス本文。(function.json ファイルの $return として出力が構成されている場合) |
※ https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-custom-handlers#response-payload
#html(</div>)
#html(</div>)
* 動作確認 [#zeeabbed]
#html(<div class="pl10">)
** カスタムハンドラ起動 [#l12c2f76]
#myterm2(){{
go build
func start
:
:
Now listening on: http://0.0.0.0:7071
Application started. Press Ctrl+C to shut down.
:
}}
** テスト用のBlobストレージコンテナの作成 [#s21b18ed]
#myterm2(){{
# ローカルのエミュレータに接続するように環境変数を設定
export AZURE_STORAGE_CONNECTION_STRING="UseDevelopmentStorage=true"
# 入出力用のコンテナをそれぞれ作成
az storage container create -n test-input-container
az storage container create -n test-out-container
}}
** コンテナにファイルをアップロード [#s88bff7e]
#myterm2(){{
az storage blob upload -f ./sample.txt -c test-input-container -n sample.txt
}}
#html(</div>)
// .NET Core SDK
// https://dotnet.microsoft.com/download
//
//https://functionscdn.azureedge.net/public/2.0.1-beta.35/Azure.Functions.Cli.win-x86.2.0.1-beta.35.zip
//npm i -g azure-functions-core-tools@core --unsafe-perm true
//* 構築するFunctionsの仕様 [#d37ba3b6]
//#html(<div class="pl10">)
//以下の処理を行う関数を作成する。
//#TODO
//- Blobストレージの画像ファイルが追加/変更された際にトリガーされる
//- 追加/変更されたファイルのサムネイルを作成し、同じBlobストレージに格納する
//#html(</div>)