Azure Functionsの実践ガイド|サーバーレスで業務処理を自動化する方法

kento_morota 21分で読めます

「定型業務を自動化したいが、専用のサーバーを立てるほどではない」「イベント発生時にだけ処理を実行したい」――Azure Functionsは、そんなニーズに応えるサーバーレスコンピューティングサービスです。

Azure Functionsでは、サーバーの管理を一切気にすることなく、関数(Function)単位でコードを記述・実行できます。HTTPリクエスト、タイマースケジュール、メッセージキューへの到着、Blobストレージへのファイルアップロードなど、さまざまなイベントをトリガーとして処理を自動実行できます。

この記事では、Azure Functionsの基本概念から、トリガーとバインディングの活用、ローカル開発環境の構築、本番運用に必要な設定、CI/CDパイプラインの構築、コスト管理まで、実務で使える知識を体系的に解説します。サーバーレスアーキテクチャの基礎と合わせて読むと、理解が深まります。

Azure Functionsの基本概念とホスティングプラン

Azure Functionsを正しく使いこなすために、まず基本概念とプランの選び方を理解しましょう。

Functions Appのリソース構造

Azure Functionsは、以下の構成で動作します。

  • Function App:関数のデプロイと管理の単位。1つのFunction Appに複数の関数を含めることができる
  • 関数(Function):実際のコードと設定。トリガーとバインディングの定義を含む
  • ホスティングプラン:関数が実行されるコンピューティングリソースの種類と課金方式を決定する

ホスティングプランの比較

従量課金プラン(Consumption Plan)

  • 実行回数と実行時間に応じた完全な従量課金
  • 月間100万回の実行と40万GB秒のメモリ使用量が無料枠として提供される
  • 自動スケーリング(0インスタンスからスケール)
  • コールドスタート(数秒の初期起動遅延)が発生する可能性がある
  • 最大実行時間:デフォルト5分、最大10分

Premium Plan(Elastic Premium)

  • 常時ウォームインスタンスを維持し、コールドスタートを回避
  • VNet統合、無制限の実行時間に対応
  • より高性能なインスタンスサイズを選択可能
  • 月額:約18,000円〜(最小1インスタンス常時起動)

Dedicated Plan(App Service Plan)

  • 既存のApp Service Plan上で関数を実行
  • App Service Planの空きリソースを活用する場合にコスト効率が良い
  • 自動スケーリングの粒度はApp Service Planに依存

Container Apps

  • コンテナベースでFunction Appを実行
  • Kubernetesベースの環境で、マイクロサービスアーキテクチャとの統合に適している

多くのケースでは、まず従量課金プランから始め、コールドスタートが問題になる場合やVNet統合が必要な場合にPremium Planへ移行するのが実践的なアプローチです。

トリガーとバインディングの活用

Azure Functionsの最大の特徴は、豊富なトリガーとバインディングにより、少ないコードで複雑な連携処理を実装できることです。

主要なトリガーの種類

  • HTTP トリガー:HTTPリクエストで関数を実行。REST APIの構築に使用
  • Timer トリガー:CRON式によるスケジュール実行。定期バッチ処理に使用
  • Blob トリガーBlob Storageへのファイルアップロードで関数を実行
  • Queue トリガー:Azure Queue Storageへのメッセージ到着で関数を実行
  • Service Bus トリガー:Service Busキューやトピックへのメッセージ到着で関数を実行
  • Event Grid トリガー:Azureリソースのイベント発生で関数を実行
  • Cosmos DB トリガー:Cosmos DBのドキュメント変更で関数を実行

バインディングとは

バインディングは、関数の入出力を外部リソースに宣言的に接続する仕組みです。トリガー(入力)のほかに、入力バインディングと出力バインディングがあります。

たとえば、「HTTPリクエストを受けて、Blob Storageにファイルを保存する」という処理を実装する場合、Blob StorageのSDKを直接操作するコードを書く代わりに、出力バインディングを宣言するだけで実現できます。

実装例:定期的なデータ集計処理

以下は、毎日午前9時にデータベースからデータを取得し、集計結果をBlob Storageに保存するTypeScript関数の例です。

// src/functions/dailyReport.ts
import { app, InvocationContext, Timer, output } from "@azure/functions";
import sql from "mssql";

const blobOutput = output.storageBlob({
  path: "reports/{DateTime:yyyy}/{DateTime:MM}/{DateTime:yyyy-MM-dd}.json",
  connection: "AzureWebJobsStorage"
});

async function dailyReport(
  myTimer: Timer,
  context: InvocationContext
): Promise {
  context.log("Daily report generation started");

  // Azure SQL Databaseからデータを取得
  const pool = await sql.connect(process.env.SQL_CONNECTION_STRING!);
  const result = await pool.request().query(`
    SELECT
      department,
      COUNT(*) as total_orders,
      SUM(amount) as total_amount
    FROM orders
    WHERE order_date = CAST(GETDATE()-1 AS DATE)
    GROUP BY department
  `);

  // 集計結果をBlob Storageに出力
  const report = {
    generatedAt: new Date().toISOString(),
    data: result.recordset
  };

  context.extraOutputs.set(blobOutput, JSON.stringify(report, null, 2));
  context.log(`Report generated: ${result.recordset.length} departments`);
}

app.timer("dailyReport", {
  schedule: "0 0 9 * * *", // 毎日9:00 JST
  handler: dailyReport,
  extraOutputs: [blobOutput]
});

実装例:画像アップロード時の自動リサイズ

// src/functions/resizeImage.ts
import { app, InvocationContext, StorageBlobHandler, output } from "@azure/functions";
import sharp from "sharp";

const thumbnailOutput = output.storageBlob({
  path: "thumbnails/{name}",
  connection: "AzureWebJobsStorage"
});

const resizeImage: StorageBlobHandler = async (
  blob: Buffer,
  context: InvocationContext
): Promise => {
  context.log(`Processing blob: ${context.triggerMetadata.name}`);

  // 画像をリサイズ
  const thumbnail = await sharp(blob)
    .resize(300, 300, { fit: "cover" })
    .jpeg({ quality: 80 })
    .toBuffer();

  context.extraOutputs.set(thumbnailOutput, thumbnail);
  context.log("Thumbnail created successfully");
};

app.storageBlob("resizeImage", {
  path: "uploads/{name}",
  connection: "AzureWebJobsStorage",
  handler: resizeImage,
  extraOutputs: [thumbnailOutput]
});

この関数は、uploadsコンテナに画像がアップロードされるたびに自動実行され、300x300のサムネイルをthumbnailsコンテナに保存します。

ローカル開発環境の構築

Azure Functionsは、ローカル環境での開発とテストが充実しています。Azure Functions Core Toolsを使えば、ローカルマシン上で関数を実行・デバッグできます。

開発環境のセットアップ

# Azure Functions Core Toolsのインストール
npm install -g azure-functions-core-tools@4 --unsafe-perm true

# 新しいFunction Appプロジェクトの作成
func init my-functions --typescript

# プロジェクトディレクトリに移動
cd my-functions

# HTTP トリガー関数の作成
func new --name hello --template "HTTP trigger" --authlevel anonymous

# ローカルでの実行
func start

func startを実行すると、ローカルでHTTPサーバーが起動し、http://localhost:7071/api/helloでHTTPトリガー関数にアクセスできます。

local.settings.jsonの設定

ローカル開発用の環境変数は、local.settings.jsonファイルに定義します。

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "SQL_CONNECTION_STRING": "Server=localhost;Database=mydb;..."
  }
}

UseDevelopmentStorage=trueを指定すると、Azurite(ローカルのAzure Storageエミュレータ)を使用します。このファイルは.gitignoreに含め、リポジトリにコミットしないようにしましょう。

VS Codeとの統合

Azure Functions拡張機能をインストールすると、VS Code上で以下の操作がGUIから行えます。

  • 関数の作成とテンプレートの選択
  • ブレークポイントを使ったデバッグ
  • Azureへの直接デプロイ
  • ログのリアルタイム表示

Claude Codeの環境構築ガイドでも紹介しているように、開発ツールの環境構築を効率化することで、実装に集中できる環境が整います。

Function AppのデプロイとCI/CD構築

本番環境へのデプロイは、手動デプロイとCI/CDパイプラインの両方の方法があります。

Azure CLIによるデプロイ

# リソースグループの作成
az group create --name rg-func-prod --location japaneast

# ストレージアカウントの作成(Functions実行に必要)
az storage account create \
  --name stfuncprod001 \
  --resource-group rg-func-prod \
  --location japaneast \
  --sku Standard_LRS

# Function Appの作成(従量課金プラン、Node.js)
az functionapp create \
  --name func-myapp-prod \
  --resource-group rg-func-prod \
  --storage-account stfuncprod001 \
  --consumption-plan-location japaneast \
  --runtime node \
  --runtime-version 20 \
  --functions-version 4

# コードのデプロイ
func azure functionapp publish func-myapp-prod

GitHub Actionsによる自動デプロイ

以下は、mainブランチへのpushをトリガーにしたGitHub Actionsのワークフロー例です。

# .github/workflows/deploy-functions.yml
name: Deploy Azure Functions

on:
  push:
    branches: [main]

env:
  AZURE_FUNCTIONAPP_NAME: func-myapp-prod
  NODE_VERSION: "20.x"

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

      - name: Run tests
        run: npm test

      - name: Deploy to Azure Functions
        uses: Azure/functions-action@v1
        with:
          app-name: ${{ env.AZURE_FUNCTIONAPP_NAME }}
          publish-profile: ${{ secrets.AZURE_FUNCTIONAPP_PUBLISH_PROFILE }}
          package: .

Publish ProfileはAzure Portalから取得し、GitHubリポジトリのSecretsに登録します。よりセキュアな方法として、OpenID Connect(OIDC)を使ったフェデレーション認証も利用できます。

アプリケーション設定とシークレット管理

本番環境の関数で使用するデータベース接続文字列やAPIキーなどのシークレットは、適切に管理する必要があります。

アプリケーション設定の構成

# アプリケーション設定の追加
az functionapp config appsettings set \
  --name func-myapp-prod \
  --resource-group rg-func-prod \
  --settings \
    SQL_CONNECTION_STRING="Server=sql-myapp-prod.database.windows.net;..." \
    BLOB_STORAGE_CONNECTION="DefaultEndpointsProtocol=https;..."

Azure Key Vaultとの統合

接続文字列やAPIキーをアプリケーション設定に直接格納する代わりに、Azure Key Vaultを使って安全に管理できます。

# Key Vaultの作成
az keyvault create \
  --name kv-func-prod \
  --resource-group rg-func-prod \
  --location japaneast

# シークレットの追加
az keyvault secret set \
  --vault-name kv-func-prod \
  --name SqlConnectionString \
  --value "Server=sql-myapp-prod.database.windows.net;..."

# Function AppのマネージドIDを有効化
az functionapp identity assign \
  --name func-myapp-prod \
  --resource-group rg-func-prod

# Key Vaultへのアクセスポリシーを設定
az keyvault set-policy \
  --name kv-func-prod \
  --object-id "マネージドIDのオブジェクトID" \
  --secret-permissions get list

アプリケーション設定でKey Vaultの参照構文を使うことで、関数のコードを変更せずにKey Vaultのシークレットを利用できます。

# Key Vault参照の設定
az functionapp config appsettings set \
  --name func-myapp-prod \
  --resource-group rg-func-prod \
  --settings \
    SQL_CONNECTION_STRING="@Microsoft.KeyVault(VaultName=kv-func-prod;SecretName=SqlConnectionString)"

この構文により、Function Appは起動時にKey VaultからシークレットをJIT(Just-In-Time)で取得します。シークレットのローテーション時にFunction Appの設定を変更する必要がありません。

監視・エラーハンドリングとリトライ設定

サーバーレス関数は分散環境で実行されるため、適切なエラーハンドリングと監視が重要です。

Application Insightsによる監視

Function Appの作成時にApplication Insightsが自動的に構成されます。以下のメトリクスがデフォルトで収集されます。

  • 関数の実行回数:成功・失敗別の実行回数
  • 実行時間:各関数の平均実行時間と95パーセンタイル
  • メモリ使用量:関数実行時のメモリ消費量
  • 例外:発生した例外のスタックトレースと発生頻度

リトライポリシーの設定

外部APIの一時的な障害やデータベースの接続エラーに対応するため、リトライポリシーを設定できます。

// host.jsonでのリトライ設定
{
  "version": "2.0",
  "retry": {
    "strategy": "exponentialBackoff",
    "maxRetryCount": 3,
    "minimumInterval": "00:00:05",
    "maximumInterval": "00:05:00"
  },
  "extensions": {
    "queues": {
      "maxDequeueCount": 5,
      "visibilityTimeout": "00:01:00"
    }
  }
}

Queueトリガーの場合、処理に失敗したメッセージは指定回数リトライされた後、poison queueに移動されます。poison queueを監視し、失敗したメッセージの原因を調査・対応する運用フローを構築しましょう。

構造化ログの実装

// 構造化ログの例
async function processOrder(
  message: unknown,
  context: InvocationContext
): Promise {
  const order = message as { orderId: string; amount: number };

  context.log("Order processing started", {
    orderId: order.orderId,
    amount: order.amount
  });

  try {
    // 注文処理のロジック
    await processPayment(order);

    context.log("Order processed successfully", {
      orderId: order.orderId
    });
  } catch (error) {
    context.error("Order processing failed", {
      orderId: order.orderId,
      error: error instanceof Error ? error.message : "Unknown error"
    });
    throw error; // リトライポリシーに従ってリトライされる
  }
}

コスト管理と最適化

Azure Functionsの従量課金プランはコスト効率が高いですが、適切な管理を怠ると想定外のコストが発生することがあります。

コスト構造の理解

従量課金プランの料金は、以下の2つの要素で決まります。

  • 実行回数:100万回あたり約24円(月間100万回まで無料)
  • リソース消費量:GB秒あたり約0.002円(月間40万GB秒まで無料)

たとえば、128MBメモリで1秒の処理を月間500万回実行した場合のコスト概算は以下のとおりです。

  • 実行回数:(500万 - 100万) × 0.000024円 = 約96円
  • リソース消費量:500万 × 0.128GB × 1秒 = 64万GB秒。(64万 - 40万) × 0.002円 = 約480円
  • 合計:約576円/月

コスト最適化のポイント

  • 実行時間の短縮:データベースクエリの最適化、不要なI/Oの削減、非同期処理の活用
  • メモリサイズの適正化:必要以上のメモリを割り当てないように、実際の使用量をモニタリングする
  • 不要な実行の排除:Timerトリガーのスケジュールが適切か定期的に見直す
  • Durable Functionsの活用:長時間のワークフローでは、Durable Functionsのモニターパターンを使って無駄な実行を減らす

Azure全体のコスト管理については、クラウドコスト削減の方法Azure Cost Managementの活用も参照してください。

まとめ:Azure Functionsで効率的な業務自動化を実現する

Azure Functionsは、サーバー管理なしにイベント駆動型の処理を実装できるサーバーレスサービスです。この記事で解説した内容を振り返ります。

  • プラン選定:従量課金プランから始め、要件に応じてPremiumやDedicatedに移行する
  • トリガーとバインディング:宣言的な設定で、少ないコードでAzureサービスと連携できる
  • ローカル開発:Azure Functions Core ToolsとVS Codeで、本番に近い環境でのテストが可能
  • デプロイ:GitHub Actionsによる自動デプロイで、安全かつ迅速なリリースを実現
  • シークレット管理:Azure Key Vault参照を使って、機密情報を安全に管理する
  • 監視:Application Insightsで実行状況を可視化し、リトライポリシーで一時障害に対応する
  • コスト:従量課金の無料枠を活用し、実行時間とメモリの最適化でコストを抑制する

Azure Functionsは、Azure App Serviceで構築したWebアプリのバックエンド処理、Azure Blob Storageのファイル処理、Azure SQL Databaseのデータ集計など、Azureサービスとの連携で真価を発揮します。

認証にはMicrosoft Entra IDを統合し、インフラの構成管理にはTerraformを活用することで、セキュアで再現性の高いサーバーレス基盤を構築できます。

#Azure#Functions#サーバーレス
共有:
無料メルマガ

週1回、最新の技術記事をお届け

AI・クラウド・開発の最新記事を毎週月曜にメールでお届けします。登録は無料、いつでも解除できます。

プライバシーポリシーに基づき管理します

AI活用のヒントをお探しですか?お気軽にご相談ください。

まずは話だけ聞いてもらう