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ネットワーク上では、パケットは以下の順番で評価されます。

  1. VPCルーティングテーブル ─ 宛先IPに一致するルートが存在するか
  2. ファイアウォールルール(Egress) ─ 送信が許可されているか
  3. 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_usageVM当たりのポート使用数
compute.googleapis.com/nat/dropped_sent_packets_countドロップされたパケット数と原因
compute.googleapis.com/nat/nat_allocation_failedIPアドレス割り当て失敗の有無

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_usagenat/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_count0超過パケットロスの発生
nat_allocation_failedtrueIPアドレス割り当て失敗
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 NATDIY 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の planapply 実行時に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を事前に有効化しておくことで、問題発生時の原因特定が格段に速くなります。