はじめに どうも、龍ちゃんです! 今月は Azure Functions を使ったサーバーレス開発に取り組んでいるのですが、ローカル開発環境の構築で結構ハマりポイントがあったので、その知見を共有したいと思います。 サンプルリポジトリ : 本記事で解説する環境をすぐに試せるサンプルコードを公開しています。 GitHub : azure-functions-nodejs-devcontainer クローンして DevContainer で開くだけで、すぐに動作確認できます! 特に、 DevContainer を使った環境構築 は、チーム開発で環境差異をなくすために非常に有効なアプローチです。前回の「 Claude Code×DevContainer 環境構築ガイド 」でも DevContainer の便利さを紹介しましたが、今回は Azure Functions に特化した DevContainer 環境構築 を解説します。 なぜ DevContainer で Azure Functions なのか? 私が DevContainer を推奨する理由はいくつかあります: 1. 再現性のある環境構築 チームメンバー全員が同じ環境で開発できます。「自分の環境では動くのに…」という問題、ありますよね。これが完全になくなります! 2. ホスト OS を汚さない Node.js のバージョン、npm のグローバルパッケージ、Azure Functions Core Tools など、すべてコンテナ内で完結 3. プロジェクトごとに異なるバージョンを使い分け プロジェクト A は Node.js 18、プロジェクト B は Node.js 22 といった使い分けが簡単 今回は、 Node.js 22 + TypeScript で Azure Functions の開発環境を構築します。次回の「Python 編」では Python 3.11 を使った環境構築も紹介しますので、お楽しみに! Azure Functions とは? Azure Functions は、 サーバーレスコンピューティング のサービスです。サーバーの管理をせずに、コードだけを書いて実行できます。 主要なトリガー Azure Functions では、さまざまな「トリガー」でコードを実行できます: トリガー 用途 例 HTTP Trigger REST API、Webhook API エンドポイント作成 Timer Trigger 定期実行 毎日深夜にバッチ処理 Blob Trigger ファイルアップロード 画像アップロード時に圧縮 Queue Trigger メッセージキュー 非同期タスク処理 今回は、 HTTP Trigger と Timer Trigger を使ってローカル開発環境を構築します。次回の記事では、この 2 つを組み合わせた 実践パターン (Timer Trigger を HTTP Trigger でデバッグする方法)を紹介する予定です。 なぜローカル開発環境が必要なのか Azure にデプロイしてからデバッグするのって、めちゃくちゃ時間かかりますよね。ローカル環境があれば: 即座にデバッグ – コードを変更したら即座に動作確認! ログ確認が簡単 – コンソールに直接ログが表示される コスト削減 – ローカルでのテストは Azure の課金対象外 前提条件 本記事では、以下がインストール済みであることを前提とします: 必須 Docker Desktop – DevContainer を使うために必須 インストール方法: Docker Desktop 公式サイト 動作確認: docker --version で Docker version 24.x.x 以上が表示されること Visual Studio Code – エディタ インストール方法: VSCode 公式サイト 本記事でインストールするもの Dev Containers 拡張機能 – VSCode でインストール Node.js 22、Azure Functions Core Tools、Azurite – DevContainer 内で自動インストール 必要なツール一覧 DevContainer を使った Azure Functions 開発に必要なツールは以下の通りです: ツール名 バージョン 役割 インストール先 Docker Desktop 最新 コンテナランタイム ホスト OS(前提) Visual Studio Code 最新 エディタ ホスト OS(前提) Dev Containers 拡張機能 最新 DevContainer サポート VSCode Node.js 22.x LTS JavaScript ランタイム DevContainer 内で自動 Azure Functions Core Tools v4.x ローカル実行・デバッグ DevContainer 内で自動 Azurite 最新 Azure Storage エミュレータ DevContainer 内で自動 ポイント : ホスト OS には Docker Desktop と VSCode が既にインストール済み Node.js、Core Tools、Azurite は DevContainer 内で自動的にインストール これにより、ホスト OS を汚さずに開発環境を構築可能 Dev Containers 拡張機能のインストール VSCode に Dev Containers 拡張機能をインストールします。 VSCode を起動 拡張機能パネルを開く( Ctrl+Shift+X / Cmd+Shift+X ) 「 Dev Containers 」で検索 「 Dev Containers 」(ID: ms-vscode-remote.remote-containers )をインストール 動作確認 : VSCode 左下に「 >< 」アイコンが表示されていることを確認 このアイコンをクリックすると、DevContainer 関連のコマンドが表示される Node.js DevContainer の構築 これから構築する環境の全体像を把握しましょう。 構築後のディレクトリ構成 azure-functions-nodejs-devcontainer/ # プロジェクトルート ├── .devcontainer/ # DevContainer 設定 │ ├── Dockerfile # コンテナイメージ定義 │ └── devcontainer.json # DevContainer 設定ファイル │ └── MyFunctionApp/ # Azure Functions プロジェクト ├── .funcignore # デプロイ除外ファイル ├── .gitignore # Git 除外設定 ├── host.json # Functions ランタイム設定 ├── local.settings.json # ローカル環境変数 ├── package.json # npm 依存関係 ├── tsconfig.json # TypeScript 設定 │ └── src/ # ソースコード └── functions/ # 関数ファイル ├── HttpExample.ts # HTTP Trigger 関数 └── TimerExample.ts # Timer Trigger 関数 ポイント : .devcontainer/ で開発環境を定義 MyFunctionApp/ が実際の Functions プロジェクト TypeScript ファイルは src/functions/ 配下に配置 構築方法 DevContainer を構築する方法は主に 2 つあります: Dockerfile 方式 – カスタム Dockerfile で詳細に制御(推奨) PostCreateCommand 方式 – 既存イメージにコマンドを追加 方法 1: Dockerfile 方式(推奨) この方式は、再現性が高く、ビルド時間も短いため推奨します。 ステップ 1: プロジェクトディレクトリの作成 mkdir azure-functions-nodejs-devcontainer cd azure-functions-nodejs-devcontainer mkdir .devcontainer ステップ 2: Dockerfile の作成 .devcontainer/Dockerfile を作成: # .devcontainer/Dockerfile FROM mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm # 作業ディレクトリ WORKDIR /workspace # 実行ユーザー USER node # Azure Functions Core Tools と Azurite のインストール RUN npm install -g \ npm@11.5.2 \ azure-functions-core-tools@4 \ azurite # バージョン確認用コマンド(デバッグ用) RUN echo "=== Installed Versions ===" \ && node --version \ && npm --version \ && func --version \ && echo "=========================" # デフォルトコマンド(devContainer では sleep infinity で上書きされる) CMD ["sleep", "infinity"] ポイント : mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm は Microsoft 公式の Node.js 22 + TypeScript イメージ azure-functions-core-tools@4 で Azure Functions v4 ランタイムをインストール azurite は Timer Trigger のローカル実行に必須! ステップ 3: devcontainer.json の作成 .devcontainer/devcontainer.json を作成: { "name": "Azure Functions Node.js DevContainer", "build": { "dockerfile": "./Dockerfile" }, "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", "remoteUser": "node", "forwardPorts": [7071, 10000, 10001, 10002], "customizations": { "vscode": { "extensions": [ "ms-azuretools.vscode-azurefunctions", "dbaeumer.vscode-eslint", "esbenp.prettier-vscode" ] } } } ポイント : forwardPorts : Azure Functions (7071) と Azurite (10000-10002) のポート転送を設定 extensions : Azure Functions 拡張機能、ESLint、Prettier を自動インストール ステップ 4: DevContainer の起動 VSCode で azure-functions-nodejs-devcontainer フォルダを開く 左下の「 >< 」アイコンをクリック 「 Reopen in Container 」を選択 Docker イメージのビルドと起動が開始されます(初回は 5-10 分程度) 成功すると : VSCode の左下に「 Dev Container: Azure Functions Node.js DevContainer 」と表示 ターミナルを開くと、コンテナ内のシェルが起動 方法 2: PostCreateCommand 方式 既存イメージを使い、起動後にコマンドでツールをインストールする方式です。 .devcontainer/devcontainer.json : { "name": "Azure Functions Node.js DevContainer", "image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm", "workspaceFolder": "/workspace", "remoteUser": "node", "postCreateCommand": "npm install -g npm@11.5.2 azure-functions-core-tools@4 azurite", "forwardPorts": [7071, 10000, 10001, 10002], "customizations": { "vscode": { "extensions": [ "ms-azuretools.vscode-azurefunctions", "dbaeumer.vscode-eslint", "esbenp.prettier-vscode" ] } } } メリット : 設定ファイル 1 つで完結 シンプルでわかりやすい デメリット : DevContainer 起動のたびにインストールが実行される(起動が遅い) Dockerfile 方式の方が確実性が高く、再現性に優れる 私は Dockerfile 方式 を推奨します。 Functions プロジェクトの作成 DevContainer 内で Azure Functions プロジェクトを作成します。 プロジェクト初期化 DevContainer 内のターミナルで実行: func init MyFunctionApp --typescript cd MyFunctionApp 生成されるファイル : MyFunctionApp/ ├── .funcignore # Functions デプロイ時の除外ファイル ├── .gitignore # Git 除外設定 ├── host.json # Functions ランタイム設定 ├── local.settings.json # ローカル環境変数 ├── package.json # npm 依存関係 ├── tsconfig.json # TypeScript 設定 └── src/ # ソースコード格納ディレクトリ local.settings.json の設定 local.settings.json を編集して、Azurite 接続設定を追加: { "IsEncrypted": false, "Values": { "AzureWebJobsStorage": "UseDevelopmentStorage=true", "FUNCTIONS_WORKER_RUNTIME": "node" } } 重要 : AzureWebJobsStorage: "UseDevelopmentStorage=true" は Azurite を使用するための設定 この設定がないと Timer Trigger でエラーになるので注意! 依存関係のインストール npm install HTTP Trigger の作成と動作確認 まずは、基本的な HTTP Trigger を作成して動作確認します。 HTTP Trigger 関数の作成 func new --name HttpExample --template "HTTP trigger" --authlevel "anonymous" 生成されるファイル : src/functions/HttpExample.ts 実装内容の確認 src/functions/HttpExample.ts : import { app, HttpRequest, HttpResponseInit, InvocationContext, } from "@azure/functions"; export async function HttpExample( request: HttpRequest, context: InvocationContext ): Promise<HttpResponseInit> { context.log("HTTP trigger function processed a request."); const name = request.query.get("name") || "World"; return { status: 200, body: `Hello, ${name}!`, }; } app.http("HttpExample", { methods: ["GET", "POST"], authLevel: "anonymous", handler: HttpExample, }); ポイント : request.query.get('name') でクエリパラメータを取得 app.http() でエンドポイントを登録 ローカル実行 npm start 実行結果 : 動作確認 別のターミナルで curl コマンドを実行: curl "http://localhost:7071/api/HttpExample?name=Azure" 期待される結果 : Hello, Azure! ブラウザでの確認 : http://localhost:7071/api/HttpExample にアクセスすると「Hello, World!」と表示されます Azurite と Timer Trigger Timer Trigger を使うには、 Azurite (Azure Storage エミュレータ)が必要です。 なぜ Azurite が必要なのか? Azure Functions の Timer Trigger は、内部的に Blob Storage を使って Timer の状態(次回実行時刻など)を保存します。ローカル開発では、この Blob Storage を Azurite でエミュレートするんですね。 HTTP Trigger のみの場合 : Azurite 不要 Timer Trigger を使う場合 : Azurite 必須! Azurite の起動 DevContainer 内で、 別のターミナル を開いて Azurite を起動します: azurite --silent # 設定やログを保存する先を指定 azurite --location .azurite --debug .azurite/debug.log 期待される結果 : Azurite Blob service is starting at http://127.0.0.1:10000 Azurite Blob service is successfully listening at http://127.0.0.1:10000 Azurite Queue service is starting at http://127.0.0.1:10001 Azurite Queue service is successfully listening at http://127.0.0.1:10001 Azurite Table service is starting at http://127.0.0.1:10002 Azurite Table service is successfully listening at http://127.0.0.1:10002 デフォルトポート : Blob Service: 10000 Queue Service: 10001 Table Service: 10002 Timer Trigger 関数の作成 func new --name TimerExample --template "Timer trigger" 生成されるファイル : src/functions/TimerExample.ts 実装内容の確認 src/functions/TimerExample.ts : import { app, InvocationContext, Timer } from "@azure/functions"; export async function TimerExample( myTimer: Timer, context: InvocationContext ): Promise<void> { context.log("Timer trigger function executed at:", new Date().toISOString()); if (myTimer.isPastDue) { context.log("Timer is running late!"); } } app.timer("TimerExample", { schedule: "0 */5 * * * *", // 5分ごとに実行 handler: TimerExample, }); CRON 式の説明 : 0 */5 * * * * は 5 分ごとに実行 CRON 式は UTC 時刻 で動作(重要!) ローカル実行 Azurite が起動している状態で、Functions を起動: npm start 実行結果 : 5 分ごとにログが表示されます。 Azurite が起動していない場合のエラー Azurite が起動していないと、以下のエラーが発生します: [Error] Microsoft.Azure.WebJobs.Host: Error indexing method 'TimerExample'. → 対処法 : Azurite を起動してから Functions を再起動 トラブルシューティング よくあるエラーと対処法をまとめます。 1. Docker Desktop が起動しない 症状 : VSCode で「Docker daemon is not running」エラー 対処法 : Docker Desktop を起動する(Windows/Mac) Linux の場合: sudo systemctl start docker 2. DevContainer のビルドが失敗する 症状 : 「Failed to build image」エラー 対処法 : Dockerfile の構文エラーを確認 Docker Desktop のディスク容量を確認 VSCode のコマンドパレット( Ctrl+Shift+P )→「Dev Containers: Rebuild Container」を実行 3. func コマンドが見つからない 症状 : bash: func: command not found 対処法 : DevContainer が正しくビルドされているか確認 ターミナルを再起動 Dockerfile の npm install -g azure-functions-core-tools@4 が正しく実行されているか確認 4. Azurite 接続エラー 症状 : No connection could be made because the target machine actively refused it 対処法 : Azurite が起動しているか確認( curl http://127.0.0.1:10000 ) local.settings.json に AzureWebJobsStorage: "UseDevelopmentStorage=true" が設定されているか確認 Azurite を再起動 5. ポート競合エラー 症状 : Port 7071 is already in use 対処法 : 既存のプロセスを終了 別のポートで起動: func start --port 7072 6. TypeScript コンパイルエラー 症状 : npm start で TypeScript エラー 対処法 : npm install を実行して依存関係を再インストール tsconfig.json の設定を確認 npm run build で明示的にビルド 開発の推奨フロー DevContainer を使った Azure Functions 開発の推奨フローです。 標準的な開発手順 ターミナル 1: Azurite 起動 azurite --silent ターミナル 2: Functions ランタイム起動 cd MyFunctionApp npm start 開発作業 TypeScript ファイル( .ts )を編集 保存すると自動的にリロード(watch mode) 動作確認 HTTP Trigger: curl やブラウザでアクセス Timer Trigger: コンソールログで確認 VSCode のターミナル分割 VSCode のターミナルを分割すると便利です: ターミナル 1 : Azurite 起動( azurite --silent ) ターミナル 2 : Functions 起動( npm start ) ターミナル 3 : curl コマンドやその他の操作 分割方法 : ターミナルパネルの右上の「 + 」アイコン横の「 Split Terminal 」ボタン または Ctrl+Shift+5 / Cmd+Shift+5 推奨 VSCode 拡張機能 DevContainer 内で自動的にインストールされる拡張機能以外にも、以下があると便利です: Azure Functions ( ms-azuretools.vscode-azurefunctions ) – 既に設定済み ESLint ( dbaeumer.vscode-eslint ) – 既に設定済み Prettier ( esbenp.prettier-vscode ) – 既に設定済み Thunder Client ( rangav.vscode-thunder-client ) – HTTP クライアント(任意) まとめと次回予告 本記事で学んだこと DevContainer を使った Azure Functions 環境構築 Docker Desktop と VSCode のインストール Node.js 22 + TypeScript の DevContainer 構築 Dockerfile 方式と PostCreateCommand 方式の違い Azure Functions の基本 HTTP Trigger の作成と動作確認 Timer Trigger と Azurite の関係 ローカル開発環境での実行方法 トラブルシューティング よくあるエラーと対処法 Azurite 接続エラーの解決方法 次回の記事予告 次回は、以下の内容を予定しています: Azure Functions×DevContainer 環境構築| Python 編 Python 3.11 を使った DevContainer 構築 Node.js 版との違い Python 仮想環境との組み合わせ Azure Functions 入門| HTTP Trigger と Timer Trigger の基礎と実践パターン HTTP Trigger と Timer Trigger の詳細な使い方 実践パターン : Timer Trigger を HTTP Trigger でデバッグする方法 タイムゾーン(UTC/JST)の扱い方 DRY 原則に基づいた共通ロジックの設計 サンプルリポジトリ 本記事で解説した環境を、すぐに試せるサンプルコードを公開しています: GitHub : azure-functions-nodejs-devcontainer Node.js 22 + TypeScript HTTP Trigger + Timer Trigger 実装済み DevContainer 設定ファイル完備 クローンして VSCode で開くだけで動作します 関連記事 Claude Code×DevContainer 環境構築ガイド – Node.js・Python 対応 DevContainer の基本的な使い方 npm グローバルインストールの注意点 DevContainer を使った Azure Functions 開発、ぜひ試してみてください! チーム開発での環境差異がなくなり、開発効率が大幅に向上すること間違いなしです。 次回は Python 編 をお届けしますので、お楽しみに〜! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Azure Functions×DevContainer環境構築|Node.js 22 + TypeScript first appeared on SIOS Tech. Lab .