GCPのCompute EngineやCloud Run、GKEで外部通信を試みた際に connect: no route to host というエラーが返ってくることがあります。このエラーはOSレベルで「宛先への経路が見つからない」ことを示しますが、GCP環境では単純なルーティング不備だけでなく、Cloud NATの設定ミスやファイアウォールルールの暗黙的な拒否など、複数の要因が絡み合っています。
GCP固有の「No route to host」は大きく7つのパターンに分類でき、それぞれ診断コマンドと対処法が異なります。
「No route to host」エラーの仕組み
LinuxカーネルはICMP Destination Unreachable(Type 3, Code 1)を受信するか、ローカルのルーティングテーブルに該当経路がない場合に EHOSTUNREACH(No route to host)を返します。
GCPのVPCネットワーク上では、パケットは以下の順番で評価されます。
- VPCルーティングテーブル ─ 宛先IPに一致するルートが存在するか
- ファイアウォールルール(Egress) ─ 送信が許可されているか
- Cloud NAT ─ 外部IPを持たないVMの場合、NATゲートウェイ経由で変換されるか
この3段階のどこかで処理が止まると、「No route to host」に類似した接続エラーが発生します。特にGCPのファイアウォールはパケットをサイレントにドロップするため、ルーティング問題と見分けがつきにくい点に注意が必要です。
パターン1: デフォルトルート(0.0.0.0/0)が存在しない
VPCネットワークを作成すると自動的にデフォルトルート 0.0.0.0/0 → default-internet-gateway が作成されますが、セキュリティ要件で削除されていることがあります。
診断
# VPCのルート一覧を確認
gcloud compute routes list --filter="network=VPC_NAME"
# デフォルトルートの存在チェック
gcloud compute routes list \
--filter="network=VPC_NAME AND destRange=0.0.0.0/0" \
--format="table(name,destRange,nextHopGateway,priority,tags)"
出力にデフォルトルートが表示されなければ、外部への経路が存在しません。
対処
# デフォルトルートを再作成(全VMに適用)
gcloud compute routes create default-internet-route \
--network=VPC_NAME \
--destination-range=0.0.0.0/0 \
--next-hop-gateway=default-internet-gateway \
--priority=1000
Cloud NATを利用する構成でも、デフォルトルート自体は必要です。Cloud NATは default-internet-gateway 経由のトラフィックをインターセプトしてNAT変換を行うためです。
注意: デフォルトルートを削除すると、Private Google Access(Google APIへのアクセス)にも影響が出ます。セキュリティ目的でインターネットアクセスを制限する場合は、ルート削除ではなくファイアウォールルールで制御してください。
パターン2: Cloud NATが未構成または対象サブネットに紐付いていない
外部IPアドレスを持たないVMがインターネットに通信するにはCloud NATが必須です。Cloud NATが作成されていても、対象のサブネットやリージョンが一致していなければ機能しません。
診断
# Cloud NATゲートウェイの一覧を確認
gcloud compute routers nats list --router=ROUTER_NAME --region=REGION
# Cloud NATの詳細設定を表示
gcloud compute routers nats describe NAT_NAME \
--router=ROUTER_NAME \
--region=REGION
# NATゲートウェイに割り当てられたIPアドレスを確認
gcloud compute routers get-nat-ip-info ROUTER_NAME --region=REGION
sourceSubnetworkIpRangesToNat の値が ALL_SUBNETWORKS_ALL_IP_RANGES でない場合、特定のサブネットのみがNAT対象です。VMが存在するサブネットが含まれているか確認してください。
対処
# Cloud Router + Cloud NATを作成(全サブネット対象)
gcloud compute routers create my-router \
--network=VPC_NAME \
--region=REGION
gcloud compute routers nats create my-nat \
--router=my-router \
--region=REGION \
--nat-all-subnet-ip-ranges \
--auto-allocate-nat-external-ips
Terraformでの構成
resource "google_compute_router" "router" {
name = "my-router"
network = google_compute_network.vpc.id
region = "asia-northeast1"
}
resource "google_compute_router_nat" "nat" {
name = "my-nat"
router = google_compute_router.router.name
region = google_compute_router.router.region
nat_ip_allocate_option = "AUTO_ONLY"
source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES"
log_config {
enable = true
filter = "ERRORS_ONLY"
}
}
パターン3: ファイアウォールルールによるサイレントドロップ
GCPのVPCファイアウォールはデフォルトで全Egressを許可(priority 65535の暗黙ルール)しますが、組織ポリシーやカスタムルールで上書きされていることがあります。ファイアウォールによるドロップはICMP unreachableを返さず、OSからは「No route to host」や「Connection timed out」として見えます。
米国のArchLinuxコミュニティでの事例として、nftables のデフォルト厳格ルールが原因で「No route to host」が発生し、ルーティング問題と誤診されたケースが報告されています。GCP環境でも同様に、ファイアウォールが根本原因であるにもかかわらずルーティングを疑い続けるのはよくある落とし穴です。
診断
# Egressファイアウォールルールを一覧表示
gcloud compute firewall-rules list \
--filter="network=VPC_NAME AND direction=EGRESS" \
--format="table(name,direction,action,priority,targetTags)"
# 特定VMに適用されるファイアウォールルールを確認
gcloud compute instances describe VM_NAME --zone=ZONE \
--format="get(tags.items)"
Connectivity Tests を使うと、パケットがどの段階でドロップされるかを視覚的に確認できます。
# 接続テストを作成して実行
gcloud network-management connectivity-tests create test-nat \
--source-instance=projects/PROJECT/zones/ZONE/instances/VM_NAME \
--destination-ip-address=8.8.8.8 \
--destination-port=443 \
--protocol=TCP
# テスト結果を取得
gcloud network-management connectivity-tests describe test-nat
結果に Firewall rule ... blocked the traffic と表示された場合、ファイアウォールが原因です。
対処
# 特定タグを持つVMからの外部通信を許可
gcloud compute firewall-rules create allow-egress-internet \
--network=VPC_NAME \
--direction=EGRESS \
--action=ALLOW \
--rules=tcp:443,tcp:80 \
--destination-ranges=0.0.0.0/0 \
--target-tags=allow-internet \
--priority=900
パターン4: Cloud NATのポート枯渇(OUT_OF_RESOURCES)
Cloud NATは各VMに一定数のNATポート(デフォルト64ポート)を割り当てます。同時接続数がこの上限を超えると、新しい接続を確立できず connect: no route to host や接続タイムアウトが発生します。
APIクライアントやクローラーのように大量の外部接続を行うワークロードで頻発します。
診断
Cloud Monitoringで以下のメトリクスを確認します。
| メトリクス | 確認内容 |
|---|---|
compute.googleapis.com/nat/port_usage | VM当たりのポート使用数 |
compute.googleapis.com/nat/dropped_sent_packets_count | ドロップされたパケット数と原因 |
compute.googleapis.com/nat/nat_allocation_failed | IPアドレス割り当て失敗の有無 |
dropped_sent_packets_count の reason が OUT_OF_RESOURCES であればポート枯渇が確定します。
OS上からも確認できます。
# 現在の接続状態を確認(Linux)
netstat -an | egrep 'ESTABLISHED|TIME_WAIT|CLOSE_WAIT' | wc -l
# エフェメラルポートの使用範囲を確認
cat /proc/sys/net/ipv4/ip_local_port_range
対処
方法1: 動的ポート割り当てを有効にする
Cloud NATの動的ポート割り当て(Dynamic Port Allocation)は、VMのポート使用状況に応じて自動的にポート数を調整します。
gcloud compute routers nats update my-nat \
--router=my-router \
--region=REGION \
--enable-dynamic-port-allocation \
--min-ports-per-vm=64 \
--max-ports-per-vm=65536
動的ポート割り当てを使う場合、Endpoint-Independent Mapping(EIM)を無効にする必要があります。この2つの機能は排他的です。
gcloud compute routers nats update my-nat \
--router=my-router \
--region=REGION \
--no-enable-endpoint-independent-mapping
方法2: 最小ポート数を増やす(静的割り当て)
gcloud compute routers nats update my-nat \
--router=my-router \
--region=REGION \
--min-ports-per-vm=4096
方法3: NATに割り当てる外部IPアドレスを追加する
1つの外部IPアドレスあたり最大64,512ポートが利用できます。必要なIPアドレス数は以下の計算式で見積もれます。
必要なIPアドレス数 = (VM数 × VM当たりのポート数) ÷ 64,512
方法4: アプリケーション側で接続を効率化する
- HTTP/2による接続の多重化
- コネクションプーリングの活用
- TCP TIME_WAIT タイムアウトの短縮
# TIME_WAITの再利用を有効化(Linux)
sudo sysctl -w net.ipv4.tcp_tw_reuse=1
パターン5: Cloud Runやサーバーレス環境固有の制限
Cloud RunからVPCネットワーク内のリソースにアクセスする際、特定のサブネットCIDR範囲で接続が失敗する既知の問題があります。特に 192.168.1.0/24 の範囲で dial tcp 192.168.1.x:5432: connect: no route to host が発生するケースが報告されています。
これはCloud RunのDirect VPC EgressやServerless VPC Access Connectorの内部実装に起因する制約です。
診断
- Cloud Runのサービスログで
connect: no route to hostを検索 - 宛先リソースのサブネットCIDRが
192.168.1.0/24に該当するか確認 - Cloud Run jobsとCloud Run servicesで挙動が異なる場合がある
対処
| 方法 | 概要 |
|---|---|
| サブネットの変更 | 問題のあるCIDR範囲を避けてリソースを再作成する(例: 10.0.0.0/24 へ移行) |
| Compute Engine VMプロキシ | Cloud SQL Auth Proxyなどを経由してアクセスする |
| パブリックIPアドレス経由 | Auth Proxy + パブリックIPで接続する |
最新のGoogle Cloud公式ドキュメントでこの制約がアップデートされている可能性があるため、該当する場合は Cloud Run のネットワーキング を確認してください。
パターン6: Shared VPCやVPCピアリングのルーティング問題
Shared VPC環境では、ホストプロジェクトとサービスプロジェクト間でルーティングやCloud NATの設定が分離されています。Cloud NATはホストプロジェクト側で設定しますが、サービスプロジェクトのVMに対して正しく適用されていないケースがあります。
Google Developer ForumsではShared VPC環境で Packet could be dropped due to no routes というエラーが発生し、デフォルトルートにインスタンスタグ(例: egress-internet)が設定されていたためにタグなしのVMがルートを利用できなかったという事例が報告されています。
診断
# デフォルトルートのタグ条件を確認
gcloud compute routes list \
--filter="network=VPC_NAME AND destRange=0.0.0.0/0" \
--format="table(name,destRange,priority,tags)"
# VPCピアリング状態を確認
gcloud compute networks peerings list --network=VPC_NAME
対処
- デフォルトルートのインスタンスタグを確認し、対象VMにタグが付与されているか検証する
- VPCピアリングではカスタムルートのエクスポート/インポートが明示的に有効になっているか確認する
# ピアリング先のカスタムルートをインポートする設定を追加
gcloud compute networks peerings update PEERING_NAME \
--network=VPC_NAME \
--import-custom-routes \
--export-custom-routes
パターン7: インスタンスタグによるルーティング制限
GCPのルートは tags フィールドを持ち、特定のインスタンスタグが付いたVMにのみ適用できます。デフォルトルートにタグが設定されていると、タグを持たないVMはインターネットへのルートを参照できません。
AWSのサブネット単位のルートテーブルとは異なり、GCPのルーティングはVPCレベルで定義され、インスタンスタグで適用先を制御するという独自の設計です。
診断
# ルートの適用条件(タグ)を確認
gcloud compute routes describe ROUTE_NAME \
--format="yaml(name,destRange,nextHopGateway,tags)"
# VMに付与されているタグを確認
gcloud compute instances describe VM_NAME --zone=ZONE \
--format="get(tags.items)"
対処
VMに必要なタグを追加するか、ルートからタグ制限を外します。
# VMにタグを追加
gcloud compute instances add-tags VM_NAME \
--zone=ZONE \
--tags=egress-internet
体系的なトラブルシューティング手順
上記7パターンを効率的に切り分けるための診断フローです。
ステップ1: VMの外部IPアドレスを確認する
gcloud compute instances describe VM_NAME --zone=ZONE \
--format="get(networkInterfaces[0].accessConfigs[0].natIP)"
- 外部IPがある → Cloud NATは不要。ファイアウォールルールまたはOS内のルーティング/ファイアウォールを確認
- 外部IPがない → ステップ2へ
ステップ2: デフォルトルートの存在を確認する
gcloud compute routes list \
--filter="network=VPC_NAME AND destRange=0.0.0.0/0"
- ルートがない → パターン1(デフォルトルート欠如)
- ルートがある → ステップ3へ
ステップ3: ルートにタグ制限があるか確認する
gcloud compute routes list \
--filter="network=VPC_NAME AND destRange=0.0.0.0/0" \
--format="table(name,tags)"
- タグが設定されている → VMに同じタグがあるか確認(パターン7)
- タグが空 → ステップ4へ
ステップ4: Cloud NATの状態を確認する
gcloud compute routers nats list --router=ROUTER_NAME --region=REGION
- Cloud NATがない → パターン2(NAT未構成)
- Cloud NATがある → ステップ5へ
ステップ5: Egressファイアウォールルールを確認する
gcloud compute firewall-rules list \
--filter="network=VPC_NAME AND direction=EGRESS AND action=DENY"
- Denyルールが該当する → パターン3(ファイアウォール)
- 問題なし → ステップ6へ
ステップ6: NATポート使用率を確認する
Cloud Monitoringで nat/port_usage と nat/dropped_sent_packets_count を確認します。
- ドロップがある → パターン4(ポート枯渇)
- ドロップがない → VM内部のOS設定(iptables、nftablesなど)を確認
Cloud NATの監視と予防策
障害が発生してから調査するのではなく、Cloud MonitoringとCloud Loggingを活用して異常を早期に検知できます。
Cloud NATログの有効化
gcloud compute routers nats update my-nat \
--router=my-router \
--region=REGION \
--enable-logging \
--log-filter=ERRORS_ONLY
監視すべきメトリクスと閾値
| メトリクス | アラート閾値の目安 | 説明 |
|---|---|---|
nat/port_usage | 割り当て数の80% | ポート枯渇の予兆 |
dropped_sent_packets_count | 0超過 | パケットロスの発生 |
nat_allocation_failed | true | IPアドレス割り当て失敗 |
open_connections | 平常時の2倍超 | 異常な接続数増加 |
GKE環境の追加設定
GKEクラスタでCloud NATを使用する場合、Podのトラフィックが意図せずNATをバイパスすることがあります。
ip-masq-agentを導入して、Pod IPから外部宛の通信を適切にNAT変換する--disable-default-snatフラグを使用して、GKEのデフォルトSNATを無効化し、Cloud NATに処理を委任する
Cloud NATとDIYのNATゲートウェイの比較
海外のコスト検証では、Cloud NATとCompute EngineベースのDIY NATゲートウェイの料金差が議論されています。
| 項目 | Cloud NAT | DIY NATゲートウェイ(f1-micro) |
|---|---|---|
| 管理の手間 | フルマネージド | iptables設定・監視が必要 |
| 可用性 | Google SLA準拠 | MIG + ヘルスチェックで自前構築 |
| コスト(20VM利用時) | 約$0.029/時間 | 約$0.008/時間 |
| スケーラビリティ | 自動 | 手動でインスタンス追加 |
| 推奨用途 | 本番環境 | 開発環境・コスト重視 |
大規模環境(数百VM以上)でコストが課題となる場合、DIY NATゲートウェイも選択肢に入ります。ただし可用性と運用負荷のトレードオフを考慮してください。
DIY構成の基本コマンドは以下の通りです。
# NATゲートウェイ用VMを作成(IP転送を有効化)
gcloud compute instances create nat-gateway \
--machine-type=e2-micro \
--network=VPC_NAME \
--subnet=SUBNET_NAME \
--can-ip-forward \
--zone=ZONE \
--image-family=debian-12 \
--image-project=debian-cloud \
--tags=nat-gateway
# VM内でIP転送とMASQUERADEを設定
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A POSTROUTING -o ens4 -j MASQUERADE
# NATゲートウェイ経由のルートを作成
gcloud compute routes create nat-route \
--network=VPC_NAME \
--destination-range=0.0.0.0/0 \
--next-hop-instance=nat-gateway \
--next-hop-instance-zone=ZONE \
--tags=use-nat \
--priority=800
よくある質問
「No route to host」と「Connection timed out」の違いは?
No route to host はルーティングテーブルに経路がないか、ICMP unreachableを受信した場合に発生します。Connection timed out はパケットが送信されたものの応答がなかった場合に発生します。GCPのファイアウォールはサイレントドロップのため、実際にはファイアウォールが原因でも Connection timed out として表示されることが多いです。
Cloud NATを設定したのにVMが外部IPで通信しているのはなぜ?
VMに外部IPアドレスが割り当てられている場合、Google Cloudは自動的に1対1のNATを行い、Cloud NATを経由しません。Cloud NATを利用するにはVMから外部IPを削除する必要があります。
# VMから外部IPを削除
gcloud compute instances delete-access-config VM_NAME \
--zone=ZONE \
--access-config-name="External NAT"
GKEのPodがCloud NATを経由していない場合は?
GKEのノードに外部IPがある(非Privateクラスタの)場合、トラフィックはCloud NATを経由せずノードの外部IPで通信します。Privateクラスタを使用するか、ip-masq-agent を設定してPodトラフィックを制御してください。
Cloud NATはリージョンをまたげる?
Cloud NATはリージョナルリソースです。リージョンごとにCloud RouterとCloud NATゲートウェイを作成する必要があります。マルチリージョン構成の場合、各リージョンに個別のNATゲートウェイを設置してください。
Terraformで「443: connect: no route to host」が出る場合は?
Terraformの plan や apply 実行時にGoogle APIへの接続で no route to host が発生する場合、ローカルマシンのIPv6設定が原因の可能性があります。海外の事例では、ローカルマシンではなくGCP上のVMからTerraformを実行することで解消したケースがあります。
# IPv6を一時的に無効化して切り分け
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1
まとめ
GCP環境での「No route to host」は、原因が7パターンに分かれます。
| パターン | 確認コマンド | 頻度 |
|---|---|---|
| デフォルトルート欠如 | gcloud compute routes list | 中 |
| Cloud NAT未構成 | gcloud compute routers nats list | 高 |
| ファイアウォールのドロップ | gcloud compute firewall-rules list | 高 |
| NATポート枯渇 | Cloud Monitoring メトリクス | 中 |
| サーバーレス環境の制限 | Cloud Runログ | 低 |
| Shared VPC/ピアリング | gcloud compute routes list(タグ確認) | 低 |
| インスタンスタグ制限 | gcloud compute routes describe | 中 |
トラブルシューティングの鍵は、体系的な診断フローに従い、ルーティング → ファイアウォール → Cloud NATの順に切り分けることです。Cloud MonitoringとCloud Loggingを事前に有効化しておくことで、問題発生時の原因特定が格段に速くなります。