「Docker で動かしているはずの Azure Functions が、なぜか fuse.zip をマウントして Zip Deploy(Run‑From‑Package)として起動してしまう」——この症状は、過去のデプロイ痕跡が優先されることで起きます。原因の構造を正しく押さえ、競合設定を無効化し、不要ファイルを掃除するだけで、コンテナ内のコードが確実に使われ、イメージ更新も即時に反映される状態に戻せます。
現象の概要と観測ポイント
Function App を linuxFxVersion = DOCKER|<image>:<tag> に設定しているにもかかわらず、実機では /home/site/wwwroot に fuse.zip がマウントされ、コンテナに内包したコードが無視される現象です。結果として、新しいイメージを push してもアプリに反映されません。
- 確認済みの前提:
WEBSITE_RUN_FROM_PACKAGEは App Settings に存在しない/イメージとタグ指定は正しい/Linux コンテナベースの Function App。 - 望まれる状態:Zip Deploy の挙動を無効化し、Docker イメージ内のコードが 唯一の実行ソースになること。イメージ更新の即時反映。
以下では、なぜ Zip Deploy が優先されるのかのメカニズム、確実に解消する手順、再発防止の運用指針までを一気通貫で解説します。
なぜ Zip Deploy(Run‑From‑Package)が勝ってしまうのか
Azure Functions(App Service 基盤)は、起動時に「どこからアプリの実体をマウントするか」を段階的に評価します。Docker コンテナであっても、プラットフォームは 過去の Run‑From‑Package の痕跡 が残っていればそれを優先します。キーとなるのが次のファイルです。
/home/data/SitePackages/packagename.txt
このテキストには、最後にデプロイした ZIP パッケージのパスが記録されます。App Settings から WEBSITE_RUN_FROM_PACKAGE を削除していても、packagename.txt が残っている限り、プラットフォームは ZIP を FUSE でマウントし、/home/site/wwwroot を fuse.zip で置き換えます。これが「Docker にしたのに ZIP が乗ってくる」根本原因です。
さらに、VS Code の Zip デプロイ、CLI の az functionapp deployment source config-zip、ポータルの Deployment Center などは、このファイルを自動生成することがあるため、一度でも Zip Deploy を使うと痕跡が残り続けます。
対処の全体像(結論の早見表)
| ステップ | 対応内容 | 目的/効果 | コマンド例 |
|---|---|---|---|
| 原因の理解 | /home/data/SitePackages/packagename.txt が残っていると Run‑From‑Package が優先される。 | 誤作動のトリガーを特定。 | cat /home/data/SitePackages/packagename.txt |
| 競合設定を無効化 | WEBSITE_RUN_FROM_PACKAGE を 0 に設定。 | Run‑From‑Package を明示的に止める。 | az functionapp config appsettings set --name <app> --resource-group <rg> --settings WEBSITE_RUN_FROM_PACKAGE=0 |
| 残存ファイルの削除 | packagename.txt と不要 ZIP を削除。 | ZIP マウントの根拠を消す。 | rm /home/data/SitePackages/packagename.txt |
| 再起動 | アプリを再起動してマウント構成を再評価。 | Docker の WORKDIR に戻す。 | az functionapp restart --name <app> --resource-group <rg> |
| 動作確認 | fuse.zip が消え、コンテナのディレクトリが見えることを確認。 | 修復の確証を得る。 | mount | grep wwwroot |
実施手順(詳細)
競合設定を明示的にオフにする
値を空文字ではなく 0 に設定する点がポイントです。空の削除だけでは再発します。
az functionapp config appsettings set \
--name <FunctionApp名> \
--resource-group <リソースグループ名> \
--settings WEBSITE_RUN_FROM_PACKAGE=0
この操作で「パッケージから実行」をプラットフォームレベルで抑止します。
Run‑From‑Package の痕跡を削除する
Azure Portal の SSH(ランタイム側)または https://<appname>.scm.azurewebsites.net(Kudu/高度なツール)の Bash に入って、残存ファイルを削除します。
# 中身を確認(任意)
ls -l /home/data/SitePackages
cat /home/data/SitePackages/packagename.txt || true
# 痕跡を削除
rm -f /home/data/SitePackages/packagename.txt
# ZIP が残っていれば合わせて削除
find /home/data/SitePackages -maxdepth 1 -type f -name '*.zip' -delete
なお、トラブルシューティングは SSH(ランタイム側)で行うのが確実です。Kudu の Bash は scm サイト側のファイルシステムを表示するため、内容が一致しないことがあります。
アプリを再起動する
az functionapp restart --name <FunctionApp名> --resource-group <リソースグループ名>
再起動により、コンテナ起動時のマウント構成が再評価され、/home/site/wwwroot がコンテナ内の実ディレクトリに戻ります。
修復を確認する
# fuse.zip が消えていることを確認
mount | grep wwwroot
# コンテナの実体が見えること(例)
ls -la /home/site/wwwroot
mount の結果に fuse.zip が含まれない、かつ Dockerfile で用意したフォルダ構造(例:host.json、function.json、言語ごとのエントリなど)が見えていれば完了です。
追加クリーニングと再発防止の設定
- SitePackages の再点検:
ls /home/data/SitePackagesで不要 ZIP/TXT が残っていないか確認し、すべて削除。 - Deployment Center を「None」へ:ポータル > Deployment Center > Settings で Build provider を None に変更(Zip Deploy/ビルドの自動化を無効化)。
- ビューの食い違いに注意:Kudu Bash は scm サイト側、SSH はランタイム側。整合性チェックやファイル操作は SSH を基準に。
- App Settings の棚卸し:過去の Zip Deploy が残した
SCM_DO_BUILD_DURING_DEPLOYMENT、RUN_FROM_PACKAGE系のキーがないか見直し。不要なら削除。
コンテナ運用に統一するための指針
「Zip デプロイとコンテナ」の混在は不具合の温床です。以降は次の流れに 一本化 してください。
- Docker イメージを再ビルド(
/home/site/wwwrootにアプリコードを配備)。 - レジストリへ push(推奨:毎回新しいタグまたはイメージダイジェストを使用)。
linuxFxVersionのタグを更新(後述のコマンド例)。
これだけで構成がぶれません。Zip Deploy は使用しない方針にします。
イメージ更新を即座にアプリへ反映させる方法
方法 A:イミュータブルタグ/ダイジェストで linuxFxVersion を更新
タグを更新すればプラットフォームは新イメージを pull し直します。CLI で linuxFxVersion を確実に切り替える最短手は次のとおりです。
# 現在の Function App リソース ID を取得
APP_ID=$(az functionapp show -g <rg> -n <app> --query id -o tsv)
# イメージタグを更新(例:v2025.11.11)
az resource update
--ids "$APP_ID"
--set properties.siteConfig.linuxFxVersion="DOCKER|/:"
同じタグを上書きする運用(例::latest 固定)は、プラットフォーム側キャッシュや pull 最適化の影響で 取りこぼし が発生しやすく、避けるのが無難です。新しいタグ(または @sha256:<digest>)を毎回指定してください。
方法 B:コンテナの継続的デプロイ(ACR Webhook 連携)
Deployment Center でレジストリと連携すると、レポジトリの更新をトリガーに 再起動+再 pull が自動化できます。ただし、本記事の主題である Zip Deploy 痕跡が残っていると正常に切り替わらないため、まずは前章までのクリーニングを先に実施してください。
方法 C:強制再起動/擬似変更で即時反映
手元から即時反映したい場合は、再起動やダミーの App Setting 更新でも引き金にできます。
# 即時再起動
az functionapp restart -g <rg> -n <app>
# ダミー設定でウォームリスタートを誘発
az functionapp config appsettings set
--name --resource-group
--settings FORCE_ROLL="v$(date +%s)"
Dockerfile の健全性チェック(最小テンプレート)
コンテナ内に /home/site/wwwroot を正しく用意できているかも確認しましょう。代表的なテンプレートを示します。
Python(Functions v4 の一例)
FROM mcr.microsoft.com/azure-functions/python:4-python3.11
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
AzureFunctionsJobHost__Logging__Console__IsEnabled=true
WORKDIR /home/site/wwwroot
COPY . /home/site/wwwroot
# 依存関係(例)
RUN pip install -r requirements.txt
Node.js(Functions v4 の一例)
FROM mcr.microsoft.com/azure-functions/node:4-node18
ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
AzureFunctionsJobHost__Logging__Console__IsEnabled=true
WORKDIR /home/site/wwwroot
COPY . /home/site/wwwroot
# 依存関係(例)
RUN npm ci --only=production
WORKDIR や COPY の行が欠けていると、Zip Deploy 痕跡を消しても関数が見つからないケースがあるため、合わせて点検してください。
Kudu Bash と SSH の違い(つまずきやすいポイント)
| 機能 | Kudu(scm サイト) | SSH(ランタイム側) | 使い分けの要点 |
|---|---|---|---|
| 表示する FS | デプロイ/ビルド側の FS | 実行中コンテナの FS | 実行実体の確認・削除は SSH が正。 |
| Zip Deploy の痕跡 | 残って見えることがある | 実マウントの可否が分かる | mount | grep wwwroot は SSH で。 |
| ログ | /home/LogFiles/kudu/ 等 | /home/LogFiles/(ホスト/関数) | 両方見比べて因果を特定。 |
トラブルシューティングのコマンド集
# Run-From-Package に関する環境変数の確認
env | sort | grep -E 'WEBSITE|RUN_FROM|SCM|FUNCTIONS'
# Run-From-Package 痕跡の確認
ls -l /home/data/SitePackages
cat /home/data/SitePackages/packagename.txt || true
# wwwroot のマウント確認(fuse.zip が出ていないか)
mount | grep wwwroot
# 直近のホストログ
ls -l /home/LogFiles
tail -n 200 /home/LogFiles/default_docker.log 2>/dev/null || true
tail -n 200 /home/LogFiles/kudu/trace/* 2>/dev/null || true
運用のベストプラクティス(再発させないために)
- デプロイ経路は「コンテナのみ」:VS Code/CLI の Zip デプロイは使わない。
- タグは毎回新規:
:latest固定は避け、バージョンタグまたはダイジェストで明示。 - 設定の単一責任:Deployment Center を None に戻し、構成の源泉を一本化。
- ヘルスチェックを設定:
WEBSITE_HEALTHCHECK_PATHを用意すると不整合時の再起動が自動化しやすい。 - 監査ジョブ:起動後に
mountとpackagename.txtの有無を検査する小さなスクリプトを仕込むと早期検知できる。
よくある質問(FAQ)
Q:WEBSITE_RUN_FROM_PACKAGE を削除したのに ZIP がマウントされ続けます。
A:/home/data/SitePackages/packagename.txt が残っています。値の削除だけでなく、0 を明示設定し、ファイルも削除してください。
Q:WEBSITE_ENABLE_APP_SERVICE_STORAGE を false にすれば消えますか?
A:/home の永続ストレージ挙動が変わるため副作用が大きく、Functions では推奨しません。本記事の手順(競合無効化+痕跡削除)で対処してください。
Q:コンテナ更新を確実に拾うには?
A:新しいタグ/ダイジェストで linuxFxVersion を更新するのが堅実です。上書きタグ運用は避けましょう。自動化したい場合は、Deployment Center でレジストリと連携して Webhook による再起動を有効化します。
Q:Zip Deploy に戻したくなったら?
A:WEBSITE_RUN_FROM_PACKAGE=1 またはパッケージ URL を設定し、packagename.txt を復元すれば ZIP マウントが有効化されます。ただし本記事の前提(コンテナ運用に統一)とは相反します。
最小再現と自己診断シナリオ
- コンテナで正常起動させる(
mount | grep wwwrootで FUSE がないことを確認)。 - あえて Zip Deploy を 1 度だけ実行。
- 結果:以降の再起動で
fuse.zipがマウントされるようになる。 - 本記事の手順(
WEBSITE_RUN_FROM_PACKAGE=0設定、packagename.txt削除、再起動)を実施。 - 期待結果:FUSE が消え、コンテナの
/home/site/wwwrootが有効になる。
開発・運用チーム向けチェックリスト
- [ ] デプロイ経路は 1 つ(コンテナのみ)。
- [ ] Zip Deploy 痕跡の消去(
packagename.txt、不要 ZIP なし)。 - [ ] App Settings 整理(
WEBSITE_RUN_FROM_PACKAGE=0/不要キー無し)。 - [ ] タグ戦略(イミュータブルタグ or ダイジェスト)。
- [ ] 更新トリガー(
linuxFxVersion更新 or Webhook)。 - [ ] 起動後の自己診断(
mount | grep wwwroot自動検査)。
障害復旧のためのワンライナー集(まとめて実行)
# 1) Run-From-Package を完全無効化
az functionapp config appsettings set \
--name <app> --resource-group <rg> \
--settings WEBSITE_RUN_FROM_PACKAGE=0
# 2) 痕跡削除(失敗しても続行)
( rm -f /home/data/SitePackages/packagename.txt || true ) &&
( find /home/data/SitePackages -maxdepth 1 -type f -name '*.zip' -delete || true )
# 3) 再起動
az functionapp restart -g -n
# 4) 検証
mount | grep wwwroot || echo "OK: fuse.zip はマウントされていません"
問題が再発する典型パターンと回避策
| パターン | 説明 | 対策 |
|---|---|---|
| VS Code の Zip デプロイをうっかり実行 | 便利なワンクリックが packagename.txt を生成。 | 拠点メンバーの権限/手順を見直し、コンテナのみに限定。 |
| Deployment Center が Zip か Oryx ビルドに設定 | scm 側で ZIP が継続生成される。 | None に戻す。コンテナ CD を使うなら コンテナのみ選択。 |
:latest タグ固定 | キャッシュにより pull の取りこぼしが発生。 | 毎回新タグ、またはダイジェスト固定に切替。 |
Dockerfile で /home/site/wwwroot にコピーしていない | 痕跡を消しても関数が見えない。 | COPY . /home/site/wwwroot と WORKDIR を定義。 |
まとめ
本件の本質は「Docker と Zip Deploy の優先衝突」です。主犯は /home/data/SitePackages/packagename.txt。WEBSITE_RUN_FROM_PACKAGE=0 を明示し、痕跡を削除し、再起動して fuse.zip を排除すれば、コンテナのコードが唯一の実行ソースに戻ります。以後はデプロイ経路をコンテナに統一し、イミュータブルなタグで linuxFxVersion を更新する運用にすれば、イメージ更新が即座に、そして確実に本番へ反映されるようになります。

コメント