読者です 読者をやめる 読者になる 読者になる

えいのうにっき

あたまのなかのデトックスを、不定期的に。主に Web 系技術ネタ。

AWS VPC を使ってよくやるネットワーク構成を GCP でも再現したいんだけど、

AWS GCP インフラ

AWS VPCを使ってよくやるネットワーク構成」。実際に「よくやる(やられてる)」のかどうかは、正直、僕の狭い観測範囲内でのことなので自信は持てないけど、それはこんなん↓だ(手書きでゴメン)。

f:id:a-know:20160403221306j:plain

  • VPC を作成
  • VPC 内に2つのサブネットを作成
  • そのうちの片方のサブネットをプライベートサブネットとする
    • 実際には「プライベートサブネット」という設定が存在するわけではなく、以下の2点のようなことを実施することでプライベート扱いとなる(と理解している...)
      • 片方のサブネット用のルートテーブルからはインターネットゲートウェイへのルートを外しておく
      • そのサブネット内に建てるインスタンスにはグローバル IP アドレスを割り当てない
  • パブリックサブネットの方に、踏み台サーバ( bastion )や NAT サーバを置く
    • 踏み台サーバを経由して、プライベートサブネットの方にあるインスタンスssh したり
    • NAT サーバを経由して、プライベートサブネットの方にあるインスタンスからインターネットへの通信を行ったり

こんな構成を GCP で再現したかったのだけど。GCP にも、AWS VPC っぽい Network 、サブネットっぽい subnet があるので、楽勝でできるかなと思ったけど、そうは問屋が卸してくれなかったのだ。

AWSGCP のネットワークの考え方には、微妙な違いが...

ドキュメントを読んだり、AWS 側の設定項目とにらめっこしてみたり、もしくは手当たり次第に試してみたりしてようやく見えてきたのが、以下の様な両者間の違い。

  • ルート(ルートテーブル)の持ち方
    • AWS】サブネット毎にルートテーブルを定義する
    • GCP】ネットワーク単位でルートテーブルを定義する・優先度( priority )で使用されるルートを制御する
  • サブネットまわりの扱い
    • AWS】サブネットは複数設定可能・ルートテーブルはサブネットごとに定義可能だし、VPC にも定義できる(メインルートテーブル?)・インターネットゲートウェイVPC 単位で持つ
    • GCP】サブネットは複数設定可能・ ルートはサブネット単位ではなくネットワーク単位に定義・インターネットゲートウェイはサブネット単位で持つ
      • ネットワーク内にサブネットを作成した場合、ネットワーク自体にはアドレス範囲・インターネットゲートウェイを持つことはできない

上記のような特性のため、AWS と同じ感覚でサブネットを作成しちゃうと、目的のことはできない感じになる。

NAT ゲートウェイを持つネットワークを構築してみる

このことに気づいたあと、「じゃあ、"AWS VPCを使ってよくやるネットワーク構成" を GCP でも再現しようとしたら、どのようにするのがいいのかなあ」といろいろ調べてみたら、GCP のドキュメント内に GCP で NAT ゲートウェイを構築する手順(Using Networks and Firewalls  |  Compute Engine Documentation  |  Google Cloud Platform)について記述されている項目を見つけた。

This example shows setting up the gateway in a legacy network. と書かれていて、"AWS VPCを使ってよくやるネットワーク構成" がレガシー、という意味なのか、はたまたそうではないのかもよくわからなかったんだけど、NAT が出てくるってことは "よくやるネットワーク構成" になるはずだって思ったので、まずは、このドキュメントに示されている gcloud コマンドをそっくりそのまま愚直に叩き、その通りの構成に仕上げてみた。

$ gcloud compute networks create gce-network --range 10.240.0.0/16
$ gcloud compute firewall-rules create gce-network-allow-ssh \
         --allow tcp:22 --network gce-network
$ gcloud compute firewall-rules create gce-network-allow-internal \
         --allow tcp:1-65535;udp:1-65535;icmp \
         --source-ranges 10.240.0.0/16 --network gce-network
$ gcloud compute instances create nat-gateway --network gce-network --can-ip-forward \
         --zone asia-east1-b \
         --image centos-7 \
         --tags nat
$ gcloud compute instances create example-instance --network gce-network --no-address \
         --zone asia-east1-b --image centos-7 --tags no-ip
$ gcloud compute routes create no-ip-internet-route --network gce-network \
         --destination-range 0.0.0.0/0 \
         --next-hop-instance nat-gateway \
         --next-hop-instance-zone asia-east1-b \
         --tags no-ip --priority 800

a-know@nat-gateway:~$ sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
a-know@nat-gateway:~$ sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

(ちなみに tcp:1-65535;udp:1-65535;icmp ここの部分はドキュメントではセミコロン区切りではなくてカンマ区切りになってるのだけど、gcloud コマンドはセミコロン区切りでよこせと怒ってくる)

2016/09/10 追記:やはりカンマが正しいようす。この記事のコメント欄も参照してください。)

これらのコマンドにより、下の図のような構成のネットワークが作成できた。

f:id:a-know:20160403221518j:plain

このネットワークについて、整理する。

  • ネットワーク内のインスタンス同士のルーティング(自身のネットワークに対するルーティング)
    • ネットワーク作成時に自動で作られる、デフォルトのルートが該当。
    • dest 10.240.0.0/16 , priority 1000
  • ネットワーク内からネットワーク外への通信ルーティング
    • ネットワーク作成時に自動で作られる、デフォルトのルートが該当。
    • dest 0.0.0.0/0 , priority 1000 , next hop 10.240.0.1(ネットワークのデフォルトインターネットゲートウェイ)
    • ただし、インスタンスタグ no-ip が付与されたインスタンスからの通信については、priority が 800 のため( 1000 > 800 のため)、下記ルートが優先して適用される。
      • dest 0.0.0.0/0 , priority 800 , next hop nat-gateway
  • ネットワーク内インスタンスへの外部からのアクセス
    • ネットワークに設定されているファイアウォールルールが「0.0.0.0/0 からの ssh を許可」だけある状態なので、ssh なら可能な状態。
  • nat-gateway への ssh
    • global ip address が割り振られている為、可能。
  • example-instance への(外部からの直接的な)ssh
    • global ip address が割り振られてない為、不可能。

うん、いいかんじ。作られたネットワークにはサブネットが無いけれど、だいぶ近い気がする。

サブネットの有無に後ろ髪を引かれる

とはいえ、GCP でのサブネットは、そのネットワークを作成する時点でサブネットを一つも作成していない場合、あとからそのネットワークにサブネットを作成することはできない?様子(GCPでサブネットが使えるようになった。 - 14Room)。なので、今々では必要がないにしても、少なくとも1つのサブネットは作っておいたほうがよさそうな気がしてきた。

ということで、gcloud コマンド群を若干見直し、改めて構築しなおしてみた。各種名称は自分の目的のものっぽいものにしているので、適宜読み替えて欲しい。

$ gcloud compute --project "a-know-home" networks create "a-know-home-network" \
         --mode "custom"
$ gcloud compute --project "a-know-home" networks subnets create "home-subnet" \
         --network "a-know-home-network" \
         --region "asia-east1" \
         --range "10.240.0.0/16"
$ gcloud compute firewall-rules create allow-ssh \
         --allow tcp:22 \
         --network a-know-home-network
$ gcloud compute firewall-rules create allow-internal \
         --allow tcp:1-65535;udp:1-65535;icmp \
         --source-ranges 10.240.0.0/16 \
         --network a-know-home-network
$ gcloud compute --project "a-know-home" instances create "nat-gateway" \
         --zone "asia-east1-a" \
         --machine-type "f1-micro" \
         --subnet "home-subnet" \
         --metadata "ssh-keys=xxx" \
         --can-ip-forward \
         --maintenance-policy "MIGRATE" \
         --image "/centos-cloud/centos-7-v20160329" \
         --boot-disk-size "10" \
         --boot-disk-type "pd-standard" \
         --boot-disk-device-name "nat-gateway" \
         --no-scopes
$ gcloud compute --project "a-know-home" instances create "web" \
         --zone "asia-east1-a" \
         --machine-type "f1-micro" \
         --subnet "home-subnet" \
         --no-address \
         --metadata "ssh-keys=xxx" \
         --maintenance-policy "MIGRATE" \
         --tags "no-ip" \
         --image "/centos-cloud/centos-7-v20160329" \
         --boot-disk-size "10" \
         --boot-disk-type "pd-standard" \
         --boot-disk-device-name "web" \
         --no-scopes
$ gcloud compute routes create no-ip-internet-route --network a-know-home-network \
         --destination-range 0.0.0.0/0 \
         --next-hop-instance nat-gateway \
         --next-hop-instance-zone asia-east1-a \
         --tags no-ip --priority 800


a-know@nat-gateway:~$ sudo sh -c "echo 1 > /proc/sys/net/ipv4/ip_forward"
a-know@nat-gateway:~$ sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

このコマンド群で構築できるネットワークは、下の図のような構成になっている。と思う。

f:id:a-know:20160403221706j:plain

先ほどの図と比べてみても微妙な違いだけど、サブネットの有無を表現してみた。「AWS VPCを使ってよくやるネットワーク構成」が再現できているのかどうかは微妙かもしれないけれど、いったんはこれで僕は満足した。

まとめ

長々と書いたけど、ポイントをまとめるとすれば下記になるだろうか。

  • GCP でも、ネットワーク内にサブネットを複数設定可能だけど、下記のような点が AWS VPC と異なっているのでアタマの切り替えが必要
    • ルートはサブネット単位ではなくネットワーク単位に定義する、という点
    • インターネットゲートウェイはサブネット単位で設定される
    • (ネットワーク内にサブネットを作成した場合、)ネットワーク自体にはアドレス範囲・インターネットゲートウェイを持つことはできない
  • AWS VPC でいうプライベートサブネットに相当する構成にしたい場合は、

...と、まとめてみたけども、先日基礎の見直しを始めたばかりの人間が言っていることなので、何かアドバイスをもらえるなら非常に嬉しいっす!

参考リンク

関連エントリ

blog.a-know.me

blog.a-know.me

blog.a-know.me