GKEのPodから他クラウドサービスへの通信について

こんにちは。仙台オフィスの阿部です。

はじめに

弊社では、GCPを始めとしていくつかのパブリッククラウドサービスを利用しています。そのため、要件によってはパブリッククラウドサービス間での通信が必要となります。

今回の内容は、GCPのGKEのPodから他クラウドサービスへの通信が出来ずにハマった話とその解決方法です。内容的に真新しい内容ではありませんが、このブログが誰かの目に止まって少しでも役に立ってくれたら幸いです。

事象

繰り返しになりますが、GKEのPodから他パブリックサービスに設置しているDBサーバに接続出来ませんでした。 以下の状態だったといえます。

f:id:yuji_abe:20210430205703p:plain
接続NG

GCPに構築したVPCからはCloudVPNを利用してVPN接続します。初め、VPCとCloudVPNの設定を確認しました。GCEのインスタンスを立て、疎通確認としてGCEからDBサーバへのpingを実行したところ、正常に接続できます。GKEのPodからの接続が不可であるという状況です。

原因

事象で示した図からも分かる通り、送信元IPアドレスとサブネットのIPアドレス範囲の相違が接続不可の原因となります。GKEにおけるIPアドレスの管理については、公式の以下の記事が参考になります。

cloud.google.com

解決方法

IPマスカレードエージェントを利用します。こちらも公式ドキュメントがあります。

cloud.google.com

IPマスカレードとはIPアドレスの変換技術です。GKEにおいては、IPマスカレードエージェントを利用することでパケットの送信元IPアドレスをPodのアドレスからNodeのアドレスに変換して通信することが可能となります。 今回の環境では、ガイドに記載されたデフォルトのマスカレード以外の宛先にある宛先範囲にマッチし、マスカレードされずに通信した結果、接続不可となっていました。(gkeバージョンは1.18.16-gke.502利用)

IPマスカレードエージェントを利用した場合の通信は以下のようになります。

f:id:yuji_abe:20210430212237p:plain
接続OK

IPマスカレードエージェント設定方法

DaemonSet作成

以下のマニフェストからDaemonSetを作成します。

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ip-masq-agent
  namespace: kube-system
spec:
  selector:
    matchLabels:
      k8s-app: ip-masq-agent
  template:
    metadata:
      labels:
        k8s-app: ip-masq-agent
    spec:
      hostNetwork: true
      containers:
      - name: ip-masq-agent
        image: gcr.io/google-containers/ip-masq-agent-amd64:v2.5.0
        args:
            - --masq-chain=IP-MASQ
            # To non-masquerade reserved IP ranges by default, uncomment the line below.
            # - --nomasq-all-reserved-ranges
        securityContext:
          privileged: true
        volumeMounts:
          - name: config
            mountPath: /etc/config
      volumes:
        - name: config
          configMap:
            # Note this ConfigMap must be created in the same namespace as the
            # daemon pods - this spec uses kube-system
            name: ip-masq-agent
            optional: true
            items:
              # The daemon looks for its config in a YAML file at /etc/config/ip-masq-agent
              - key: config
                path: ip-masq-agent
      tolerations:
      - effect: NoSchedule
        operator: Exists
      - effect: NoExecute
        operator: Exists
      - key: "CriticalAddonsOnly"
        operator: "Exists"

ConfigMap作成

以下の内容を記載したファイルを作成します。ファイル名はconfigとします。

nonMasqueradeCIDRs:
      - 10.0.0.0/8
resyncInterval: 60s

nonMasqueradeCIDRsには、PodのIPアドレスを保持したい宛先範囲を指定します。

ConfigMapを作成します。以下ではip-masq-agentというリソース名で作成しています。

kubectl create configmap ip-masq-agent \
  --from-file config \
  --namespace kube-system

通信の確認

Node内に一時的なPodを立て、そのPod内からpingを実行して通信確認を行います。

kubectl run -it debug --image=alpine:latest --rm --restart=Never -- ping xx.xx.xx.xx

無事通信することができました。

Autopilotモードの場合

IPマスカレードエージェントはnamespace=kube-systemにDaemonSetを作成します。Autopilotモードで試したところ、以下のエラーが発生して作成することが出来ませんでした。公式ドキュメントの冒頭にStandardモードにのみ適用される旨のアイコンが表示されているとおり、Autopilotモードにはやはり対応していなさそうです。

Error from server (Forbidden): error when creating "ip-masq-agent.yml": daemonsets.apps is forbidden: User "xxxxx" cannot create resource "daemonsets" in API group "apps" in the namespace "kube-system": GKEAutopilot authz: the namespace "kube-system" is managed and the request's verb "create" is denied