概要
マネージドIDでSQLにアクセス、マネージドIDでキュートリガーを試したので、Blobトリガーを試してみる。
コード
チュートリアル: イベント サブスクリプションを使用して BLOB コンテナーで Azure Functions をトリガーするを参考に作成。
import { app, InvocationContext, output } from '@azure/functions';
import { isBlobTriggerMetadata } from '../domain/blobTrigger';
const sqlOutput = output.sql({
commandText: '[dbo].[YakumiCharacter]',
connectionStringSetting: 'DATABASE_CONNECTION_STRING',
});
export async function BlobTriggerEventGrid(
blob: unknown, // Buffer
context: InvocationContext,
): Promise<void> {
console.log('context'.endsWith('json'), JSON.stringify(context));
if (!isBlobTriggerMetadata(context.triggerMetadata)) {
context.warn('context.triggerMetadata is not BlobTriggerMetadata');
return;
}
// zipファイルは処理しない
if (!context.triggerMetadata.blobTrigger.endsWith('json')) return;
if (!Buffer.isBuffer(blob)) return;
const blobContent = blob.toString('utf-8');
const data = JSON.parse(blobContent);
const { uid, characterId } = data;
if (!uid || !characterId) {
context.log('obj is not Character', data);
return;
}
context.extraOutputs.set(sqlOutput, {
id: characterId,
uid,
data: blobContent,
updated: new Date(),
});
}
app.storageBlob('BlobTriggerEventGrid', {
path: 'web',
source: 'EventGrid',
connection: 'TARGET_STORAGE_ACCOUNT',
handler: BlobTriggerEventGrid,
extraOutputs: [sqlOutput],
});
インフラ
#!/bin/bash
BIN_DIR=$(cd $(dirname $0) && pwd)
BICEP_DIR=$(cd $BIN_DIR/../biceps && pwd)
# 環境変数読み込み
source $BIN_DIR/.env
cd $BICEP_DIR && az deployment group create \
--name ExampleDeployment \
--template-file batch.bicep \
--parameters batch.bicepparam \
--parameters \
functionAppName=$BATCH_NAME \
uploadStroageAccountName=$UPLOAD_STORAGE_ACCOUNT_NAME \
sqlServerName=$DB_SERVER_NAME \
sqlServerDbName=$SQLSERVER_DB_NAME \
-g $RESOURCE_GROUP_NAME
#!/bin/bash
BIN_DIR=$(cd $(dirname $0) && pwd)
BICEP_DIR=$(cd $BIN_DIR/../biceps && pwd)
# 環境変数読み込み
source $BIN_DIR/.env
EXT_KEY=$(az functionapp keys list -g yakumi -n nkymspaiut5dsazfunctionsapp | jq -r '.systemKeys.blobs_extension' | tr -d '[:space:]' )
cd $BICEP_DIR && az deployment group create \
--name ExampleDeployment \
--template-file eventGrid.bicep \
--parameters \
functionAppName=$BATCH_NAME \
blobExtensionKey=$EXT_KEY \
uploadStroageAccountName=$UPLOAD_STORAGE_ACCOUNT_NAME \
-g $RESOURCE_GROUP_NAME
param functionAppName string
param blobExtensionKey string
var eventSubName = 'subToStorage'
var systemTopicName = 'mystoragesystemtopic'
resource systemTopic 'Microsoft.EventGrid/systemTopics@2023-12-15-preview' existing = {
name: systemTopicName
}
var endpoint = 'https://${functionAppName}.azurewebsites.net/runtime/webhooks/blobs?functionName=Host.Functions.BlobTriggerEventGrid&code=${blobExtensionKey}'
resource eventSubscription 'Microsoft.EventGrid/systemTopics/eventSubscriptions@2023-12-15-preview' = {
parent: systemTopic
name: eventSubName
properties: {
destination: {
properties: {
endpointUrl: endpoint
}
endpointType: 'WebHook'
}
filter: {
includedEventTypes: [
'Microsoft.Storage.BlobCreated' // BLOB が作成または置換されたときにトリガー. https://learn.microsoft.com/ja-jp/azure/event-grid/event-schema-blob-storage
]
}
}
}
マネージドIDでBlobに対するロールの付与が必要。
キューに対するロールはこちらの方法だとblobトリガーと異なり不要となる。
param location string
param uploadStroageAccountName string
var systemTopicName = 'mystoragesystemtopic'
resource uploadedStorageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = {
name: uploadStroageAccountName
}
resource systemTopic 'Microsoft.EventGrid/systemTopics@2023-12-15-preview' = {
name: systemTopicName
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
source: uploadedStorageAccount.id
topicType: 'Microsoft.Storage.StorageAccounts'
}
}
param location string = resourceGroup().location
param functionsRuntime object
param functionAppName string
param uploadStroageAccountName string
param sqlServerName string
param sqlServerDbName string
var storageAccountName = '${uniqueString(resourceGroup().id)}azfunctions'
var applicationInsightsName = '${uniqueString(resourceGroup().id)}applicationinsights'
var logAnalyticsName = '${uniqueString(resourceGroup().id)}logAnalytics'
var environments = [
{
name: 'TARGET_STORAGE_ACCOUNT__accountName'
value: uploadStroageAccountName
}
{
name: 'TARGET_STORAGE_ACCOUNT__blobServiceUri'
value: 'https://${uploadStroageAccountName}.blob.core.windows.net'
}
{
name: 'TARGET_STORAGE_ACCOUNT__queueServiceUri'
value: 'https://${uploadStroageAccountName}.queue.core.windows.net'
}
{
name: 'DATABASE_CONNECTION_STRING'
value: 'Server=tcp:${sqlServerName}.database.windows.net;Authentication=Active Directory Default; Database=${sqlServerDbName};'
}
]
module myFunctionsApplicationInsights 'core/host/applications.bicep' = {
name: 'myFunctionsApplicationInsights'
params: {
location: location
applicationInsightsName: applicationInsightsName
logAnalyticsName: logAnalyticsName
}
}
module myFunctionsStorage 'core/storage/storage-account.bicep' = {
name: 'myFunctionsStorage'
params: {
location: location
storageAccountName: storageAccountName
}
}
module myFunctions 'core/host/functions.bicep' = {
name: 'myFunctions'
params: {
functionAppName: functionAppName
location: location
storageAccountName: storageAccountName
kind: functionsRuntime.kind
runtime: functionsRuntime.runtime
linuxFxVersion: functionsRuntime.linuxFxVersion
extensionVersion: functionsRuntime.extensionVersion
applicationInsightsInstrumentationKey: myFunctionsApplicationInsights.outputs.applicationInsightsInstrumentationKey
environments: environments
}
}
// 組み込みロール: https://learn.microsoft.com/ja-jp/azure/role-based-access-control/built-in-roles
var storageRoleDefinitionId= 'ba92f5b4-2d11-453d-a403-e96b0029c9fe' // ストレージ BLOB データ共同作成者
var principalId = myFunctions.outputs.principalId
module myStorageRole 'core/rbac/role.bicep' = {
name: 'myStorageRole'
params: {
uploadStroageAccountName: uploadStroageAccountName
principalId: principalId
roleDefinitionId: storageRoleDefinitionId
}
}
デプロイ
Functionsをデプロイしてblobs_extension
が作成されたのちにEventGridを設定する流れとする。
./infrastructure/bin/createBatch.bash
cd packages/batch-functions && npm run deploy
./infrastructure/bin/addBatchTrigger.bash
確認
BlobトリガーでデータをDBに保存できた。*
参考: contextからとれる情報
第2引数。第1引数はBlobデータがBuffer型で入っている。
{
"invocationId": "00000000-0000-0000-0000-000000000000",
"functionName": "BlobTriggerEventGrid",
"extraInputs": {},
"extraOutputs": {},
"traceContext": {
"traceParent": "00-00000000000000000000000000000000-0000000000000000-00",
"traceState": "",
"attributes": { "OperationName": "BlobTriggerEventGrid" }
},
"triggerMetadata": {
"blobTrigger": "$web/sample-path/character-data/path-to-blob/sample-file.json",
"uri": "https://example.blob.core.windows.net/$web/sample-path/character-data/path-to-blob/sample-file.json",
"properties": {
"lastModified": "2024-09-25T22:53:51+00:00",
"createdOn": "2024-05-27T13:46:29+00:00",
"metadata": {},
"objectReplicationDestinationPolicyId": null,
"objectReplicationSourceProperties": null,
"blobType": 0,
"copyCompletedOn": "0001-01-01T00:00:00+00:00",
"copyStatusDescription": null,
"copyId": null,
"copyProgress": null,
"copySource": null,
"copyStatus": 0,
"blobCopyStatus": null,
"isIncrementalCopy": false,
"destinationSnapshot": null,
"leaseDuration": 0,
"leaseState": 0,
"leaseStatus": 1,
"contentLength": 362814,
"contentType": "application/octet-stream",
"eTag": {},
"contentHash": "00000000000000000000000000000000",
"contentEncoding": null,
"contentDisposition": null,
"contentLanguage": null,
"cacheControl": null,
"blobSequenceNumber": 0,
"acceptRanges": "bytes",
"blobCommittedBlockCount": 0,
"isServerEncrypted": true,
"encryptionKeySha256": null,
"encryptionScope": null,
"accessTier": "Hot",
"accessTierInferred": true,
"archiveStatus": null,
"accessTierChangedOn": "0001-01-01T00:00:00+00:00",
"versionId": null,
"isLatestVersion": false,
"tagCount": 0,
"expiresOn": "0001-01-01T00:00:00+00:00",
"isSealed": false,
"rehydratePriority": null,
"lastAccessed": "0001-01-01T00:00:00+00:00",
"immutabilityPolicy": { "expiresOn": null, "policyMode": null },
"hasLegalHold": false
},
"metadata": {}
},
"options": {
"trigger": {
"path": "web",
"source": "EventGrid",
"connection": "TARGET_STORAGE_ACCOUNT",
"type": "blobTrigger",
"name": "blobTrigger00000000",
"direction": "in"
},
"extraInputs": [],
"extraOutputs": []
}
}
検討
マネージド関数ではBlobトリガーを作れないので普通の関数として作成。
apis-functions
参考
Azure Functions の Azure SQL 出力バインド
SQLバインド接続文字列 ConnectionString マネージド ID 接続の使用
Azure Functions の Azure Blob Storage トリガー
クイック スタート: Bicep を使用して BLOB ストレージ イベントを Web エンドポイントにルーティングする
Blob Event Grid Triggerを動かしてみる
Event Grid経由でのBlob storage triggerでBlobの変更をSlackに自動通知する
EventGridを使用してAzureリソースのデプロイ完了をフックする
Event Grid ソースとしての Azure Blob Storage