GKE本番環境へ向けた準備のベストプラクティス

以下のメモ。図なども以下のサイトから引用。
https://cloud.google.com/solutions/prep-container-engine-for-prod?hl=ja#communicating_within_the_same_cluster

# プロジェクト、ネットワーク、クラスタの構成
以下の構成がベストな構成。

![スクリーンショット 2017-07-18 18.07.20.png](https://qiita-image-store.s3.amazonaws.com/0/95399/3bef875a-eb7f-907e-3bf7-620aacbc3914.png)

本番環境用とテスト開発環境用のプロジェクトは分けて、本番環境は厳密なポリシーを設定する。

デフォルトネットワークを使うのではなく、自分でネットワークを作成し、管理しているIPアドレスにマップした方がよい。
FirewallルールはGKEノードへのIngressとEgressのトラフィックをフィルタするためにネットワークに適用される。
デフォルトではGKEノードに対する全てのインターネットトラフィックは拒否される。
サブネットワークは複数のゾーンを跨げるが、リージョンは跨げない。サブネットワーク間の通信をコントロールするために、トラフィックをパスするfirewallルールを作成する必要がある。"--tags"フラグをクラスタやノードプール作成時に付与すると、firewallルールの効果を受けることができる。またタグはルーティングにも利用できる。

# Identityとアクセス管理
プロジェクトレベルアクセス
IAMロールはユーザだけではなくグループに対しても付与できる。

![スクリーンショット 2017-07-19 12.48.38.png](https://qiita-image-store.s3.amazonaws.com/0/95399/af6cc7e9-d05e-bd21-3f09-5f40be6c0cc9.png)


| チーム | IAMロール | プロジェクト | 権限 |
|:-:|:-:|:-:|:-:|
| Developers  | container.developer  | dev  | 既に存在するクラスタに対してk8sのリソースを作成可能。クラスタの作成や削除は禁止。|
| Operations  | container.admin  | prod  | クラスタとk8sリソースに対する全ての管理者アクセスを許可。|
| Security  |  container.viewer, security.admin | prod  | FirewallルールやSSL証明書の作成、修正、削除とリソース（ログを含む）の参照権限。 |
| Network  | network.admin  | prod  | ネットワークリソースに対する作成、修正、削除。ただしFirewallルールやSSL証明書は除く。  |

prodプロジェクトにアクセスできる３チームに加えて、"container.developer"のロールを与えられたサービスアカウントがリソースの作成、リスト、削除が可能。サービスアカウントは自動化スクリプトや開発フレームワークで使用される。クラスタへのデプロイは自動化されたパイプラインによってされるべきである。

devプロジェクトでは同じクラスタ上で複数の開発者が同じアプリケーションの開発を行っている。これはネームスペースによって分けられるべきである。そのためネームスペースのコンフリクトを避けないといけない。
ネームスペースはクラスタ内のCPUやメモリ、ストレージ使用のquotaを作成するためにも使用される。quotaによりあまりに多くのリソースが使用されるのを防ぐ。

# RBAC authorization
k8s 1.6以上で起動しているコンテナエンジンクラスタは更なる制限をユーザに適用することができる。
Cloud IAMはユーザにクラスタやリソースのフルアクセスを提供することができるが、k8sのRole Based Access Control(RBAC)はクラスタ内でのユーザの行動を抑止することができる。
RBACで、クラスタ管理者は細かいポリシーを個々のネームスペースに適用することができる。
kubectlはgcloud toolからアクティブなクレデンシャルを使用して、ロールをユーザやサービスアカウントにマップする。

この例では２人のユーザがおり、app-aネームスペースのconfig-readerとpod-readerロールを持っている。
![スクリーンショット 2017-07-19 18.20.19.png](https://qiita-image-store.s3.amazonaws.com/0/95399/f36ea849-bddc-26f5-e8d8-d7c602145cc2.png)

この例では、GCPプロジェクトレベルのIAMロールはユーザにクラスタへのアクセスを与え、ネームスペースとクラスタレベルのロール割当はRBACによって細かいアクセスが与えられる。
![スクリーンショット 2017-07-19 18.31.46.png](https://qiita-image-store.s3.amazonaws.com/0/95399/2d147dc6-791a-42bc-9f61-4ae74ed016b0.png)

k8sはいくつかのデフォルトロールを含んでいるが、クラスタ管理者は組織の要求に合ったロールを作成することができる。

ConfigMapsのview,, edit, updateを許可するロールの例
![スクリーンショット 2017-07-19 20.13.55.png](https://qiita-image-store.s3.amazonaws.com/0/95399/9f4bf845-0cfa-8d26-7cd5-fac1875211bb.png)

ロールを定義した後、"bindings"を通してこれらのロールをクラスタやネームスペースに割り当てる。
Bindingsはロールをユーザ、グループ、サービスカウントに関連付ける。
以下は先程作ったロール（config-editor)をbob@example.orgユーザとdevelopmentネームスペースに割り当てる例。
![スクリーンショット 2017-07-19 20.31.05.png](https://qiita-image-store.s3.amazonaws.com/0/95399/a0e85529-0fb5-3abc-359c-5fc30a3a3adb.png)
RBACの詳細は以下を参照
https://cloud.google.com/container-engine/docs/role-based-access-control?hl=ja

# イメージへへのアクセスと共有
Google Container RegistryにあるイメージはGCSにストアされている。
コンテナイメージが含まれる Cloud Storageバケットをpublicにするとイメージをpublicに公開できる。
サービスアカウントにstorage.viewrの権限を付与して、プロジェクト間でimageを共有することもできる。

# ネットワーク構成
k8sはサービスの抽象化（ロードバランシングと一連のpodを跨いだサービスディスカバリ）を提供する。
ここではk8sのpodが他システムと通信するためのベストプラクティスを述べる。

### 同じクラスタ内での通信
クラスタ内のこのpodグループはDNSを使って発見することができる。
kube-dns（クラスタローカルのDNS）は各コンテナエンジンクラスタにデプロイされる。これはサービス名と正常なpodのipをマップするサービス。このDNSはデフォルトではサービスのクラスタIPを返す。このIPへのトラフィックはpodに跨ってロードバランスされる。このiptableはkube proxyにより自動でプログラムされる。
※VIPではなく各podのipを返すようにしたい場合は、ClusterIPフィールドを"None"にセットする。

![スクリーンショット 2017-07-19 22.17.03.png](https://qiita-image-store.s3.amazonaws.com/0/95399/e4812629-c3ff-c6e6-b297-db22c1511b18.png)

### GCPからコンテナエンジンクラスタへの接続
クラスタ外からサービスに接続したい場合（ただしGCP内のprivate ipネットワークから）、internal load balancerを利用すべきである。サービスが外らからアクセス可能とするためにはNodePortを使用してサービスをexposeしないといけない。

![スクリーンショット 2017-07-19 22.28.12.png](https://qiita-image-store.s3.amazonaws.com/0/95399/42ed6f54-8234-4301-765b-10f9e8c174d4.png)

k8sは一つのポートをサービスを外部に提供する全てのクラスタノードに割り当てることができ、これをバックエンドのinternal load balancerから利用できるようにする。このinternal load balancerはクラスタと同じリージョンに配置しないといけない。kube-proxyはトラフィックをフォワードする一連のiptablesルールを最新状態に保ち、availableでないpodにはtラフィックを送らないなどの処理を行う。

### クラスタ内部から外部サービスを利用
以下の３つの方法がある。

##### スタブドメイン
k8s 1.6以上だとkube-dnsを外部のDNSにフォワードできる。権威DNSサーバを持っている場合は有効な手段。

##### 外部ネームサービス
外部のDNSサーバにレコードを追加する。このときDNSはCNAMEレコードを返す。件数が少ない場合は有効。

##### selectorなしのサービス
selectorなしでサービスを作成し、エンドポイントを手動でservice discoveryに追加する。この手法は自由度が高いが、多くの設定と長期間のメンテナンスが必要。
https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/

### Internetからクラスタへのトラフィックを受ける
k8sはnetwork load balancerをGCPプロジェクト内に作成し、コンテナエンジンクラスタのノードにマップする。同じリージョン内のpodに対するトラフィックはこれでバランスされる。

![スクリーンショット 2017-07-20 20.32.47.png](https://qiita-image-store.s3.amazonaws.com/0/95399/6eab5592-6960-8e97-9f7a-cb19d38f6e7f.png)

GoogleのグローバルHTTPロードバランサーを活用し、複数のリージョンに跨ったロードバランシングを行うことができる。

![スクリーンショット 2017-07-20 20.36.18.png](https://qiita-image-store.s3.amazonaws.com/0/95399/37823949-e6b1-7acb-35ee-4dd35f907a74.png)


### Firewall
コンテナエンジンのノードはGCEのノードとしてプロビジョニングされるので、GCEインスタンスと同じようにタグによるFIrewallが適用できる。

![スクリーンショット 2017-07-20 21.38.14.png](https://qiita-image-store.s3.amazonaws.com/0/95399/248cbc8a-1ac6-ba91-38fa-bc945622c993.png)

### オンプレミスのデータセンターと接続
Cloud Interconnectを使ったオンプレミスのデータセンターと接続にいくつかの方法がある。

- ダイレクトピアリング
- キャリアインターコネクト
- CloudVPN