AKS でオートスケールを使っていると、「ノードプールの Target は増えているのに Ready が 0 のまま」「Pod が Pending のまま動かない」「しばらくすると Target も 0 に戻ってしまう」という事象に遭遇しがちです。この記事では、VMSS ノードプール(例: D8s v6 / 最小 0 / 最大 3)がまさにこの状態に陥るケースを題材に、原因の切り分け方・ログの見方・リージョン/ゾーン在庫不足の見極め方、さらに TLS 証明書エラーを含む具体的な対処方法までを、実運用を意識して詳しく解説します。
AKS の VMSS ノードプールが「Ready にならない」とはどういう状態か
まず、症状を少し整理しておきます。代表的なパターンは次のようなものです。
- AKS クラスターには複数のノードプールが存在する(例: 3 つ)。
- そのうち 1 つの VMSS ノードプール(例: D8s v6、最小 0/最大 3)がオートスケーラーにより Target=2 までスケールアウトしようとする。
- しかし、kubectl get nodes で見ると、該当プールのノードは一向に Ready にならないか、そもそもノード一覧に出てこない。
- 対象の Pod は Pending のままスケジュールされない。
- 数分〜十数分経過すると、オートスケーラーが「ノードを増やせない」と判断し、Target が再び 0 に戻る。
このとき、VM 自体は Azure 上で起動しかけているため、ポータルや VMSS 画面では一見「増えている」ように見えますが、AKS の制御プレーンにノードとして参加できていない状態です。
さらに、別のユーザーがノードから API サーバーに curl した際に、次のようなエラーが出ていると報告する場合があります。
SSL certificate problem: unable to get local issuer certificate
これは TLS 証明書の信頼に関する問題で、kubelet が API サーバーと安全に通信できず、ノードが参加できない状況と密接に関係します。
よくある原因パターンを整理する
このような「Target は増えるが Ready にならない」現象は、最終的には次のいずれかに集約されます。
- 容量/在庫・SKU・ゾーンの制約
- クォータ不足(反映遅延含む)
- 仮想ネットワーク/サブネットの制約
- ノード側(イメージ・kubelet・containerd 等)の不調
- Azure ポリシー(Deny)によるブロック
- TLS/証明書エラー、TLS インスペクション等
まずは、「どの層で詰まっているのか」を切り分けることが重要です。以下の表は、主な原因と症状の対応関係をざっくり俯瞰したものです。
| 原因カテゴリ | 典型的な症状 | よく見るエラー/ログ | 最初に確認すべき場所 |
|---|---|---|---|
| 容量/在庫・SKU/ゾーン | VMSS インスタンスが “Creating” のまま or すぐ削除 | Insufficient capacity, VM SKU not available, AllocationFailed | アクティビティ ログ、VMSS のインスタンス状態 |
| クォータ不足 | VM 作成が失敗、オートスケールがすぐロールバック | Operation could not be completed as it results in exceeding approved standardDSv6Family Cores quota など | アクティビティ ログ、az vm list-usage |
| VNet/サブネット | VM は起動しているがノードとして参加しない | サブネット IP 不足エラー、API サーバー疎通エラー | サブネットの IP 使用状況、NSG/UDR/FW のルール |
| ノード側不調 | ノードは “NotReady” のまま or そもそも登録されない | kubelet 起動失敗、containerd 起動失敗 | ノード内の journalctl、ブート診断 |
| Azure ポリシー | 特定 SKU やゾーンのみ失敗 | Policy violation, Request is disallowed by policy | ポリシーの割り当て状況、コンプライアンス |
| TLS/証明書 | API サーバーへ curl で証明書エラー | SSL certificate problem: unable to get local issuer certificate | 企業 FW/プロキシ設定、ノードの CA ストア |
次の章では、これらの原因を切り分けるために、どの順番で何を見ていけばよいかを具体的に解説します。
原因を特定するための切り分け手順
アクティビティ ログでスケール失敗の理由を確認する
最初に見るべきは Azure のアクティビティ ログです。VM の作成やスケール操作が Azure 側でどう扱われたかが記録されています。
- 対象リソースグループは AKS のマネージド RG(例:
MC_<リソースグループ>_<クラスター名>_<リージョン>)。 - 操作名としては Microsoft.Compute/virtualMachines/write や Microsoft.Compute/virtualMachineScaleSets/write、または AKS の Microsoft.ContainerService/managedClusters のスケール操作などを探します。
- 結果が Failed になっているイベントを重点的に確認します。
CLI から確認する場合は、次のようなコマンドが使えます。
az monitor activity-log list \
--resource-group MC_<RG>_<CLUSTER>_<REGION> \
--status Failed --max-events 50 -o table
ここで、Insufficient capacity や VM SKU not available、AllocationFailed があれば、リージョン/ゾーンの在庫不足または SKU 非対応を疑います。逆に、could not be completed as it results in exceeding approved... のようなメッセージであれば、クォータ不足が濃厚です。
VMSS インスタンスの状態を直接確認する
次に、問題のノードプールが紐づく VMSS を確認します。VMSS の「インスタンス」ビューで、各インスタンスの Provisioning state と拡張機能(Extension)の状態をチェックします。
az vmss list-instances -g MC_<RG>_<CLUSTER>_<REGION> -n <POOL_VMSS_NAME> \
--query "[].{id:instanceId,state:provisioningState}" -o table
az vmss get-instance-view -g MC_<RG>_<CLUSTER>_<REGION> -n <POOL_VMSS_NAME> \
--instance-id 0 -o jsonc
ProvisioningState が Failed や Creating のまま止まっている場合、VM レベルで何かしらエラーが起きている可能性があります。VM 拡張機能のステータスに Provisioning failed が出ていれば、kubelet のセットアップやネットワーク構成など、AKS のエージェントノードとしての構成に失敗している可能性が高くなります。
クラスターオートスケーラーのログを確認する
AKS の自動スケールは、cluster-autoscaler というコンポーネントが制御しています。このログを見ることで、「なぜ Target を増やしたのか」「なぜ諦めて 0 に戻したのか」が分かります。
kubectl -n kube-system logs deploy/cluster-autoscaler
ここでは次のようなメッセージに注目します。
- 特定ノードプールをスケールアウトしようとした理由(Pending Pod の数など)。
- スケールアウトの試行が、SKU 在庫不足やクォータ不足などの理由で拒否された記録。
- 複数回のリトライの末に断念しているかどうか。
オートスケーラーは Azure 側の失敗理由までは詳細に把握できませんが、「どのノードプールを対象にスケールしようとしたか」「それが継続中か、諦めたのか」が分かるだけでも大きなヒントになります。
ノード内部の kubelet/containerd の状態を確認する
VM 自体は起動しているように見えるのに、AKS クラスターにノードとして参加していない場合、ノード内部で kubelet や containerd が正常に動いていない可能性があります。
シリアルコンソールや SSH で VM に入り、次のようにログを確認します。
sudo journalctl -u kubelet -b --no-pager | tail -n 200
sudo journalctl -u containerd -b --no-pager | tail -n 200
ここで、API サーバーへの接続エラーや証明書エラー、コンテナランタイムの起動失敗などがないかを確認します。特に、x509: certificate signed by unknown authority などのメッセージは、TLS 証明書周りの問題を示唆します。
SKU 在庫とクォータを客観的に確認する
「昔クォータエラーになったが、今は引き上げ済み」というケースでも、実は別のクォータ枠や SKU 家族の上限に引っかかっていることが少なくありません。代表的な確認ポイントは次の通りです。
- リージョン全体の vCPU クォータ
- 対象 SKU ファミリ(例:
standardDSv6Family)の vCPU クォータ - Public IP のクォータ
- Managed Disk(Premium / Standard)のクォータ
CLI では次のコマンドを使います。
# 指定リージョンの SKU が使えるか、ゾーン対応しているか
az vm list-skus -l <REGION> --size D8s_v6 --zone -o table
# vCPU 等のクォータ状況
az vm list-usage -l <REGION> -o table
ここで「現在の使用量」と「上限値」を比べ、スケールアウトに必要な vCPU 数を確保できるかを確認します。クォータを増やした直後は反映に少し時間がかかる場合もあるため、アクティビティ ログと照らし合わせて時系列で見ると分かりやすくなります。
ネットワーク(VNet/サブネット・NSG・FW)の確認
VM が起動しているのにノードとして参加できない場合、ネットワーク周りも重要なチェックポイントです。
- サブネットの空き IP が残っているか(IP 枯渇していないか)。
- NSG や UDR、企業ファイアウォールで、AKS 制御プレーンやコンテナレジストリへの通信がブロックされていないか。
- Private DNS を利用している場合、AKS API サーバーの FQDN が誤った宛先に解決されていないか。
API サーバーに対して名前解決と TLS を確認するには、次のようなコマンドが有効です。
nslookup <API_FQDN>
openssl s_client -connect <API_FQDN>:443 -servername <API_FQDN>
さらに、curl で実際にアクセスしてみることで、「SSL certificate problem: unable to get local issuer certificate」などの TLS エラーが出ていないかを確認できます。
curl -v https://<API_FQDN>
ここで unknown CA や証明書チェーンのエラーが出る場合、企業の TLS インスペクションやプロキシ設定、あるいはノードイメージの CA ストアに問題がある可能性が高いです。
状況別の具体的な解決策
リージョン/ゾーンの在庫不足・SKU 非対応が原因の場合
アクティビティ ログや VMSS のエラーメッセージで Insufficient capacity や AllocationFailed が確認できた場合は、該当リージョン/ゾーンで D8s v6 が一時的に在庫切れ、またはそのゾーンではサポート外である可能性が高いです。
対処の方向性は次の通りです。
- 同リージョン内で 別のアベイラビリティゾーン に新しいノードプール(同サイズ or 近い SKU)を作成する。
- D8s v6 にこだわる必要がなければ、D8s v5 や他の互換 SKU を使ったノードプールを追加する。
- 重要なワークロードは、別の常設ノードプールにスケジュールするよう、
nodeSelectorやnodeAffinity、taints/tolerationsを設定して逃がしておく。
在庫不足は Azure 側の事情であり、ユーザーが直接解消することはできません。そのため、複数ゾーン・複数 SKU を組み合わせて在庫リスクを分散する設計が重要になります。
クォータ不足が原因の場合
クォータ不足は、単に「一度上限を上げたから大丈夫」というものではなく、別のクォータ枠に引っかかるケースも多い点に注意が必要です。
対応のポイントは次の通りです。
- 該当 SKU ファミリの vCPU 枠(例: standardDSv6Family Cores)を十分な値まで引き上げる。
- リージョン全体の vCPU 上限も忘れずに確認する。
- Public IP や Managed Disk(Premium / Standard)など、VM 作成に付随するクォータも確認する。
- クォータ申請後、アクティビティ ログでスケール操作が成功するようになったかを確認する。
クォータ申請は Azure ポータルの「クォータ」メニューから行うことができ、数分〜数時間で承認されることが多いですが、即時反映ではない場合もあるため、時刻を意識して検証するとよいでしょう。
VNet/サブネットの IP 枯渇や NSG・UDR が原因の場合
VNet 周りの問題は、VM 自体は成功しているものの、ノードとして参加できないケースでよく見られます。
代表的な対処は次の通りです。
- サブネットの空き IP が不足している場合は、サブネットのアドレス範囲を拡張するか、別のサブネットを用意して新しいノードプールを作成する。
- NSG や UDR、企業ファイアウォールのルールを確認し、AKS 制御プレーン(
*.azmk8s.io等)とコンテナレジストリ(mcr.microsoft.comや利用中の ACR)との通信を許可する。 - 特に、プライベート クラスターの場合は、Private Endpoint と Private DNS の設定が正しいかを再確認する。
ネットワーク要件を整理すると、次のようなチェックリストになります。
| 項目 | チェック内容 |
|---|---|
| サブネット IP | スケールアウト後に必要なノード数分の IP が空いているか |
| NSG | アウトバウンドで 443/TCP が AKS 制御プレーンとレジストリに到達できるか |
| UDR | 0.0.0.0/0 をオンプレ FW 経由にしている場合、AKS への疎通が許可されているか |
| DNS | API FQDN が正しい IP(Private Endpoint を使うならその IP)に解決されるか |
| TLS インスペクション | AKS 制御プレーン FQDN が SSL 検査の対象から除外されているか |
ノードイメージ/kubelet/containerd の不調が原因の場合
特定のノードだけが Ready にならない、あるいは全く登録されない場合、ノードイメージ側の問題や kubelet/containerd の起動失敗が疑われます。
典型的な対処としては次のようなものがあります。
- ノードイメージのみアップグレードして OS や証明書を最新化する。
az aks nodepool upgrade \
--resource-group <RG> \
--cluster-name <CLUSTER> \
--name <POOL> \
--node-image-only
- それでも解消しないノードは、cordon → drain → 削除 → 再作成という流れでリフレッシュする。
- 時刻同期(NTP)が大きくずれていると TLS まわりで問題が出るため、時刻も合わせて確認する。
ノードイメージの更新を定期的に行うことで、古い CA 証明書や OS の不具合に起因するトラブルを未然に防ぐことができます。
Azure ポリシー(Deny)が原因の場合
サブスクリプションやリソースグループに Azure Policy を適用している場合、特定 SKU・リージョン・タグ・VM サイズを禁止するポリシーによって、ノードの作成が拒否されることがあります。
この場合、アクティビティ ログやポリシーのコンプライアンス画面に、Request is disallowed by policy のようなメッセージが表示されます。
対処の方向性は次の通りです。
- 該当クラスターやノードプールが属するリソースグループ/サブスクリプションに割り当てられたポリシーを確認する。
- テスト目的で、一時的に「監査(Audit)」モードに変更し、deny が発生しないかを検証する。
- 本番環境として適切なポリシーに調整した上で、AKS で使いたい SKU/ゾーンが許可されるようにルールを更新する。
TLS/証明書エラーが原因の場合(SSL certificate problem)
ノードから API サーバーに curl した際に、次のようなエラーが出るという報告がある場合は、TLS 証明書エラーが原因の可能性が非常に高いです。
SSL certificate problem: unable to get local issuer certificate
このエラーは、「サーバー証明書は存在するが、証明書チェーンを検証するための中間 CA などが信頼されていない」ことを意味します。AKS の場合、主な原因は次のようなものです。
- 企業ファイアウォールやプロキシによる TLS インスペクション(SSL オフロード)により、API サーバーの証明書が企業独自の CA で再署名されている。
- ノードイメージの CA ストアが古い/破損しているため、新しい中間 CA を信頼できない。
- Private DNS の誤設定により、意図しない宛先に接続している(結果として証明書が一致しない)。
対処の基本方針は次の通りです。
- AKS 制御プレーンの FQDN を、TLS インスペクションの対象から除外する。
- 企業プロキシを経由せずに、直接 API サーバーに到達できる経路を確保する。
- ノードイメージを最新化し、CA ストアを更新する(前述の node-image-only アップグレード)。
- Private DNS ゾーンで、AKS API FQDN が正しい Private Endpoint / パブリック IP に解決されているか確認する。
特に企業ネットワークでは、「セキュリティのために全 HTTPS 通信を検査する」設定が広く使われていますが、AKS の制御プレーン FQDN を含めると、証明書のすり替えが発生し、kubelet からは「信頼できない証明書」と見なされてしまいます。AKS を安定運用する上では、AKS 関連 FQDN を TLS インスペクションから除外するポリシーを設計段階で定義しておくことが重要です。
確認するログとコマンドのまとめ
ここまでで登場したログ・コマンドを一覧にまとめると、次のようになります。実際のトラブルシュート時には、この表を上から順に確認していくと効率的です。
| レイヤー | 目的 | コマンド/場所 |
|---|---|---|
| Azure コントロールプレーン | スケールアウトの失敗理由を確認する | az monitor activity-log list ...ポータルのアクティビティ ログ |
| VMSS | VM インスタンスの状態と拡張機能のエラーを確認する | az vmss list-instances ...az vmss get-instance-view ... |
| オートスケーラー | どのプールをどの理由でスケールしようとしたか確認する | kubectl -n kube-system logs deploy/cluster-autoscaler |
| ノード内部 | kubelet/containerd の起動状況を確認する | journalctl -u kubeletjournalctl -u containerd |
| SKU/クォータ | SKU が利用可能か、クォータが足りているか確認する | az vm list-skus ...az vm list-usage ... |
| ネットワーク/TLS | API サーバーへの疎通と証明書を確認する | nslookup <API_FQDN>openssl s_client ...curl -v https://<API_FQDN> |
設計・運用での再発防止策とベストプラクティス
AKS の VMSS ノードプールが Ready にならない問題は、原因を潰していけば必ず解決できますが、できれば本番環境ではそうした事態を事前に防ぎたいところです。ここでは、設計・運用の観点からのポイントをまとめます。
最小ノード数 0 のプールはリスクを理解して使う
オートスケールのコスト最適化のために、最小ノード数を 0 に設定するケースはよくありますが、在庫不足や起動時間の影響を受けやすいというリスクがあります。
- 基盤的なワークロード(システム系 Pod や SLA が厳しいサービス)は、常にノードを 1 台以上保持するプールに載せる。
- バッチ処理やスポット的なワークロード専用に、最小 0 のプールを用意する。
- クリティカルなサービスを最小 0 のプールにのみ置かないよう、
affinityやtaintを設計する。
複数ゾーン・複数 SKU で在庫リスクを分散する
在庫不足はユーザー側で制御できないため、ゾーンと SKU を分散することで影響を最小限に抑えることが重要です。
- 3 ゾーン対応リージョンでは、可能な限り 複数ゾーンにまたがるノードプールを構成する。
- 1 つの SKU に依存しすぎず、性能や料金が近い別 SKUを併用する。
- ノードアフィニティを使って、重要な Pod を特定ゾーンや特定 SKU に偏らせすぎない。
ノードイメージの定期更新とヘルスチェック
ノードイメージの更新を放置すると、OS の脆弱性だけでなく、CA 証明書チェーンの陳腐化による TLS エラーなど、地味に厄介な問題を引き起こします。
- 月次または四半期ごとに node-image-only アップグレードを実施する運用ルールを決める。
- 更新直後に簡易的なヘルスチェックを行い、問題があればすぐに気付けるようにする。
- CI/CD や GitOps のパイプラインに、ノードイメージ更新のタスクを組み込むことも検討する。
企業ネットワークの TLS インスペクションと AKS の相性を理解する
企業ネットワークで TLS インスペクションを導入している場合、AKS の制御プレーンには原則として TLS インスペクションをかけないのが安全です。
- AKS 関連の FQDN を列挙し、それらを TLS インスペクションの 除外リストに登録する。
- どうしてもインスペクションをかける必要がある場合は、ノードイメージに企業 CA を信頼させるなど、より高度な設計が必要になる。
- Private Endpoint と Private DNS を併用する場合は、オンプレ/クラウド間のルーティングと合わせて総合的に設計する。
実践シナリオでイメージする:2 つのケーススタディ
ケース 1: D8s v6 の在庫不足で Target が 0 に戻る
ある日、D8s v6(最小 0/最大 3)のノードプールで急に Pod が Pending のままになり、オートスケーラーが Target=2 まで増やすものの、数分後に 0 に戻ってしまう現象に遭遇しました。
- アクティビティ ログを確認すると、
AllocationFailedとInsufficient capacityのメッセージが記録されている。 az vm list-skusで確認すると、当該リージョンの特定ゾーンでは D8s v6 が利用不可になっていることが分かった。- 同リージョンの別ゾーンでは D8s v6 が利用可能だったため、そのゾーンに新しいノードプールを作成した。
- 重要な Pod には
preferredDuringSchedulingIgnoredDuringExecutionのnodeAffinityを設定し、在庫が安定している別 SKU プールを優先するように変更した。
この結果、Pending の Pod は新しいノードプールにスケジュールされ、Ready ノード数も安定しました。
ケース 2: TLS インスペクションによる SSL certificate problem
別の環境では、ノードから API サーバーに curl を実行すると、次のエラーが必ず発生していました。
SSL certificate problem: unable to get local issuer certificate
- 同じコマンドをインターネット直結の検証 VM から実行すると、問題なく接続できる。
- 企業ネットワークのルールを確認すると、すべての HTTPS 通信がプロキシ経由+ TLS インスペクションの対象になっていることが判明。
- プロキシログや FW の設定を確認すると、AKS の API FQDN に対しても企業 CA で再署名された証明書が返されていることが分かった。
- ネットワークチームと調整し、AKS 制御プレーン FQDN を TLS インスペクションの除外対象に追加した。
- 除外設定反映後に再度
curlを実行すると、証明書エラーは解消し、kubelet も正常に API サーバーに接続できるようになった。
最終的に、Ready ノード数が期待通りに増え、Pending の Pod も解消しました。このケースでは、AKS 側ではなく企業ネットワークの設計がボトルネックになっていたことが分かります。
まとめ:Target が増えるのに Ready にならないときの考え方
AKS の VMSS ノードプールで、Target が増えるのに Ready が 0 のまま、Pod が Pending のまま動かないという現象は、一見すると「AKS が壊れた」ように見えます。しかし、実際には次のような原因のどれかに必ず行き着きます。
- リージョン/ゾーンの在庫・SKU 非対応
- クォータ不足(SKU 家族 vCPU、リージョン vCPU、Public IP、Managed Disk 等)
- VNet/サブネットの IP 枯渇や NSG・UDR・FW による疎通不可
- ノードイメージ・kubelet/containerd の不調
- Azure ポリシーの Deny
- TLS インスペクションや CA ストアに起因する証明書エラー
重要なのは、アクティビティ ログ → VMSS → オートスケーラー → ノード内部 → ネットワーク/TLS の順に、レイヤーごとに事実を積み上げていくことです。一つひとつの証拠を確認していけば、必ず「どこで」「なぜ」止まっているのかが見えてきます。
設計段階で在庫リスクや TLS インスペクションを意識し、複数ゾーン・複数 SKU を組み合わせた構成や、ノードイメージの定期更新、TLS 除外ルールの整備を行っておくことで、この種のトラブルは大幅に減らすことができます。この記事の内容を、自身の AKS クラスターの設計レビューやトラブルシュートのチェックリストとして役立てていただければ幸いです。

コメント