addon-manager

# これはなに？
https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/addon-manager

Kubernetesクラスタでデフォルトで動いておく必要のあるmanifestを自動的にデプロイするソフトウェア。GKEやminikubeでも利用されています。
LeaderElectionの機能があり、クラスタ内で複数動作させることでHAを実現できます。
実態はこのシェルスクリプトです https://github.com/kubernetes/kubernetes/blob/master/cluster/addons/addon-manager/kube-addons.sh

k8sクラスタにあらかじめ特定のPodを稼働させておく場合などに使えそうなので、詳細を調べてみました。

# addonの管理方法
addon-managerは `$ADDON_PATH`(デフォルトは `/etc/kubernetes/addons/` )にあるマニフェストテンプレートを管理します。
2種類の管理方法があり、これらをラベルで指定します。

- `addonmanager.kubernetes.io/mode=Reconcile`
  - もしリソースが消されていれば作り直す
  - もしテンプレートがが変更されていたら反映し直す
  - もしテンプレートが消されていたらリソースを消す
  - バージョン・設定値も含めて固定で動く必要のあるmanifestの管理に使えそう
- `addonmanager.kubernetes.io/mode=EnsureExists`
  - 存在があることを保証する
  - そのリソースがないときは作成・再作成する
  - テンプレートが消えていても作ったリソースはそのまま
  - バージョン・設定値は利用者にカスタマイズさせるようなmanifestの管理に使えそう

**注意すること**

- 上記どちらかの管理方法をラベルで指定する必要がある
- namespaceに属するリソースについてはkube-systemのものにする必要がある


要するにaddon-managerというのは、あるディレクトリにあるマニフェストをapplyし続けるデーモンのようなアプリケーションなのです。

# リーダー選出はどうやっているのか？

addon-managerは、HAでマスターを構成している場合に、kube-controller-managerのリーダー選出を借りて自身のリーダー選出に利用しています。

（HAでのクラスタの構成はこちらを参照 https://kubernetes.io/docs/admin/high-availability/ )

下記でkube-controller-managerがどのホストで動いているかを知ることができます。

```
$ kubectl get ep -n kube-system kube-controller-manager -o yaml
apiVersion: v1
kind: Endpoints
metadata:
  annotations:
    control-plane.alpha.kubernetes.io/leader: '{"holderIdentity":"現在のリーダーのホスト名","leaseDurationSeconds":15,"acquireTime":"2017-12-07T08:02:04Z","renewTime":"2017-12-08T02:59:44Z","leaderTransitions":49}'
  creationTimestamp: 2017-10-24T05:00:36Z
  name: kube-controller-manager
  namespace: kube-system
  resourceVersion: "7842073"
  selfLink: /api/v1/namespaces/kube-system/endpoints/kube-controller-manager
  uid: 45ac6cb7-b878-11e7-bc9c-fa163e6b368e
subsets: null
```

addon-managerはmaster nodeで動くことを想定しており、上記コマンドで取得した現在のリーダーのホスト名と、自身のホスト名が同じであれば動作するようになってます。 （ https://github.com/kubernetes/kubernetes/blob/master/cluster/addons/addon-manager/kube-addons.sh#L156 ）

ちょっとトリッキーな方法だが簡単にHAが実現できる方法です。

# addon-managerをどうやってデプロイするか？

addon-managerはコンテナとして提供されています ( https://console.cloud.google.com/gcr/images/google-containers/GLOBAL/kube-addon-manager )  これをデプロイするにはいくつかの方法が考えられます。

**方法1 master NodeにDaemonSetsで起動するようにしておく**

- クラスタ提供者からすると、利用者に消される恐れがある
- そのdaemonsetsを提供する仕組みで必要なmanifestをデプロイすれば良いのではないか
  - kube-systemを触る権限がある人はこの機能を停止できてしまう
    - RBACでkube-systemの操作を限定するならそれでも良さそう
  - EnsureExistsの挙動はaddon-mangerを使わないと実現できない

**方法2 master Nodeにstatic podで起動するようにしておく**

- Static pod と呼ばれる方法 https://kubernetes.io/docs/tasks/administer-cluster/static-pod/
- kubectlで消すことができない
- minikubeもこの方法を使っている（後述）

**方法3 master Nodeにsystemdで起動するようにしておく**

- kubectlで消すことができない
- static pod（方法2）より大袈裟なので使う利点がなさそう

**方法まとめ**

方法を3つ書きましたが、利用者に消して欲しくないmanifestを提供するには 方法2がよさそうです。

# minikubeでの事例

minikubeはStatic podと呼ばれる方法。具体的には `/etc/kubernetes/manifestにaddon-manager` に
 https://github.com/kubernetes/minikube/blob/master/deploy/addons/addon-manager.yaml のようなマニフェストを配置することで、addon-managerをデプロイしています。

このmanifestでは環境変数でkubeconfigを渡し、hostPathで`/etc/kubernetes/addons/` をマウントしています。
`minikube addons enable`したときはminikueがlocalkubeに指令を出し、localkubeが `/etc/kubernetes/addons` にファイルをコピーし、 それをhostPathでマウントしているaddon-managerが検知して、Kubernetesにaddonをデプロイするという流れになっています。

## どういう時に嬉しいか？
kube-dnsなどクラスタを構成するために必要なコンポーネントを立ち上げる時に便利そうです。

さらに、この方式を使ったmanifestは通常のkubectlでの更新ができなくなる（mode=Reconcileのとき）ため、Kubernetesクラスタを第三者に提供する時に、クラスタを構成するのに不可欠なリソースを注入する場合に利用できそうです。 （managed kubernetes提供業者はこういうことをしたいのでは？）

# おわりに
このエントリは、Z Lab　のメンバーによる [Z Lab Advent Calendar 2017](https://qiita.com/advent-calendar/2017/zlab) として業務時間中に書きました。