KubeCon NA 2019(Day3) 参加メモ

# Day3

最終日！
自分用参加・聴講メモ
※Keynoteは省略

## [Handling Risky Business: Cluster Upgrades](https://static.sched.com/hosted_files/kccncna19/8e/Handling%20Cluster%20Upgrades%20K8srotator.pdf)

Lyftのクラスタ自動アップグレードの話
2017年からK8sを調査・構築して、2018年にはレガシーシステムを移行開始、2019年に(K8sが)急成長

OSセキュリティパッチ, バグフィックス, 機能追加などでK8sのバージョンアップは避けられない

目指すのはp95,99 latencyやCluster Healthなどを守ったアップグレード
(ということは、zero-downtimeは前提のようだ)

次のような流れでコード化して、クラスタ更新を自動化する

```
do
while
  !is_cluster_updated() and
  cluster_is_healthy() {
    NODE = get_old_node()
    kubectl cordon NODE
    kubectl drain NODE
    kubectl delete NODE
    terminate(NODE)
  }
```

それで作ったのが`k8srotator`(最初はv0)
GO言語で実装したOperator

FleezeとRotateの状態をもつ

Fleezeはクラスタアップグレードを停止する

<img width="546" alt="スクリーンショット 2019-11-21 午前11.07.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314463/d1c1a100-4a44-f579-e489-c13cd10fa91b.png">

RotateはCluster Cycleをローテートする

<img width="528" alt="スクリーンショット 2019-11-21 午前11.07.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314463/194f0b87-440d-18d6-d35a-0fb97ae6c3c0.png">

ローテーションの順番は資料に細かく書いてあるので、それを読んだ方がいい
簡単にいうと、Kubelet(Node)単位で、Old KubeletからNew KubeletへPodを移して、Drainしていく

K8srotator v1も登場
Cluster Healthを拡張, 特定ノードのフィルタリング, Cluster設定のカスタムなどを追加

取り込むべき障害シナリオは下記
・etcdがquorumを失う
・api-server, ingressの疲弊
・AWSのQuotaに当たる
・In-placeでのバージョン不整合

・ダメージコントロール
 - Fleezeモードに切り替える
 - User/ 管理者 / チームにアラート
・応急措置
 - ログ・ステータス確認
 - ローテートモードに戻す

今後やっていくとして、ML用のWorkloadの対応, Triggerの廃止, Multi Cluster, PDB, Custom Cluster Health, Node Terminateの順序化などがある

#### 感想

Lyftでのクラスタアップグレードのお話で、クラスタ更新を自動で達成するためにOperatorを書くというアプローチが非常に面白かった
(TriggerベースでReconcile Modelではないので、たぶん厳密にはOperatorではない(似てるけど))
こうしたクラスタ自動更新のモチベーションは今のチームでもあって、非常に参考になった

今の日本だとクラスタ更新自動化を達成できている企業は限られていると思っているが、近いうちに同じモチベーションで様々な企業がこうしたクラスタ更新自動化に取り組んでいくのではないかな、という予感がしている

惜しむらくはKubeConでの世界のテックカンパニー各社が各社で別々の仕組みを構築していること。つまりデファクトスタンダードはない
ビジネスの特性によってWorkloadの特性も違うので、当然といえば当然かもしれないが...
公式からはkubeadm以上のものは出ない気がするので、もしやるならその選択になるのかもしれない

## [Am I Using It Right? Checking Best Practices on Live Kubernetes Clusters](https://static.sched.com/hosted_files/kccncna19/06/clusterlint-slides.pdf)

DigitalOceanのClusterlintの話
Clusterlintというクラスタチェックツールを開発したようだ

> best practices checker for Kubernetes clusters
> https://github.com/digitalocean/clusterlint

DOKSというのがDigitalOceanのマネージドK8sサービス

Clusterlintで、K8sのベストプラクティスをチェックする

> Clusterlint queries live Kubernetes clusters for resources, executes
common and platform specific checks against these resources and
provides actionable feedback to cluster operators.

とのこと

あとはClusterlintの使い方がメイン

Clusterlintの目指していることは
・マニフェストではなく、クラスタそのもののチェック
・プラットフォームごとの分析
・他のコードとの統合

ClusterlintはK8sからResourceを取得して、チェックし、結果をレポートする

次のように使う

```
clusterlint run -G aws
```

チェックするルールはコードで書く

実際にベストプラクティスに則っていないPodをデプロイし、チェックするデモもありました。

DigitalOceanの商用にはこのClusterlintを組み込んでいるらしい

最後には、他のLintツールにも触れていました

#### 感想

YAML LinterはOSSで見かけることがあったものの、Clusterそのものをチェックする、というアプローチは初めてだったので興味深かった。
ベンダロック感も少し感じたが、利用者がコードを書いて、それでチェックできるのであれば良い選択肢かもしれない

## [The Gotchas of Zero-Downtime Traffic /w Kubernetes](https://static.sched.com/hosted_files/kccncna19/f7/The%20Gotchas%20of%20Zero-Downtime%20Traffic.pdf)

Graceful Trafficでzero-downtimeを実現する話

前半はNginx + NodeJSのアプリを元に、説明

Podのシャットダウンは、kube-apiserverがDeleteを受信
PodはTerminatingステータスになる
全てのコンテナのPID 1がSIGTERMを受信する → (Termination Grace Period Seconds) → 全てのコンテナのPID 1がSIGKILLを受信する

#### Gotcha #1 CMD vs ENTRYPOINT

ENTRYPOINTで`sh -c nginx`を使うと、shにSIGTERMが送られる

#### Gotcha #2 STOPSIGNAL

Docker RuntimeだとSTOPSIGNALでSIGTERMを書き換えできる

#### Gotcha #3 Readiness / Liveness Probe

LivenessはプロセスがOKかどうかを確認
Readinessはプロセスが応答を受けられるかを確認

#### Gotcha #4 PreStop

preStopが動いている or SIGTERMが送られた時、Applicationは通信を受け続けている
(ServiceのEndpointが非同期で更新されるため)

重要なのは、ほとんどの場合のグレースフルシャットダウンの定義で、プログラムはKubernetesの期待に沿っていない。

新しい通信を受け付けないように、/bin/sleepも必要になる
(おそらく、新しい「sleep」LifeCycleHookを入れた方が良いのでは、と)

#### Gotcha #5 Deployment

replicasが1の時はRollingUpdateのmaxUnavailableを0にしておく
DefaultではmaxUnavaliableが1になっている(apps/v1betaで修正)
apps/v1を使っていることを確認しよう

#### Gotcha #6 Deployment

.spec.strategy.minReadySecondsと.spec.strategy.progressDeadlineSecondsの時間の間に、アプリケーションのウォームアップが完了するようにする

そして.spec.strategy.rollingUpdate.maxSurgeがキャパシティを超えないようにする

#### Gotcha #7 SideCar

AppがDBに接続するためのプロキシをSideCarとしている場合、preStop hookの間に競合しないように、同期またはスケジューリングするべき

#### まとめ
1. entrypointはシグナルをハンドルすべき
2. STOPSIGNALが必要になるかもしれない
3. Liveness / Readiness Probeは異なる間隔を設定する
4. 接続を受け付けないように、preStopではSleepを入れる
5. apps/v1 Deploymentを使う
6. RollingUpdateの間にウォームアップを行う
7. SideCarのシャットダウンを同期させる

#### 感想

アプリケーションで502,503を発生させずにいかに(ローリング)アップデートさせるか、という点に焦点をあてたセッションで非常にためになりました。

結局、リクエスト停止はsleepが最善なのか……
すでに取り組めていること、考えたことすらなかったことのどちらもあるので、もうGracefulについて考え直そうかな…

## [Evolving the Kubernetes Ingress APIs to GA and Beyond](https://static.sched.com/hosted_files/kccncna19/a5/Kubecon%20San%20Diego%202019%20-%20Evolving%20the%20Kubernetes%20Ingress%20APIs%20to%20GA%20and%20Beyond%20%5BPUBLIC%5D.pdf)

Ingressの現状はNginx Ingress ControllerやHAProxy Ingress Controllerのようなプロダクトが出ている

v1ではIngressClassというモデルにクリーンアップする

backendをdefaultBackendにリネーム

パスが正規表現だが、Nginx/HAProxyでは合わないことも
v1ではPathTypeが追加される(詳しくは資料内の表を参考に)
PathTypeでPrefixも許容される

HostnameのWildcard
*.foo.comで「bar.foo.com」はOK。「baz.bar.foo.com」「foo.com」はNG

IngressClassはControllerとParameterをフィールドに持つ

v1betaではIngressBackendにserviceNameを持っているが、v1ではServiceBackendやServiceBackendPortなどの構造体が増える

v1 API Timelineとして、v1.18でIngress v1をRelease予定
v1.19でextension/v1beta1から取り除かれる。networking.k8s.io/v1beta1もv1.2xで取り除かれる

早期設定デザインは“self-service” oriented
現在は実装がたくさん...

より良いResource管理モデルの構築や、携帯性を保ちながら現在のLoadBalancing機能をサポートするのがゴール

※あくまで以下のAPIは提案ステージ。これからも変わっていく予定

Ingressはセルフサービスモデル
IngressClassがインフラプロバイダによって開発される

GatewayClassもインフラプロバイダが開発する
GatewayはLBのインスタンスのこと

RouteとServiceをApplicationエンジニアなどが定義する

<img width="1217" alt="スクリーンショット 2019-11-21 午後3.42.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314463/d41e0c96-84bd-7673-0ac5-245743f89177.png">

<img width="1172" alt="スクリーンショット 2019-11-21 午後3.43.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314463/44a3c756-d4a1-82da-53be-ae01758076e5.png">

RBACモデルでUSERがどういったROLEで、どのRESOURCEをどうVERBするのか、という記述ができるようにした

API Resourceのデザインや実装はこれから(Help Wanted!)

#### 感想

IngressをGAに持って行こうという話で、まずはv1の拡張。
そしてv2でモデルを綺麗にするという話でした。
モデルを綺麗にすることでResourceが増えて、より複雑性は増しますが、ようやくそれでプロバイダー関係なく綺麗にまとまるのならアリかなと個人的には思いました。
Resourceが分割されることで、インフラプロバイダ•クラスタ管理者•アプリ開発者の役割が分割されて適正化されることに期待です。
(でもv2の実装はまだまだ先のよう)

## [Tutorial: Mastering Multi-version CRDs: From YAML to a Serious Development Project](https://static.sched.com/hosted_files/kccncna19/58/KubeCon%20NA%2019_%20Multi-version%20CRDs.pdf)

CRDの応用機能は多数ある(Defaulting, Pruning, Conversion, etc...)
今回はConversionが主役

KubernetesのオブジェクトにはVersion XXのオブジェクトという考え方はない(裏側でバージョンの違いをConversionして互換性を保っている)

今回は機能の説明をしながら、実際のConversion, Admissionのソースに手を入れていくチュートリアル形式

こちらにソースがあるので、気になる人は読むと良いかも
(Programming Kubernetesを読んでいれば理解できると思う)

ClusterはMinikubeやKindなどでv1.16のクラスタを用意して、リポジトリに用意してあるYAMLをApplyすれば良い

チュートリアルリポジトリ:
https://github.com/jpbetz/Ko

#### 感想

Programmin Kubernetesの著者の一人によるMulti Version CRDのチュートリアルという、すごく豪華なセッションでした。
CRDはv1.16でGAになりましたが、「今後CRDに他の応用機能が追加される予定がありますか？」と聞いたところ、[Deep Dive Into API Machinery](https://static.sched.com/hosted_files/kccncna19/1c/KubeCon%20NA%2019_%20Sig%20API%20Machinery%20Deep%20Dive.pdf)のKEP2つとUnionTypeのKEPが予定に入っているとのこと
CRDにはBreaking Changeがなさそうで安心した