はじめに
どうも、龍ちゃんです!
今月は 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 installHTTP 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 編をお届けしますので、お楽しみに〜!

