コンテンツにスキップ

NATGatewayでVPC外への通信を成立させる

Juneauでは、NATGatewayを使うことでVpc内のPodがVpc外(クラスタ外を含む)へN:1のソースNATで出ていくegress経路を構築できます。各Nodeに1つずつNAPTソースIPアドレスが払い出され、Pod がVpc外へ通信する際は配置されているNodeに対応するアドレスがソースIPとして利用されます。

このガイドでは、custom Vpcに対してBGPベースのNATGatewayを構築し、Podがクラスタ外まで疎通する手順を一通り示します。

このガイドで構築するもの

  • NAPTソースIP用のAddressPool (nat-pool, 10.225.53.0/24)
  • 上流ルータ (AS 65002, 10.225.32.1) とのBGPピアリング
  • BGPで広報するExternalNetwork (nat-net)
  • 専用Vpc (egress-vpc) とSubnet (egress-subnet, 10.90.0.0/24)
  • NATGateway (egress-natgw)
  • VpcのRouteTableに0.0.0.0/0via.type: natGatewayで追加
  • Podからcurl https://1.1.1.1/cdn-cgi/traceで外部に到達し、戻ってきたip=行がNATGatewayの払い出したNAPTソースIPと一致

前提条件

  • Juneauのcontroller/daemon/bgp-speakerが動作しているクラスター
  • クラスターのAS番号(本ガイドでは 65001
  • 上流BGPルータ側でJuneauクラスターを受け入れる設定(AS 65002、Juneauノード各IPとのピアリング)
  • 広報に使うCIDRが上流ネットワークで未使用であること(本ガイドでは 10.225.53.0/24
  • Pod がインターネットに出るための上流側の経路設定

手順

1. AddressPoolを作成

NAPTソースIPを払い出すためのCIDRを定義します。

apiVersion: juneau.loutres.me/v1alpha1
kind: AddressPool
metadata:
  name: nat-pool
spec:
  advertiseMode: bgp
  addresses:
    - 10.225.53.0/24

advertiseMode: bgpは変更不可です。詳細はAddressPoolを参照してください。

2. BGPPeerを作成

上流ルータを宣言します。

apiVersion: juneau.loutres.me/v1alpha1
kind: BGPPeer
metadata:
  name: upstream
spec:
  myASN: 65001
  peerASN: 65002
  peerAddress: 10.225.32.1

この時点で各Nodeのbgp-speakerが10.225.32.1にBGPセッションを張りに行きます。詳細はBGPPeerを参照してください。

3. BGPセッションの確立を確認

$ kubectl get bgpnodestate
NAME       READY   BIRD   BMP    AGE
worker-1   True    True   True   2m
worker-2   True    True   True   2m

すべての列がTrueになっていれば、そのNode上でbgp-speakerが正常に動作し、上流とのセッションが確立しています。詳細はBGPNodeStateを参照してください。

4. ExternalNetworkを作成

AddressPoolを1つの論理的な外部ネットワークとしてまとめます。

apiVersion: juneau.loutres.me/v1alpha1
kind: ExternalNetwork
metadata:
  name: nat-net
spec:
  type: bgp
  addressPools:
    - nat-pool

type: bgpの場合、参照するAddressPoolはadvertiseMode: bgpである必要があります。詳細はExternalNetworkを参照してください。

5. Vpc/Subnetを作成

NATGateway経由で外部に出るPodを置く専用のVpcとSubnetを用意します。

apiVersion: juneau.loutres.me/v1alpha1
kind: Vpc
metadata:
  name: egress-vpc
---
apiVersion: juneau.loutres.me/v1alpha1
kind: Subnet
metadata:
  name: egress-subnet
spec:
  vpc: egress-vpc
  cidr: 10.90.0.0/24

詳細はVpc / Subnetを参照してください。

6. NATGatewayを作成

Vpcと出口となるExternalNetworkを参照するNATGatewayを作成します。

apiVersion: juneau.loutres.me/v1alpha1
kind: NATGateway
metadata:
  name: egress-natgw
spec:
  vpc: egress-vpc
  externalNetwork: nat-net
$ kubectl get natgateway
NAME           VPC          EXTERNALNETWORK   GATEWAYID   READY
egress-natgw   egress-vpc   nat-net           1           True

Ready: TrueになればNATGatewayの基本的な準備は完了です。詳細はNATGatewayを参照してください。

7. RouteTableに0.0.0.0/0ルートを追加

VpcのメインRouteTableは自動生成されますが、Vpc外への経路はデフォルトでは含まれません。NATGateway向けのデフォルトルートを追記します。

apiVersion: juneau.loutres.me/v1alpha1
kind: RouteTable
metadata:
  name: egress-vpc
spec:
  vpc: egress-vpc
  routes:
    - dst: 0.0.0.0/0
      via:
        type: natGateway
        natGateway: egress-natgw

RouteTableのメタ名はVpc名と同じです。このルートが無いとVpc内のPodからVpc外への経路が成立しません。詳細はRouteTableを参照してください。

8. ExternalNetworkAttachmentが払い出されたことを確認

NATGatewayを作成すると、対象ExternalNetworkに対してNodeごとに1つずつExternalNetworkAttachmentが自動的に作成され、それぞれにNAPTソースIPアドレスが割り当てられます。各assignedIPはBGPで上流に広報され、戻り通信が正しいNodeへ届くようになります。

$ kubectl get externalnetworkattachment
NAME                EXTERNALNETWORK   NODE       ASSIGNEDIP     READY
nat-net--worker-1   nat-net           worker-1   10.225.53.5    True
nat-net--worker-2   nat-net           worker-2   10.225.53.6    True

すべてのNodeに対してREADY: TrueASSIGNEDIPが埋まっていれば、NAPTソースIPの払い出しは完了です。詳細はExternalNetworkAttachmentを参照してください。

9. Podをデプロイ

egress-subnetにcurl用のPodを配置します。

apiVersion: v1
kind: Pod
metadata:
  name: curl
  annotations:
    juneau.loutres.me/subnet: egress-subnet
spec:
  containers:
    - name: curl
      image: curlimages/curl:8.7.1
      command: ["sleep", "infinity"]

10. 外部からの送信元IPを確認

Podから外部に出るときのソースIPアドレスを、外部の応答サービスで確認します。custom VpcのPodからはCoreDNSが利用できないため、IP直指定で叩ける応答サービスを使います。

$ kubectl exec curl -- curl -sS https://1.1.1.1/cdn-cgi/trace
fl=...
h=1.1.1.1
ip=10.225.53.5
ts=...
visit_scheme=https
uag=curl/8.7.1
...

応答のip=行が、Podが動作しているNodeに対応するExternalNetworkAttachmentのstatus.assignedIPと一致していれば、NATGateway経由のN:1 NAPTで外部に出ている状態です。

うまくいかないとき

  1. NATGatewayがReady=Falseのまま
    • spec.vpcで参照したVpcが存在するか
    • spec.externalNetworkで参照したExternalNetworkが存在するか
  2. kubectl get externalnetworkattachmentが空、または対象NodeのAttachmentが無い
    • NATGatewayがReady=Trueになっているか(Attachmentは、NATGatewayから参照されているExternalNetworkに対してのみ作成されます)
    • 対象Nodeがクラスターに登録されているか
  3. AttachmentのassignedIPが払い出されない(READY=Falseのまま)
    • 参照しているAddressPoolのadvertiseModebgp
    • AddressPoolにIP在庫が残っているか(Node数より多くのIPが必要)
  4. Podから外部に出られない
    • PodのSubnetが、NATGatewayと同じVpcに属しているか
    • VpcのRouteTableに0.0.0.0/0via.type: natGatewayとするルートが入っているか
    • via.natGatewayの名前が、対象NATGatewayのname と一致しているか
    • kubectl get bgpnodestateで、各NodeのassignedIPに対応する/32status.advertisements[].prefixesに乗っているか
  5. 送信元IPが期待値と違う
    • Pod が動作しているNodeに対応するExternalNetworkAttachmentのassignedIPを改めて確認
    • 上流ルータで、該当/32がそのNodeを次ホップに学習しているか

参照