GitHub Actions×Azure Functions実装ガイド|OIDC認証で実現するセキュアなCI/CD(Node.js編)

目次

はじめに

ども!ふと振り返って、ブログを執筆しだして 3 年が経過していることにびっくりした龍ちゃんです。いろいろな開発環境を使っていますが、最近はデプロイする環境なども考えながら開発環境を整備するように至高の変化が起きていました。

今回は、Azure Functions を本番環境で運用するとき、「どうやってデプロイするか」ってお話です。

開発初期以外の手動デプロイは論外として、CI/CD パイプラインを構築するとなると:

  • シークレットキーの管理どうする? – 有効期限切れたら手動更新?
  • デプロイ失敗したときどうする? – 毎回 Azure Portal でログ確認?
  • 複数の Functions どう管理する? – 全部まとめてビルド?それとも個別?

今回は GitHub Actions を使った Azure Functions のデプロイ実装 を実践的に解説します。

特に、OIDC 認証によるパスワードレスデプロイ を採用することで、シークレットキー管理の手間をゼロにできたのが大きな収穫でした。

この記事でわかること

GitHub Actions による Azure Functions デプロイの実装方法
OIDC 認証によるパスワードレスデプロイ(シークレットキー不要)
パス条件トリガーによる効率的な CI/CD
npm ci + キャッシュ戦略
パッケージ構造検証とトラブルシューティング
実測パフォーマンスとベストプラクティス

前提条件

この記事では、以下がセットアップ済みであることを前提としています:

必須環境

  • Azure CLI: バージョン 2.30 以上
  • Azure サブスクリプション: Azure Functions をデプロイするため
  • GitHub リポジトリ: Admin 権限(Secrets/Variables 設定のため)
  • Azure Functions プロジェクト: Node.js + TypeScript
    • Node.js 22: この記事では Node.js 22 を使用
    • Programming Model v4 必須: Node.js 22 を使用する場合、Azure Functions Programming Model v4 への移 行が必須です
    • Azure Functions Runtime v4.25+: Programming Model v4 をサポートするランタイムバージョン
    • @azure/functions v4.0+: Programming Model v4 対応パッケージ

参考記事

OIDC 認証の詳細なセットアップ手順については、以下の記事で詳しく解説しています:

ローカル開発環境の構築については、こちらを参照してください:

GitHub Actions CI/CD フロー全体像

まずは、全体の流れを把握しましょう。

flowchart TD
    A[GitHub Repository main branch] --> B[Push with path filter]
    B --> C[GitHub Actions Workflow]

    C --> D1[1. Checkout code]
    D1 --> D2[2. Setup Node.js 22 with cache]
    D2 --> D3[3. npm ci reproducible install]
    D3 --> D4[4. npm run build TypeScript to JS]
    D4 --> D5[5. Verify package structure]
    D5 --> D5a[host.json validation]
    D5a --> D5b[package.json validation]
    D5b --> D5c[dist/ directory check]
    D5c --> D6[6. npm test --passWithNoTests]
    D6 --> D7[7. Azure Login OIDC no secrets]
    D7 --> D8[8. Check Function App status]
    D8 --> D9[9. Deploy to Azure Functions]
    D9 --> D10[10. Verify deployment]

    D10 --> E[Azure Functions Production]

    style A fill:#e1f5ff
    style C fill:#fff4e1
    style D7 fill:#e8f5e9
    style E fill:#f3e5f5

フローのポイント

  1. パス条件でトリガー – 関連ファイルが変更されたときのみ実行
  2. npm ci でクリーンビルド – 再現性の高いインストール
  3. パッケージ構造検証 – デプロイ前に必須ファイルをチェック
  4. OIDC 認証 – シークレットキー不要のパスワードレス認証
  5. デプロイ後検証 – 成功確認とエンドポイント表示

それでは、各ステップを詳しく見ていきましょう。

ステップ 1: パス条件トリガーの設定

なぜ必要か

モノレポ環境で複数のプロジェクトを管理している場合、フロントエンドの変更でバックエンドの CI/CD が実行される といった無駄なビルドが発生します。

これを防ぐために、パスフィルター を設定します。

プロジェクト構成の確認

プロジェクトのディレクトリ構成は、以下のようなディレクトリ構成を想定しています。:

/
├── application/
│   ├── backend/                          # NestJS API Server
│   ├── frontend/                         # Next.js App Router
│   ├── functions/                        # X Scheduler Functions
│   └── blog-search-mcp-functions/        # Blog Search MCP Functions ⭐
├── .github/
│   └── workflows/
│       ├── deploy-blog-search-mcp-functions.yml  # このワークフロー ⭐
│       ├── deploy-x-scheduler-functions.yml
│       ├── deploy-backend.yml
│       └── deploy-frontend.yml
└── infrastructure/                       # Azure Bicep IaC

ポイント:

  • 各プロジェクトが独立したディレクトリに配置
  • ワークフローファイルも各プロジェクトごとに分離
  • パス条件でトリガーを制御することで、無関係なビルドを防止

実装

name: Deploy Blog Search MCP Functions

on:
  push:
    branches:
      - main
    paths:
      - "application/blog-search-mcp-functions/**"
      - ".github/workflows/deploy-blog-search-mcp-functions.yml"
  workflow_dispatch:
    inputs:
      environment:
        description: "Deployment environment"
        required: true
        default: "production"
        type: choice
        options:
          - production
          - staging
          - dev

ポイント

  • pathsフィルターで 関連ファイルの変更のみトリガー
  • ワークフロー自体の変更もトリガー対象 に含める(.github/workflows/...
  • workflow_dispatch手動実行を可能 にする(緊急時のロールバック等)

効果

実際にこの設定を導入した結果:

  • 不必要なビルド: 70%削減
  • CI/CD コスト: 65%削減
  • デプロイ時間: 50%短縮(並列実行)

ステップ 2: OIDC 認証の設定

OIDC 認証とは

OIDC(OpenID Connect)認証は、短命なトークンを使った認証方式 です。

従来のシークレットキーベース認証との違いを見てみましょう。

従来の認証方式の問題点

# ❌ 非推奨:シークレットベース認証
- uses: azure/login@v2
  with:
    creds: ${{ secrets.AZURE_CREDENTIALS }}

問題:

  • シークレットの有効期限管理が必要
  • 定期的なローテーション作業
  • シークレット漏洩リスク

OIDC 認証の実装

permissions:
  id-token: write # OIDC トークン取得に必要
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: "production"

    steps:
      - name: Azure Login (OIDC)
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

必要な GitHub Secrets

AZURE_CLIENT_ID: xxx-xxx-xxx  (Managed IdentityのClient ID)
AZURE_TENANT_ID: xxx-xxx-xxx  (テナントID)
AZURE_SUBSCRIPTION_ID: xxx-xxx-xxx  (サブスクリプションID)

重要: これらは すべて識別子のみ で、シークレットキーは含まれていません。つまり、万が一漏洩しても、それだけでは Azure にアクセスできない 仕組みです。

OIDC 認証の仕組み(簡略版)

GitHub Actions Job
    ↓
Request OIDC Token (JWT)
    ↓
GitHub OIDC Provider
    ↓
GitHub OIDC Token (5分間有効)
    ↓
Azure AD (トークン交換)
    ↓ (Verify Federated Identity Credential)
User Assigned Managed Identity
    ↓
Azure Access Token (1-24時間有効)
    ↓
Azure Functions Deployment

メリット

  • シークレットキー不要 – パスワードレス認証でセキュリティリスク削減
  • 自動ローテーション – トークンは短命で自動更新、手動ローテーション不要
  • 漏洩リスク最小化 – 識別子のみで、シークレットが存在しない
  • セキュリティベストプラクティス – Microsoft 公式推奨

トークンの有効期限について:

  • GitHub OIDC トークン: 5分間(GitHub が発行する認証用 JWT)
  • Azure アクセストークン: 1時間(Service Principal)または24時間(Managed Identity)
  • 実際のワークフロー実行では Azure アクセストークンが使用されるため、十分な有効期限があります

詳細なセットアップ手順と OIDC 認証の仕組みについては、こちらの記事 を参照してください。

ステップ 3: Node.js セットアップと npm ci

Setup Node.js with Cache

- name: Setup Node.js
  uses: actions/setup-node@v4
  with:
    node-version: "22"
    cache: "npm"
    cache-dependency-path: "application/blog-search-mcp-functions/package-lock.json"

ポイント

  • Node.js 22 LTS を使用(Azure Functions v4 対応)
  • npm キャッシュ を有効化(cache: "npm"
  • cache-dependency-path でモノレポの特定パスを指定

補足: setup-node は package-lock.json のハッシュ値を自動計算してキャッシュキーを生成します。より高度なキャッシング戦略(actions/cache + hashFiles() による明示的制御)については、actions/setup-node 公式リポジトリ を参照してください。

npm ci vs npm install

- name: Install dependencies
  run: |
    cd application/blog-search-mcp-functions
    npm ci  # ✅ npm install ではなく npm ci

npm ci の利点:

  • package-lock.jsonを厳密に尊重(再現性)
  • node_modules/をクリーンインストール
  • CI/CD 環境に最適化(高速)
  • バージョンの不一致を防ぐ

実測値

処理初回キャッシュヒット
npm ci~30 秒~5 秒
npm run build~15 秒~15 秒

キャッシュ効果: ビルド時間 30-40%短縮

ステップ 4: パッケージ構造検証

なぜ必要か

Azure Functions のデプロイは、正しいファイル構成がないと失敗 します。

特に以下のファイルは必須:

  • host.json – Functions App 設定
  • package.json – 依存関係定義
  • dist/ – ビルド成果物(TypeScript → JavaScript)

デプロイ前にこれらを検証することで、失敗を早期に検出 できます。

実装

- name: Verify package structure
  run: |
    cd application/blog-search-mcp-functions
    echo "=== Package root contents ==="
    ls -la
    echo ""

    # host.json検証
    echo "=== Checking host.json ==="
    if [ -f "host.json" ]; then
      echo "✅ host.json exists"
      cat host.json | jq . || echo "⚠️ host.json is not valid JSON"
    else
      echo "❌ host.json missing!"
      exit 1
    fi
    echo ""

    # package.json検証
    echo "=== Checking package.json ==="
    if [ -f "package.json" ]; then
      echo "✅ package.json exists"
      node -e "console.log('✅ package.json is valid JSON')" -p "require('./package.json')"
    else
      echo "❌ package.json missing!"
      exit 1
    fi
    echo ""

    # dist/ ディレクトリ検証
    echo "=== Checking for compiled files in dist ==="
    if [ -d "dist" ]; then
      echo "✅ dist directory exists"
      find dist -name "*.js" | head -10
    else
      echo "❌ dist directory missing!"
      exit 1
    fi
    echo ""

    echo "=== All files in package (first 50) ==="
    find . -type f | head -50

ポイント

  • jqで JSON 妥当性検証
  • ✅ Node.js でrequire()テスト(構文エラー検出)
  • ✅ 失敗時はexit 1で即座にワークフロー停止
  • ✅ ログ出力を見やすくフォーマット

実際のログ出力例

=== Package root contents ===
drwxr-xr-x  dist
-rw-r--r--  host.json
-rw-r--r--  package.json
...

=== Checking host.json ===
✅ host.json exists
{
  "version": "2.0",
  "extensionBundle": {
    "id": "Microsoft.Azure.Functions.ExtensionBundle.Experimental",
    "version": "[4.*, 5.0.0)"
  }
}

=== Checking package.json ===
✅ package.json exists
✅ package.json is valid JSON

=== Checking for compiled files in dist ===
✅ dist directory exists
dist/src/app.js
dist/src/functions/searchBlogPosts.mcp.js
...

この検証により、デプロイ失敗の原因を事前に特定 できます。

ステップ 5: テスト実行

–passWithNoTests フラグ

プロジェクト初期段階では、テストファイルがないことがあります。

- name: Run tests
  run: |
    cd application/blog-search-mcp-functions
    npm test -- --passWithNoTests

なぜ必要か

Jest のデフォルト動作では、テストが見つからない場合はexit code 1で失敗 します。

--passWithNoTestsフラグを使うことで:

  • ✅ テストファイルがなくても CI/CD が通る
  • ✅ 将来テストを追加した際、自動的にテストが実行される
  • ✅ 開発初期段階の CI/CD 構築に最適

推奨アプローチ

  1. プロジェクト初期(テストなし): --passWithNoTests使用
  2. テスト追加開始: フラグ維持、段階的にテスト追加
  3. テストカバレッジ確立後: フラグ削除(テスト必須化)

ステップ 6: Azure Functions デプロイ

デプロイ前の確認

- name: Check Function App status before deployment
  run: |
    echo "Checking current Function App status..."
    az functionapp show \
      --name ${{ vars.BLOG_SEARCH_MCP_FUNCTION_APP_NAME }} \
      --resource-group ${{ vars.RESOURCE_GROUP }} \
      --query "{name:name, state:state, kind:kind}" \
      --output table

現在の Function App の状態を確認することで、デプロイ前の異常を検出できます。

デプロイ実行

- name: Deploy to Azure Functions
  uses: Azure/functions-action@v1
  with:
    app-name: ${{ vars.BLOG_SEARCH_MCP_FUNCTION_APP_NAME }}
    package: "application/blog-search-mcp-functions"
    respect-funcignore: true
    scm-do-build-during-deployment: false
    enable-oryx-build: false
  id: deploy

デプロイを実行する際は、作成しているAzure Functionsのアプリ名のみで指定をすることができます。

デプロイ設定の詳細

respect-funcignore: true

.funcignoreファイルを尊重し、不要なファイルをデプロイパッケージから除外します。

# .funcignore
*.ts
src/
tsconfig.json
.git/
.github/
node_modules/
tests/
*.md

効果:

  • デプロイパッケージサイズを最小化
  • ビルド成果物(dist/)のみアップロード
  • デプロイ時間短縮

scm-do-build-during-deployment: false

Azure 側でのビルドをスキップします。

理由:

  • GitHub Actions 側で事前ビルド済み
  • デプロイ時間短縮
  • 予測可能性向上

enable-oryx-build: false

Oryx(Azure 自動ビルドシステム)を無効化します。

理由:

  • 明示的なビルドプロセス管理
  • トラブルシューティングが容易

⚠️ 設定の互換性に関する重要な注意事項

WEBSITE_RUN_FROM_PACKAGE との非互換性

以下の設定の組み合わせは互換性がありません

  • WEBSITE_RUN_FROM_PACKAGE=1 + SCM_DO_BUILD_DURING_DEPLOYMENT=true(非互換)
  • WEBSITE_RUN_FROM_PACKAGE=1 + SCM_DO_BUILD_DURING_DEPLOYMENT=false(推奨)

理由: WEBSITE_RUN_FROM_PACKAGE は ZIP パッケージから直接実行する設定であり、デプロイ時のビルドと競合します。

リモートビルドを有効化する場合(Linux):

ネイティブモジュール(Puppeteer、Sharp等)を使用する場合は、リモートビルドが必要です:

- name: Deploy to Azure Functions
  uses: Azure/functions-action@v1
  with:
    app-name: ${{ vars.FUNCTION_APP_NAME }}
    package: "path/to/function"
    scm-do-build-during-deployment: true   # リモートビルド有効化
    enable-oryx-build: true                # Oryx ビルド有効化

注意: 両方を true に設定する必要があります(Linuxのみ)。

ステップ 7: デプロイ後検証

成功時の検証

- name: Verify deployment success
  if: success()
  run: |
    echo "✅ Deployment successful. Verifying MCP Server..."
    sleep 30  # Function App起動待機

    # アプリ設定確認
    az functionapp config show \
      --name ${{ vars.BLOG_SEARCH_MCP_FUNCTION_APP_NAME }} \
      --resource-group ${{ vars.RESOURCE_GROUP }} \
      --query "{nodeVersion:nodeVersion, platform:linuxFxVersion}" \
      --output table

    # Function App URL取得
    FUNCTION_APP_URL=$(az functionapp show \
      --name ${{ vars.BLOG_SEARCH_MCP_FUNCTION_APP_NAME }} \
      --resource-group ${{ vars.RESOURCE_GROUP }} \
      --query "defaultHostName" \
      --output tsv)

    echo "MCP Endpoint: https://$FUNCTION_APP_URL/runtime/webhooks/mcp/sse"

ポイント

  • sleep 30で Function App 起動待機(コールドスタート対策)
  • ✅ Node.js バージョン確認(意図しないバージョン使用防止)
  • ✅ エンドポイント URL を明示的に表示(手動テスト用)

失敗時のリカバリー

- name: Check deployment result and restart if needed
  if: failure()
  run: |
    echo "❌ Deployment failed. Attempting recovery..."
    echo "Restarting Function App..."
    az functionapp restart \
      --name ${{ vars.BLOG_SEARCH_MCP_FUNCTION_APP_NAME }} \
      --resource-group ${{ vars.RESOURCE_GROUP }}

    echo "Waiting for restart to complete..."
    sleep 60

    echo "Checking Function App logs..."
    az functionapp logs tail \
      --name ${{ vars.BLOG_SEARCH_MCP_FUNCTION_APP_NAME }} \
      --resource-group ${{ vars.RESOURCE_GROUP }} \
      --timeout 60 || echo "Could not retrieve logs"

自動リカバリーの利点

  • ✅ デプロイ失敗後の手動介入を減らす
  • ✅ ログ取得による問題診断の容易化
  • ✅ 一時的な問題(ネットワークエラーなど)からの自動復旧

実装例:Blog Search MCP Functions

ここまでの設定を統合した完全なワークフローファイルを見てみましょう。

完全なワークフロー

name: Deploy Blog Search MCP Functions

on:
  push:
    branches:
      - main
    paths:
      - "application/blog-search-mcp-functions/**"
      - ".github/workflows/deploy-blog-search-mcp-functions.yml"
  workflow_dispatch:

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: "production"

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "22"
          cache: "npm"
          cache-dependency-path: "application/blog-search-mcp-functions/package-lock.json"

      - name: Install dependencies
        run: |
          cd application/blog-search-mcp-functions
          npm ci

      - name: Build Functions
        run: |
          cd application/blog-search-mcp-functions
          npm run build

      - name: Verify package structure
        run: |
          cd application/blog-search-mcp-functions
          # ... (前述の検証スクリプト)

      - name: Run tests
        run: |
          cd application/blog-search-mcp-functions
          npm test -- --passWithNoTests

      - name: Azure Login (OIDC)
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - name: Deploy to Azure Functions
        uses: Azure/functions-action@v1
        with:
          app-name: ${{ vars.BLOG_SEARCH_MCP_FUNCTION_APP_NAME }}
          package: "application/blog-search-mcp-functions"
          respect-funcignore: true
          scm-do-build-during-deployment: false
          enable-oryx-build: false

      - name: Verify deployment success
        if: success()
        run: |
          # ... (前述の検証スクリプト)

プロジェクト構成

application/blog-search-mcp-functions/
├── package.json
├── tsconfig.json
├── host.json              # Experimental Bundle設定
├── .funcignore            # デプロイ除外ファイル
├── src/
│   ├── app.ts             # エントリーポイント
│   ├── functions/         # MCP Tool定義
│   │   ├── searchBlogPosts.mcp.ts
│   │   ├── listAllCategories.mcp.ts
│   │   └── listAllHashtags.mcp.ts
│   └── blog-search-mcp/   # 共通モジュール
│       ├── types/
│       ├── schemas/
│       └── services/
└── dist/                  # ビルド成果物(TypeScript → JS)

package.json

{
  "name": "blog-search-mcp-functions",
  "version": "1.0.0",
  "scripts": {
    "build": "tsc",
    "start": "npm run build && func start",
    "test": "jest --passWithNoTests"
  },
  "dependencies": {
    "@azure/functions": "^4.0.0",
    "@supabase/supabase-js": "^2.76.1",
    "zod": "^4.1.12"
  },
  "devDependencies": {
    "@types/node": "^22.10.1",
    "typescript": "^5.7.2"
  },
  "engines": {
    "node": ">=22.0.0"
  }
}

Environment 変数 vs Secrets

GitHub Secrets と Variables の適切な使い分けも重要です。

使い分けの基準

Secrets(機密情報):

secrets:
  AZURE_CLIENT_ID        # OIDC認証情報
  AZURE_TENANT_ID
  AZURE_SUBSCRIPTION_ID

Variables(非機密情報):

variables:
  APP_NAME                           # アプリケーション名
  RESOURCE_GROUP                     # リソースグループ名
  BLOG_SEARCH_MCP_FUNCTION_APP_NAME  # Function App名
  X_SCHEDULER_FUNCTION_APP_NAME      # Function App名

判断基準

  • Secrets: 漏洩すると重大な影響(認証情報、API キー、トークン)
  • Variables: 公開されても問題ない(リソース名、設定値)

設定方法

手動設定

GitHub リポジトリの「Settings」→「Secrets and variables」→「Actions」から設定します。

自動設定(推奨)

Bicep デプロイスクリプト(deploy.sh)で自動設定することも可能です:

# GitHub CLI の存在確認
if command -v gh &> /dev/null; then
    echo "GitHub CLIを使用してシークレットを設定中..."

    # Repository secrets(リポジトリ全体で共通)
    echo "$MANAGED_IDENTITY_CLIENT_ID" | gh secret set AZURE_CLIENT_ID --repo "$GITHUB_ORG/$GITHUB_REPO"

    # Environment variables(環境ごと)
    gh variable set BLOG_SEARCH_MCP_FUNCTION_APP_NAME \
      --repo "$GITHUB_ORG/$GITHUB_REPO" \
      --env production \
      --body "$BLOG_SEARCH_MCP_FUNCTION_APP_NAME"
fi

メリット:

  • インフラデプロイと GitHub 設定を一括実行
  • 手動設定ミスの防止
  • 環境構築の再現性向上

パフォーマンス実測値

実際に運用している環境での実測値を紹介します。

ビルド時間(Blog Search MCP Functions)

ステップ初回キャッシュヒット
Setup Node.js~10 秒~10 秒
npm ci~30 秒~5 秒
npm run build~15 秒~15 秒
Deploy~2-8 分~2-8 分
合計約 3-9 分約 2.5-8.5 分

: デプロイ時間は、関数のパッケージサイズ、依存関係の数、Azure リージョンの混雑状況によって大きく変動します。

  • 小規模関数(最小限の依存関係):約 2-3 分
  • 中規模関数(一般的な依存関係):約 5-8 分
  • 大規模関数(多数の依存関係):約 10-15 分

上記の実測値は、小規模な MCP Functions の場合です。本番環境での一般的なアプリケーションでは、5-15 分程度を見込むことを推奨します。

最適化効果

最適化項目効果
パスフィルター導入不必要なビルド 70%削減
npm キャッシュビルド時間 30-40%短縮
並列ワークフロー全体デプロイ時間 50%短縮

トラブルシューティング

よくあるエラーと対処法をまとめます。

エラー 1: Package deployment failed

症状:

Error: Package deployment failed

原因:

  • host.jsonがパッケージに含まれていない
  • package.jsonが不正な JSON
  • dist/ディレクトリが空

解決策:
パッケージ構造検証ステップを追加し、.funcignoreを確認します。

- name: Verify package structure
  run: |
    # host.json, package.json, dist/ の検証

エラー 2: OIDC token exchange failed

症状:

Error: OIDC token exchange failed

原因:

  • Federated Identity Credential の設定ミス
  • permissions: id-token: writeの欠落

解決策:

  1. permissions 確認:
permissions:
  id-token: write # 必須
  contents: read
  1. Federated Credential 確認:
    Azure Portal で、User Assigned Managed Identity の「Federated credentials」を確認し、subject パターンが一致しているか確認します。
repo:org/repo:environment:production

詳細は こちらの記事 を参照してください。

エラー 3: Function runtime error

症状:
デプロイは成功するが、Function App が起動しない

原因:

  • Node.js バージョン不一致
  • 依存関係の欠落

解決策:

デプロイ後に Node.js バージョンを確認:

az functionapp config show \
  --name <app-name> \
  --resource-group <rg> \
  --query "nodeVersion"

package.jsonenginesフィールドと一致しているか確認します。

{
  "engines": {
    "node": ">=22.0.0"
  }
}

エラー 4: npm ci fails

症状:

Error: npm ci can only install packages when your package.json and package-lock.json are in sync

原因:
package.jsonpackage-lock.jsonの不一致

解決策:

ローカルでpackage-lock.jsonを再生成:

rm package-lock.json
npm install
git add package-lock.json
git commit -m "chore: regenerate package-lock.json"

実装のポイントまとめ

カテゴリ✅ DO(推奨)❌ DON’T(非推奨)
認証OIDC 認証を使用
・パスワードレス、セキュア
・シークレット管理不要
・自動ローテーション
シークレットベース認証
・有効期限管理の負担
・定期的なローテーション作業
・漏洩リスク
依存関係管理npm ci を使用
package-lock.jsonを厳密に尊重
・再現性、高速性
・CI/CD 専用の最適化
npm install 使用
・バージョン不一致リスク
・再現性が低い
・予期しない依存関係の更新
トリガー設定パスフィルターを設定
・不必要なビルド 70%削減
・CI/CD コスト 65%削減
・デプロイ時間 50%短縮
パスフィルターなし
・すべての変更でビルド実行
・リソース浪費
・CI/CD コスト増大
テスト–passWithNoTests(初期段階)
・テストなしでも CI/CD 通過
・段階的なテスト追加
・開発速度維持
テスト必須化(初期段階)
・開発速度低下
・CI/CD 構築の遅延
・実装優先フェーズで障害
検証パッケージ構造検証
・デプロイ前の構造確認
・失敗の早期検出
・デバッグ時間短縮
手動検証のみ
・人的ミス防止できない
・デプロイ失敗後に気づく
・手戻りコスト増大
デプロイ設定事前ビルド戦略
scm-do-build: false
enable-oryx-build: false
・GitHub Actions 側で事前ビルド
Azure 側ビルド
scm-do-build: true
・デプロイ時間が長い
・予測可能性が低い
リカバリー自動リカバリー処理
・失敗時の自動再起動
・ログ自動取得
・一時的な問題から自動復旧
手動リカバリーのみ
・毎回手動介入が必要
・復旧時間が長い
・夜間デプロイ失敗時の対応遅延

: 本番環境に移行する際は、--passWithNoTests フラグを削除してテストを必須化しましょう。品質保証のため、テストカバレッジを確立した後は必ずテストが実行される状態にすることを推奨します。

まとめ

この記事で実装したこと

GitHub Actions による Azure Functions デプロイパイプライン
OIDC 認証によるパスワードレスデプロイ
パス条件トリガーで効率化(不要なビルド 70%削減)
npm ci + キャッシュで高速化(ビルド時間 30-40%短縮)
パッケージ構造検証で品質保証
自動リカバリー処理

得られる効果

セキュリティ面:

  • シークレットキー管理不要
  • 自動ローテーション
  • 漏洩リスク最小化

効率面:

  • デプロイ時間短縮(小規模関数で約 2-3 分、一般的には 5-15 分)
  • CI/CD コスト削減(65%)
  • 手動作業の削減

品質面:

  • デプロイ失敗の早期検出
  • 自動検証とリカバリー
  • 再現性の高いビルド

次のステップ

さらに発展させるには:

  1. マルチ環境デプロイ – staging/production 環境の管理
  2. Bicep 統合 – インフラと CI/CD の完全自動化
  3. Python 版 – Python Runtime での実装
  4. モニタリング統合 – Application Insights との連携

参考リンク

公式ドキュメント

関連記事


GitHub Actions を使った Azure Functions のデプロイ、ぜひ試してみてください!

OIDC 認証によるパスワードレスデプロイで、セキュリティと効率性の両方を手に入れられます。

質問や改善提案があれば、ぜひコメントで教えてください!

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です