PythonのAzure FunctionsをVS CodeからデプロイするとOryxビルドでNo matching distribution foundになる原因と対処法

VS CodeからPythonのAzure Functionsをデプロイしたとき、Oryx(Kudu)ビルドで「No matching distribution found(azure-functions==1.23.0)」が出て止まることがあります。複数パッケージが一斉に失敗するなら、原因はパッケージの有無よりも「ビルド環境がPyPIへ出られない」ケースが大半です。

目次

まず結論:ほぼ「requirements.txt」ではなくネットワーク到達性が原因

VS Code から Python ベースの Azure Functions をデプロイすると、Oryx(Kudu)によるリモートビルドで次のようなエラーが出て止まることがあります。

  • Could not find a version that satisfies the requirement azure-functions==1.23.0 (from versions: none)
  • No matching distribution found for azure-functions==1.23.0

このとき、azure-functions のバージョンが存在しないのが原因に見えますが、ログに from versions: none が出ていて、しかも 他の複数パッケージも同様に失敗するなら、典型的には次の状態です。

ビルド環境(Kudu/Oryx)が PyPI(pypi.org)や配布ホスト(files.pythonhosted.org)に到達できず、pip がパッケージを取得できていない

つまり、パッケージが「ない」のではなく、取りに行けていないために「versions: none(候補が1つも見えない)」という表示になります。

症状の整理:「from versions: none」が示していること

pip のエラー文言だけでは原因が分かりづらいので、まずはログのパターンを整理します。特に重要なのは、候補バージョンが列挙されるか/されないかです。

ログの見え方疑うべき原因次にやること
from versions: none が出る(複数パッケージで同時多発)PyPI へ到達できない/インデックスURLが誤っている/プロキシ未設定ネットワーク・プロキシ・pipの参照先を確認
from versions: ... と候補が並ぶが最終的に失敗Python バージョン不一致、OS/CPU不一致、依存関係の衝突、ビルドツール不足Python 版・wheel 有無・依存関係を確認
SSL: CERTIFICATE_VERIFY_FAILED など証明書系の明確なエラーSSLインスペクション、社内CA未導入、プロキシ経由の証明書検証失敗プロキシ設定とCA証明書の取り込みを検討

今回のように「requirements.txt の書き方を変えても」「バージョン指定を外しても」「複数パッケージが全部落ちる」という条件が揃うほど、ネットワーク到達性(外部HTTPS)の可能性が濃厚です。

なぜ VS Code デプロイで Oryx(Kudu)ビルドが走るのか

切り分けを早くするには、デプロイの裏側をざっくり理解しておくと役立ちます。

  • VS Code の Azure Functions 拡張などでデプロイすると、通常は ZIP デプロイに近い仕組みでアプリが送られます。
  • Linux ベースの Function App などでは、サーバー側(Kudu/Oryx)で requirements.txt を見て pip install する「リモートビルド」になることがあります。
  • このビルドが Oryx(ビルダー)で実行され、ログ上は --platform python --platform-version 3.12 のように表示されます。

重要なのは、pip が動くのはあなたのPCではなく、Azure 側のビルド環境だという点です。ローカルでは問題なくインストールできても、Azure 側のネットワーク制限やプロキシ制約で失敗することがあります。

どこを見れば良い?ログの入口を3つ押さえる

原因を決め打ちせず、まずは「ビルド環境が何をしているか」をログで確認します。VS Code の出力は要点しか出ないことがあるので、次の3つをセットで見るのが効率的です。

  • VS Code の出力(Output/Terminal):デプロイ開始〜失敗までの概要を掴む
  • Azure Portal のデプロイログ:Oryx の詳細ログが残っていることがある
  • Kudu(SCM)側のログ:より生のログ(pip コマンドや失敗箇所)が追える

Kudu の入口は一般に https://<アプリ名>.scm.azurewebsites.net です(アクセス制限を掛けている場合は許可が必要)。ログを見たときに pip install がどの URL を引こうとしているか、DNS解決に失敗していないか、プロキシ設定が反映されているかが判断材料になります。

最短で原因を切り分けるチェック(優先度順)

ローカルで同じ指定が通るかを確認する

まずは「本当にそのバージョンが存在するのか」をローカルで確認します。ローカルで入るなら、パッケージ不存在の線は薄くなり、ビルド環境側の問題に絞れます。

python -m pip install --upgrade pip
python -m pip install azure-functions==1.23.0

ここで成功するなら、次は「Azure 側が外へ出られていない」仮説を検証します。

ビルド環境から PyPI に到達できるかを確認する

Function App が App Service 系のプランで動いている場合、Kudu のコンソールや SSH で疎通確認できることがあります。次を試し、DNS解決とHTTPS疎通の両方を確認します。

curl -I https://pypi.org/simple/
curl -I https://files.pythonhosted.org/

curl が使えない環境でも、同等の確認(DNS、HTTPS 443 が外へ抜けるか)さえできれば十分です。ここでタイムアウトや名前解決失敗になるなら、ほぼネットワークが原因です。

pip が参照しているインデックスURL(index-url / extra-index-url)を確認する

「社内のプライベートPyPIだけを参照する設定」になっていると、外へ出られる環境でも versions: none のような見え方になります。特に、アプリ設定で PIP_INDEX_URL がセットされていないか、ビルドログ内で Looking in indexes: の行がどうなっているかを確認してください。

まず確認したいアプリ設定(App Settings)

Azure Functions / App Service では、アプリ設定(環境変数)がビルドにも影響します。意図せず設定が入っていると、突然ビルドだけ落ちるようになります。

設定名(例)用途この問題との関係
HTTP_PROXY / HTTPS_PROXYプロキシ経由で外部へ出す未設定だと外に出られず失敗。設定ミスだと別の通信まで壊す
NO_PROXYプロキシを経由しない宛先内部宛てがプロキシ経由になって二次障害が起きるのを防ぐ
PIP_INDEX_URLpip の参照インデックスを固定社内フィードのみを見て “versions: none” になる原因になりやすい
PIP_EXTRA_INDEX_URL追加インデックス(フォールバック)社内フィード+PyPI の併用で解決しやすい
WEBSITE_VNET_ROUTE_ALL全アウトバウンドをVNet経由にするRoute All で出口設計が必須になり、PyPI が塞がりやすい
SCM_DO_BUILD_DURING_DEPLOYMENTデプロイ時にサーバー側ビルドを走らせるリモートビルドで pip install が発生し、ネットワーク制約の影響を受ける

とくに PIP_INDEX_URL と WEBSITE_VNET_ROUTE_ALL は「いつの間にか入っていてハマる」代表格です。設定を入れた記憶がない場合は、テンプレートや IaC(ARM/Bicep/Terraform)側で入っていないかも確認してください。

根本原因の本命:VNet 統合・出口制御で PyPI が塞がれている

「全パッケージが同時に落ちる」ケースで最も多いのが、VNet 統合(Regional VNet Integration)や強制トンネリングによって、Function App のアウトバウンド通信が意図せず閉じているパターンです。

よくある構成ミスの典型

  • VNet 統合したが、サブネットの NSG アウトバウンド規則で Internet への 443/TCP を拒否している
  • UDR(ルートテーブル)で 0.0.0.0/0 を Azure Firewall / NVA に送っているが、Firewall 側の許可(FQDN/URL)が足りない
  • NAT Gateway を付けていない(あるいは出口IPが想定と違う)ため、組織側の許可リストに合わない
  • WEBSITE_VNET_ROUTE_ALL=1 を有効にしてすべてのアウトバウンドがVNet経由になったが、外部宛ての経路が未整備

最低限許可したい宛先(PyPI 周辺)

pip が依存解決とダウンロードで参照する主要な宛先は次の2つです。

  • インデックス:pypi.org(どのバージョンがあるか、どのファイルを取るかを引く)
  • 配布ファイル:files.pythonhosted.org(wheel や sdist を実際にダウンロードする)

片方だけ許可しても失敗します。たとえば pypi.org が見えていても、files.pythonhosted.org がブロックされているとダウンロード段階で詰まります(この場合は別のエラーになることもあります)。

ネットワーク観点のチェック表(VNet 統合あり)

確認ポイント見るべき場所よくある落とし穴対処の方向性
443/TCP アウトバウンドが許可されているか統合先サブネットの NSG(アウトバウンド)「Internet拒否」を優先度高く置いている必要な経路を許可(最終制御はFirewall側へ)
外向きルートが成立しているかUDR(ルートテーブル)0/0 を NVA に送るが、NVA から外へ出られないNVA/Firewall 側の NAT と許可ルールを見直す
出口IPが固定されているかNAT Gateway / Firewall の Public IP出口IPが変動し、組織側許可リストとズレるNAT で固定化し許可リストへ登録
Route All が有効になっていないかアプリ設定(App Settings)WEBSITE_VNET_ROUTE_ALL=1 で影響範囲が拡大要否を再検討/必要なら出口と許可を整備
名前解決が成立しているかDNS(カスタムDNS/Private DNS)pypi.org が解決できず、pip が空振りするDNSフォワーダ設定、外部DNSへの転送を整える

実務上は「NSG と UDR を直したら一撃で直った」というケースが多いです。“versions: none” が出ている限り、pip はインターネット側のインデックスを見られていません。

プロキシ環境での対処:pip が外へ出る道を用意する

企業ネットワークでは、インターネットへ直接出るのではなく、HTTP/HTTPS プロキシ経由が必須なことがあります。この場合、ビルド環境にプロキシ設定が伝わっていないと PyPI へ出られず失敗します。

Function App のアプリ設定で入れることが多い環境変数

設定名例ポイント
HTTPS_PROXYhttp://proxy.example.local:8080まずは HTTPS から。認証が必要なら http://user:pass@... 形式になることも
HTTP_PROXYhttp://proxy.example.local:8080HTTPS だけでなく HTTP も使うツールがあるため併記が無難
NO_PROXYlocalhost,127.0.0.1,.azurewebsites.net内部宛て(ストレージやKeyVaultなど)をプロキシ迂回したい場合に設定

注意点として、プロキシで SSL インスペクション(中間証明書)をしている環境では、pip が証明書検証で失敗することがあります。その場合は「versions: none」ではなく証明書エラーになることが多いですが、社内CAの取り込みが必要になるケースもあります。

プライベート PyPI(社内フィード)利用時の落とし穴

もう1つ、versions: none を生みやすいのが、プライベートPyPIに切り替えているパターンです。社内フィードに azure-functions や必要な依存関係がミラーされていないと、pip からは「存在しない」ように見えます。

症状の出方

  • 特定のパッケージだけ落ちる(社内にないものだけ落ちる)
  • ただし、社内フィードの方針によっては「ミラーされていないものが大量にある」ため、結果的に複数パッケージが一斉に落ちる
  • ログ上は from versions: none になりやすい(そのフィードには候補が無いので)

フォールバックで PyPI も参照する設定例

社内フィードを優先しつつ、足りないものは PyPI から補う設定にするなら、extra-index-url を使うのが定番です。requirements.txt の先頭付近に置くのが分かりやすいです。

--index-url https://<your-private-pypi>/simple
--extra-index-url https://pypi.org/simple

azure-functions==1.23.0
requests>=2.31.0

同じことはアプリ設定でもできます(ビルド時に環境変数が読まれる場合)。

  • PIP_INDEX_URL:プライベートPyPIのURL
  • PIP_EXTRA_INDEX_URL:https://pypi.org/simple

「社内フィードしか許可できない」方針なら、逆に 必要パッケージを社内フィードへミラーする必要があります。ここで重要なのは、azure-functions本体だけでなく、その依存関係(requests など)も含めて揃っていないと結局失敗する点です。

「Python 3.12 だから落ちる?」と疑う前に見るべきポイント

ログに --platform-version 3.12 と出ると「Python 3.12 に対応した wheel が無いのでは?」と考えがちです。もちろんそれが原因のこともありますが、その場合は多くのケースで次のような特徴が出ます。

  • pip のログに候補バージョンが並ぶ(from versions: 1.18.0, 1.19.0, ... など)
  • Requires-Python の制約が表示される/ビルドが走ってコンパイルで落ちる

逆に、候補が1つも出ないのは、Python バージョン以前の問題(インデックスを引けていない)である可能性が高いです。まずはネットワークと参照先を潰すのが近道です。

具体的な復旧手順(原因別の実装ガイド)

VNet 統合がある場合:最小限のアウトバウンド許可を設計する

セキュリティ要件が厳しい環境ほど、闇雲に「Internet を許可」するのではなく、出口を固定(NAT)し、許可宛先を最小化するのが現実的です。

  • 出口は NAT Gateway / Azure Firewall の Public IP に固定し、組織の許可リストに登録する
  • Firewall のアプリケーションルール(FQDN)で pypi.org と files.pythonhosted.org を許可する(可能ならワイルドカードも検討)
  • NSG は「必要な経路に出るための許可」までを担い、最終的な宛先制限は Firewall 側で担保する

これにより、Function App のビルドが外部依存を取得できる一方、任意の宛先へ自由に出られる状態を避けられます。

プロキシ必須の場合:環境変数+NO_PROXY でハマりどころを潰す

プロキシ経由で PyPI に出す構成では、HTTP_PROXY/HTTPS_PROXY を入れたのにまだ失敗することがあります。多いのは次の2つです。

  • プロキシの認証が必要(無認証前提で設定している)
  • NO_PROXY の不足で、内部宛て(ストレージ、メタデータ、Azure の内部ドメイン)がプロキシ経由になって別のエラーが出る

ビルドログで「別の場所(ストレージ等)でも失敗し始めた」場合は、プロキシ設定が効いた結果、内部通信まで巻き込んでいる可能性があります。NO_PROXY を追加して切り戻しながら調整すると事故が減ります。

プライベートPyPIの場合:ミラー方針とフォールバック方針を決める

社内フィード運用は、「完全ミラー」か「足りない分だけPyPIにフォールバック」のどちらかを明確にしないと運用が破綻します。中途半端にすると、開発者はローカルで動くのにデプロイだけ落ちる、という状況になりがちです。

方針メリットデメリット向く組織
完全ミラー(PyPIへは出さない)出口を閉じたまま運用できるミラー作業と依存関係管理が重い厳格な閉域要件がある
フォールバック(extra-index-url で PyPI も参照)開発速度が落ちにくい外部通信が必須になる(許可設計が必要)クラウド標準の運用を許容できる

どうしても外部通信を開けられない場合の回避策

組織ルールで「ビルド環境からインターネットへ出してはいけない」場合、根本原因を直しても方針上解決できません。その場合は、“ビルド時に外へ出ない” 形へデプロイ方式を変えるのが現実解です。

ローカル(または社内CI)で依存関係を解決してからデプロイする

Python の Azure Functions は、一般に .python_packages 配下へ依存ライブラリを配置して一緒にデプロイできます。社内ネットワーク上で依存関係を解決し、アーティファクトとして固めてから Function App へ送ると、Oryx 側での pip install を減らせます。

例(ローカル or CI の Linux 環境で実行するイメージ):

python -m pip install -r requirements.txt -t .python_packages/lib/site-packages

その上で、生成された .python_packages を含めて ZIP デプロイします。これにより、デプロイ先のビルド環境が外へ出られなくても動く構成にできます(ただし、ネイティブ依存を含む場合は デプロイ先と同等のOSでビルドする必要があります)。

リモートビルドを避ける設定を検討する

サーバー側ビルド(Oryx)を止めて「ビルド済み成果物をそのまま載せる」運用に寄せると、デプロイ時の外部通信を避けられます。環境によっては SCM_DO_BUILD_DURING_DEPLOYMENT を無効化し、.python_packages を同梱したパッケージを配ることで実現できます。

ただし、組織の標準設定やプラン、デプロイ方式によって挙動が変わるため、一度ステージング環境で検証してから本番へ適用してください。

コンテナ化して依存をイメージに含める

さらに堅牢にするなら、カスタムコンテナ(Docker)で依存パッケージをイメージ内に含め、Function App はイメージを実行するだけにします。ビルドは社内のビルド基盤で完結し、実行環境のネットワーク要件を抑えられます。

最後に:この問題で最も多い誤解

  • 誤解:「azure-functions==1.23.0 が存在しない」
    現実:ローカルでは入るのにデプロイだけ落ちるなら、パッケージよりネットワークを疑うべきです。
  • 誤解:「requirements.txt を書き直せば直る」
    現実:全パッケージが落ちるときは、書式ではなく “取得経路” が壊れていることが多いです。
  • 誤解:「Python 3.12 が悪い」
    現実:候補バージョンが1つも出ないなら、まずはインデックスに到達できていません。

チェックリスト(再発防止のための運用ポイント)

  • Function App に VNet 統合を入れたら、必ずアウトバウンド(443/TCP)と出口経路をセットで設計する
  • WEBSITE_VNET_ROUTE_ALL を有効化する場合は、影響範囲(ビルド/実行の両方)を理解してから適用する
  • プロキシ必須環境では、アプリ設定に HTTP_PROXY/HTTPS_PROXY/NO_PROXY を標準テンプレート化する
  • プライベートPyPI運用は、ミラーかフォールバックかを組織で統一し、例外運用を作らない
  • 「versions: none」が出たら、まずは DNS と HTTPS 疎通を確認してから requirements.txt を疑う

Oryx ビルドの “No matching distribution found” は、表面上はパッケージの問題に見えます。しかし、複数パッケージが同時に失敗するなら、最短ルートはネットワーク・プロキシ・インデックス参照先の見直しです。そこを直せば、バージョン指定をいじらずともデプロイが通るケースがほとんどです。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次