kubernetes-the-hard-wayを魔改造した記録

## 記事の概要

正月休みに、<a href="https://github.com/kelseyhightower/kubernetes-the-hard-way">kubernetes-the-hard-way</a>（Vagrant環境でやったので実際は<a href="https://github.com/kinvolk/kubernetes-the-hard-way-vagrant">kubernetes-the-hard-way-vagrant</a>）で勉強しておりまして、気が付いたら正月終わっても休日に引きこもって改造して遊んでいたので、その記録です。

## 改造の概要

1. cniプラグインにcalicoを使う
2. workerノードにTLS bootstrappingを使う
3. kube-apiserverとかはserviceでなくpodで動かす
4. node同士の名前解決（これが魔）

ex1. 全体的にバージョンアップ
ex2. metrics-server導入

大体こんな感じです
やったことをまとめたもの-> https://github.com/buildsville/kubernetes-the-hobby-way

## 記録

__コード的な記述はなく文章です__
上のリポジトリの解説のような感じ

### まえがき（モチベーション）
そもそもkubernetes-the-hard-wayをやる理由が、
「認証とネットワーク周りをもう少しちゃんと把握したい」
だったのですが、実際やってみると、ネットワーク周りはstaticな設定でさらっと流してる感じ。
これだと私の目的とは少し離れているなと思ったので、ここから自分なりにいじり回して理解を深めていこうと思いました。
基本方針はstaticな記述をなくしてスケーラブルな感じにしていくイメージで。

### 作業の流れ

大雑把に書いてますが実際はオリジナルからの細かい変更が結構あったと思います
（都度都度で対応したし…最初は記録する気もなかったし…今更全部掘り起こすのも…）

#### 1. cniプラグインを変更

- kube-controller-managerの起動オプションに `--allocate-node-cidrs=true` を追加
    - nodeのcidrを自動で割り振ってもらう
- cniプラグインをbridgeからcalicoに変更
    - `usePodCidr` で上で割り振られたcidrからpodにipを振ってもらう
    - calicoを選んだのはなんとなく一番勢いがあるっぽかったので

#### 2. TLS-bootstrapping

- 公式ドキュメントを参考に設定しました
    - https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/
    - https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/
- 他に記事もあるし、ほぼドキュメントをなぞっただけなので設定については詳しく取り上げませんが、後でもう少し触れます

#### 3. master-componentsをpodに

- master-nodeにkubelet.serviceを設定
    - `--pod-manifest-path` を指定してそこに置いたmanifestsを読み込むようにする
        - kube-apiserverとkube-controller-managerとkube-schedulerのpodのyamlを配置
        - kube-proxyとcalicoはここではなくdaemonsetでdeploy
    - labelとtaintsを設定してworker-nodeと区別する

#### 4. node間の名前解決（魔）

- __この環境限定のお遊び__
- 最初にhostsに書いてしまうのをやめたかった
- ちょっとしたツール作ってCoreDNSと連携
    - ロードバランサの10.240.0.40をDNSサーバ兼用にする
    - cluster内nodeのhostnameとinternalIPを取得してhosts形式でファイル出力する<a href="https://github.com/buildsville/node-hosts-adder">謎ツール</a>を作ってDNSサーバと同じところ配備
    - CoreDNSで上のツールが出力したファイルをhostsプラグインで読む
    - 各nodeのsystemd-resolvedは止めてしまって上をnameserverに設定する
        - systemd-resolvedはドットが入ってない名前を読むのに難があった
- これでworker-nodeはdhcpにお任せできる
    - 今回はdhcpサーバーはVirtualBoxで
    - master-nodeはetcdの関係でstaticのまま
        - LBも当然static
- 名前解決は諦めて `--kubelet-preferred-address-types` で internalIP を指定するのでもよかったがまあせっかくだし

#### ex1. バージョンアップ

- 各所の数字を大きくしただけ
    - 今回見た範囲では特に変な動きは確認できず
        - そんな踏み込んだことはしてないので…
    - kubeletの `--allow-privileged` がdeprecatedだったけど見なかったことにした

#### ex2. metrics-serverを導入

- `kubectl top` がしたくて
- https://github.com/feiskyer/kubernetes-handbook/blob/master/en/addons/metrics.md ここを参考にkube-apiserverにflagを追加
    - aggregator用の証明書を作成してcontrollerのnodeに配置
- https://github.com/kubernetes-incubator/metrics-server/tree/master/deploy/1.8+ ここのmanifestをdeploy
    - metrics-server用の証明書を作成してそれらとca.pemを読むようdeploymentに設定を追加
        - 普通はsecretでdeployすると思うけど今回はスクリプトの都合上nodeに置いてマウント

### ハマったところ ・ よくわからないところ

#### nodeをまたいだ通信ができなかった

calicoをdeployして動作確認してみたところ、node間の通信ができないようでした。
結論から言うと、`net.ipv4.conf.all.forwarding = 1` を設定する必要がありました。
routingとかiptablesばかり見ててカーネルパラメータは完全にノーマークだったので恐ろしくハマった…
他にも設定しないといけないのがありそうな感じ。
ちなみにubuntuにdockerをインストールすると変更されるカーネルパラメータは<a href="https://gist.github.com/buildsville/8866467fb38bd463c5796ac6fa63ba30">こんな感じ</a>。
あとflannelはこれをやらなくても動いてました。

#### serverのTLS-bootstrappingのapprove

<a href="https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#certificate-rotation">ここ</a>のnoteを読む感じだと、kubernetes自体の機能ではserverの場合はcsrのapproveを自動でできないぽいです。
ググると`certificatesigningrequests/selfnodeserver`が云々とか出てくるけど古い情報っぽい。
https://github.com/coreos/kapprover こういうのを使ってやりなさいってことでしょうか。（ちなみにこれは動かなくて、<a href="https://github.com/proofpoint/kapprover">こっちのfork</a>が動くもののちょっと怪しい感じ）
それにセキュリティの問題で敢えて止めてある機能をこっちで付けちゃっていいのかどうか…
でもこれserverも自動でapproveしてもらわないとclusterがautoscaleした後とかmetrics-serverが困ることに…
TLS-bootstrappingガチ勢はどうしてるんでしょうね。

#### kube-apiserverのデバッグ

apiserverをserviceで起動させた場合は設定にミスがあればjournaldでログを確認できると思うんですが、podとして起動させた場合はどういう道筋になるんでしょう。
apiserverが起動してないから当然 `kubectl logs` なんてできないし…
一度manifestのtypoをやって立ち上がらなかったんですけど、 どこ見ていいのかわからなかったです。

## 注意ポイント

### 結構なリソース食い

ちょっと色々動かそうとすると結構なリソース（特にメモリ）が必要になってしまいます。
オリジナルは各nodeにメモリを512ずつ振ってあるけど全然足りなくてよくハングした…のでmasterには2048、workerには1024を設定してます。（合計で10GBくらいメモリが必要）
host側でリソースが不足するともちろんhostがハングします。
私の場合は使ってないマシンがあったのでそれを専用機にしましたが、__メモリ16GのマシンでIDEとかブラウザとか開きながらやったら普通に死ぬと思います。__（先に言うべきか）
これからはこの環境をベースにして色々やりたいと思ったけどこれが少しネックになりそう…