LoginSignup
18
9

More than 5 years have passed since last update.

GKEのPodからVPNを経由してAWSと通信してみた

Posted at

はじめに

前回の投稿でGCPとAWSをVPNで繋ぐところまでやってみました。
その続きで今回は GKE の Pod から VPN を経由して AWS のサービスを利用したかったので、その方法をまとめます。

普通にサブネットと GKE クラスタを作成して、AWS と通信できるか確認

サブネットの準備

AWS と VPN 接続されている VPC aws-internal-connect に、サブネット aws-internal-connect-subnet-1 を CIDR 10.1.0.0/24 で作成します。
gcp_vpc_subnet_1.png

GKEクラスタの作成

クラスタ test-cluster を、普通に作成してみます。その際、サブネットには上記 aws-internal-connect-subnet-1 を設定します。

$ gcloud beta container clusters create test-cluster \
    --region=asia-northeast1 \
    --cluster-version=1.9.7-gke.3 \
    --machine-type=n1-standard-1 \
    --image-type=cos \
    --num-nodes=1 \
    --network=aws-internal-connect \
    --subnetwork=aws-internal-connect-subnet-1 \
    --enable-autorepair

デプロイ

作成したクラスタに Pod をいくつかデプロイします。

$ kubectl run <Deployment Name> \
    --image=asia.gcr.io/<My Project>/<Image Name>:v1 \
    --replicas=1 \
    --port=80
deployment.apps "<Deployment Name>" created

クラスタ内のネットワーク

デプロイ後のGKEクラスタのネットワークを調べてみた結果、下図のようなネットワークを構成していることが判りました。

topology_1.png

今回作成した GKE クラスタのネットワークは、次の CIDR で構成されていました。

  • Node IP (10.1.0.0/24)
  • Pod IP (10.32.0.0/24, 10.32.1.0/24, 10.32.2.0/24)
  • Service IP (10.35.240.0/20)

Node IP はクラスタ作成時に指定したサブネット aws-internal-connect-subnet-1 から IP が割り当てられており、Pod IPService IP は 自動的に割り当てられているようです。

さて、このクラスタ内の Pod から AWS VPC 内のプライベート IP に対して通信することはできるでしょうか?

答えは NO です。

Cloud Router の BGP アドバタイズ(広報)を確認すれば判るのですが、あくまでもアドバタイズされるのは VPC 内に作成したサブネットの CIDR だけですので、Pod IPService IP の CIDR が AWS 側にアドバタイズされない為です。(AWSへリクエストは到達するが、AWS側はPodへのルートを知らない為、レスポンスを GCP に返せない)

# Cloud Router の BGP アドバタイズ確認
$ gcloud compute routers get-status <Cloud Router Name> --region asia-northeast1
・・・
  bgpPeerStatus:
  - advertisedRoutes:
    - destRange: 10.1.0.0/24
      kind: compute#route
      nextHopIp: 169.254.24.222
      priority: 100
    ipAddress: 169.254.24.222
    name: aws-vpn-1-bgp-1
    numLearnedRoutes: 6
    peerIpAddress: 169.254.24.221
    state: Established
    status: UP
    uptime: 1 weeks, 1 days, 23 hours, 0 minutes, 0 seconds
    uptimeSeconds: '774000'
  - advertisedRoutes:
    - destRange: 10.1.0.0/24
      kind: compute#route
      nextHopIp: 169.254.27.98
      priority: 100
    ipAddress: 169.254.27.98
    name: aws-vpn-2-bgp-1
    numLearnedRoutes: 6
    peerIpAddress: 169.254.27.97
    state: Established
    status: UP
    uptime: 2 days, 13 hours, 19 minutes, 0 seconds
    uptimeSeconds: '220740'
・・・

Pod から AWS へプライベート IP 通信する方法

GKE クラスタ内の Pod から VPN を介してプライベート IP で通信させるには、 「Pod IP と Service IP を BGP アドバタイズできるように GKE クラスタを構成すればよい」のです。
具体的には、IP エイリアスを利用した『VPCネイティブ クラスタ』を作成すれば、Pod IP と Service IP がアドバタイズされるようになります。

セカンダリ IP の CIDR を指定してサブネットを作成

新しいサブネット aws-internal-connect-subnet-2 を作成します。その際、セカンダリ IP 範囲 を2つ作成します。
セカンダリ IP のひとつは Pod IP の CIDR、もうひとつには Service IP の CIDR を設定します。(下図参照)

gcp_vpc_subnet_2.png

セカンダリ IP 範囲を設定する際、注意する点はネットマスク長です。
GKE クラスタでは各 IP 範囲のマスク長に制限が設けられています(下表参照)ので、その範囲を超えないマスク長をセカンダリ IP の CIDR に設定します。
今回はそれぞれ最小マスク長でセカンダリ IP の CIDR を設定しました。

IP 範囲 デフォルトマスク長 最小マスク長 最大マスク長
Pod IP /14 /19 /11
Service IP /20 /22 /18

これでプライマリ IP とセカンダリ IP の CIDR (つまり Pod IP と Service IP の CIDR)もアドバタイズされるようになります。

IP エイリアスを使用して VPC ネイティブ クラスタを再作成

VPC ネイティブ(IP エイリアス)を有効化して GKE クラスタ test-cluster を再作成します。
VPC ネイティブを有効化するには、次のようにオプション --enable-ip-alias と、前述でサブネットに設定した2つのセカンダリ IP の CIDR を指定します。

#GKEクラスタ作成(VPCネイティブ有効)
$ gcloud beta container clusters create test-cluster \
    --region=asia-northeast1 \
    --cluster-version=1.9.7-gke.3 \
    --machine-type=n1-standard-1 \
    --image-type=cos \
    --num-nodes=1 \
    --network=aws-internal-connect \
    --subnetwork=aws-internal-connect-subnet-2 \
    --enable-ip-alias \
    --cluster-secondary-range-name=subnet-2-pod \
    --services-secondary-range-name=subnet-2-svc \
    --enable-autorepair

クラスタ作成後は、任意のPodをデプロイします。

クラスタのネットワーク確認

VPC ネイティブ クラスタ作成後のネットワークは、下図のように構成されています。

topology_2.png

Cloud Router の BGP アドバタイズを確認すると、Pod IPService IP の CIDR がアドバタイズされていることが判ります。

$ gcloud compute routers get-status <Cloud Router Name> --region asia-northeast1
・・・
  bgpPeerStatus:
  - advertisedRoutes:
    - destRange: 10.1.128.0/19
      kind: compute#route
      nextHopIp: 169.254.24.222
      priority: 100
    - destRange: 10.1.160.0/22
      kind: compute#route
      nextHopIp: 169.254.24.222
      priority: 100
    - destRange: 10.1.0.0/24
      kind: compute#route
      nextHopIp: 169.254.24.222
      priority: 100
    - destRange: 10.1.1.0/24
      kind: compute#route
      nextHopIp: 169.254.24.222
      priority: 100
    ipAddress: 169.254.24.222
    name: aws-vpn-1-bgp-1
    numLearnedRoutes: 6
    peerIpAddress: 169.254.24.221
    state: Established
    status: UP
    uptime: 1 weeks, 1 days, 23 hours, 0 minutes, 0 seconds
    uptimeSeconds: '774000'
  - advertisedRoutes:
    - destRange: 10.1.128.0/19
      kind: compute#route
      nextHopIp: 169.254.27.98
      priority: 100
    - destRange: 10.1.160.0/22
      kind: compute#route
      nextHopIp: 169.254.27.98
      priority: 100
    - destRange: 10.1.0.0/24
      kind: compute#route
      nextHopIp: 169.254.27.98
      priority: 100
    - destRange: 10.1.1.0/24
      kind: compute#route
      nextHopIp: 169.254.27.98
      priority: 100
    ipAddress: 169.254.27.98
    name: aws-vpn-2-bgp-1
    numLearnedRoutes: 6
    peerIpAddress: 169.254.27.97
    state: Established
    status: UP
    uptime: 2 days, 13 hours, 19 minutes, 0 seconds
    uptimeSeconds: '220740'
・・・

クラスタ内にある Pod にログイン(kubectl exec)し、AWS VPC 内にある任意の IPアドレス 宛に疎通テストを行ってみます。
尚、以下では EC2 インスタンス 宛に Ping テストを行いましたが、テストの前に EC2 インスタンス 側のセキュリティグループのルールに、 Pod IP の CIDR を追加(プロトコル = ICMP)する必要があるので注意してください。

# Pod 内から AWS の VPC IP へ疎通テスト 
$ ping -c 1 10.0.1.7
PING 10.0.1.7 (10.0.1.7) 56(84) bytes of data.
64 bytes from 10.0.1.7: icmp_seq=1 ttl=62 time=10.0 ms

--- 10.0.1.7 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 10.000/10.000/10.000/0.000 ms

これで GKE クラスタ内の Pod から VPN を介して、AWS の色々なサービスを利用できるようになりました :grinning:

GKE サービスのエンドポイントについて

Pod が提供するアプリケーションはサービスを作成し、そのサービスを介してネットワーク上に公開しますが、そのサービスのエンドポイントにはデフォルトでは外部(パブリック) IP アドレスが割り当てられます。

折角オンプレミス、AWS、GCP を VPN で繋いでシームレスに連携できる環境が出来たので、社内向けに公開したいサービス等、GKE サービスのエンドポイントにプライベート IP アドレスを割り当てたいと思います。

YAML ファイルの準備

サービスを定義した YAML ファイルを準備します。
今回は例として plot というサービスを作成することにします。

service_plot.yaml
apiVersion: v1
kind: Service
metadata:
  name: plot
  namespace: default
  annotations:
    cloud.google.com/load-balancer-type: "internal"
  labels:
    run: plot
spec:
  type: LoadBalancer
  #loadBalancerIP: [IP-ADDRESS]
  ports:
  - port: 80
    protocol: TCP
    targetPort: 5000
  selector:
    run: plot

ポイントは annotations の部分です。
cloud.google.com/load-balancer-typeinternal と定義することで、Node IP(≒クラスタに設定したサブネットのプライマリ IP の CIDR)から任意の IP アドレスがエンドポイントに割り当てられます。
ちなみに任意の IP アドレスではなく、割り当てる IP アドレスを指定したい場合は、loadBalancerIP のコメントを削除して [IP-ADDRESS] にその IP アドレスを記述します。

サービスの作成

準備した YAML ファイルを元に、サービスを作成します。

$ kubectl create -f service_plot.yaml

サービスの確認

作成されたサービスを確認します。
EXTERNAL-IPが外部 IP アドレスではなく、Node IP の CIDR から IP アドレスが割り当てられていることが判ります :grinning:

$ kubectl get svc
NAME         TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
plot         LoadBalancer   10.1.163.57   10.1.1.7      80:32141/TCP   6d

参考

https://cloud.google.com/kubernetes-engine/docs/ip-aliases?hl=ja
https://cloud.google.com/kubernetes-engine/docs/how-to/alias-ips

18
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
9