はじめに
こんにちは、TIG所属DXユニット 1の市川燿と申します。
現在は、プロジェクト内で利用しているGoogle Cloud Platform(以下GCP)の環境構築と、Go言語でバックエンドアプリの開発などをしています。
今回は、GCPのKubernetesサービスであるGoogle Kubernetes Engine(以下GKE)を利用している際にハマった事象について共有します。
本記事について
(2019/09/02) GKEのクラスタがルートベースである旨を追記
(2019/09/02) Export設定について追記
GKEとは
コンテナ化されたアプリケーションをデプロイするための、本番稼働に対応したマネージド型環境です。
https://cloud.google.com/kubernetes-engine/?hl=ja
ハマった事象
GKE内のPodから他のGCPプロジェクトのプライベートIPアドレスに対し接続できないことです。
もちろんFirewall Ruleの設定上は接続できる状態です。
具体的には、CurlによるHTTPやTelnetはもちろん、pingによるICMPも接続ができません。不思議なことにGKEを構成するGCEノードにssh接続し、そこから外部のプライベートIPアドレスを持つリソースに対しては”接続が可能”でした。
実はパブリックIPが付与されていた、といったオチもありません。全てプライベートIPのみを持っているインスタンスです。
システム構成前提
今回の環境は以下の設定を使用しています。
VPC
- 専有VPCを利用
GKE
- バージョン: v1.12.7-gke.10
- レガシーネットワークを利用
- クラスタのネットワークはルートベース
他GCPプロジェクトとの接続
- VPCネットワークピアリングを設定済み
各サービスは以下のCIDRが設定してある前提で説明します。
サービス | CIDR | レンジ |
---|---|---|
接続元プロジェクト | 10.1.0.0/16 | 10.1.0.0~10.1.255.254 |
接続先プロジェクト | 10.2.0.0/16 | 10.2.0.0~10.2.255.254 |
接続元のGKE | 172.16.0.0/16 | 172.16.0.0~172.16.255.254 |
設定・接続状況
設定や接続確認し情報を整理したところ以下のことが分かっています。
- GKE内Podから他プロジェクト内GCEへの接続は不可能 (a)
- GKE内Pod(my-pod)から自プロジェクト内GCE(test-gce-01)への接続は可能 (b)
- 自プロジェクトと接続先のプロジェクトとのVPC Peeringは設定済み
- 自プロジェクトのGCE上(test-gce-01)から他プロジェクトGCE(target-gce-01)へ接続は可能 (c)
- GKE内Podが稼働している物理Node(gke-node-02)から他プロジェクトGCEへの接続も可能
GKE内Podとプロジェクト内GCE、テスト用GCEと他プロジェクトGCEはそれぞれきちんと繋がるのに、GKE内Podと他プロジェクトGCEは繋がらないので、そんなことありうるのかと当時とても焦りました。
Pod=>他Project IPへの接続がうまくいかない原因
GKE用のCIDRが接続先PJのCloud Routerに上手く連携されていないため、戻りのルーティング失敗していると思われます(未確認)。
「Pod=>同一Project IP」への接続については、GKEクラスタを作成した際に以下のようなルートがGKE物理ノードごとに自動作成されます。
そのため、同一PJの同一VPC内のPod通信は問題有りませんでした。
名前 | 説明 | 送信先 IP 範囲 | 優先度 | インスタンス タグ | ネクストホップ | ネットワーク |
---|---|---|---|---|---|---|
my-gke-default-pool-xxx | k8s-node-route | 172.25.0.0/24 | 1000 | なし | インスタンス my-gke-default-pool-xxx(ゾーン asia-northeast1-a) | my-network |
試した方法その1: プロキシサーバ経由でアクセス
解決手段としてまず思いついたのは手軽にnginxなどをプロキシサーバ代わりにして方法です。
- 通信経路
GKE内Pod => nginxなどのプロキシサーバ => 他プロジェクトGCE
しかし、GKE内Podとしてnginxを作ってしまうとnginxと他プロジェクトGCE間での通信ができず目的が達成できません。
nginxをGCE上にインストールしてインストールする必要があります。
worker_processes 1; |
この方法で不格好ですが、無事にGKE内Podから他プロジェクトGCEにアクセスできました。
GCE上にプロキシサーバをインストールしているため、冗長性やオートヒーリングとしてKubernetesの機能が利用できず
別の方法で担保する必要があります。
試した方法その2: IPマスカレードエージェントを利用してアクセス (本題)
やっと本題です。
もう少し調べてみるとkubernetes-incubator配下にIPマスカレードエージェント(ip-masq-agent)というプロダクトがあり今回のケースに使えそうなことが分かりました。
IPマスカレードエージェントを利用することで、PodのアドレスからPodが稼働している物理Nodeのアドレスへとアドレスの変換を行い、物理Nodeのアドレスとして接続GKE外部のアドレスに接続しに行きます。
GKEでもバージョン1.7以上で一定条件を満たすとデフォルトで有効になっており、追加インストール作業が不要で利用できます。
IPマスカレードエージェントの使い方はとても簡単で、kubernetesのconfig mapを登録だけで適用されます。
GKE内部のネットワーク(172.16.0.0/16)と自プロジェクトネットワーク(10.1.0.0/16)のみIPマスカレードエージェントの対象外としたい場合には、以下のようにファイルを編集しconfigのファイル名で保存した後、
nonMasqueradeCIDRs: |
以下のコマンドを実行することで適用されます。
kubectl create configmap ip-masq-agent --from-file config --namespace kube-system |
※config以外の名前でファイルを保存すると上手く適用されないため注意
私の環境ではkubectlコマンド実行から1分ほどで、設定が適用されアクセスできるようになりました。
$ kubectl exec my-pod -- curl http://10.2.0.1/health |
この方法であれば、GKE内で完結し、コマンドも1コマンドだけなので、とてもスマートに実現できます。
(2019/09/02 追記) カスタムルートのimport/export
--import-custom-routes
, --export-custom-route
の設定を追加してVPC Peeringの構築をすれば、異なるGCP PJのVPC間でもGKEのルートが上手くExport/Importされるようです。
If you have GKE clusters without VPC native addressing, you might have multiple static routes to direct traffic to VM instances that are hosting your containers. You can export these static routes so that the containers are reachable from peered networks.
https://cloud.google.com/vpc/docs/vpc-peering#benefits_of_exchanging_custom_routes
今回のように、 172.16.0.0/16のようなGKEのPODに割り当てるCIDRが、接続先のGCP PJで重複していない前提であればこちらの手法のほうが良いかもしれません。
その他
今回は試しませんでしたが、紹介した2の方法以外にも以下の方法も検討していました。
ケースによっては検討するのも有りだと思います。
- Nativeクラスタを利用
- 共有VPCを利用
- Publicなネットワーク経由での利用
まとめ
GKE内Podから他プロジェクトのIPへの接続する方法について紹介しました。本記事ではGCPの別PJでしたが、AWSへのVPC Peeringであったり、オンプレミスに対するVPN接続でも同じ事象が発生しうると思います。
IPマスカレードエージェントを利用することで、プロキシサーバなど余分なサーバを作る必要なくアクセスできます。
本記事を通して、皆さまのGCP・GKEライフが少しでも快適になれば幸いです。
- 1.Technology Innovation Groupの略で、フューチャーの中でも特にIT技術に特化した部隊です。その中でもDXチームは特にデジタルトランスフォーメーションに関わる仕事を推進していくチームです。 ↩