プロジェクトの異なる GKE クラスタ同士で通信する方法

# はじめに

* GKE で異なるプロジェクトのクラスタ同士で通信するための手段はいくつかある
* 一つめは Ingress などで外部 IP アドレスを割り当てて外部ネットワーク経由で通信する方法。
  * これは設定が容易であるというメリットがあるが、外部ネットワークの帯域使用料がかかるのと内部ネットワークを利用する場合にくらべて低速になる（はず）というデメリットがある。
* 二つめは共有 VPC を使う方法。
  * これは GCP アカウントが組織に所属していないと利用できないので今回は検証できていない。
* 三つめは VPC ネットワークピアリングを利用する方法。
  * 異なるプロジェクトの VPC ネットワーク同士をピアリングし、それをそれぞれのプロジェクトの GKE クラスタで利用することで、クラスタ同士が内部ネットワークを使って通信できるようになる。
  * この方法は内部ネットワークを利用するので外部帯域使用料がかからず高速に通信できるというメリットがあるが、設定が複雑であり、作成済みのクラスタでは（ネットワークの変更ができないために）適用できないというデメリットがある。
  * 当記事ではこの VPC ネットワークピアリングを利用した異なる GKE クラスタ同士での通信設定手順について記載する。


# 概要

* 大まかな流れは以下の通り
  * プロジェクトの作成
  * VPC ネットワークの作成
  * VPC ネットワーク同士をピアリング
  * GKE クラスタの作成
  * GKE クラスタ同士での通信確認


# プロジェクトを作成

* 「project-a」と「project-b」という名前でふたつのプロジェクトを作成する


# VPC ネットワークの作成

* VPC ネットワーク > VPC ネットワークを作成
* 「サブネット作成モード」を「カスタム」
* 任意の「名前」「リージョン」で「IP アドレス範囲」が 2 プロジェクトで重複しないようにする
* 以上を踏まえてそれぞれのプロジェクトで下記の内容で作成

```
* project-a
  * 名前: network-1a
  * サブネットワーク
    * 名前: us-central1
    * リージョン: us-central1
    * IPアドレス範囲: 10.64.0.0/10

* project-b
  * 名前: network-1b
  * サブネットワーク
    * 名前: us-central1
    * リージョン: us-central1
    * IPアドレス範囲: 10.128.0.0/10
```


# VPC ネットワークピアリングの作成

* VPC ネットワークピアリング > 接続の作成
* 「名前」を任意で入力
* 「VPC ネットワーク」を作成したネットワークで
* 「ピアリングした VPC ネットワーク」を「別のプロジェクトで作成」
* 「プロジェクトID」と「VPC ネットワークの名前」に相手のプロジェクトとネットワークのものを入力
* 以上を踏まえてそれぞれのプロジェクトで下記の内容で作成

```
* project-a
  * 名前: network-1ab
  * VPC ネットワーク: network-1a
  * ピアリングした VPC ネットワーク: 別のプロジェクト
  * プロジェクト ID: project-b
  * VPC ネットワークの名前: network-1b

* project-b
  * 名前: network-1ab
  * VPC ネットワーク: network-1b
  * ピアリングした VPC ネットワーク: 別のプロジェクト
  * プロジェクト ID: project-a
  * VPC ネットワークの名前: network-1a
```

# Kubernetes クラスタの作成

* Kubernetes クラスタ > クラスタを作成する
* 「その他」で詳細オプションを開く
* 「VPC ネイティブ」を有効に
  * VPC ネイティブ（IP エイリアス）を有効にするとピアリングしたネットワークで接続されたクラスタ同士でのルートが自動で作成される
* 「ネットワーク」で作成した VPC ネットワークを選択
* 以上を踏まえてそれぞれのプロジェクトで下記の内容で作成

```
* project-a
  * 名前: cluster-1a
  * ゾーン: us-central1-a
  * VPC ネイティブ: 有効
  * セカンダリ範囲を自動的に作成する: 有効
  * ネットワーク: network-1a
  * サブネットワーク: us-central1
  
* project-b
  * 名前: cluster-1a
  * ゾーン: us-central1-a
  * VPC ネイティブ: 有効
  * セカンダリ範囲を自動的に作成する: 有効
  * ネットワーク: network-1b
  * サブネットワーク: us-central1
```

# Kubernetes サービスの作成

* 動作確認のため Nginx の Pod と、その Nginx をサービスする内部ロードバランサーを作成する

```
# クラスタに接続
$ gcloud container clusters get-credentials cluster-1a --zone us-central1-a --project project-a-205505

# ReplicationController の作成（設定ファイルは後に記載）
$ kubectl apply -f rc.yaml

# 内部ロードバランサーサービスの作成（設定ファイルは後に記載）
$ kubectl apply -f svc.yaml

# ロードバランサーの外部 IP アドレスを確認
# あとで動作確認に使うのでメモしておく
# ロードバランサーの外部 IP アドレスはペアリングした VPC の範囲のものが割り当てられる
$ kubectl get svc
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
backend      LoadBalancer   10.217.13.211   10.64.0.6     80:32214/TCP   1m
kubernetes   ClusterIP      10.217.0.1      <none>        443/TCP        7m

# project-b でも同様にクラスタ接続、Pod と Service の作成、アドレスを確認を行う
$ gcloud container clusters get-credentials cluster-1b --zone us-central1-a --project project-b-205505
$ kubectl apply -f rc.yaml svc.yaml
$ kubectl get svc
NAME         TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
backend      LoadBalancer   10.60.5.197   10.128.0.6    80:30032/TCP   4m
kubernetes   ClusterIP      10.60.0.1     <none>        443/TCP        11m
```

* 設定ファイルの内容は以下の通り

```rc.yaml
apiVersion: v1
kind: ReplicationController
metadata:
  name: nginx
spec:
  replicas: 2
  selector:
    app: nginx
  template:
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
```

```svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: backend
  annotations:
    cloud.google.com/load-balancer-type: "internal"
spec:
  type: LoadBalancer
  ports:
    - port: 80
  selector:
    app: nginx
```


# 動作確認

* 動作確認用の Pod を使って project-a と project-b それぞれのクラスタの中から相手のプロジェクトの内部ロードバランサーに対してアクセス可能であることを確認する

```
# curl が実行できる pod を起動してログインする
$ kubectl run -i -t --image ellerbrock/alpine-bash-curl-ssl curl --command bash --limits "cpu=10m,memory=128Mi"

# project-a から project-b の nginx サービスへ curl でアクセスできることを確認する
$ curl 10.128.0.6

# project-b から project-a の nginx サービスへ curl でアクセスできることを確認する
$ curl 10.64.0.6
```


# 参考資料

* http://containertutorials.com/get_started_kubernetes/k8s_example.html
  * サンプル用の設定ファイルを利用
* https://github.com/cb372/gke-vpc-peering-tutorial
  * VPC ネットワークピアリングを利用した GKE クラスタ間通信の手順について
  * IP エイリアスが利用できなかった時点のものでルーティング設定などの手順が必要になっている