Kubernetes The Hard Wayする

Kubernetesについての勉強のため、以下のとてもよくできたチュートリアルを実施したログ。

- [Kubernetes The Hard Way](https://github.com/kelseyhightower/kubernetes-the-hard-way)

このチュートリアルではGCP上にKubernetesのクラスターをスクラッチ構築する。スクラッチインストールに関する公式ドキュメントは以下。

- [Creating a Custom Cluster from Scratch](https://kubernetes.io/docs/setup/scratch/)
- [Kubernetes 1.11 カスタム・クラスタをゼロ（スクラッチ）から構築（参考訳）](https://qiita.com/zembutsu/items/f3ca774c52fc8b329c66)

# 概要

## 作成するクラスターの特徴

- 3 Master、3 Workerノード構成
- OSはUbuntu Server 18.04
- 各k8sコンポーネントは公式のバイナリを使用し、Systemdサービスとして稼働させる
- API ServerはTLSで公開し、各k8sコンポーネントはそれぞれ毎にクライアント証明書を用意する

## バージョン

やった時点でドキュメントに記載されていた各コンポーネントのバージョンは以下。

- Kubernetes 1.12.0
- containerd Container Runtime 1.2.0-rc.0
- gVisor 50c283b9f56bb7200938d9e207355f05f79f0d17
- CNI Container Networking 0.6.0
- etcd v3.3.9
- CoreDNS v1.2.2

## 全体の流れ

作業は14のLabに分かれており各Labではそれぞれ以下のことをする。

- [Prerequisites](https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/01-prerequisites.md)
  - gcloudコマンドをセットアップする
- [Installing the Client Tools](https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/02-client-tools.md)
  - 作業用のPCに`kubectl`と`cfssl`をインストールする
- [Provisioning Compute Resources](https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/03-compute-resources.md)
  - GCP上にネットワークとインスタンスを作成する
- [Provisioning the CA and Generating TLS Certificates](https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/04-certificate-authority.md)
  - ルートCAを作成し、各k8sコンポーネント用の鍵と証明書を作成する
- [Generating Kubernetes Configuration Files for Authentication](https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/05-kubernetes-configuration-files.md)
  - 各k8sコンポーネントが使用する`kubeconfig`を作成する
- [Generating the Data Encryption Config and Key](https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/06-data-encryption-keys.md)
  - Secretを暗号化してからetcdに保存するための鍵と設定ファイルを作成する
- [Bootstrapping the etcd Cluster](https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/07-bootstrapping-etcd.md)
  - etcdクラスターを起動する
- [Bootstrapping the Kubernetes Control Plane](https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/08-bootstrapping-kubernetes-controllers.md)
  - Masterノードのk8sコンポーネント（`apiserver`、`scheduler`、`controller-manager`）を起動する
- [Bootstrapping the Kubernetes Worker Nodes](https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/09-bootstrapping-kubernetes-workers.md)
  - Workerノードのk8sコンポーネント（`kubelet`、`kube-proxy`）を起動する
- [Configuring kubectl for Remote Access](https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/10-configuring-kubectl.md)
  - 作業用PCから`kubectl`が実行できるようにする
- [Provisioning Pod Network Routes](https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/11-pod-network-routes.md)
  - GCPのルーティングルールを作成し、ノードをまたいだPod間の通信ができるようにする
- [Deploying the DNS Cluster Add-on](https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/12-dns-addon.md)
  - CoreDNSをデプロイする
- [Smoke Test](https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/13-smoke-test.md)
  - クラスターが機能しているかテストする
- [Cleaning Up](https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/14-cleanup.md)
  - 作成したGCP上のリソースを削除する

# Prerequisites

https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/01-prerequisites.md

このLabではgcloudコマンドをセットアップする。

## Google Cloud Platform

GCPのアカウントがなければサインアップする。アカウントはあったので特に何もせず。
このチュートリアルにかかるコストは0.22ドル/1時間（5.39ドル/1日）。アカウントを新規作成した場合は300ドル分のトライアルでチュートリアルを実施できるはず。

## Google Cloud Platform SDK

### Install the Google Cloud SDK

Google Cloud SDKを導入する

```
brew cask install google-cloud-sdk
```

`.bashrc`に以下を追加し、`PATH`を通して補完を有効にする。

```
source '/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.bash.inc'
source '/usr/local/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/completion.bash.inc'
```

バージョンを確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~
$ gcloud version
Google Cloud SDK 221.0.0
bq 2.0.35
core 2018.10.12
gsutil 4.34
sotoiwa@Soto-no-MacBook-Air:~
$
```

### Set a Default Compute Region and Zone

CLIを初期化し、デフォルトの地域とゾーンを設定する。

```
gcloud init
```

```shell-session
sotoiwa@Soto-no-MacBook-Air:~
$ gcloud config set compute/zone asia-northeast1-a
Updated property [compute/zone].
sotoiwa@Soto-no-MacBook-Air:~
$
```

```shell-session
sotoiwa@soto-no-air:~
$ gcloud config list
[compute]
region = asia-northeast1
zone = asia-northeast1-a
[core]
account = hogehoge@hogehoge.com
disable_usage_reporting = True
project = hogehoge

Your active configuration is: [default]
sotoiwa@soto-no-air:~
$
```

## Running Commands in Parallel with tmux

`tmux`を使うと同じコマンドを複数のウインドウに入力できるので便利らしい。`tmux`はほとんど使ったことがないので以下のリンクを読む。

- [tmux基本まとめ](https://qiita.com/ijiest/items/4a42e8543df373babcf2)
- [tmuxを使い始めたので基本的な機能の使い方とかを整理してみた](http://kanjuku-tomato.blogspot.com/2014/02/tmux.html)

結局使わなかったが、同じコマンドを複数のペインに入力するために、最低限`tmux`を使うには以下のようにする。

- `brew install tmux`
- マウススクロールができるように以下を設定する

```:~/.tmux.conf
set-option -g mouse on
```

- `tmux`でウインドウを立ち上げる
- `Ctrl+b`→`"`でペインを上下に分割する
- もう一度`Ctrl+b`→`"`でペインをさらに上下に分割する
- マウスでペインの境界をドラッグしてペインのサイズをいい感じにする
- 各ペインで各サーバーにログインする
- `Ctrl+b`→`;`で`synchronize-panes`を有効化する
- 戻すときは`Ctrl+b`→`:`でコマンドモードに入り、`set synchronize-panes off`と入力

# Installing the Client Tools

https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/02-client-tools.md

このLabでは作業用のPCに`kubectl`と`cfssl`をインストールする。

## Install CFSSL

`cfssl`をインストールする。

### OS X

```
brew install cfssl
```

### Verification

バージョン1.2.0以上であることを確認。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~
$ cfssl version
Version: 1.3.2
Revision: dev
Runtime: go1.10.2
sotoiwa@Soto-no-MacBook-Air:~
$
```

## Install kubectl

`kubectl`をインストールする。

### OS X

`brew`で入れたものが入ってたのでそのまま使う。

### Verification

バージョン1.12.0以上であることを確認する。

```
sotoiwa@Soto-no-MacBook-Air:~
$ kubectl version --client
Client Version: version.Info{Major:"1", Minor:"12", GitVersion:"v1.12.2", GitCommit:"17c77c7898218073f14c8d573582e8d2313dc740", GitTreeState:"clean", BuildDate:"2018-10-30T21:39:38Z", GoVersion:"go1.11.1", Compiler:"gc", Platform:"darwin/amd64"}
sotoiwa@soto-no-air:~
$
```

# Provisioning Compute Resources

https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/03-compute-resources.md

このLabではGCP上にネットワークとインスタンスを作成する。

## Networking

最終的に以下のようなネットワークとアドレスを使用することになる。

|ネットワーク／アドレス|名前|説明|設定方法|
|---|---|---|---|
|10.240.0.0/24||今回のVMインスタンスが配置されるサブネット|gcloudコマンド|
|10.240.0.10|controller-0|Masterノード#0のIP|gcloudコマンド|
|10.240.0.11|controller-1|Masterノード#1のIP|gcloudコマンド|
|10.240.0.12|controller-2|Masterノード#2のIP|gcloudコマンド|
|10.240.0.20|worker-0|Wokerノード#0のIP|gcloudコマンド|
|10.240.0.21|worker-1|Wokerノード#1のIP|gcloudコマンド|
|10.240.0.22|worker-2|Wokerノード#2のIP|gcloudコマンド|
|35.243.101.236||apiserverの外部公開用アドレス|gcloudコマンド|
|10.200.0.0/16||クラスター全体のCIDR|controller-managerの`--cluster-cidr`で指定|
|10.200.0.0/24||worker-0のPodのサブネット|CNIのブリッジネットワーク設定ファイル|
|10.200.1.0/24||worker-1のPodのサブネット|CNIのブリッジネットワーク設定ファイル|
|10.200.2.0/24||worker-2のPodのサブネット|CNIのブリッジネットワーク設定ファイル|
|10.32.0.0/24||Serviceで使用するアドレス範囲|apiserver（とcontroller-manager）の`--service-cluster-ip-range`で指定|
|10.32.0.1|kubernetes|apiserverのサービスIP|Serviceのアドレス範囲の一番目がapiserverのServiceになる|
|10.32.0.10|kube-dns|clusterDNSのアドレス|CoreDNSのマニフェストで指定|

### Virtual Private Cloud Network

VPCネットワークを作成する。

```:コマンド
gcloud compute networks create kubernetes-the-hard-way --subnet-mode custom
```

```shell-session:実行ログ
sotoiwa@soto-no-air:~
$ gcloud compute networks create kubernetes-the-hard-way --subnet-mode custom
Created [https://www.googleapis.com/compute/v1/projects/sotoiwa/global/networks/kubernetes-the-hard-way].
NAME                     SUBNET_MODE  BGP_ROUTING_MODE  IPV4_RANGE  GATEWAY_IPV4
kubernetes-the-hard-way  CUSTOM       REGIONAL

Instances on this network will not be reachable until firewall rules
are created. As an example, you can allow all internal traffic between
instances as well as SSH, RDP, and ICMP by running:

$ gcloud compute firewall-rules create <FIREWALL_NAME> --network kubernetes-the-hard-way --allow tcp,udp,icmp --source-ranges <IP_RANGE>
$ gcloud compute firewall-rules create <FIREWALL_NAME> --network kubernetes-the-hard-way --allow tcp:22,tcp:3389,icmp

sotoiwa@soto-no-air:~
$
```

作成したVPCネットワークを確認する。

```shell-session
sotoiwa@soto-no-air:~
$ gcloud compute networks list
NAME                     SUBNET_MODE  BGP_ROUTING_MODE  IPV4_RANGE  GATEWAY_IPV4
default                  AUTO         REGIONAL
kubernetes-the-hard-way  CUSTOM       REGIONAL
sotoiwa@soto-no-air:~
$
```

サブネットを作成する。

```:コマンド
gcloud compute networks subnets create kubernetes \
  --network kubernetes-the-hard-way \
  --range 10.240.0.0/24
```

```shell-session:実行ログ
sotoiwa@soto-no-air:~
$ gcloud compute networks subnets create kubernetes \
>   --network kubernetes-the-hard-way \
>   --range 10.240.0.0/24
Created [https://www.googleapis.com/compute/v1/projects/sotoiwa/regions/asia-northeast1/subnetworks/kubernetes].
NAME        REGION           NETWORK                  RANGE
kubernetes  asia-northeast1  kubernetes-the-hard-way  10.240.0.0/24
sotoiwa@soto-no-air:~
$
```

作成したサブネットを確認する。

```shell-session
sotoiwa@soto-no-air:~
$ gcloud compute networks subnets list --network kubernetes-the-hard-way
NAME        REGION           NETWORK                  RANGE
kubernetes  asia-northeast1  kubernetes-the-hard-way  10.240.0.0/24
sotoiwa@soto-no-air:~
$
```

### Firewall Rules

全てのプロトコルで内部通信を許可するルールを作成する

- `10.240.0.0/24`はVMインスタンスを配置したネットワーク
- `10.200.0.0/16`はPodが使用するアドレス範囲（クラスター全体のCIDR）

```:コマンド
gcloud compute firewall-rules create kubernetes-the-hard-way-allow-internal \
  --allow tcp,udp,icmp \
  --network kubernetes-the-hard-way \
  --source-ranges 10.240.0.0/24,10.200.0.0/16
```

```shell-session:実行ログ
sotoiwa@soto-no-air:~
$ gcloud compute firewall-rules create kubernetes-the-hard-way-allow-internal \
>   --allow tcp,udp,icmp \
>   --network kubernetes-the-hard-way \
>   --source-ranges 10.240.0.0/24,10.200.0.0/16
Creating firewall...⠏Created [https://www.googleapis.com/compute/v1/projects/sotoiwa/global/firewalls/kubernetes-the-hard-way-allow-internal].
Creating firewall...done.
NAME                                    NETWORK                  DIRECTION  PRIORITY  ALLOW         DENY  DISABLED
kubernetes-the-hard-way-allow-internal  kubernetes-the-hard-way  INGRESS    1000      tcp,udp,icmp        False
sotoiwa@soto-no-air:~
$
```

外部からのSSH、ICMP、HTTPSを許可する。

```:コマンド
gcloud compute firewall-rules create kubernetes-the-hard-way-allow-external \
  --allow tcp:22,tcp:6443,icmp \
  --network kubernetes-the-hard-way \
  --source-ranges 0.0.0.0/0
```

```shell-session:実行ログ
sotoiwa@soto-no-air:~
$ gcloud compute firewall-rules create kubernetes-the-hard-way-allow-external \
>   --allow tcp:22,tcp:6443,icmp \
>   --network kubernetes-the-hard-way \
>   --source-ranges 0.0.0.0/0
Creating firewall...⠏Created [https://www.googleapis.com/compute/v1/projects/sotoiwa/global/firewalls/kubernetes-the-hard-way-allow-external].
Creating firewall...done.
NAME                                    NETWORK                  DIRECTION  PRIORITY  ALLOW                 DENY  DISABLED
kubernetes-the-hard-way-allow-external  kubernetes-the-hard-way  INGRESS    1000      tcp:22,tcp:6443,icmp        False
sotoiwa@soto-no-air:~
$
```

作成したルールを確認する。

```shell-session
sotoiwa@soto-no-air:~
$ gcloud compute firewall-rules list --filter="network:kubernetes-the-hard-way"
NAME                                    NETWORK                  DIRECTION  PRIORITY  ALLOW                 DENY  DISABLED
kubernetes-the-hard-way-allow-external  kubernetes-the-hard-way  INGRESS    1000      tcp:22,tcp:6443,icmp        False
kubernetes-the-hard-way-allow-internal  kubernetes-the-hard-way  INGRESS    1000      tcp,udp,icmp                False

To show all fields of the firewall, please show in JSON format: --format=json
To show all fields in table format, please see the examples in --help.

sotoiwa@soto-no-air:~
$
```

### Kubernetes Public IP Address

API Serverの外部公開用のIPアドレスを取得する。

```:コマンド
gcloud compute addresses create kubernetes-the-hard-way \
  --region $(gcloud config get-value compute/region)
```

```shell-session:実行ログ
sotoiwa@soto-no-air:~
$ gcloud compute addresses create kubernetes-the-hard-way \
>   --region $(gcloud config get-value compute/region)
Created [https://www.googleapis.com/compute/v1/projects/sotoiwa/regions/asia-northeast1/addresses/kubernetes-the-hard-way].
sotoiwa@soto-no-air:~
$
```

作成されたアドレスを確認する。

```shell-session
sotoiwa@soto-no-air:~
$ gcloud compute addresses list --filter="name=('kubernetes-the-hard-way')"
NAME                     REGION           ADDRESS         STATUS
kubernetes-the-hard-way  asia-northeast1  35.243.101.236  RESERVED
sotoiwa@soto-no-air:~
$
```

## Compute Instances

Ubuntu Server 18.04のVMインスタンスを作成する。各インスタンスは固定のプライベートIPを持つ。

### Kubernetes Controllers

Masterノード（コントロールプレーン）の3台を作成する。

```:コマンド
for i in 0 1 2; do
  gcloud compute instances create controller-${i} \
    --async \
    --boot-disk-size 200GB \
    --can-ip-forward \
    --image-family ubuntu-1804-lts \
    --image-project ubuntu-os-cloud \
    --machine-type n1-standard-1 \
    --private-network-ip 10.240.0.1${i} \
    --scopes compute-rw,storage-ro,service-management,service-control,logging-write,monitoring \
    --subnet kubernetes \
    --tags kubernetes-the-hard-way,controller
done
```

```shell-session:実行ログ
sotoiwa@soto-no-air:~
$ for i in 0 1 2; do
>   gcloud compute instances create controller-${i} \
>     --async \
>     --boot-disk-size 200GB \
>     --can-ip-forward \
>     --image-family ubuntu-1804-lts \
>     --image-project ubuntu-os-cloud \
>     --machine-type n1-standard-1 \
>     --private-network-ip 10.240.0.1${i} \
>     --scopes compute-rw,storage-ro,service-management,service-control,logging-write,monitoring \
>     --subnet kubernetes \
>     --tags kubernetes-the-hard-way,controller
> done
Instance creation in progress for [controller-0]: https://www.googleapis.com/compute/v1/projects/sotoiwa/zones/asia-northeast1-a/operations/operation-1541756265972-57a381a904121-5c3b74e7-36e449c1
Use [gcloud compute operations describe URI] command to check the status of the operation(s).
Instance creation in progress for [controller-1]: https://www.googleapis.com/compute/v1/projects/sotoiwa/zones/asia-northeast1-a/operations/operation-1541756270177-57a381ad06ae9-9ebc254c-e604d3d4
Use [gcloud compute operations describe URI] command to check the status of the operation(s).
Instance creation in progress for [controller-2]: https://www.googleapis.com/compute/v1/projects/sotoiwa/zones/asia-northeast1-a/operations/operation-1541756274215-57a381b0e085a-d986a783-47ccc0f6
Use [gcloud compute operations describe URI] command to check the status of the operation(s).
sotoiwa@soto-no-air:~
$
```

### Kubernetes Workers

Workerノードを作成する。各ノードが使用するPodネットワークのサブネットの値（`pod-cidr`）をメタデータに格納しておく。クラスター全体のCIDRは後でController Managerの`--cluster-cidr`パラメータで指定することになり、このチュートリアルでは`10.200.0.0/16`を使う。各Workerノードはそのうちのぞれぞれ`10.200.0.0/24`、`10.200.1.0/24`、`10.200.2.0/24`を使う。

```:コマンド
for i in 0 1 2; do
  gcloud compute instances create worker-${i} \
    --async \
    --boot-disk-size 200GB \
    --can-ip-forward \
    --image-family ubuntu-1804-lts \
    --image-project ubuntu-os-cloud \
    --machine-type n1-standard-1 \
    --metadata pod-cidr=10.200.${i}.0/24 \
    --private-network-ip 10.240.0.2${i} \
    --scopes compute-rw,storage-ro,service-management,service-control,logging-write,monitoring \
    --subnet kubernetes \
    --tags kubernetes-the-hard-way,worker
done
```

```:実行ログ
sotoiwa@soto-no-air:~
$ for i in 0 1 2; do
>   gcloud compute instances create worker-${i} \
>     --async \
>     --boot-disk-size 200GB \
>     --can-ip-forward \
>     --image-family ubuntu-1804-lts \
>     --image-project ubuntu-os-cloud \
>     --machine-type n1-standard-1 \
>     --metadata pod-cidr=10.200.${i}.0/24 \
>     --private-network-ip 10.240.0.2${i} \
>     --scopes compute-rw,storage-ro,service-management,service-control,logging-write,monitoring \
>     --subnet kubernetes \
>     --tags kubernetes-the-hard-way,worker
> done
Instance creation in progress for [worker-0]: https://www.googleapis.com/compute/v1/projects/sotoiwa/zones/asia-northeast1-a/operations/operation-1541757249739-57a38553358f8-a5900c8d-449e5ada
Use [gcloud compute operations describe URI] command to check the status of the operation(s).
Instance creation in progress for [worker-1]: https://www.googleapis.com/compute/v1/projects/sotoiwa/zones/asia-northeast1-a/operations/operation-1541757252867-57a38556313ba-b4658130-00e19bc3
Use [gcloud compute operations describe URI] command to check the status of the operation(s).
Instance creation in progress for [worker-2]: https://www.googleapis.com/compute/v1/projects/sotoiwa/zones/asia-northeast1-a/operations/operation-1541757256094-57a3855945131-9896d4b4-a81fd823
Use [gcloud compute operations describe URI] command to check the status of the operation(s).
sotoiwa@soto-no-air:~
$
```

### Verification

作成されたインスタンスを確認する。

```shell-session
sotoiwa@soto-no-air:~
$ gcloud compute instances list
NAME          ZONE               MACHINE_TYPE   PREEMPTIBLE  INTERNAL_IP  EXTERNAL_IP     STATUS
controller-0  asia-northeast1-a  n1-standard-1               10.240.0.10  35.221.104.74   RUNNING
controller-1  asia-northeast1-a  n1-standard-1               10.240.0.11  35.200.119.187  RUNNING
controller-2  asia-northeast1-a  n1-standard-1               10.240.0.12  35.187.211.56   RUNNING
worker-0      asia-northeast1-a  n1-standard-1               10.240.0.20  35.243.75.112   RUNNING
worker-1      asia-northeast1-a  n1-standard-1               10.240.0.21  35.243.106.204  RUNNING
worker-2      asia-northeast1-a  n1-standard-1               10.240.0.22  35.200.35.27    RUNNING
sotoiwa@soto-no-air:~
$
```

## Configuring SSH Access

はじめてインスタンスに接続すると、SSH鍵が作成され、プロジェクトまたはインスタンスメタデータに保存される。

`controller-0`インスタンスへのSSHログインできることを確認する。

```
gcloud compute ssh controller-0
```

# Provisioning a CA and Generating TLS Certificates

https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/04-certificate-authority.md

cfsslを使って認証局を立て、各コンポーネント用の証明書を生成する。

（参考）
https://kubernetes.io/docs/concepts/cluster-administration/certificates/

## Certificate Authority

作業用PCで作業する。

ルートCAの設定ファイルのjsonを作成する。`kubernetes`というプロファイルを定義し、このCAが署名する証明書の有効期限と、X509v3拡張で証明書に含まれるパブリックキーの用途を指定している。後でCAから証明書を発行するときにこの設定ファイルとプロファイルを指定する。

```
cat > ca-config.json <<EOF
{
  "signing": {
    "default": {
      "expiry": "8760h"
    },
    "profiles": {
      "kubernetes": {
        "usages": ["signing", "key encipherment", "server auth", "client auth"],
        "expiry": "8760h"
      }
    }
  }
}
EOF
```

ルートCAのCSR（証明書署名要求）を作成するためのjsonを作成する。ルートCAのCNは先頭大文字の`Kubernetes`としている。

```
cat > ca-csr.json <<EOF
{
  "CN": "Kubernetes",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "US",
      "L": "Portland",
      "O": "Kubernetes",
      "OU": "CA",
      "ST": "Oregon"
    }
  ]
}
EOF
```

CA秘密鍵（ca-key.pem）とCA証明書（ca.pem）を作成する。このとき証明書署名要求（ca.csr）もできる。前半の`cfssl gencert`コマンドが秘密鍵とCSRと証明書を作成していて、出力されたjsonを`cfssljson`コマンドがファイルにしている。

```:コマンド
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ cfssl gencert -initca ca-csr.json | cfssljson -bare ca
2018/11/11 13:17:28 [INFO] generating a new CA key and certificate from CSR
2018/11/11 13:17:28 [INFO] generate received request
2018/11/11 13:17:28 [INFO] received CSR
2018/11/11 13:17:28 [INFO] generating key: rsa-2048
2018/11/11 13:17:29 [INFO] encoded CSR
2018/11/11 13:17:29 [INFO] signed certificate with serial number 689603942501758426539296774063220033367462065061
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

鍵の内容を確認する。

```
openssl rsa -text -noout -in ca-key.pem
```

CSRの内容を確認する。

```
openssl req -text -noout -in ca.csr
```

証明書の内容を確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ openssl x509 -text -noout -in ca.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            78:ca:e9:06:c9:fb:05:0c:d7:24:9e:e8:cf:9f:bd:5c:fb:ab:33:a5
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, ST=Oregon, L=Portland, O=Kubernetes, OU=CA, CN=Kubernetes
        Validity
            Not Before: Nov 11 04:12:00 2018 GMT
            Not After : Nov 10 04:12:00 2023 GMT
        Subject: C=US, ST=Oregon, L=Portland, O=Kubernetes, OU=CA, CN=Kubernetes
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
（省略）
```

## Client and Server Certificates

各Kubernetesコンポーネント用のサーバー／クライアント証明書と、`admin`ユーザー用のクライアント証明書を作成する。

### The Admin Client Certificate

`admin`ユーザーの秘密鍵と証明書を作成する。

設定ファイルを作成する。`CN=admin`を指定している。

```
cat > admin-csr.json <<EOF
{
  "CN": "admin",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "US",
      "L": "Portland",
      "O": "system:masters",
      "OU": "Kubernetes The Hard Way",
      "ST": "Oregon"
    }
  ]
}
EOF
```

秘密鍵と証明書を作成する。

```:コマンド
cfssl gencert \
  -ca=ca.pem \
  -ca-key=ca-key.pem \
  -config=ca-config.json \
  -profile=kubernetes \
  admin-csr.json | cfssljson -bare admin
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ cfssl gencert \
>   -ca=ca.pem \
>   -ca-key=ca-key.pem \
>   -config=ca-config.json \
>   -profile=kubernetes \
>   admin-csr.json | cfssljson -bare admin
2018/11/11 13:37:46 [INFO] generate received request
2018/11/11 13:37:46 [INFO] received CSR
2018/11/11 13:37:46 [INFO] generating key: rsa-2048
2018/11/11 13:37:46 [INFO] encoded CSR
2018/11/11 13:37:46 [INFO] signed certificate with serial number 194040900673817816765523470049772624081356590203
2018/11/11 13:37:46 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitable for
websites. For more information see the Baseline Requirements for the Issuance and Management
of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
specifically, section 10.2.3 ("Information Requirements").
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

`admin-key.pem`と`admin.csr`と`admin.pem`が作られる。

証明書を確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ openssl x509 -text -noout -in admin.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            21:fd:18:4c:6d:25:82:a8:53:9c:fd:e8:4e:b0:d3:4b:21:10:0c:7b
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, ST=Oregon, L=Portland, O=Kubernetes, OU=CA, CN=Kubernetes
        Validity
            Not Before: Nov 11 04:33:00 2018 GMT
            Not After : Nov 11 04:33:00 2019 GMT
        Subject: C=US, ST=Oregon, L=Portland, O=system:masters, OU=Kubernetes The Hard Way, CN=admin
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
（省略）
```

### The Kubelet Client Certificates

Kubeletのクライアント証明書を作成する。Kubeletのリクエストは特別な認可モードである`Node Authorizer`で認可する（controller-managerなどはRBAC）が、そのためには`CN=system:node:<nodeName>`とする必要がある。全てのWorkerノード用にKubeletのクライアント証明書を作成する。

また、KubeletはクライアントであるだけでなくKubelet APIを提供するサーバーでもあるため、生成時に`-hostname`を指定している。これによって作成する証明書には`Subject Alternative Name`が含まれる。

```:コマンド
for instance in worker-0 worker-1 worker-2; do
cat > ${instance}-csr.json <<EOF
{
  "CN": "system:node:${instance}",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "US",
      "L": "Portland",
      "O": "system:nodes",
      "OU": "Kubernetes The Hard Way",
      "ST": "Oregon"
    }
  ]
}
EOF

EXTERNAL_IP=$(gcloud compute instances describe ${instance} \
  --format 'value(networkInterfaces[0].accessConfigs[0].natIP)')

INTERNAL_IP=$(gcloud compute instances describe ${instance} \
  --format 'value(networkInterfaces[0].networkIP)')

cfssl gencert \
  -ca=ca.pem \
  -ca-key=ca-key.pem \
  -config=ca-config.json \
  -hostname=${instance},${EXTERNAL_IP},${INTERNAL_IP} \
  -profile=kubernetes \
  ${instance}-csr.json | cfssljson -bare ${instance}
done
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ for instance in worker-0 worker-1 worker-2; do
> cat > ${instance}-csr.json <<EOF
> {
>   "CN": "system:node:${instance}",
>   "key": {
>     "algo": "rsa",
>     "size": 2048
>   },
>   "names": [
>     {
>       "C": "US",
>       "L": "Portland",
>       "O": "system:nodes",
>       "OU": "Kubernetes The Hard Way",
>       "ST": "Oregon"
>     }
>   ]
> }
> EOF
>
> EXTERNAL_IP=$(gcloud compute instances describe ${instance} \
>   --format 'value(networkInterfaces[0].accessConfigs[0].natIP)')
>
> INTERNAL_IP=$(gcloud compute instances describe ${instance} \
>   --format 'value(networkInterfaces[0].networkIP)')
>
> cfssl gencert \
>   -ca=ca.pem \
>   -ca-key=ca-key.pem \
>   -config=ca-config.json \
>   -hostname=${instance},${EXTERNAL_IP},${INTERNAL_IP} \
>   -profile=kubernetes \
>   ${instance}-csr.json | cfssljson -bare ${instance}
> done
2018/11/11 13:54:09 [INFO] generate received request
2018/11/11 13:54:09 [INFO] received CSR
2018/11/11 13:54:09 [INFO] generating key: rsa-2048
2018/11/11 13:54:09 [INFO] encoded CSR
2018/11/11 13:54:09 [INFO] signed certificate with serial number 607068271717182629182608002048778592028239367009
2018/11/11 13:54:12 [INFO] generate received request
2018/11/11 13:54:12 [INFO] received CSR
2018/11/11 13:54:12 [INFO] generating key: rsa-2048
2018/11/11 13:54:12 [INFO] encoded CSR
2018/11/11 13:54:13 [INFO] signed certificate with serial number 265349660986184529136660474458334524391738562848
2018/11/11 13:54:15 [INFO] generate received request
2018/11/11 13:54:15 [INFO] received CSR
2018/11/11 13:54:15 [INFO] generating key: rsa-2048
2018/11/11 13:54:15 [INFO] encoded CSR
2018/11/11 13:54:15 [INFO] signed certificate with serial number 441273454681782563464999456585802366467077262409
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

作成されたファイルを確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ ls -l worker*
-rw-r--r--  1 sotoiwa  staff   244 11 11 13:54 worker-0-csr.json
-rw-------  1 sotoiwa  staff  1679 11 11 13:54 worker-0-key.pem
-rw-r--r--  1 sotoiwa  staff  1119 11 11 13:54 worker-0.csr
-rw-r--r--  1 sotoiwa  staff  1493 11 11 13:54 worker-0.pem
-rw-r--r--  1 sotoiwa  staff   244 11 11 13:54 worker-1-csr.json
-rw-------  1 sotoiwa  staff  1679 11 11 13:54 worker-1-key.pem
-rw-r--r--  1 sotoiwa  staff  1119 11 11 13:54 worker-1.csr
-rw-r--r--  1 sotoiwa  staff  1493 11 11 13:54 worker-1.pem
-rw-r--r--  1 sotoiwa  staff   244 11 11 13:54 worker-2-csr.json
-rw-------  1 sotoiwa  staff  1679 11 11 13:54 worker-2-key.pem
-rw-r--r--  1 sotoiwa  staff  1119 11 11 13:54 worker-2.csr
-rw-r--r--  1 sotoiwa  staff  1493 11 11 13:54 worker-2.pem
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

`worker-0`の証明書を確認する。SANが含まれる。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ openssl x509 -text -noout -in worker-0.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            6a:55:e1:fd:ea:e0:e4:7a:5c:d4:cf:90:44:b5:e5:34:c4:28:8b:61
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, ST=Oregon, L=Portland, O=Kubernetes, OU=CA, CN=Kubernetes
        Validity
            Not Before: Nov 11 04:49:00 2018 GMT
            Not After : Nov 11 04:49:00 2019 GMT
        Subject: C=US, ST=Oregon, L=Portland, O=system:nodes, OU=Kubernetes The Hard Way, CN=system:node:worker-0
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
（省略）
            X509v3 Subject Alternative Name:
                DNS:worker-0, IP Address:35.243.75.112, IP Address:10.240.0.20
（省略）
```

### The Controller Manager Client Certificate

Controller Managerの証明書は`CN=system:kube-controller-manager`とする。

```:コマンド
{

cat > kube-controller-manager-csr.json <<EOF
{
  "CN": "system:kube-controller-manager",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "US",
      "L": "Portland",
      "O": "system:kube-controller-manager",
      "OU": "Kubernetes The Hard Way",
      "ST": "Oregon"
    }
  ]
}
EOF

cfssl gencert \
  -ca=ca.pem \
  -ca-key=ca-key.pem \
  -config=ca-config.json \
  -profile=kubernetes \
  kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager

}
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ {
>
> cat > kube-controller-manager-csr.json <<EOF
> {
>   "CN": "system:kube-controller-manager",
>   "key": {
>     "algo": "rsa",
>     "size": 2048
>   },
>   "names": [
>     {
>       "C": "US",
>       "L": "Portland",
>       "O": "system:kube-controller-manager",
>       "OU": "Kubernetes The Hard Way",
>       "ST": "Oregon"
>     }
>   ]
> }
> EOF
>
> cfssl gencert \
>   -ca=ca.pem \
>   -ca-key=ca-key.pem \
>   -config=ca-config.json \
>   -profile=kubernetes \
>   kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager
>
> }
2018/11/11 14:05:17 [INFO] generate received request
2018/11/11 14:05:17 [INFO] received CSR
2018/11/11 14:05:17 [INFO] generating key: rsa-2048
2018/11/11 14:05:18 [INFO] encoded CSR
2018/11/11 14:05:18 [INFO] signed certificate with serial number 663059462179332133204598729540750202823868590760
2018/11/11 14:05:18 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitable for
websites. For more information see the Baseline Requirements for the Issuance and Management
of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
specifically, section 10.2.3 ("Information Requirements").
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ openssl x509 -text -noout -in kube-controller-manager.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            74:24:9d:56:20:af:2a:3b:a1:90:4c:2a:21:1b:4b:64:9c:be:aa:a8
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, ST=Oregon, L=Portland, O=Kubernetes, OU=CA, CN=Kubernetes
        Validity
            Not Before: Nov 11 05:00:00 2018 GMT
            Not After : Nov 11 05:00:00 2019 GMT
        Subject: C=US, ST=Oregon, L=Portland, O=system:kube-controller-manager, OU=Kubernetes The Hard Way, CN=system:kube-controller-manager
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
（省略）
```

### The Kube Proxy Client Certificate

Kube Proxyの証明書は`CN=system:kube-proxy`とする。

```:コマンド
{

cat > kube-proxy-csr.json <<EOF
{
  "CN": "system:kube-proxy",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "US",
      "L": "Portland",
      "O": "system:node-proxier",
      "OU": "Kubernetes The Hard Way",
      "ST": "Oregon"
    }
  ]
}
EOF

cfssl gencert \
  -ca=ca.pem \
  -ca-key=ca-key.pem \
  -config=ca-config.json \
  -profile=kubernetes \
  kube-proxy-csr.json | cfssljson -bare kube-proxy

}
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ {
>
> cat > kube-proxy-csr.json <<EOF
> {
>   "CN": "system:kube-proxy",
>   "key": {
>     "algo": "rsa",
>     "size": 2048
>   },
>   "names": [
>     {
>       "C": "US",
>       "L": "Portland",
>       "O": "system:node-proxier",
>       "OU": "Kubernetes The Hard Way",
>       "ST": "Oregon"
>     }
>   ]
> }
> EOF
>
> cfssl gencert \
>   -ca=ca.pem \
>   -ca-key=ca-key.pem \
>   -config=ca-config.json \
>   -profile=kubernetes \
>   kube-proxy-csr.json | cfssljson -bare kube-proxy
>
> }
2018/11/11 14:13:28 [INFO] generate received request
2018/11/11 14:13:28 [INFO] received CSR
2018/11/11 14:13:28 [INFO] generating key: rsa-2048
2018/11/11 14:13:29 [INFO] encoded CSR
2018/11/11 14:13:29 [INFO] signed certificate with serial number 419734016720855630130671555622742251431767916802
2018/11/11 14:13:29 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitable for
websites. For more information see the Baseline Requirements for the Issuance and Management
of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
specifically, section 10.2.3 ("Information Requirements").
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ openssl x509 -text -noout -in kube-proxy.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            49:85:86:35:c2:1e:dc:59:66:12:4d:e6:9a:65:d1:df:45:65:41:02
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, ST=Oregon, L=Portland, O=Kubernetes, OU=CA, CN=Kubernetes
        Validity
            Not Before: Nov 11 05:08:00 2018 GMT
            Not After : Nov 11 05:08:00 2019 GMT
        Subject: C=US, ST=Oregon, L=Portland, O=system:node-proxier, OU=Kubernetes The Hard Way, CN=system:kube-proxy
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
（省略）
```

### The Scheduler Client Certificate

Schedulerの証明書は`CN=system:kube-scheduler`とする。

```:コマンド
{

cat > kube-scheduler-csr.json <<EOF
{
  "CN": "system:kube-scheduler",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "US",
      "L": "Portland",
      "O": "system:kube-scheduler",
      "OU": "Kubernetes The Hard Way",
      "ST": "Oregon"
    }
  ]
}
EOF

cfssl gencert \
  -ca=ca.pem \
  -ca-key=ca-key.pem \
  -config=ca-config.json \
  -profile=kubernetes \
  kube-scheduler-csr.json | cfssljson -bare kube-scheduler

}
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ {
>
> cat > kube-scheduler-csr.json <<EOF
> {
>   "CN": "system:kube-scheduler",
>   "key": {
>     "algo": "rsa",
>     "size": 2048
>   },
>   "names": [
>     {
>       "C": "US",
>       "L": "Portland",
>       "O": "system:kube-scheduler",
>       "OU": "Kubernetes The Hard Way",
>       "ST": "Oregon"
>     }
>   ]
> }
> EOF
>
> cfssl gencert \
>   -ca=ca.pem \
>   -ca-key=ca-key.pem \
>   -config=ca-config.json \
>   -profile=kubernetes \
>   kube-scheduler-csr.json | cfssljson -bare kube-scheduler
>
> }
2018/11/11 14:17:29 [INFO] generate received request
2018/11/11 14:17:29 [INFO] received CSR
2018/11/11 14:17:29 [INFO] generating key: rsa-2048
2018/11/11 14:17:30 [INFO] encoded CSR
2018/11/11 14:17:30 [INFO] signed certificate with serial number 291023982831656432886923858896283759904092510905
2018/11/11 14:17:30 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitable for
websites. For more information see the Baseline Requirements for the Issuance and Management
of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
specifically, section 10.2.3 ("Information Requirements").
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ openssl x509 -text -noout -in kube-scheduler.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            32:f9:f7:7b:6e:58:65:42:8f:4e:52:c2:e1:85:f0:81:8a:2e:da:b9
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, ST=Oregon, L=Portland, O=Kubernetes, OU=CA, CN=Kubernetes
        Validity
            Not Before: Nov 11 05:13:00 2018 GMT
            Not After : Nov 11 05:13:00 2019 GMT
        Subject: C=US, ST=Oregon, L=Portland, O=system:kube-scheduler, OU=Kubernetes The Hard Way, CN=system:kube-scheduler
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
（省略）
```

### The Kubernetes API Server Certificate

API Serverはクラスター内部からは`kubernetes`というServiceとしてアクセスされるので`CN=kubernetes`とする。`kube-apiserver`ではない。また、外部からもアクセスできるようにするため、`-hostname`オプションでSANに以下を指定する。

|アドレス／ホスト名|説明|
|---|---|
|10.32.0.1|apiserverのServiceのIP（Serviceが使用するアドレス範囲はあとで指定するが、その1番目のアドレスになる）|
|10.240.0.10,10.240.0.11,10.240.0.12|各Masterノードのプライベートアドレス|
|${KUBERNETES_PUBLIC_ADDRESS}|外部公開用のIPアドレス|
|127.0.0.1|ループバックアドレス|
|kubernetes.default|apiserverのServiceのホスト名|

（疑問）
`kubernetes`、`kubernetes.default.svc`、`kubernetes.default.svc.cluster`、`kubernetes.default.svc.cluster.local`もSANに含めた方がよいのでは？

```:コマンド
{

KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-hard-way \
  --region $(gcloud config get-value compute/region) \
  --format 'value(address)')

cat > kubernetes-csr.json <<EOF
{
  "CN": "kubernetes",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "US",
      "L": "Portland",
      "O": "Kubernetes",
      "OU": "Kubernetes The Hard Way",
      "ST": "Oregon"
    }
  ]
}
EOF

cfssl gencert \
  -ca=ca.pem \
  -ca-key=ca-key.pem \
  -config=ca-config.json \
  -hostname=10.32.0.1,10.240.0.10,10.240.0.11,10.240.0.12,${KUBERNETES_PUBLIC_ADDRESS},127.0.0.1,kubernetes.default \
  -profile=kubernetes \
  kubernetes-csr.json | cfssljson -bare kubernetes

}
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ {
>
> KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-hard-way \
>   --region $(gcloud config get-value compute/region) \
>   --format 'value(address)')
>
> cat > kubernetes-csr.json <<EOF
> {
>   "CN": "kubernetes",
>   "key": {
>     "algo": "rsa",
>     "size": 2048
>   },
>   "names": [
>     {
>       "C": "US",
>       "L": "Portland",
>       "O": "Kubernetes",
>       "OU": "Kubernetes The Hard Way",
>       "ST": "Oregon"
>     }
>   ]
> }
> EOF
>
> cfssl gencert \
>   -ca=ca.pem \
>   -ca-key=ca-key.pem \
>   -config=ca-config.json \
>   -hostname=10.32.0.1,10.240.0.10,10.240.0.11,10.240.0.12,${KUBERNETES_PUBLIC_ADDRESS},127.0.0.1,kubernetes.default \
>   -profile=kubernetes \
>   kubernetes-csr.json | cfssljson -bare kubernetes
>
> }
2018/11/11 14:37:02 [INFO] generate received request
2018/11/11 14:37:02 [INFO] received CSR
2018/11/11 14:37:02 [INFO] generating key: rsa-2048
2018/11/11 14:37:03 [INFO] encoded CSR
2018/11/11 14:37:03 [INFO] signed certificate with serial number 265279844700410116849351878684631182647597918003
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ openssl x509 -text -noout -in kubernetes.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            2e:77:8f:45:14:b3:8a:c1:0c:5a:98:57:6a:b7:a7:a1:09:66:e7:33
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, ST=Oregon, L=Portland, O=Kubernetes, OU=CA, CN=Kubernetes
        Validity
            Not Before: Nov 11 05:32:00 2018 GMT
            Not After : Nov 11 05:32:00 2019 GMT
        Subject: C=US, ST=Oregon, L=Portland, O=Kubernetes, OU=Kubernetes The Hard Way, CN=kubernetes
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
（省略）
            X509v3 Subject Alternative Name:
                DNS:kubernetes.default, IP Address:10.32.0.1, IP Address:10.240.0.10, IP Address:10.240.0.11, IP Address:10.240.0.12, IP Address:35.243.101.236, IP Address:127.0.0.1
（省略）
```

## The Service Account Key Pair

Controller Managerで稼働するToken ControllerがService Account Tokenを生成するための秘密鍵を作成する。`CN=service-accounts`の証明書と秘密鍵を作成する。

（参考）
[Managing Service Accounts](https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/)

```:コマンド
{

cat > service-account-csr.json <<EOF
{
  "CN": "service-accounts",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "US",
      "L": "Portland",
      "O": "Kubernetes",
      "OU": "Kubernetes The Hard Way",
      "ST": "Oregon"
    }
  ]
}
EOF

cfssl gencert \
  -ca=ca.pem \
  -ca-key=ca-key.pem \
  -config=ca-config.json \
  -profile=kubernetes \
  service-account-csr.json | cfssljson -bare service-account

}
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ {
>
> cat > service-account-csr.json <<EOF
> {
>   "CN": "service-accounts",
>   "key": {
>     "algo": "rsa",
>     "size": 2048
>   },
>   "names": [
>     {
>       "C": "US",
>       "L": "Portland",
>       "O": "Kubernetes",
>       "OU": "Kubernetes The Hard Way",
>       "ST": "Oregon"
>     }
>   ]
> }
> EOF
>
> cfssl gencert \
>   -ca=ca.pem \
>   -ca-key=ca-key.pem \
>   -config=ca-config.json \
>   -profile=kubernetes \
>   service-account-csr.json | cfssljson -bare service-account
>
> }
2018/11/11 14:51:48 [INFO] generate received request
2018/11/11 14:51:48 [INFO] received CSR
2018/11/11 14:51:48 [INFO] generating key: rsa-2048
2018/11/11 14:51:48 [INFO] encoded CSR
2018/11/11 14:51:48 [INFO] signed certificate with serial number 35293248960946258940722654882849406852741852896
2018/11/11 14:51:48 [WARNING] This certificate lacks a "hosts" field. This makes it unsuitable for
websites. For more information see the Baseline Requirements for the Issuance and Management
of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
specifically, section 10.2.3 ("Information Requirements").
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ openssl x509 -text -noout -in service-account.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            06:2e:9a:a0:f0:7c:02:82:7f:2b:4e:c7:14:46:3c:5a:24:bd:ee:e0
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, ST=Oregon, L=Portland, O=Kubernetes, OU=CA, CN=Kubernetes
        Validity
            Not Before: Nov 11 05:47:00 2018 GMT
            Not After : Nov 11 05:47:00 2019 GMT
        Subject: C=US, ST=Oregon, L=Portland, O=Kubernetes, OU=Kubernetes The Hard Way, CN=service-accounts
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
（省略）
```

## Distribute the Client and Server Certificates

ここまでに作成した秘密鍵・証明書は以下。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ ls -l *.pem
-rw-------  1 sotoiwa  staff  1679 11 11 13:37 admin-key.pem
-rw-r--r--  1 sotoiwa  staff  1428 11 11 13:37 admin.pem
-rw-------  1 sotoiwa  staff  1675 11 11 13:17 ca-key.pem
-rw-r--r--  1 sotoiwa  staff  1318 11 11 13:17 ca.pem
-rw-------  1 sotoiwa  staff  1679 11 11 14:05 kube-controller-manager-key.pem
-rw-r--r--  1 sotoiwa  staff  1484 11 11 14:05 kube-controller-manager.pem
-rw-------  1 sotoiwa  staff  1679 11 11 14:13 kube-proxy-key.pem
-rw-r--r--  1 sotoiwa  staff  1452 11 11 14:13 kube-proxy.pem
-rw-------  1 sotoiwa  staff  1679 11 11 14:17 kube-scheduler-key.pem
-rw-r--r--  1 sotoiwa  staff  1460 11 11 14:17 kube-scheduler.pem
-rw-------  1 sotoiwa  staff  1679 11 11 14:37 kubernetes-key.pem
-rw-r--r--  1 sotoiwa  staff  1521 11 11 14:37 kubernetes.pem
-rw-------  1 sotoiwa  staff  1679 11 11 14:51 service-account-key.pem
-rw-r--r--  1 sotoiwa  staff  1440 11 11 14:51 service-account.pem
-rw-------  1 sotoiwa  staff  1679 11 11 13:54 worker-0-key.pem
-rw-r--r--  1 sotoiwa  staff  1493 11 11 13:54 worker-0.pem
-rw-------  1 sotoiwa  staff  1679 11 11 13:54 worker-1-key.pem
-rw-r--r--  1 sotoiwa  staff  1493 11 11 13:54 worker-1.pem
-rw-------  1 sotoiwa  staff  1679 11 11 13:54 worker-2-key.pem
-rw-r--r--  1 sotoiwa  staff  1493 11 11 13:54 worker-2.pem
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

それぞれの秘密鍵と証明書の最終的な行き先は次の通り。PEMファイルのまま、あるいはkubeconfigの中のBase64エンコードされたデータとして配布される。

- admin-key.pem
  - 作業用PC:admin.kubeconfig
- admin.pem
  - 作業用PC:admin.kubeconfig
- ca-key.pem
  - controller-${i}:/var/lib/kubernetes/ca-key.pem
- ca.pem
  - controller-${i}:/etc/etcd/ca.pem
  - controller-${i}:/var/lib/kubernetes/ca.pem
  - worker-${i}:/var/lib/kubernetes/ca.pem
  - worker-${i}:/var/lib/kubelet/kubeconfig
  - worker-${i}:/var/lib/kube-proxy/kubeconfig
  - controller-${i}:/var/lib/kubernetes/kube-controller-manager.kubeconfig
  - controller-${i}:/var/lib/kubernetes/kube-scheduler.kubeconfig
  - 作業用PC:admin.kubeconfig
- kube-controller-manager-key.pem
  - controller-${i}:/var/lib/kubernetes/kube-controller-manager.kubeconfig
- kube-controller-manager.pem
  - controller-${i}:/var/lib/kubernetes/kube-controller-manager.kubeconfig
- kube-proxy-key.pem
  - worker-${i}:/var/lib/kube-proxy/kubeconfig
- kube-proxy.pem
  - worker-${i}:/var/lib/kube-proxy/kubeconfig
- kube-scheduler-key.pem
  - controller-${i}:/var/lib/kubernetes/kube-scheduler.kubeconfig
- kube-scheduler.pem
  - controller-${i}:/var/lib/kubernetes/kube-scheduler.kubeconfig
- kubernetes-key.pem
  - controller-${i}:/etc/etcd/kubernetes-key.pem
  - controller-${i}:/var/lib/kubernetes/kubernetes-key.pem
- kubernetes.pem
  - controller-${i}:/etc/etcd/kubernetes.pem
  - controller-${i}:/var/lib/kubernetes/kubernetes.pem
- service-account-key.pem
  - controller-${i}:/var/lib/kubernetes/service-account-key.pem
- service-account.pem
  - controller-${i}:/var/lib/kubernetes/service-account.pem
- worker-0-key.pem
  - worker-0:/var/lib/kubelet/worker-0-key.pem
  - worker-0:/var/lib/kubelet/kubeconfig
- worker-0.pem
  - worker-0:/var/lib/kubelet/worker-0.pem
  - worker-0:/var/lib/kubelet/kubeconfig
- worker-1-key.pem
  - worker-1:/var/lib/kubelet/worker-1-key.pem
  - worker-1:/var/lib/kubelet/kubeconfig
- worker-1.pem
  - worker-1:/var/lib/kubelet/worker-1.pem
  - worker-1:/var/lib/kubelet/kubeconfig
- worker-2-key.pem
  - worker-2:/var/lib/kubelet/worker-2-key.pem
  - worker-2:/var/lib/kubelet/kubeconfig
- worker-2.pem
  - worker-2:/var/lib/kubelet/worker-2.pem
  - worker-2:/var/lib/kubelet/kubeconfig

WorkerノードにCAの証明書と各ノード（Kubelet）秘密鍵と証明書を転送する。

```
for instance in worker-0 worker-1 worker-2; do
  gcloud compute scp ca.pem ${instance}-key.pem ${instance}.pem ${instance}:~/
done
```

MasterノードにCAの秘密鍵と証明書、API Serverの秘密鍵と証明書、Service Account作成用の秘密鍵と証明書をコピーする。

```
for instance in controller-0 controller-1 controller-2; do
  gcloud compute scp ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
    service-account-key.pem service-account.pem ${instance}:~/
done
```

以下のコンポーネントの証明書は次のLabでkubeconfigを作成するのに使用する。

- kube-proxy
- kube-controller-manager
- kube-scheduler
- kubelet

# Generating Kubernetes Configuration Files for Authentication

https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/05-kubernetes-configuration-files.md

このLabでは各k8sコンポーネントが使用するkubeconfigを作成する。

## Client Authentication Configs

### Kubernetes Public IP Address

API Serverの外部公開用のIPアドレスを確認する。

```:コマンド
KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-hard-way \
  --region $(gcloud config get-value compute/region) \
  --format 'value(address)')
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-hard-way \
>   --region $(gcloud config get-value compute/region) \
>   --format 'value(address)')
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ echo $KUBERNETES_PUBLIC_ADDRESS
35.243.101.236
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

### The kubelet Kubernetes Configuration File

Kubelet用のkubeconfigを作成する。Kubeletは`CN=system:node:<nodeName>`と設定されたクライアント証明書を使うことでノード認可をする。ノード認可を行うために、あとでAPI Serverは`--authorization-mode=Node`として起動する。

（参考）
[Using Node Authorization](https://kubernetes.io/docs/reference/access-authn-authz/node/)

```:コマンド
for instance in worker-0 worker-1 worker-2; do
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=ca.pem \
    --embed-certs=true \
    --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 \
    --kubeconfig=${instance}.kubeconfig

  kubectl config set-credentials system:node:${instance} \
    --client-certificate=${instance}.pem \
    --client-key=${instance}-key.pem \
    --embed-certs=true \
    --kubeconfig=${instance}.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=system:node:${instance} \
    --kubeconfig=${instance}.kubeconfig

  kubectl config use-context default --kubeconfig=${instance}.kubeconfig
done
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ for instance in worker-0 worker-1 worker-2; do
>   kubectl config set-cluster kubernetes-the-hard-way \
>     --certificate-authority=ca.pem \
>     --embed-certs=true \
>     --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 \
>     --kubeconfig=${instance}.kubeconfig
>
>   kubectl config set-credentials system:node:${instance} \
>     --client-certificate=${instance}.pem \
>     --client-key=${instance}-key.pem \
>     --embed-certs=true \
>     --kubeconfig=${instance}.kubeconfig
>
>   kubectl config set-context default \
>     --cluster=kubernetes-the-hard-way \
>     --user=system:node:${instance} \
>     --kubeconfig=${instance}.kubeconfig
>
>   kubectl config use-context default --kubeconfig=${instance}.kubeconfig
> done
Cluster "kubernetes-the-hard-way" set.
User "system:node:worker-0" set.
Context "default" created.
Switched to context "default".
Cluster "kubernetes-the-hard-way" set.
User "system:node:worker-1" set.
Context "default" created.
Switched to context "default".
Cluster "kubernetes-the-hard-way" set.
User "system:node:worker-2" set.
Context "default" created.
Switched to context "default".
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ cat worker-0.kubeconfig
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: <CA証明書>
    server: https://35.243.101.236:6443
  name: kubernetes-the-hard-way
contexts:
- context:
    cluster: kubernetes-the-hard-way
    user: system:node:worker-0
  name: default
current-context: default
kind: Config
preferences: {}
users:
- name: system:node:worker-0
  user:
    client-certificate-data: <Kubeletのクライアント証明書>
    client-key-data: <Kubeletの秘密鍵>
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

証明書や秘密鍵のデータはbase64エンコードされている。`base64 -D`で戻して確認することができる。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ cat worker-0.kubeconfig | grep certificate-authority-data | awk '{print $2}' | base64 -D
-----BEGIN CERTIFICATE-----
MIIDoDCCAoigAwIBAgIUeMrpBsn7BQzXJJ7oz5+9XPurM6UwDQYJKoZIhvcNAQEL
BQAwaDELMAkGA1UEBhMCVVMxDzANBgNVBAgTBk9yZWdvbjERMA8GA1UEBxMIUG9y
dGxhbmQxEzARBgNVBAoTCkt1YmVybmV0ZXMxCzAJBgNVBAsTAkNBMRMwEQYDVQQD
EwpLdWJlcm5ldGVzMB4XDTE4MTExMTA0MTIwMFoXDTIzMTExMDA0MTIwMFowaDEL
MAkGA1UEBhMCVVMxDzANBgNVBAgTBk9yZWdvbjERMA8GA1UEBxMIUG9ydGxhbmQx
EzARBgNVBAoTCkt1YmVybmV0ZXMxCzAJBgNVBAsTAkNBMRMwEQYDVQQDEwpLdWJl
cm5ldGVzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1mOweOZlxEvV
HcpA2T0G0LC58yqgzAj9M27QB9FOUIFTRRYmdZ3QlGKM2TaHUwMVMBLobh3EUrp9
e6ThAh1Tc2S/NsSTbmXpVlx4kHiJKAJK6M/srLFE3r6gWDdKsMh7o0AVmylVn9M0
bQrJ0vg2gbFXNaD0aXpYVFWPlxhqeZrf7nAgx6R7Kl5US4rlZ3Pyn8UMNLBDsGWC
QFcmdFOP8aV8zIjsDwyeVwjTOIzNo8DSBnrYu+z0zDkgUKccp+HgNt/7SLW7u4Zq
d2gHjVXfIrlwzikZ69IcCCg5YdvH8A9exObCDzYgj7Pi+0bn1qa3+P2jrkcJch+0
ERMAAK8SVwIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUhdE6ktI5OtKwCPAtnjGpf9tIUMQwDQYJKoZIhvcNAQELBQAD
ggEBAGoGeJdYdAYZ9frfK+KBAu5QQyYh56u6UxZfHgqJ4NNIo2sM1YYX1EP6LPKI
TnsYzDw5t+XzN1twrgCazjQjR6Hus0iv5R4eTQprL65vbaPpUSD+x8FkJ6V8X6cJ
go4xPUUp4dfq3JY27dqdFyKBPcNme6j4TCxZiCAnro8v8X7dVLbvWoSe2QxPuw05
l4j4Hk/Cwl8yCmK1GNL7q9OW3VaImTN2KbUuhQrpqN9BM3wOwdiOrW/BnodMY2QD
pwh5TEV6TDDpDSlM85jXfL2No7wQXFReZVQ0P1wEk5kLx0A5HmRK3HpqnkLXGSE6
AMekXv0nLbGEcMYlIZgluubFgPw=
-----END CERTIFICATE-----
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

### The kube-proxy Kubernetes Configuration File

Kube Proxy用のkubeconfigを作成する。

```:コマンド
{
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=ca.pem \
    --embed-certs=true \
    --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 \
    --kubeconfig=kube-proxy.kubeconfig

  kubectl config set-credentials system:kube-proxy \
    --client-certificate=kube-proxy.pem \
    --client-key=kube-proxy-key.pem \
    --embed-certs=true \
    --kubeconfig=kube-proxy.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=system:kube-proxy \
    --kubeconfig=kube-proxy.kubeconfig

  kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
}
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ {
>   kubectl config set-cluster kubernetes-the-hard-way \
>     --certificate-authority=ca.pem \
>     --embed-certs=true \
>     --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443 \
>     --kubeconfig=kube-proxy.kubeconfig
>
>   kubectl config set-credentials system:kube-proxy \
>     --client-certificate=kube-proxy.pem \
>     --client-key=kube-proxy-key.pem \
>     --embed-certs=true \
>     --kubeconfig=kube-proxy.kubeconfig
>
>   kubectl config set-context default \
>     --cluster=kubernetes-the-hard-way \
>     --user=system:kube-proxy \
>     --kubeconfig=kube-proxy.kubeconfig
>
>   kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
> }
Cluster "kubernetes-the-hard-way" set.
User "system:kube-proxy" set.
Context "default" created.
Switched to context "default".
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

### The kube-controller-manager Kubernetes Configuration File

Controller Manager用のkubeconfigを作成する。接続先はAPIサーバーの外部公開用のIPアドレスではなく`127.0.0.1`を指定している。3台のAPI Serverは対等でありリーダーがいるわけではないので、同居しているAPI Serverに接続するようにしているが、外部公開用のIPアドレスを使用したとしても問題ないはず。

```:コマンド
{
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=ca.pem \
    --embed-certs=true \
    --server=https://127.0.0.1:6443 \
    --kubeconfig=kube-controller-manager.kubeconfig

  kubectl config set-credentials system:kube-controller-manager \
    --client-certificate=kube-controller-manager.pem \
    --client-key=kube-controller-manager-key.pem \
    --embed-certs=true \
    --kubeconfig=kube-controller-manager.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=system:kube-controller-manager \
    --kubeconfig=kube-controller-manager.kubeconfig

  kubectl config use-context default --kubeconfig=kube-controller-manager.kubeconfig
}
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ {
>   kubectl config set-cluster kubernetes-the-hard-way \
>     --certificate-authority=ca.pem \
>     --embed-certs=true \
>     --server=https://127.0.0.1:6443 \
>     --kubeconfig=kube-controller-manager.kubeconfig
>
>   kubectl config set-credentials system:kube-controller-manager \
>     --client-certificate=kube-controller-manager.pem \
>     --client-key=kube-controller-manager-key.pem \
>     --embed-certs=true \
>     --kubeconfig=kube-controller-manager.kubeconfig
>
>   kubectl config set-context default \
>     --cluster=kubernetes-the-hard-way \
>     --user=system:kube-controller-manager \
>     --kubeconfig=kube-controller-manager.kubeconfig
>
>   kubectl config use-context default --kubeconfig=kube-controller-manager.kubeconfig
> }
Cluster "kubernetes-the-hard-way" set.
User "system:kube-controller-manager" set.
Context "default" created.
Switched to context "default".
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

### The kube-scheduler Kubernetes Configuration File

Scheduler用のkubeconfigを作成する。こちらも接続先はAPIサーバーの外部公開用のIPアドレスではなく`127.0.0.1`を指定している。

```:コマンド
{
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=ca.pem \
    --embed-certs=true \
    --server=https://127.0.0.1:6443 \
    --kubeconfig=kube-scheduler.kubeconfig

  kubectl config set-credentials system:kube-scheduler \
    --client-certificate=kube-scheduler.pem \
    --client-key=kube-scheduler-key.pem \
    --embed-certs=true \
    --kubeconfig=kube-scheduler.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=system:kube-scheduler \
    --kubeconfig=kube-scheduler.kubeconfig

  kubectl config use-context default --kubeconfig=kube-scheduler.kubeconfig
}
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ {
>   kubectl config set-cluster kubernetes-the-hard-way \
>     --certificate-authority=ca.pem \
>     --embed-certs=true \
>     --server=https://127.0.0.1:6443 \
>     --kubeconfig=kube-scheduler.kubeconfig
>
>   kubectl config set-credentials system:kube-scheduler \
>     --client-certificate=kube-scheduler.pem \
>     --client-key=kube-scheduler-key.pem \
>     --embed-certs=true \
>     --kubeconfig=kube-scheduler.kubeconfig
>
>   kubectl config set-context default \
>     --cluster=kubernetes-the-hard-way \
>     --user=system:kube-scheduler \
>     --kubeconfig=kube-scheduler.kubeconfig
>
>   kubectl config use-context default --kubeconfig=kube-scheduler.kubeconfig
> }
Cluster "kubernetes-the-hard-way" set.
User "system:kube-scheduler" set.
Context "default" created.
Switched to context "default".
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

### The admin Kubernetes Configuration File

`admin`ユーザー用の設定ファイルを作成する。外部公開用のIPアドレスではなく`127.0.0.1`を指定しているが、Masterノードに配置してMasterノードで`kubectl`を実行することを想定しているため。作業用PCで使用するkubeconfigはまたあとで作成するが、そのときはAPI Serverの外部公開用のIPアドレスを指定する。

```:コマンド
{
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=ca.pem \
    --embed-certs=true \
    --server=https://127.0.0.1:6443 \
    --kubeconfig=admin.kubeconfig

  kubectl config set-credentials admin \
    --client-certificate=admin.pem \
    --client-key=admin-key.pem \
    --embed-certs=true \
    --kubeconfig=admin.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=admin \
    --kubeconfig=admin.kubeconfig

  kubectl config use-context default --kubeconfig=admin.kubeconfig
}
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ {
>   kubectl config set-cluster kubernetes-the-hard-way \
>     --certificate-authority=ca.pem \
>     --embed-certs=true \
>     --server=https://127.0.0.1:6443 \
>     --kubeconfig=admin.kubeconfig
>
>   kubectl config set-credentials admin \
>     --client-certificate=admin.pem \
>     --client-key=admin-key.pem \
>     --embed-certs=true \
>     --kubeconfig=admin.kubeconfig
>
>   kubectl config set-context default \
>     --cluster=kubernetes-the-hard-way \
>     --user=admin \
>     --kubeconfig=admin.kubeconfig
>
>   kubectl config use-context default --kubeconfig=admin.kubeconfig
> }
Cluster "kubernetes-the-hard-way" set.
User "admin" set.
Context "default" created.
Switched to context "default".
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

## Distribute the Kubernetes Configuration Files

作成したkubeconfigは以下。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ ls -l *.kubeconfig
-rw-------  1 sotoiwa  staff  6265 11 11 16:47 admin.kubeconfig
-rw-------  1 sotoiwa  staff  6391 11 11 16:37 kube-controller-manager.kubeconfig
-rw-------  1 sotoiwa  staff  6326 11 11 16:17 kube-proxy.kubeconfig
-rw-------  1 sotoiwa  staff  6341 11 11 16:44 kube-scheduler.kubeconfig
-rw-------  1 sotoiwa  staff  6388 11 11 16:04 worker-0.kubeconfig
-rw-------  1 sotoiwa  staff  6388 11 11 16:04 worker-1.kubeconfig
-rw-------  1 sotoiwa  staff  6388 11 11 16:04 worker-2.kubeconfig
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

Workerノードに`kubelet`と`kube-proxy`のkubeconfigを配布する。

```
for instance in worker-0 worker-1 worker-2; do
  gcloud compute scp ${instance}.kubeconfig kube-proxy.kubeconfig ${instance}:~/
done
```

Masterノードに`admin`と`kube-controller-manager`と`kube-scheduler`のkubeconfigを配布する。

```
for instance in controller-0 controller-1 controller-2; do
  gcloud compute scp admin.kubeconfig kube-controller-manager.kubeconfig kube-scheduler.kubeconfig ${instance}:~/
done
```

# Generating the Data Encryption Config and Key

このLabではSecretを暗号化してからetcdに保存するための鍵と設定ファイルを作成する。

（参考）
[Encrypting Secret Data at Rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/)

## The Encryption Key

暗号化キーを作成する。

```
ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)
```

## The Encryption Config File

設定ファイルを作成する。

```
cat > encryption-config.yaml <<EOF
kind: EncryptionConfig
apiVersion: v1
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: ${ENCRYPTION_KEY}
      - identity: {}
EOF
```

作成したファイルをMasterノードに転送する。

```
for instance in controller-0 controller-1 controller-2; do
  gcloud compute scp encryption-config.yaml ${instance}:~/
done
```

# Bootstrapping the etcd Cluster

https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/07-bootstrapping-etcd.md

このLabではetcdクラスターを起動する。

## Prerequisites

このLabでのコマンドは`controller-0`、`controller-1`、`controller-2`のそれぞれのノードで実行する。ノードへのログインは以下のコマンド。

```
gcloud compute ssh controller-0
```

### Running commands in parallel with tmux

（最初のLabでも記載があった内容なので省略）

## Bootstrapping an etcd Cluster Member

### Download and Install the etcd Binaries

etcdのバイナリをダウンロードする。バイナリのダウンロード元は以下のリリースページ。バージョンはv3.3.9をダウンロードしている。

https://github.com/etcd-io/etcd/releases

```
wget -q --show-progress --https-only --timestamping \
  "https://github.com/coreos/etcd/releases/download/v3.3.9/etcd-v3.3.9-linux-amd64.tar.gz"
```

ダウンロードしたファイルを展開して`/usr/local/bin`ディレクトリーにインストールする。

```
{
  tar -xvf etcd-v3.3.9-linux-amd64.tar.gz
  sudo mv etcd-v3.3.9-linux-amd64/etcd* /usr/local/bin/
}
```

### Configure the etcd Server

`/etc/etcd`と`/var/lib/etcd`ディレクトリーを作成して以下のファイルをコピーする。

- CA証明書
- APIサーバーの秘密鍵と証明書

```
{
  sudo mkdir -p /etc/etcd /var/lib/etcd
  sudo cp ca.pem kubernetes-key.pem kubernetes.pem /etc/etcd/
}
```

現在のVMインスタンス自身のIPアドレスを取得して変数に入れる。

```:コマンド
INTERNAL_IP=$(curl -s -H "Metadata-Flavor: Google" \
  http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ip)
```

```:実行ログ
sotoiwa@controller-0:~$ INTERNAL_IP=$(curl -s -H "Metadata-Flavor: Google" \
>   http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ip)
sotoiwa@controller-0:~$ echo $INTERNAL_IP
10.240.0.10
sotoiwa@controller-0:~$
```

Etcdメンバーはユニークな名前を持つ必要があるので、名前としてインスタンス名を使う。`-s`は短い形式（最初のドットまで）のホスト名を表示するオプション。

```:コマンド
ETCD_NAME=$(hostname -s)
```

```:実行ログ
sotoiwa@controller-0:~$ ETCD_NAME=$(hostname -s)
sotoiwa@controller-0:~$ echo $ETCD_NAME
controller-0
sotoiwa@controller-0:~$
```

Systemdサービスの定義ファイル`etcd.service`を作成する。etcdの引数として指定しているものについては以下のドキュメントに解説がある。

（参考）
[Operating etcd clusters for Kubernetes](https://kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/)

```:コマンド
cat <<EOF | sudo tee /etc/systemd/system/etcd.service
[Unit]
Description=etcd
Documentation=https://github.com/coreos

[Service]
ExecStart=/usr/local/bin/etcd \\
  --name ${ETCD_NAME} \\
  --cert-file=/etc/etcd/kubernetes.pem \\
  --key-file=/etc/etcd/kubernetes-key.pem \\
  --peer-cert-file=/etc/etcd/kubernetes.pem \\
  --peer-key-file=/etc/etcd/kubernetes-key.pem \\
  --trusted-ca-file=/etc/etcd/ca.pem \\
  --peer-trusted-ca-file=/etc/etcd/ca.pem \\
  --peer-client-cert-auth \\
  --client-cert-auth \\
  --initial-advertise-peer-urls https://${INTERNAL_IP}:2380 \\
  --listen-peer-urls https://${INTERNAL_IP}:2380 \\
  --listen-client-urls https://${INTERNAL_IP}:2379,https://127.0.0.1:2379 \\
  --advertise-client-urls https://${INTERNAL_IP}:2379 \\
  --initial-cluster-token etcd-cluster-0 \\
  --initial-cluster controller-0=https://10.240.0.10:2380,controller-1=https://10.240.0.11:2380,controller-2=https://10.240.0.12:2380 \\
  --initial-cluster-state new \\
  --data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
```

```shell-session:実行ログ
sotoiwa@controller-0:~$ cat <<EOF | sudo tee /etc/systemd/system/etcd.service
> [Unit]
> Description=etcd
> Documentation=https://github.com/coreos
>
> [Service]
> ExecStart=/usr/local/bin/etcd \\
>   --name ${ETCD_NAME} \\
>   --cert-file=/etc/etcd/kubernetes.pem \\
>   --key-file=/etc/etcd/kubernetes-key.pem \\
>   --peer-cert-file=/etc/etcd/kubernetes.pem \\
>   --peer-key-file=/etc/etcd/kubernetes-key.pem \\
>   --trusted-ca-file=/etc/etcd/ca.pem \\
>   --peer-trusted-ca-file=/etc/etcd/ca.pem \\
>   --peer-client-cert-auth \\
>   --client-cert-auth \\
>   --initial-advertise-peer-urls https://${INTERNAL_IP}:2380 \\
>   --listen-peer-urls https://${INTERNAL_IP}:2380 \\
>   --listen-client-urls https://${INTERNAL_IP}:2379,https://127.0.0.1:2379 \\
>   --advertise-client-urls https://${INTERNAL_IP}:2379 \\
>   --initial-cluster-token etcd-cluster-0 \\
>   --initial-cluster controller-0=https://10.240.0.10:2380,controller-1=https://10.240.0.11:2380,controller-2=https://10.240.0.12:2380 \\
>   --initial-cluster-state new \\
>   --data-dir=/var/lib/etcd
> Restart=on-failure
> RestartSec=5
>
> [Install]
> WantedBy=multi-user.target
> EOF
[Unit]
Description=etcd
Documentation=https://github.com/coreos

[Service]
ExecStart=/usr/local/bin/etcd \
  --name controller-0 \
  --cert-file=/etc/etcd/kubernetes.pem \
  --key-file=/etc/etcd/kubernetes-key.pem \
  --peer-cert-file=/etc/etcd/kubernetes.pem \
  --peer-key-file=/etc/etcd/kubernetes-key.pem \
  --trusted-ca-file=/etc/etcd/ca.pem \
  --peer-trusted-ca-file=/etc/etcd/ca.pem \
  --peer-client-cert-auth \
  --client-cert-auth \
  --initial-advertise-peer-urls https://10.240.0.10:2380 \
  --listen-peer-urls https://10.240.0.10:2380 \
  --listen-client-urls https://10.240.0.10:2379,https://127.0.0.1:2379 \
  --advertise-client-urls https://10.240.0.10:2379 \
  --initial-cluster-token etcd-cluster-0 \
  --initial-cluster controller-0=https://10.240.0.10:2380,controller-1=https://10.240.0.11:2380,controller-2=https://10.240.0.12:2380 \
  --initial-cluster-state new \
  --data-dir=/var/lib/etcd
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
sotoiwa@controller-0:~$
```

- `--cert-file`と`--key-file`がサーバーとしての通信に使う証明書と秘密鍵
- `--peer-cert-file`と`--peer-key-file`はetcd間の通信に使う証明書と秘密鍵
- API Server用に作成した秘密鍵や証明書をetcdでも使用している
- `--peer-client-cert-auth`、`--client-cert-auth`が指定されているので、サーバーとしての通信でもetcd間の通信でもクライアント認証する

### Start the etcd Server

etcdを起動する。

```
{
  sudo systemctl daemon-reload
  sudo systemctl enable etcd
  sudo systemctl start etcd
}
```

サービスのステータスを確認。

```
sudo systemctl status etcd
```

## Verification

etcdクラスターのメンバーをリストするコマンドを実行する。

```:コマンド
sudo ETCDCTL_API=3 etcdctl member list \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/etcd/ca.pem \
  --cert=/etc/etcd/kubernetes.pem \
  --key=/etc/etcd/kubernetes-key.pem
```

```:実行ログ
sotoiwa@controller-0:~$ sudo ETCDCTL_API=3 etcdctl member list \
>   --endpoints=https://127.0.0.1:2379 \
>   --cacert=/etc/etcd/ca.pem \
>   --cert=/etc/etcd/kubernetes.pem \
>   --key=/etc/etcd/kubernetes-key.pem
3a57933972cb5131, started, controller-2, https://10.240.0.12:2380, https://10.240.0.12:2379
f98dc20bce6225a0, started, controller-0, https://10.240.0.10:2380, https://10.240.0.10:2379
ffed16798470cab5, started, controller-1, https://10.240.0.11:2380, https://10.240.0.11:2379
sotoiwa@controller-0:~$
```

# Bootstrapping the Kubernetes Control Plane

https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/08-bootstrapping-kubernetes-controllers.md

このLabではMasterノードのk8sコンポーネント（apiserver、scheduler、controller-manager）を起動する。

## Prerequisites

前のLabと同じく、このLabのコマンドは全てのMasterノードで実施する必要がある。

### Running commands in parallel with tmux

（省略）

## Provision the Kubernetes Control Plane

Kubenetesの構成ファイル用ディレクトリーを作成する。

```
sudo mkdir -p /etc/kubernetes/config
```

### Download and Install the Kubernetes Controller Binaries

公式のバイナリをダウンロードする。この直接ダウンロードリンクにどうやってたどり着けばいいのかわからなかった。以下のリリースページからtarをダウンロードできる。tarの中にはバイナリは入っておらず、解凍して`kubernetes/cluster/get-kube-binaries.sh`を実行するとダウンロードできる。バージョンはv1.12.0をダウンロードする。

https://github.com/kubernetes/kubernetes/releases

```
wget -q --show-progress --https-only --timestamping \
  "https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kube-apiserver" \
  "https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kube-controller-manager" \
  "https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kube-scheduler" \
  "https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubectl"
```

バイナリを`/usr/local/bin`ディレクトリーにインストールする。

```
{
  chmod +x kube-apiserver kube-controller-manager kube-scheduler kubectl
  sudo mv kube-apiserver kube-controller-manager kube-scheduler kubectl /usr/local/bin/
}
```

確認する。

```shell-session
sotoiwa@controller-0:~$ ls -l /usr/local/bin/
total 493164
-rwxr-xr-x 1 sotoiwa sotoiwa  18934016 Jul 24 17:13 etcd
-rwxr-xr-x 1 sotoiwa sotoiwa  15809280 Jul 24 17:13 etcdctl
-rwxrwxr-x 1 sotoiwa sotoiwa 192766426 Sep 27 23:04 kube-apiserver
-rwxrwxr-x 1 sotoiwa sotoiwa 162936572 Sep 27 23:04 kube-controller-manager
-rwxrwxr-x 1 sotoiwa sotoiwa  57180560 Sep 27 23:04 kube-scheduler
-rwxrwxr-x 1 sotoiwa sotoiwa  57343669 Sep 27 23:04 kubectl
sotoiwa@controller-0:~$
```

### Configure the Kubernetes API Server

`/var/lib/kubernetes/`ディレクトリーを作成して以下のファイルを移動する。

- CAの秘密鍵と証明書
- API Serverの秘密鍵と証明書
- Service Account作成用の秘密鍵と証明書
- Secretの暗号化用の設定ファイル

```
{
  sudo mkdir -p /var/lib/kubernetes/

  sudo mv ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
    service-account-key.pem service-account.pem \
    encryption-config.yaml /var/lib/kubernetes/
}
```

確認する。

```shell-session
sotoiwa@controller-2:~$ ls -l /var/lib/kubernetes/
total 28
-rw------- 1 sotoiwa sotoiwa 1675 Nov 11 06:04 ca-key.pem
-rw-r--r-- 1 sotoiwa sotoiwa 1318 Nov 11 06:04 ca.pem
-rw-r--r-- 1 sotoiwa sotoiwa  196 Nov 11 08:09 encryption-config.yaml
-rw------- 1 sotoiwa sotoiwa 1679 Nov 11 06:04 kubernetes-key.pem
-rw-r--r-- 1 sotoiwa sotoiwa 1521 Nov 11 06:04 kubernetes.pem
-rw------- 1 sotoiwa sotoiwa 1679 Nov 11 06:04 service-account-key.pem
-rw-r--r-- 1 sotoiwa sotoiwa 1440 Nov 11 06:04 service-account.pem
sotoiwa@controller-2:~$
```

現在のVMインスタンス自身のIPアドレスを取得して変数に入れる。

```
INTERNAL_IP=$(curl -s -H "Metadata-Flavor: Google" \
  http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/ip)
```

Systemdサービスの定義ファイル`kube-apiserver.service`を作成する。引数については以下のリンク先に説明がある。

（参考）
[kube-apiserver](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/)

```:コマンド
cat <<EOF | sudo tee /etc/systemd/system/kube-apiserver.service
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-apiserver \\
  --advertise-address=${INTERNAL_IP} \\
  --allow-privileged=true \\
  --apiserver-count=3 \\
  --audit-log-maxage=30 \\
  --audit-log-maxbackup=3 \\
  --audit-log-maxsize=100 \\
  --audit-log-path=/var/log/audit.log \\
  --authorization-mode=Node,RBAC \\
  --bind-address=0.0.0.0 \\
  --client-ca-file=/var/lib/kubernetes/ca.pem \\
  --enable-admission-plugins=Initializers,NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \\
  --enable-swagger-ui=true \\
  --etcd-cafile=/var/lib/kubernetes/ca.pem \\
  --etcd-certfile=/var/lib/kubernetes/kubernetes.pem \\
  --etcd-keyfile=/var/lib/kubernetes/kubernetes-key.pem \\
  --etcd-servers=https://10.240.0.10:2379,https://10.240.0.11:2379,https://10.240.0.12:2379 \\
  --event-ttl=1h \\
  --experimental-encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml \\
  --kubelet-certificate-authority=/var/lib/kubernetes/ca.pem \\
  --kubelet-client-certificate=/var/lib/kubernetes/kubernetes.pem \\
  --kubelet-client-key=/var/lib/kubernetes/kubernetes-key.pem \\
  --kubelet-https=true \\
  --runtime-config=api/all \\
  --service-account-key-file=/var/lib/kubernetes/service-account.pem \\
  --service-cluster-ip-range=10.32.0.0/24 \\
  --service-node-port-range=30000-32767 \\
  --tls-cert-file=/var/lib/kubernetes/kubernetes.pem \\
  --tls-private-key-file=/var/lib/kubernetes/kubernetes-key.pem \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
```

```shell-session:実行ログ
sotoiwa@controller-0:~$ cat <<EOF | sudo tee /etc/systemd/system/kube-apiserver.service
> [Unit]
> Description=Kubernetes API Server
> Documentation=https://github.com/kubernetes/kubernetes
>
> [Service]
> ExecStart=/usr/local/bin/kube-apiserver \\
>   --advertise-address=${INTERNAL_IP} \\
>   --allow-privileged=true \\
>   --apiserver-count=3 \\
>   --audit-log-maxage=30 \\
>   --audit-log-maxbackup=3 \\
>   --audit-log-maxsize=100 \\
>   --audit-log-path=/var/log/audit.log \\
>   --authorization-mode=Node,RBAC \\
>   --bind-address=0.0.0.0 \\
>   --client-ca-file=/var/lib/kubernetes/ca.pem \\
>   --enable-admission-plugins=Initializers,NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \\
>   --enable-swagger-ui=true \\
>   --etcd-cafile=/var/lib/kubernetes/ca.pem \\
>   --etcd-certfile=/var/lib/kubernetes/kubernetes.pem \\
>   --etcd-keyfile=/var/lib/kubernetes/kubernetes-key.pem \\
>   --etcd-servers=https://10.240.0.10:2379,https://10.240.0.11:2379,https://10.240.0.12:2379 \\
>   --event-ttl=1h \\
>   --experimental-encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml \\
>   --kubelet-certificate-authority=/var/lib/kubernetes/ca.pem \\
>   --kubelet-client-certificate=/var/lib/kubernetes/kubernetes.pem \\
>   --kubelet-client-key=/var/lib/kubernetes/kubernetes-key.pem \\
>   --kubelet-https=true \\
>   --runtime-config=api/all \\
>   --service-account-key-file=/var/lib/kubernetes/service-account.pem \\
>   --service-cluster-ip-range=10.32.0.0/24 \\
>   --service-node-port-range=30000-32767 \\
>   --tls-cert-file=/var/lib/kubernetes/kubernetes.pem \\
>   --tls-private-key-file=/var/lib/kubernetes/kubernetes-key.pem \\
>   --v=2
> Restart=on-failure
> RestartSec=5
>
> [Install]
> WantedBy=multi-user.target
> EOF
[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-apiserver \
  --advertise-address=10.240.0.10 \
  --allow-privileged=true \
  --apiserver-count=3 \
  --audit-log-maxage=30 \
  --audit-log-maxbackup=3 \
  --audit-log-maxsize=100 \
  --audit-log-path=/var/log/audit.log \
  --authorization-mode=Node,RBAC \
  --bind-address=0.0.0.0 \
  --client-ca-file=/var/lib/kubernetes/ca.pem \
  --enable-admission-plugins=Initializers,NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \
  --enable-swagger-ui=true \
  --etcd-cafile=/var/lib/kubernetes/ca.pem \
  --etcd-certfile=/var/lib/kubernetes/kubernetes.pem \
  --etcd-keyfile=/var/lib/kubernetes/kubernetes-key.pem \
  --etcd-servers=https://10.240.0.10:2379,https://10.240.0.11:2379,https://10.240.0.12:2379 \
  --event-ttl=1h \
  --experimental-encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml \
  --kubelet-certificate-authority=/var/lib/kubernetes/ca.pem \
  --kubelet-client-certificate=/var/lib/kubernetes/kubernetes.pem \
  --kubelet-client-key=/var/lib/kubernetes/kubernetes-key.pem \
  --kubelet-https=true \
  --runtime-config=api/all \
  --service-account-key-file=/var/lib/kubernetes/service-account.pem \
  --service-cluster-ip-range=10.32.0.0/24 \
  --service-node-port-range=30000-32767 \
  --tls-cert-file=/var/lib/kubernetes/kubernetes.pem \
  --tls-private-key-file=/var/lib/kubernetes/kubernetes-key.pem \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
sotoiwa@controller-0:~$
```

- `--authorization-mode=Node,RBAC`としており、Kubeletはノード認可する
- `--etcd-***`がetcdとの接続に関する設定で使用する証明書などを指定している
- `--kubelet-***`がkubeletとの接続に関する設定で使用する証明書などを指定している
- `--tls-cert-file`と`--tls-private-key-file`が自身がHTTPSサーバーとしてリクエストを受け付けるための設定
- `--service-cluster-ip-range=10.32.0.0/24`でServiceが使用するIPのCIDRを指定している

### Configure the Kubernetes Controller Manager

Controller Managerが使用するkubeconfigを`/var/lib/kubernetes/`に配置する。

```
sudo mv kube-controller-manager.kubeconfig /var/lib/kubernetes/
```

Systemdサービスの定義ファイル`kube-controller-manager.service`を作成する。

（参考）
[kube-controller-manager](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-controller-manager/)

```:コマンド
cat <<EOF | sudo tee /etc/systemd/system/kube-controller-manager.service
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-controller-manager \\
  --address=0.0.0.0 \\
  --cluster-cidr=10.200.0.0/16 \\
  --cluster-name=kubernetes \\
  --cluster-signing-cert-file=/var/lib/kubernetes/ca.pem \\
  --cluster-signing-key-file=/var/lib/kubernetes/ca-key.pem \\
  --kubeconfig=/var/lib/kubernetes/kube-controller-manager.kubeconfig \\
  --leader-elect=true \\
  --root-ca-file=/var/lib/kubernetes/ca.pem \\
  --service-account-private-key-file=/var/lib/kubernetes/service-account-key.pem \\
  --service-cluster-ip-range=10.32.0.0/24 \\
  --use-service-account-credentials=true \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
```

```shell-session:実行ログ
sotoiwa@controller-0:~$ cat <<EOF | sudo tee /etc/systemd/system/kube-controller-manager.service
> [Unit]
> Description=Kubernetes Controller Manager
> Documentation=https://github.com/kubernetes/kubernetes
>
> [Service]
> ExecStart=/usr/local/bin/kube-controller-manager \\
>   --address=0.0.0.0 \\
>   --cluster-cidr=10.200.0.0/16 \\
>   --cluster-name=kubernetes \\
>   --cluster-signing-cert-file=/var/lib/kubernetes/ca.pem \\
>   --cluster-signing-key-file=/var/lib/kubernetes/ca-key.pem \\
>   --kubeconfig=/var/lib/kubernetes/kube-controller-manager.kubeconfig \\
>   --leader-elect=true \\
>   --root-ca-file=/var/lib/kubernetes/ca.pem \\
>   --service-account-private-key-file=/var/lib/kubernetes/service-account-key.pem \\
>   --service-cluster-ip-range=10.32.0.0/24 \\
>   --use-service-account-credentials=true \\
>   --v=2
> Restart=on-failure
> RestartSec=5
>
> [Install]
> WantedBy=multi-user.target
> EOF
[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-controller-manager \
  --address=0.0.0.0 \
  --cluster-cidr=10.200.0.0/16 \
  --cluster-name=kubernetes \
  --cluster-signing-cert-file=/var/lib/kubernetes/ca.pem \
  --cluster-signing-key-file=/var/lib/kubernetes/ca-key.pem \
  --kubeconfig=/var/lib/kubernetes/kube-controller-manager.kubeconfig \
  --leader-elect=true \
  --root-ca-file=/var/lib/kubernetes/ca.pem \
  --service-account-private-key-file=/var/lib/kubernetes/service-account-key.pem \
  --service-cluster-ip-range=10.32.0.0/24 \
  --use-service-account-credentials=true \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
sotoiwa@controller-0:~$
```

- `--cluster-cidr=10.200.0.0/16`でクラスターのCIDRを指定している
- `--kubeconfig`でAPI Serverへの接続情報を指定している
- `--service-account-private-key-file`でServiec Account Tokenの作成に使用する秘密鍵を指定している
- `--service-cluster-ip-range=10.32.0.0/24`でAPI Serverと同じくServiceのCIDRを指定している
- `--leader-elect=true`を設定しているので、3台のMasterノードのうちの1つがリーダーになる
- `--cluster-signing-key-file`と`--cluster-signing-cert-file`を指定しているのは証明書のローテーション時にController Managerが署名を行うためと思われる

### Configure the Kubernetes Scheduler

Schedulerが使用するkubeconfigを`/var/lib/kubernetes/`に配置する。

```
sudo mv kube-scheduler.kubeconfig /var/lib/kubernetes/
```

Schedulerの設定ファイル`kube-scheduler.yaml`を作成する。

```:コマンド
cat <<EOF | sudo tee /etc/kubernetes/config/kube-scheduler.yaml
apiVersion: componentconfig/v1alpha1
kind: KubeSchedulerConfiguration
clientConnection:
  kubeconfig: "/var/lib/kubernetes/kube-scheduler.kubeconfig"
leaderElection:
  leaderElect: true
EOF
```

```shell-session:実行ログ
sotoiwa@controller-0:~$ cat <<EOF | sudo tee /etc/kubernetes/config/kube-scheduler.yaml
> apiVersion: componentconfig/v1alpha1
> kind: KubeSchedulerConfiguration
> clientConnection:
>   kubeconfig: "/var/lib/kubernetes/kube-scheduler.kubeconfig"
> leaderElection:
>   leaderElect: true
> EOF
apiVersion: componentconfig/v1alpha1
kind: KubeSchedulerConfiguration
clientConnection:
  kubeconfig: "/var/lib/kubernetes/kube-scheduler.kubeconfig"
leaderElection:
  leaderElect: true
sotoiwa@controller-0:~$
```

- kubeconfigをここで指定している
- `leaderElect: true`を設定しているので、3台のMasterノードのうちの1つがリーダーになる

Systemdサービスの定義ファイル`kube-scheduler.service`を作成する。

（参考）
[kube-scheduler](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-scheduler/)

```:コマンド
cat <<EOF | sudo tee /etc/systemd/system/kube-scheduler.service
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-scheduler \\
  --config=/etc/kubernetes/config/kube-scheduler.yaml \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
```

```shell-session:実行ログ
sotoiwa@controller-0:~$ cat <<EOF | sudo tee /etc/systemd/system/kube-scheduler.service
> [Unit]
> Description=Kubernetes Scheduler
> Documentation=https://github.com/kubernetes/kubernetes
>
> [Service]
> ExecStart=/usr/local/bin/kube-scheduler \\
>   --config=/etc/kubernetes/config/kube-scheduler.yaml \\
>   --v=2
> Restart=on-failure
> RestartSec=5
>
> [Install]
> WantedBy=multi-user.target
> EOF
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-scheduler \
  --config=/etc/kubernetes/config/kube-scheduler.yaml \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
sotoiwa@controller-0:~$
```

- 先ほど作成した`kube-scheduler.yaml`を指定している

### Start the Controller Services

サービスを有効にして起動する。

```
{
  sudo systemctl daemon-reload
  sudo systemctl enable kube-apiserver kube-controller-manager kube-scheduler
  sudo systemctl start kube-apiserver kube-controller-manager kube-scheduler
}
```

サービスのステータスを確認する。

```
sudo systemctl status kube-apiserver kube-controller-manager kube-scheduler
```

### Enable HTTP Health Checks

Google Network Load BalancerがAPI Serverへのリクエストを負荷分散する。API ServerはHTTPSで接続を受け付けるが、Load BalancerはHTTPしかサポートしておらずヘルスチェックが失敗してしまうため、回避策としてヘルスチェックをプロキシするnginxを動かす。nginxは`80`ポートで受け取ったヘルスチェックリクエストを`https://127.0.0.1:6443/healthz`へプロキシする。この`/healthz`エンドポイントは認証が不要。

（参考）
[Network Load Balancing Concepts](https://cloud.google.com/load-balancing/docs/network/)

nginxをインストールする。

```
sudo apt-get install -y nginx
```

設定ファイルを作成。

```
cat > kubernetes.default.svc.cluster.local <<EOF
server {
  listen      80;
  server_name kubernetes.default.svc.cluster.local;

  location /healthz {
     proxy_pass                    https://127.0.0.1:6443/healthz;
     proxy_ssl_trusted_certificate /var/lib/kubernetes/ca.pem;
  }
}
EOF
```

設定ファイルを配置してサイトを有効化する。

```
{
  sudo mv kubernetes.default.svc.cluster.local \
    /etc/nginx/sites-available/kubernetes.default.svc.cluster.local

  sudo ln -s /etc/nginx/sites-available/kubernetes.default.svc.cluster.local /etc/nginx/sites-enabled/
}
```

サービスを再起動して有効化する。

```
{
  sudo systemctl restart nginx
  sudo systemctl enable nginx
}
```

### Verification

コンポーネントの状態を確認する。

```:コマンド
kubectl get componentstatuses --kubeconfig admin.kubeconfig
```

```shell-session:実行ログ
sotoiwa@controller-0:~$ kubectl get componentstatuses --kubeconfig admin.kubeconfig
NAME                 STATUS    MESSAGE             ERROR
scheduler            Healthy   ok
controller-manager   Healthy   ok
etcd-2               Healthy   {"health":"true"}
etcd-1               Healthy   {"health":"true"}
etcd-0               Healthy   {"health":"true"}
sotoiwa@controller-0:~$
```

curlでプロキシができていることを確認する。

```:コマンド
curl -H "Host: kubernetes.default.svc.cluster.local" -i http://127.0.0.1/healthz
```

```shell-session:実行ログ
sotoiwa@controller-0:~$ curl -H "Host: kubernetes.default.svc.cluster.local" -i http://127.0.0.1/healthz
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Sun, 11 Nov 2018 11:12:28 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 2
Connection: keep-alive

oksotoiwa@controller-0:~$
```

## RBAC for Kubelet Authorization

このセクションでは、API Serverが各WorkerノードのKubelet APIにアクセスできるようにRBACを構成する。Kubelet APIにアクセスすることで、メトリックを取得したり、ログを取得したり、Pod内でコマンドを実行したりできる。

このチュートリアルでは、Kubeletの`--authorization-mode`を`Webhook`に設定する。Webhookモードではkubeconfigの設定にしたがって外部に問い合わせにいくが、Kubeletは結局API Serverに問い合わせるということだと思われる。

（参考）
[Authorization Overview](https://kubernetes.io/docs/reference/access-authn-authz/authorization/)
[Webhook Mode](https://kubernetes.io/docs/reference/access-authn-authz/webhook/)

`controller-0`で作業する。

```
gcloud compute ssh controller-0
```

`system:kube-apiserver-to-kubelet`というClusterRoleを作成し、Kubelet APIへのアクセスを許可する。`apiGroups`の`""`はcore API groupを意味する。

```:コマンド
cat <<EOF | kubectl apply --kubeconfig admin.kubeconfig -f -
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:kube-apiserver-to-kubelet
rules:
  - apiGroups:
      - ""
    resources:
      - nodes/proxy
      - nodes/stats
      - nodes/log
      - nodes/spec
      - nodes/metrics
    verbs:
      - "*"
EOF
```

```shell-session:実行ログ
sotoiwa@controller-0:~$ cat <<EOF | kubectl apply --kubeconfig admin.kubeconfig -f -
> apiVersion: rbac.authorization.k8s.io/v1beta1
> kind: ClusterRole
> metadata:
>   annotations:
>     rbac.authorization.kubernetes.io/autoupdate: "true"
>   labels:
>     kubernetes.io/bootstrapping: rbac-defaults
>   name: system:kube-apiserver-to-kubelet
> rules:
>   - apiGroups:
>       - ""
>     resources:
>       - nodes/proxy
>       - nodes/stats
>       - nodes/log
>       - nodes/spec
>       - nodes/metrics
>     verbs:
>       - "*"
> EOF
clusterrole.rbac.authorization.k8s.io/system:kube-apiserver-to-kubelet created
sotoiwa@controller-0:~$
```

Kubeletに対して、API Serverは`kubernetes`ユーザーとして`--kubelet-client-certificate`で指定されたクライアント証明書を使って認証を試みるので`kubernetes`ユーザーを`system:kube-apiserver-to-kubelet`のClusterRoleにバインドするClusterRoleBindingを作成する。

```:コマンド
cat <<EOF | kubectl apply --kubeconfig admin.kubeconfig -f -
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: system:kube-apiserver
  namespace: ""
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:kube-apiserver-to-kubelet
subjects:
  - apiGroup: rbac.authorization.k8s.io
    kind: User
    name: kubernetes
EOF
```

```shell-session:実行ログ
sotoiwa@controller-0:~$ cat <<EOF | kubectl apply --kubeconfig admin.kubeconfig -f -
> apiVersion: rbac.authorization.k8s.io/v1beta1
> kind: ClusterRoleBinding
> metadata:
>   name: system:kube-apiserver
>   namespace: ""
> roleRef:
>   apiGroup: rbac.authorization.k8s.io
>   kind: ClusterRole
>   name: system:kube-apiserver-to-kubelet
> subjects:
>   - apiGroup: rbac.authorization.k8s.io
>     kind: User
>     name: kubernetes
> EOF
clusterrolebinding.rbac.authorization.k8s.io/system:kube-apiserver created
sotoiwa@controller-0:~$
```

## The Kubernetes Frontend Load Balancer

API Serverの前に配置される外部ロードバランサーをプロビジョニングする。

### Provision a Network Load Balancer

```:コマンド
{
  KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-hard-way \
    --region $(gcloud config get-value compute/region) \
    --format 'value(address)')

  gcloud compute http-health-checks create kubernetes \
    --description "Kubernetes Health Check" \
    --host "kubernetes.default.svc.cluster.local" \
    --request-path "/healthz"

  gcloud compute firewall-rules create kubernetes-the-hard-way-allow-health-check \
    --network kubernetes-the-hard-way \
    --source-ranges 209.85.152.0/22,209.85.204.0/22,35.191.0.0/16 \
    --allow tcp

  gcloud compute target-pools create kubernetes-target-pool \
    --http-health-check kubernetes

  gcloud compute target-pools add-instances kubernetes-target-pool \
   --instances controller-0,controller-1,controller-2

  gcloud compute forwarding-rules create kubernetes-forwarding-rule \
    --address ${KUBERNETES_PUBLIC_ADDRESS} \
    --ports 6443 \
    --region $(gcloud config get-value compute/region) \
    --target-pool kubernetes-target-pool
}
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ {
  KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-hard-way \
    --region $(gcloud config get-value compute/region) \
    --format 'value(address)')

  gcloud compute http-health-checks create kubernetes \
    --description "Kubernetes Health Check" \
    --host "kubernetes.default.svc.cluster.local" \
    --request-path "/healthz"

  gcloud compute firewall-rules create kubernetes-the-hard-way-allow-health-check \
    --network kubernetes-the-hard-way \
    --source-ranges 209.85.152.0/22,209.85.204.0/22,35.191.0.0/16 \
    --allow tcp

  gcloud compute target-pools create kubernetes-target-pool \
    --http-health-check kubernetes

  gcloud compute target-pools add-instances kubernetes-target-pool \
   --instances controller-0,controller-1,controller-2

  gcloud compute forwarding-rules create kubernetes-forwarding-rule \
    --address ${KUBERNETES_PUBLIC_ADDRESS} \
    --ports 6443 \
    --region $(gcloud config get-value compute/region) \
    --targe>   KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-hard-way \
>     --region $(gcloud config get-value compute/region) \
>     --format 'value(address)')
>
>   gcloud compute http-health-checks create kubernetes \
>     --description "Kubernetes Health Check" \
>     --host "kubernetes.default.svc.cluster.local" \
>     --request-path "/healthz"
>
>   gcloud compute firewall-rules create kubernetes-the-hard-way-allow-health-check \
>     --network kubernetes-the-hard-way \
>     --source-ranges 209.85.152.0/22,209.85.204.0/22,35.191.0.0/16 \
>     --allow tcp
>
>   gcloud compute target-pools create kubernetes-target-pool \
>     --http-health-check kubernetes
>
>   gcloud compute target-pools add-instances kubernetes-target-pool \
>    --instances controller-0,controller-1,controller-2
>
>   gcloud compute forwarding-rules create kubernetes-forwarding-rule \
>     --address ${KUBERNETES_PUBLIC_ADDRESS} \
>     --ports 6443 \
>     --region $(gcloud config get-value compute/region) \
>     --target-pool kubernetes-target-pool
> }
Created [https://www.googleapis.com/compute/v1/projects/sotoiwa/global/httpHealthChecks/kubernetes].
NAME        HOST                                  PORT  REQUEST_PATH
kubernetes  kubernetes.default.svc.cluster.local  80    /healthz
Creating firewall...⠏Created [https://www.googleapis.com/compute/v1/projects/sotoiwa/global/firewalls/kubernetes-the-hard-way-allow-health-check].
Creating firewall...done.
NAME                                        NETWORK                  DIRECTION  PRIORITY  ALLOW  DENY  DISABLED
kubernetes-the-hard-way-allow-health-check  kubernetes-the-hard-way  INGRESS    1000      tcp          False
Created [https://www.googleapis.com/compute/v1/projects/sotoiwa/regions/asia-northeast1/targetPools/kubernetes-target-pool].
NAME                    REGION           SESSION_AFFINITY  BACKUP  HEALTH_CHECKS
kubernetes-target-pool  asia-northeast1  NONE                      kubernetes
Updated [https://www.googleapis.com/compute/v1/projects/sotoiwa/regions/asia-northeast1/targetPools/kubernetes-target-pool].
Created [https://www.googleapis.com/compute/v1/projects/sotoiwa/regions/asia-northeast1/forwardingRules/kubernetes-forwarding-rule].
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

### Verification

API Server公開用の外部IPを確認する。

```:コマンド
KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-hard-way \
  --region $(gcloud config get-value compute/region) \
  --format 'value(address)')
```

作業用PCからHTTPリクエストを投げ、Kubernetesのバージョンが取得出来ることを確認する。

```:コマンド
curl --cacert ca.pem https://${KUBERNETES_PUBLIC_ADDRESS}:6443/version
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ curl --cacert ca.pem https://${KUBERNETES_PUBLIC_ADDRESS}:6443/version
{
  "major": "1",
  "minor": "12",
  "gitVersion": "v1.12.0",
  "gitCommit": "0ed33881dc4355495f623c6f22e7dd0b7632b7c0",
  "gitTreeState": "clean",
  "buildDate": "2018-09-27T16:55:41Z",
  "goVersion": "go1.10.4",
  "compiler": "gc",
  "platform": "linux/amd64"
}sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

# Bootstrapping the Kubernetes Worker Nodes

https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/09-bootstrapping-kubernetes-workers.md

このLabではWorkerノードのk8sコンポーネント（kubelet、kube-proxy）を起動する。

## Prerequisites

このLabの作業は各Workerノードで行う。

### Running commands in parallel with tmux

（省略）

### Provisioning a Kubernetes Worker Node

依存パッケージをインストールする。

```
{
  sudo apt-get update
  sudo apt-get -y install socat conntrack ipset
}
```

### Download and Install Worker Binaries

cri-tools、runcs、runc、cni-plugins、containerdのバイナリをダウンロードする。runcsは公式バイナリではなくこのチュートリアル用のもの？それぞれのリリースページは以下。

- https://github.com/kubernetes-sigs/cri-tools/releases
- https://github.com/opencontainers/runc/releases
- https://github.com/containernetworking/plugins/releases
- https://github.com/containerd/containerd/releases

kubectl、kube-proxy、kubeletは先ほどMasterノードのコンポーネントをダウンロードしたときと同じtarに入っている。

```
wget -q --show-progress --https-only --timestamping \
  https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.12.0/crictl-v1.12.0-linux-amd64.tar.gz \
  https://storage.googleapis.com/kubernetes-the-hard-way/runsc-50c283b9f56bb7200938d9e207355f05f79f0d17 \
  https://github.com/opencontainers/runc/releases/download/v1.0.0-rc5/runc.amd64 \
  https://github.com/containernetworking/plugins/releases/download/v0.6.0/cni-plugins-amd64-v0.6.0.tgz \
  https://github.com/containerd/containerd/releases/download/v1.2.0-rc.0/containerd-1.2.0-rc.0.linux-amd64.tar.gz \
  https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubectl \
  https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kube-proxy \
  https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubelet
```

ディレクトリーを作成する。

```
sudo mkdir -p \
  /etc/cni/net.d \
  /opt/cni/bin \
  /var/lib/kubelet \
  /var/lib/kube-proxy \
  /var/lib/kubernetes \
  /var/run/kubernetes
```

バイナリをインストールする。

- `kube-proxy`、`kubelet`、`runc`、`runsc`、`crictl`は`/usr/local/bin/`へ
- cniプラグインは`/opt/cni/bin/`へ
- `containerd`は`/bin/`へ

```
{
  sudo mv runsc-50c283b9f56bb7200938d9e207355f05f79f0d17 runsc
  sudo mv runc.amd64 runc
  chmod +x kubectl kube-proxy kubelet runc runsc
  sudo mv kubectl kube-proxy kubelet runc runsc /usr/local/bin/
  sudo tar -xvf crictl-v1.12.0-linux-amd64.tar.gz -C /usr/local/bin/
  sudo tar -xvf cni-plugins-amd64-v0.6.0.tgz -C /opt/cni/bin/
  sudo tar -xvf containerd-1.2.0-rc.0.linux-amd64.tar.gz -C /
}
```

### Configure CNI Networking

この時点ではインターフェースは以下のみ。

```shell-session
sotoiwa@worker-0:~$ ip -d a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1460 qdisc fq_codel state UP group default qlen 1000
    link/ether 42:01:0a:f0:00:14 brd ff:ff:ff:ff:ff:ff promiscuity 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 10.240.0.20/32 scope global dynamic ens4
       valid_lft 79565sec preferred_lft 79565sec
    inet6 fe80::4001:aff:fef0:14/64 scope link
       valid_lft forever preferred_lft forever
sotoiwa@worker-0:~$
```

インスタンスのメタデータからPodサブネットのCIDRを取得する。

```:コマンド
POD_CIDR=$(curl -s -H "Metadata-Flavor: Google" \
  http://metadata.google.internal/computeMetadata/v1/instance/attributes/pod-cidr)
```

```shell-session:実行ログ
sotoiwa@worker-0:~$ POD_CIDR=$(curl -s -H "Metadata-Flavor: Google" \
>   http://metadata.google.internal/computeMetadata/v1/instance/attributes/pod-cidr)
sotoiwa@worker-0:~$ echo $POD_CIDR
10.200.0.0/24
sotoiwa@worker-0:~$
```

ブリッジネットワークの設定ファイルを作成する。

```:コマンド
cat <<EOF | sudo tee /etc/cni/net.d/10-bridge.conf
{
    "cniVersion": "0.3.1",
    "name": "bridge",
    "type": "bridge",
    "bridge": "cnio0",
    "isGateway": true,
    "ipMasq": true,
    "ipam": {
        "type": "host-local",
        "ranges": [
          [{"subnet": "${POD_CIDR}"}]
        ],
        "routes": [{"dst": "0.0.0.0/0"}]
    }
}
EOF
```

```shell-session:実行ログ
sotoiwa@worker-0:~$ cat <<EOF | sudo tee /etc/cni/net.d/10-bridge.conf
> {
>     "cniVersion": "0.3.1",
>     "name": "bridge",
>     "type": "bridge",
>     "bridge": "cnio0",
>     "isGateway": true,
>     "ipMasq": true,
>     "ipam": {
>         "type": "host-local",
>         "ranges": [
>           [{"subnet": "${POD_CIDR}"}]
>         ],
>         "routes": [{"dst": "0.0.0.0/0"}]
>     }
> }
> EOF
{
    "cniVersion": "0.3.1",
    "name": "bridge",
    "type": "bridge",
    "bridge": "cnio0",
    "isGateway": true,
    "ipMasq": true,
    "ipam": {
        "type": "host-local",
        "ranges": [
          [{"subnet": "10.200.0.0/24"}]
        ],
        "routes": [{"dst": "0.0.0.0/0"}]
    }
}
sotoiwa@worker-0:~$
```

ループバックネットワークの設定ファイルを作成する。

```:コマンド
cat <<EOF | sudo tee /etc/cni/net.d/99-loopback.conf
{
    "cniVersion": "0.3.1",
    "type": "loopback"
}
EOF
```

```shell-session:実行ログ
sotoiwa@worker-0:~$ cat <<EOF | sudo tee /etc/cni/net.d/99-loopback.conf
> {
>     "cniVersion": "0.3.1",
>     "type": "loopback"
> }
> EOF
{
    "cniVersion": "0.3.1",
    "type": "loopback"
}
sotoiwa@worker-0:~$
```

### Configure containerd

containerdの設定をする。

（参考）
[docker-containerd、docker-containerd-shim、 docker-containerd-ctr、docker-runc](http://etogen.hatenablog.com/entry/2018/07/30/030226)
[gVisorを使ってdockerコンテナをより安全に利用する](https://qiita.com/tomoyamachi/items/ac52f906816804e7cf1b)

ディレクトリーを作成する。

```
sudo mkdir -p /etc/containerd/
```

設定ファイルを作成する。untrustedなワークロードはgVisor(runsc)で実行する

```:コマンド
cat << EOF | sudo tee /etc/containerd/config.toml
[plugins]
  [plugins.cri.containerd]
    snapshotter = "overlayfs"
    [plugins.cri.containerd.default_runtime]
      runtime_type = "io.containerd.runtime.v1.linux"
      runtime_engine = "/usr/local/bin/runc"
      runtime_root = ""
    [plugins.cri.containerd.untrusted_workload_runtime]
      runtime_type = "io.containerd.runtime.v1.linux"
      runtime_engine = "/usr/local/bin/runsc"
      runtime_root = "/run/containerd/runsc"
    [plugins.cri.containerd.gvisor]
      runtime_type = "io.containerd.runtime.v1.linux"
      runtime_engine = "/usr/local/bin/runsc"
      runtime_root = "/run/containerd/runsc"
EOF
```

```shell-session:実行ログ
sotoiwa@worker-0:~$ cat << EOF | sudo tee /etc/containerd/config.toml
> [plugins]
>   [plugins.cri.containerd]
>     snapshotter = "overlayfs"
>     [plugins.cri.containerd.default_runtime]
>       runtime_type = "io.containerd.runtime.v1.linux"
>       runtime_engine = "/usr/local/bin/runc"
>       runtime_root = ""
>     [plugins.cri.containerd.untrusted_workload_runtime]
>       runtime_type = "io.containerd.runtime.v1.linux"
>       runtime_engine = "/usr/local/bin/runsc"
>       runtime_root = "/run/containerd/runsc"
>     [plugins.cri.containerd.gvisor]
>       runtime_type = "io.containerd.runtime.v1.linux"
>       runtime_engine = "/usr/local/bin/runsc"
>       runtime_root = "/run/containerd/runsc"
> EOF
[plugins]
  [plugins.cri.containerd]
    snapshotter = "overlayfs"
    [plugins.cri.containerd.default_runtime]
      runtime_type = "io.containerd.runtime.v1.linux"
      runtime_engine = "/usr/local/bin/runc"
      runtime_root = ""
    [plugins.cri.containerd.untrusted_workload_runtime]
      runtime_type = "io.containerd.runtime.v1.linux"
      runtime_engine = "/usr/local/bin/runsc"
      runtime_root = "/run/containerd/runsc"
    [plugins.cri.containerd.gvisor]
      runtime_type = "io.containerd.runtime.v1.linux"
      runtime_engine = "/usr/local/bin/runsc"
      runtime_root = "/run/containerd/runsc"
sotoiwa@worker-0:~$
```

`containerd.service`のSystemdユニットファイルを作成する。

```:コマンド
cat <<EOF | sudo tee /etc/systemd/system/containerd.service
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target

[Service]
ExecStartPre=/sbin/modprobe overlay
ExecStart=/bin/containerd
Restart=always
RestartSec=5
Delegate=yes
KillMode=process
OOMScoreAdjust=-999
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity

[Install]
WantedBy=multi-user.target
EOF
```

```shell-session:実行ログ
sotoiwa@worker-0:~$ cat <<EOF | sudo tee /etc/systemd/system/containerd.service
> [Unit]
> Description=containerd container runtime
> Documentation=https://containerd.io
> After=network.target
>
> [Service]
> ExecStartPre=/sbin/modprobe overlay
> ExecStart=/bin/containerd
> Restart=always
> RestartSec=5
> Delegate=yes
> KillMode=process
> OOMScoreAdjust=-999
> LimitNOFILE=1048576
> LimitNPROC=infinity
> LimitCORE=infinity
>
> [Install]
> WantedBy=multi-user.target
> EOF
[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target

[Service]
ExecStartPre=/sbin/modprobe overlay
ExecStart=/bin/containerd
Restart=always
RestartSec=5
Delegate=yes
KillMode=process
OOMScoreAdjust=-999
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity

[Install]
WantedBy=multi-user.target
sotoiwa@worker-0:~$
```

### Configure the Kubelet

Kubeletが使用する秘密鍵と証明書とkubeconfingを`/var/lib/kubelet/`に配置する。

```
{
  sudo mv ${HOSTNAME}-key.pem ${HOSTNAME}.pem /var/lib/kubelet/
  sudo mv ${HOSTNAME}.kubeconfig /var/lib/kubelet/kubeconfig
  sudo mv ca.pem /var/lib/kubernetes/
}
```

Kubeletの設定フィル`kubelet-config.yaml`を作成する。

- `clusterDNS`として`10.32.0.10`を指定している
- `podCIDR`を指定している
- resolvConfは`systemd-resolved`環境でのループを避けるための設定

```:コマンド
cat <<EOF | sudo tee /var/lib/kubelet/kubelet-config.yaml
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
  anonymous:
    enabled: false
  webhook:
    enabled: true
  x509:
    clientCAFile: "/var/lib/kubernetes/ca.pem"
authorization:
  mode: Webhook
clusterDomain: "cluster.local"
clusterDNS:
  - "10.32.0.10"
podCIDR: "${POD_CIDR}"
resolvConf: "/run/systemd/resolve/resolv.conf"
runtimeRequestTimeout: "15m"
tlsCertFile: "/var/lib/kubelet/${HOSTNAME}.pem"
tlsPrivateKeyFile: "/var/lib/kubelet/${HOSTNAME}-key.pem"
EOF
```

```shell-session:実行ログ
sotoiwa@worker-0:~$ cat <<EOF | sudo tee /var/lib/kubelet/kubelet-config.yaml
> kind: KubeletConfiguration
> apiVersion: kubelet.config.k8s.io/v1beta1
> authentication:
>   anonymous:
>     enabled: false
>   webhook:
>     enabled: true
>   x509:
>     clientCAFile: "/var/lib/kubernetes/ca.pem"
> authorization:
>   mode: Webhook
> clusterDomain: "cluster.local"
> clusterDNS:
>   - "10.32.0.10"
> podCIDR: "${POD_CIDR}"
> resolvConf: "/run/systemd/resolve/resolv.conf"
> runtimeRequestTimeout: "15m"
> tlsCertFile: "/var/lib/kubelet/${HOSTNAME}.pem"
> tlsPrivateKeyFile: "/var/lib/kubelet/${HOSTNAME}-key.pem"
> EOF
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
  anonymous:
    enabled: false
  webhook:
    enabled: true
  x509:
    clientCAFile: "/var/lib/kubernetes/ca.pem"
authorization:
  mode: Webhook
clusterDomain: "cluster.local"
clusterDNS:
  - "10.32.0.10"
podCIDR: "10.200.0.0/24"
resolvConf: "/run/systemd/resolve/resolv.conf"
runtimeRequestTimeout: "15m"
tlsCertFile: "/var/lib/kubelet/worker-0.pem"
tlsPrivateKeyFile: "/var/lib/kubelet/worker-0-key.pem"
sotoiwa@worker-0:~$
```

`kubelet.service`のSystemdユニットファイルを作成する。

（参考）
[kubelet](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/)

```:コマンド
cat <<EOF | sudo tee /etc/systemd/system/kubelet.service
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=containerd.service
Requires=containerd.service

[Service]
ExecStart=/usr/local/bin/kubelet \\
  --config=/var/lib/kubelet/kubelet-config.yaml \\
  --container-runtime=remote \\
  --container-runtime-endpoint=unix:///var/run/containerd/containerd.sock \\
  --image-pull-progress-deadline=2m \\
  --kubeconfig=/var/lib/kubelet/kubeconfig \\
  --network-plugin=cni \\
  --register-node=true \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
```

```shell-session:実行ログ
sotoiwa@worker-0:~$ cat <<EOF | sudo tee /etc/systemd/system/kubelet.service
> [Unit]
> Description=Kubernetes Kubelet
> Documentation=https://github.com/kubernetes/kubernetes
> After=containerd.service
> Requires=containerd.service
>
> [Service]
> ExecStart=/usr/local/bin/kubelet \\
>   --config=/var/lib/kubelet/kubelet-config.yaml \\
>   --container-runtime=remote \\
>   --container-runtime-endpoint=unix:///var/run/containerd/containerd.sock \\
>   --image-pull-progress-deadline=2m \\
>   --kubeconfig=/var/lib/kubelet/kubeconfig \\
>   --network-plugin=cni \\
>   --register-node=true \\
>   --v=2
> Restart=on-failure
> RestartSec=5
>
> [Install]
> WantedBy=multi-user.target
> EOF
[Unit]
Description=Kubernetes Kubelet
Documentation=https://github.com/kubernetes/kubernetes
After=containerd.service
Requires=containerd.service

[Service]
ExecStart=/usr/local/bin/kubelet \
  --config=/var/lib/kubelet/kubelet-config.yaml \
  --container-runtime=remote \
  --container-runtime-endpoint=unix:///var/run/containerd/containerd.sock \
  --image-pull-progress-deadline=2m \
  --kubeconfig=/var/lib/kubelet/kubeconfig \
  --network-plugin=cni \
  --register-node=true \
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
sotoiwa@worker-0:~$
```

### Configure the Kubernetes Proxy

Kube Proxyが使用するkubeconfigを配置する。

```
sudo mv kube-proxy.kubeconfig /var/lib/kube-proxy/kubeconfig
```

`kube-proxy-config.yaml`設定ファイルを作成する。

```shell-session:コマンド
cat <<EOF | sudo tee /var/lib/kube-proxy/kube-proxy-config.yaml
kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
clientConnection:
  kubeconfig: "/var/lib/kube-proxy/kubeconfig"
mode: "iptables"
clusterCIDR: "10.200.0.0/16"
EOF
```

```:実行ログ
sotoiwa@worker-0:~$ cat <<EOF | sudo tee /var/lib/kube-proxy/kube-proxy-config.yaml
> kind: KubeProxyConfiguration
> apiVersion: kubeproxy.config.k8s.io/v1alpha1
> clientConnection:
>   kubeconfig: "/var/lib/kube-proxy/kubeconfig"
> mode: "iptables"
> clusterCIDR: "10.200.0.0/16"
> EOF
kind: KubeProxyConfiguration
apiVersion: kubeproxy.config.k8s.io/v1alpha1
clientConnection:
  kubeconfig: "/var/lib/kube-proxy/kubeconfig"
mode: "iptables"
clusterCIDR: "10.200.0.0/16"
sotoiwa@worker-0:~$
```

`kube-proxy.service`のSystemdユニットファイルを作成する。

（参考）
[kube-proxy](https://kubernetes.io/docs/reference/command-line-tools-reference/kube-proxy/)

```:コマンド
cat <<EOF | sudo tee /etc/systemd/system/kube-proxy.service
[Unit]
Description=Kubernetes Kube Proxy
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-proxy \\
  --config=/var/lib/kube-proxy/kube-proxy-config.yaml
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
```

```shell-session:実行ログ
sotoiwa@worker-0:~$ cat <<EOF | sudo tee /etc/systemd/system/kube-proxy.service
> [Unit]
> Description=Kubernetes Kube Proxy
> Documentation=https://github.com/kubernetes/kubernetes
>
> [Service]
> ExecStart=/usr/local/bin/kube-proxy \\
>   --config=/var/lib/kube-proxy/kube-proxy-config.yaml
> Restart=on-failure
> RestartSec=5
>
> [Install]
> WantedBy=multi-user.target
> EOF
[Unit]
Description=Kubernetes Kube Proxy
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-proxy \
  --config=/var/lib/kube-proxy/kube-proxy-config.yaml
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
sotoiwa@worker-0:~$
```

### Start the Worker Services

サービスを起動する。

```
{
  sudo systemctl daemon-reload
  sudo systemctl enable containerd kubelet kube-proxy
  sudo systemctl start containerd kubelet kube-proxy
}
```

サービスのステータスを確認する。

```
sudo systemctl status containerd kubelet kube-proxy
```

## Verification

Masterノードでkubectlコマンドを実行する。

```:コマンド
gcloud compute ssh controller-0 \
  --command "kubectl get nodes --kubeconfig admin.kubeconfig"
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ gcloud compute ssh controller-0 \
>   --command "kubectl get nodes --kubeconfig admin.kubeconfig"
NAME       STATUS   ROLES    AGE     VERSION
worker-0   Ready    <none>   6m29s   v1.12.0
worker-1   Ready    <none>   6m22s   v1.12.0
worker-2   Ready    <none>   6m19s   v1.12.0
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

# Configuring kubectl for Remote Access

https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/10-configuring-kubectl.md

このLandでは作業用PCからkubectlが実行できるようにする。

## The Admin Kubernetes Configuration File

API Serverへの接続には外部公開用のIPアドレスを使用する。

```:コマンド
{
  KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-hard-way \
    --region $(gcloud config get-value compute/region) \
    --format 'value(address)')

  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=ca.pem \
    --embed-certs=true \
    --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443

  kubectl config set-credentials admin \
    --client-certificate=admin.pem \
    --client-key=admin-key.pem

  kubectl config set-context kubernetes-the-hard-way \
    --cluster=kubernetes-the-hard-way \
    --user=admin

  kubectl config use-context kubernetes-the-hard-way
}
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ {
>   KUBERNETES_PUBLIC_ADDRESS=$(gcloud compute addresses describe kubernetes-the-hard-way \
>     --region $(gcloud config get-value compute/region) \
>     --format 'value(address)')
>
>   kubectl config set-cluster kubernetes-the-hard-way \
>     --certificate-authority=ca.pem \
>     --embed-certs=true \
>     --server=https://${KUBERNETES_PUBLIC_ADDRESS}:6443
>
>   kubectl config set-credentials admin \
>     --client-certificate=admin.pem \
>     --client-key=admin-key.pem
>
>   kubectl config set-context kubernetes-the-hard-way \
>     --cluster=kubernetes-the-hard-way \
>     --user=admin
>
>   kubectl config use-context kubernetes-the-hard-way
> }
Cluster "kubernetes-the-hard-way" set.
User "admin" set.
Context "kubernetes-the-hard-way" created.
Switched to context "kubernetes-the-hard-way".
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

## Verification

作業用PCで`kubectl`コマンドが実行できることを確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ kubectl get componentstatuses
NAME                 STATUS    MESSAGE             ERROR
controller-manager   Healthy   ok
scheduler            Healthy   ok
etcd-1               Healthy   {"health":"true"}
etcd-0               Healthy   {"health":"true"}
etcd-2               Healthy   {"health":"true"}
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ kubectl get nodes
NAME       STATUS   ROLES    AGE     VERSION
worker-0   Ready    <none>   9m11s   v1.12.0
worker-1   Ready    <none>   9m4s    v1.12.0
worker-2   Ready    <none>   9m1s    v1.12.0
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

# Provisioning Pod Network Routes

https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/11-pod-network-routes.md

このLabではGCPのルーティングルールを作成し、ノードをまたいだPod間の通信ができるようにする。

## The Routing Table

インスタンスのIPとメタデータに保存したPodサブネットのCIDRを確認する。

```:コマンド
for instance in worker-0 worker-1 worker-2; do
  gcloud compute instances describe ${instance} \
    --format 'value[separator=" "](networkInterfaces[0].networkIP,metadata.items[0].value)'
done
```

```shell-session:実行例
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ for instance in worker-0 worker-1 worker-2; do
>   gcloud compute instances describe ${instance} \
>     --format 'value[separator=" "](networkInterfaces[0].networkIP,metadata.items[0].value)'
> done
10.240.0.20 10.200.0.0/24
10.240.0.21 10.200.1.0/24
10.240.0.22 10.200.2.0/24
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

## Routes

ルートを定義する。各Podサブネット宛のパケットを適切なノードにルーティングする。

```:コマンド
for i in 0 1 2; do
  gcloud compute routes create kubernetes-route-10-200-${i}-0-24 \
    --network kubernetes-the-hard-way \
    --next-hop-address 10.240.0.2${i} \
    --destination-range 10.200.${i}.0/24
done
```

```shell-session:実行例
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ for i in 0 1 2; do
>   gcloud compute routes create kubernetes-route-10-200-${i}-0-24 \
>     --network kubernetes-the-hard-way \
>     --next-hop-address 10.240.0.2${i} \
>     --destination-range 10.200.${i}.0/24
> done
Created [https://www.googleapis.com/compute/v1/projects/sotoiwa/global/routes/kubernetes-route-10-200-0-0-24].
NAME                            NETWORK                  DEST_RANGE     NEXT_HOP     PRIORITY
kubernetes-route-10-200-0-0-24  kubernetes-the-hard-way  10.200.0.0/24  10.240.0.20  1000
Created [https://www.googleapis.com/compute/v1/projects/sotoiwa/global/routes/kubernetes-route-10-200-1-0-24].
NAME                            NETWORK                  DEST_RANGE     NEXT_HOP     PRIORITY
kubernetes-route-10-200-1-0-24  kubernetes-the-hard-way  10.200.1.0/24  10.240.0.21  1000
Created [https://www.googleapis.com/compute/v1/projects/sotoiwa/global/routes/kubernetes-route-10-200-2-0-24].
NAME                            NETWORK                  DEST_RANGE     NEXT_HOP     PRIORITY
kubernetes-route-10-200-2-0-24  kubernetes-the-hard-way  10.200.2.0/24  10.240.0.22  1000
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ gcloud compute routes list --filter "network: kubernetes-the-hard-way"
NAME                            NETWORK                  DEST_RANGE     NEXT_HOP                  PRIORITY
default-route-9b51bcf3343f23cb  kubernetes-the-hard-way  10.240.0.0/24  kubernetes-the-hard-way   1000
default-route-cb67e0e6997aee57  kubernetes-the-hard-way  0.0.0.0/0      default-internet-gateway  1000
kubernetes-route-10-200-0-0-24  kubernetes-the-hard-way  10.200.0.0/24  10.240.0.20               1000
kubernetes-route-10-200-1-0-24  kubernetes-the-hard-way  10.200.1.0/24  10.240.0.21               1000
kubernetes-route-10-200-2-0-24  kubernetes-the-hard-way  10.200.2.0/24  10.240.0.22               1000
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

# Deploying the DNS Cluster Add-on

https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/12-dns-addon.md

このLabではCoreDNSをデプロイする。

## The DNS Cluster Add-on

CoreDNSをデプロイする。

```:コマンド
kubectl apply -f https://storage.googleapis.com/kubernetes-the-hard-way/coredns.yaml
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ kubectl apply -f https://storage.googleapis.com/kubernetes-the-hard-way/coredns.yaml
serviceaccount/coredns created
clusterrole.rbac.authorization.k8s.io/system:coredns created
clusterrolebinding.rbac.authorization.k8s.io/system:coredns created
configmap/coredns created
deployment.extensions/coredns created
service/kube-dns created
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

確認する。Serviceが`10.32.0.10`というIPであるのはマニフェストにそう書いてあるから。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ kubectl get pods -l k8s-app=kube-dns -n kube-system
NAME                       READY   STATUS    RESTARTS   AGE
coredns-699f8ddd77-9p52h   1/1     Running   0          30s
coredns-699f8ddd77-pnqgg   1/1     Running   0          30s
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ kubectl get svc -n kube-system
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
kube-dns   ClusterIP   10.32.0.10   <none>        53/UDP,53/TCP   4d22h
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

Podが稼働したノードを確認すると、CNIプラグインによってブリッジとvethができていることが確認できる。

```shell-session
sotoiwa@worker-0:~$ ip -d a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1460 qdisc fq_codel state UP group default qlen 1000
    link/ether 42:01:0a:f0:00:14 brd ff:ff:ff:ff:ff:ff promiscuity 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 10.240.0.20/32 scope global dynamic ens4
       valid_lft 76914sec preferred_lft 76914sec
    inet6 fe80::4001:aff:fef0:14/64 scope link
       valid_lft forever preferred_lft forever
3: cnio0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 0a:58:0a:c8:00:01 brd ff:ff:ff:ff:ff:ff promiscuity 0
    bridge forward_delay 1500 hello_time 200 max_age 2000 ageing_time 30000 stp_state 0 priority 32768 vlan_filtering 0 vlan_protocol 802.1Q bridge_id 8000.a:58:a:c8:0:1 designated_root 8000.a:58:a:c8:0:1 root_port 0 root_path_cost 0 topology_change 0 topology_change_detected 0 hello_timer    0.00 tcn_timer    0.00 topology_change_timer    0.00 gc_timer  105.05 vlan_default_pvid 1 vlan_stats_enabled 0 group_fwd_mask 0 group_address 01:80:c2:00:00:00 mcast_snooping 1 mcast_router 1 mcast_query_use_ifaddr 0 mcast_querier 0 mcast_hash_elasticity 4 mcast_hash_max 512 mcast_last_member_count 2 mcast_startup_query_count 2 mcast_last_member_interval 100 mcast_membership_interval 26000 mcast_querier_interval 25500 mcast_query_interval 12500 mcast_query_response_interval 1000 mcast_startup_query_interval 3124 mcast_stats_enabled 0 mcast_igmp_version 2 mcast_mld_version 1 nf_call_iptables 0 nf_call_ip6tables 0 nf_call_arptables 0 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet 10.200.0.1/24 scope global cnio0
       valid_lft forever preferred_lft forever
    inet6 fe80::649e:f8ff:fe02:8877/64 scope link
       valid_lft forever preferred_lft forever
4: veth797b7424@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master cnio0 state UP group default
    link/ether 7e:7d:3a:72:7e:d0 brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 1
    veth
    bridge_slave state forwarding priority 32 cost 2 hairpin off guard off root_block off fastleave off learning on flood on port_id 0x8001 port_no 0x1 designated_port 32769 designated_cost 0 designated_bridge 8000.a:58:a:c8:0:1 designated_root 8000.a:58:a:c8:0:1 hold_timer    0.00 message_age_timer    0.00 forward_delay_timer    0.00 topology_change_ack 0 config_pending 0 proxy_arp off proxy_arp_wifi off mcast_router 1 mcast_fast_leave off mcast_flood on neigh_suppress off group_fwd_mask 0x0 group_fwd_mask_str 0x0 vlan_tunnel off numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
    inet6 fe80::7c7d:3aff:fe72:7ed0/64 scope link
       valid_lft forever preferred_lft forever
sotoiwa@worker-0:~$
```

ノードのルーティングテーブルを表示すると以下のようになっている。`10.200.0.0/24`は自身のノードに割り当てているpod-cidrであり、cnio0ブリッジへルーティングしている。それ以外はPVCのデフォルトゲートウェイである`10.240.0.1`へルーティングしている。

```shell-session
sotoiwa@worker-0:~$ ip r
default via 10.240.0.1 dev ens4 proto dhcp metric 100
10.200.0.0/24 dev cnio0 proto kernel scope link src 10.200.0.1
10.240.0.1 dev ens4 proto dhcp scope link metric 100
sotoiwa@worker-0:~$
```

## Verification

`busybox`のPodを使って動作確認する。busyboxは1.28.4以下のバージョンを使わないと上手くいかないかもしれない。

（参考）
[dns can't resolve kubernetes.default and/or cluster.local](https://github.com/kubernetes/kubernetes/issues/66924)

Depoymentを作成してPodを起動する。

```:コマンド
kubectl run busybox --image=busybox:1.28 --command -- sleep 3600
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ kubectl run busybox --image=busybox:1.28 --command -- sleep 3600
kubectl run --generator=deployment/apps.v1beta1 is DEPRECATED and will be removed in a future version. Use kubectl create instead.
deployment.apps/busybox created
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

Pod名を変数に入れる。

```
POD_NAME=$(kubectl get pods -l run=busybox -o jsonpath="{.items[0].metadata.name}")
```

`kubernetes`が名前解決できるか確認する。

```:コマンド
kubectl exec -ti $POD_NAME -- nslookup kubernetes
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ kubectl exec -ti $POD_NAME -- nslookup kubernetes
Server:    10.32.0.10
Address 1: 10.32.0.10 kube-dns.kube-system.svc.cluster.local

Name:      kubernetes
Address 1: 10.32.0.1 kubernetes.default.svc.cluster.local
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

# Smoke Test

このLabではクラスターが機能しているかテストする。

## Data Encryption

Secretを作成する。

```
kubectl create secret generic kubernetes-the-hard-way \
  --from-literal="mykey=mydata"
```

etcdからデータを取得する。

```:コマンド
gcloud compute ssh controller-0 \
  --command "sudo ETCDCTL_API=3 etcdctl get \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/etcd/ca.pem \
  --cert=/etc/etcd/kubernetes.pem \
  --key=/etc/etcd/kubernetes-key.pem\
  /registry/secrets/default/kubernetes-the-hard-way | hexdump -C"
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ gcloud compute ssh controller-0 \
>   --command "sudo ETCDCTL_API=3 etcdctl get \
>   --endpoints=https://127.0.0.1:2379 \
>   --cacert=/etc/etcd/ca.pem \
>   --cert=/etc/etcd/kubernetes.pem \
>   --key=/etc/etcd/kubernetes-key.pem\
>   /registry/secrets/default/kubernetes-the-hard-way | hexdump -C"
00000000  2f 72 65 67 69 73 74 72  79 2f 73 65 63 72 65 74  |/registry/secret|
00000010  73 2f 64 65 66 61 75 6c  74 2f 6b 75 62 65 72 6e  |s/default/kubern|
00000020  65 74 65 73 2d 74 68 65  2d 68 61 72 64 2d 77 61  |etes-the-hard-wa|
00000030  79 0a 6b 38 73 3a 65 6e  63 3a 61 65 73 63 62 63  |y.k8s:enc:aescbc|
00000040  3a 76 31 3a 6b 65 79 31  3a b7 94 88 06 f0 45 07  |:v1:key1:.....E.|
00000050  90 c7 3c 77 8c ee d7 66  39 d6 12 fd 25 32 27 e6  |..<w...f9...%2'.|
00000060  2e ac 0d 8b f6 24 17 13  92 bf 79 64 41 a3 0c 71  |.....$....ydA..q|
00000070  5b 67 bc 2e d9 eb 82 aa  29 eb 45 c4 d4 e7 75 35  |[g......).E...u5|
00000080  81 4c 6e 81 b2 2f a6 be  2a 7e 56 33 fc 44 10 db  |.Ln../..*~V3.D..|
00000090  b4 aa 76 f6 5d 2f 3d 57  e1 e1 39 ac eb 56 6b a6  |..v.]/=W..9..Vk.|
000000a0  89 18 1c 75 fb 5e a7 7a  1f 63 cd 21 46 5b 9d 82  |...u.^.z.c.!F[..|
000000b0  bc e4 30 36 72 6e 23 4a  68 62 f6 72 57 0e b4 e7  |..06rn#Jhb.rW...|
000000c0  13 4e 99 41 8f e3 0a 68  f8 dd c4 3a 33 1b f4 b7  |.N.A...h...:3...|
000000d0  bf d8 67 45 c0 ec 72 ac  99 72 df 7f 96 70 33 d1  |..gE..r..r...p3.|
000000e0  ee 2f 76 1a cf 00 55 28  6c 0a                    |./v...U(l.|
000000ea
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

`k8s:enc:aescbc:v1:key1`となっていることを確認する。

## Deployments

Deploymentを作成する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ kubectl run nginx --image=nginx
kubectl run --generator=deployment/apps.v1beta1 is DEPRECATED and will be removed in a future version. Use kubectl create instead.
deployment.apps/nginx created
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ kubectl get pods -l run=nginx
NAME                    READY   STATUS    RESTARTS   AGE
nginx-dbddb74b8-4pnbv   1/1     Running   0          37s
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

### Port Forwarding

ポートフォワーディングできることを確認する。はじめにPod名を変数に入れる。

```
POD_NAME=$(kubectl get pods -l run=nginx -o jsonpath="{.items[0].metadata.name}")
```

ポートフォワードを行う。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ kubectl port-forward $POD_NAME 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
```

別ターミナルでcurlコマンドを実行し、Podに転送されることを確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~
$ curl --head http://127.0.0.1:8080
HTTP/1.1 200 OK
Server: nginx/1.15.6
Date: Tue, 13 Nov 2018 16:13:16 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 06 Nov 2018 13:32:09 GMT
Connection: keep-alive
ETag: "5be197d9-264"
Accept-Ranges: bytes

sotoiwa@Soto-no-MacBook-Air:~
$
```

Ctrl+Cでポートフォワーディングを終了する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ kubectl port-forward $POD_NAME 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
Handling connection for 8080
^Csotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

### Logs

ログが取得出来ることを確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ kubectl logs $POD_NAME
127.0.0.1 - - [13/Nov/2018:16:13:16 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.54.0" "-"
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

### exec

コンテナ内でコマンドが実行できることを確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ kubectl exec -ti $POD_NAME -- nginx -v
nginx version: nginx/1.15.6
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

## Services

NodePort Serviceを作成する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ kubectl expose deployment nginx --port 80 --type NodePort
service/nginx exposed
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

アサインされたNodePort Serviceのポート番号を変数に入れる。

```
NODE_PORT=$(kubectl get svc nginx \
  --output=jsonpath='{range .spec.ports[0]}{.nodePort}')
```

worker-0の外部IPを変数に入れる。

```
EXTERNAL_IP=$(gcloud compute instances describe worker-0 \
  --format 'value(networkInterfaces[0].accessConfigs[0].natIP)')
```

NodePortへのアクセスを許可するFirewall Ruleを追加する。

```:コマンド
gcloud compute firewall-rules create kubernetes-the-hard-way-allow-nginx-service \
  --allow=tcp:${NODE_PORT} \
  --network kubernetes-the-hard-way
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ gcloud compute firewall-rules create kubernetes-the-hard-way-allow-nginx-service \
>   --allow=tcp:${NODE_PORT} \
>   --network kubernetes-the-hard-way
Creating firewall...⠏Created [https://www.googleapis.com/compute/v1/projects/sotoiwa/global/firewalls/kubernetes-the-hard-way-allow-nginx-service].
Creating firewall...done.
NAME                                         NETWORK                  DIRECTION  PRIORITY  ALLOW      DENY  DISABLED
kubernetes-the-hard-way-allow-nginx-service  kubernetes-the-hard-way  INGRESS    1000      tcp:31010        False
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

curlコマンドでアクセスできることを確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ curl -I http://${EXTERNAL_IP}:${NODE_PORT}
HTTP/1.1 200 OK
Server: nginx/1.15.6
Date: Tue, 13 Nov 2018 16:44:51 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 06 Nov 2018 13:32:09 GMT
Connection: keep-alive
ETag: "5be197d9-264"
Accept-Ranges: bytes

sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

## Untrusted Workloads

UntrustedなPodをデプロイする。

```:コマンド
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: untrusted
  annotations:
    io.kubernetes.cri.untrusted-workload: "true"
spec:
  containers:
    - name: webserver
      image: gcr.io/hightowerlabs/helloworld:2.0.0
EOF
```

```shell-session:実行ログ
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ cat <<EOF | kubectl apply -f -
> apiVersion: v1
> kind: Pod
> metadata:
>   name: untrusted
>   annotations:
>     io.kubernetes.cri.untrusted-workload: "true"
> spec:
>   containers:
>     - name: webserver
>       image: gcr.io/hightowerlabs/helloworld:2.0.0
> EOF
pod/untrusted created
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

### Verification

Podを確認する。

```shell-session
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$ kubectl get pods -o wide
NAME                      READY   STATUS    RESTARTS   AGE     IP           NODE       NOMINATED NODE
busybox-bd8fb7cbd-6t52r   1/1     Running   0          55m     10.200.1.2   worker-1   <none>
nginx-dbddb74b8-4pnbv     1/1     Running   0          40m     10.200.1.3   worker-1   <none>
untrusted                 1/1     Running   0          2m13s   10.200.0.4   worker-0   <none>
sotoiwa@Soto-no-MacBook-Air:~/workspace/kubernetes-the-hard-way
$
```

Podが稼働しているノード名を変数に入れる。

```
INSTANCE_NAME=$(kubectl get pod untrusted --output=jsonpath='{.spec.nodeName}')
```

Podが稼働しているノードにSSHログインする。

```
gcloud compute ssh ${INSTANCE_NAME}
```

gVisorの配下で稼働しているコンテナをリストする。

```:コマンド
sudo runsc --root /run/containerd/runsc/k8s.io list
```

```shell-session:実行ログ
sotoiwa@worker-0:~$ sudo runsc --root /run/containerd/runsc/k8s.io list
I1113 16:52:58.756368   15780 x:0] ***************************
I1113 16:52:58.756586   15780 x:0] Args: [runsc --root /run/containerd/runsc/k8s.io list]
I1113 16:52:58.756667   15780 x:0] Git Revision: 50c283b9f56bb7200938d9e207355f05f79f0d17
I1113 16:52:58.756751   15780 x:0] PID: 15780
I1113 16:52:58.756821   15780 x:0] UID: 0, GID: 0
I1113 16:52:58.756890   15780 x:0] Configuration:
I1113 16:52:58.756947   15780 x:0] 		RootDir: /run/containerd/runsc/k8s.io
I1113 16:52:58.757071   15780 x:0] 		Platform: ptrace
I1113 16:52:58.757210   15780 x:0] 		FileAccess: exclusive, overlay: false
I1113 16:52:58.757337   15780 x:0] 		Network: sandbox, logging: false
I1113 16:52:58.757494   15780 x:0] 		Strace: false, max size: 1024, syscalls: []
I1113 16:52:58.757617   15780 x:0] ***************************
ID                                                                 PID         STATUS      BUNDLE                                                                                                                   CREATED                OWNER
a835bf9486cc50f733ad547709d7da081d3188d5604ef92aba328cad748a29f5   15140       running     /run/containerd/io.containerd.runtime.v1.linux/k8s.io/a835bf9486cc50f733ad547709d7da081d3188d5604ef92aba328cad748a29f5   0001-01-01T00:00:00Z
eb020a9beed26c2541f07af8bb35889297aceb4d44fe5b4903de7e63627fd0b2   15060       running     /run/containerd/io.containerd.runtime.v1.linux/k8s.io/eb020a9beed26c2541f07af8bb35889297aceb4d44fe5b4903de7e63627fd0b2   0001-01-01T00:00:00Z
I1113 16:52:58.761825   15780 x:0] Exiting with status: 0
sotoiwa@worker-0:~$
```

`untrusted` PodのIPを取得する。

```
POD_ID=$(sudo crictl -r unix:///var/run/containerd/containerd.sock \
  pods --name untrusted -q)
```

`untrusted` Podの中で稼働している`webserver`コンテナのIDを取得する。

```
CONTAINER_ID=$(sudo crictl -r unix:///var/run/containerd/containerd.sock \
  ps -p ${POD_ID} -q)
```

`webserver`コンテナの中で稼働しているプロセスを表示する。

```:コマンド
sudo runsc --root /run/containerd/runsc/k8s.io ps ${CONTAINER_ID}
```

```shell-session:実行ログ
sotoiwa@worker-0:~$ sudo runsc --root /run/containerd/runsc/k8s.io ps ${CONTAINER_ID}
I1113 16:54:30.817005   15909 x:0] ***************************
I1113 16:54:30.817191   15909 x:0] Args: [runsc --root /run/containerd/runsc/k8s.io ps a835bf9486cc50f733ad547709d7da081d3188d5604ef92aba328cad748a29f5]
I1113 16:54:30.817265   15909 x:0] Git Revision: 50c283b9f56bb7200938d9e207355f05f79f0d17
I1113 16:54:30.817344   15909 x:0] PID: 15909
I1113 16:54:30.817410   15909 x:0] UID: 0, GID: 0
I1113 16:54:30.817475   15909 x:0] Configuration:
I1113 16:54:30.817528   15909 x:0] 		RootDir: /run/containerd/runsc/k8s.io
I1113 16:54:30.817651   15909 x:0] 		Platform: ptrace
I1113 16:54:30.817837   15909 x:0] 		FileAccess: exclusive, overlay: false
I1113 16:54:30.817960   15909 x:0] 		Network: sandbox, logging: false
I1113 16:54:30.818085   15909 x:0] 		Strace: false, max size: 1024, syscalls: []
I1113 16:54:30.818351   15909 x:0] ***************************
UID       PID       PPID      C         STIME     TIME      CMD
0         1         0         0         16:49     0s        app
I1113 16:54:30.820659   15909 x:0] Exiting with status: 0
sotoiwa@worker-0:~$
```

# Cleaning Up

https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/14-cleanup.md

このLabでは作成したGCP上のリソースを削除する。

## Compute Instances

インスタンスを削除する。

```
gcloud -q compute instances delete \
  controller-0 controller-1 controller-2 \
  worker-0 worker-1 worker-2
```

## Networking

外部ロードバランサーを削除する。

```
{
  gcloud -q compute forwarding-rules delete kubernetes-forwarding-rule \
    --region $(gcloud config get-value compute/region)

  gcloud -q compute target-pools delete kubernetes-target-pool

  gcloud -q compute http-health-checks delete kubernetes

  gcloud -q compute addresses delete kubernetes-the-hard-way
}
```

Filewall Ruleを削除する。

```
gcloud -q compute firewall-rules delete \
  kubernetes-the-hard-way-allow-nginx-service \
  kubernetes-the-hard-way-allow-internal \
  kubernetes-the-hard-way-allow-external \
  kubernetes-the-hard-way-allow-health-check
```

VPCネットワークを削除する。

```
{
  gcloud -q compute routes delete \
    kubernetes-route-10-200-0-0-24 \
    kubernetes-route-10-200-1-0-24 \
    kubernetes-route-10-200-2-0-24

  gcloud -q compute networks subnets delete kubernetes

  gcloud -q compute networks delete kubernetes-the-hard-way
}
```