Kubernetes 1.14: SIG Node の変更内容

## はじめに

[Kubernetes 1.14 の CHANGELOG](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.14.md) から SIG Node の取り組みについてまとめます。

## 主な変更点 (1.14 What's New)
### Pid Limiting がベータになりました ([#757](https://github.com/kubernetes/enhancements/issues/757)) :tada: 
- Pid リソースの枯渇を防ぐための機能です。
- Pid リソースを Pod-Pod 間および Node-Pod 間で隔離することができます。 [kubernetes/kubernetes: #73651](http://github.com/kubernetes/kubernetes/pull/73651) / [kubernetes/enhancements: #757](https://github.com/kubernetes/enhancements/issues/757)
    - :pencil: 今回、1.14 でベータになったのは Pod 内で Pid の数を制限する、Pod-Pod 間の Pid Limiting の方です、1.13 では Feature Gate の `SupportPodPidsLimit` で有効化する必要がありました。
    - :pencil: それとは別に Node が最低限確保する Pid の数を指定するための Node-Pod 間の Pid Limiting が [kubernetes/kubernetes: #73651](http://github.com/kubernetes/kubernetes/pull/73651) で導入されました。この機能はまだアルファ機能ですので Feature Gate の `SupportNodePidsLimit` を `true` にすることで有効化する必要があります。
    - :pencil: ちなみに [2019/04/05 時点のドキュメント](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/) では未だ `SupportPodPidsLimit` はアルファ機能のままで、 `SupportNodePidsLimit` についての記載はありません…。

### Windows Node のサポートが Stable になりました([#116](https://github.com/kubernetes/enhancements/issues/757))  :tada:
- :pencil: 詳しくは [SIG Windows の記事](https://qiita.com/ainoya/items/e6441d6d3e69cc8c71d2)を参照してください。

## 既知の問題 (Known Issues)
- **既存の Flexvolume でマウントされた PVC がたくさんのディレクトリを含んでいたり、空き容量が不足していた場合 kubelet の再起動が失敗する場合があります。** [#75019](https://github.com/kubernetes/kubernetes/pull/75019)
    - :pencil: kubelet は Plugin の登録に関して、plugin ディレクトリを常に監視していますが、古い plugin ディレクトリは Flexvolume によって実際の PV がマウントされるパスでもあります。そのため、マウントされた Flexvolume の PV が大量のディレクトリを含んでいた場合や、空き容量が不足していた場合に Plugin の登録に関する監視が失敗してしまうためこの問題が発生してしまうようです。

## アップグレード時の注意点 (Urgent Upgrade Notes)
- **`--experimental-fail-swap-on` フラグが削除されました。** [#69552](https://github.com/kubernetes/kubernetes/pull/69552), [@Pingan2017](https://github.com/Pingan2017)
    - :pencil: 代わりに `--fail-swap-on` を使ってください。
    - :pencil: `--fail-swap-on` に関する議論は [#7294](https://github.com/kubernetes/kubernetes/issues/7294) を参照してください。
- **kubelet による Health check (liveness & readiness) が異なるホストに対するリダイレクトを行わなくなり、`Success` として扱われるようになりました。この場合、 `ProbeWarning` というイベントが生成され、リダイレクトが無視されたことがわかります。もし、異なるエンドポイントに対する health check のリダイレクトに依存しているようならば、リダイレクトではなく例えばプロキシするように変更してください。** [#75416](https://github.com/kubernetes/kubernetes/pull/75416), [@tallclair](https://github.com/tallclair)
    - :pencil: [チェックしているのは異なるホストへのリダイレクト](https://github.com/kubernetes/kubernetes/pull/75416/files#diff-ca8ccba349ee7f2f0cddbb8305fc86a1R133) のようですので、内部でリダイレクトする限りにおいては問題ないようです。 
    - :pencil: もともとドキュメントでは health check 時のレスポンスのステータスコードが 200-400 の間である場合は `Success` として看做すと書かれていたため、整合性を合わせるための修正のようです。

## 廃止される機能 (Deprecations)
- **OS やアーキテクチャの情報が Node オブジェクトの `kubernetes.io/os` と `kubernetes.io/arch` ラベルに記録されるようになりました。 `beta.kubernetes.io/os` と `beta.kubernetes.io/arch` ラベルはまだ利用可能ですが、 v1.18 に削除予定です。** [#73333](https://github.com/kubernetes/kubernetes/pull/73333), [@yujuhong](https://github.com/yujuhong)
- **`--containerized` フラグが非推奨となりました。将来のバージョンで削除されます。** [#74267](https://github.com/kubernetes/kubernetes/pull/74267), [@dims](https://github.com/dims)
    - :pencil: kubelet のコンテナ化サポート自体が非推奨となったのか、このフラグが非推奨になっただけなのか気になるところです。[issue の最初の方](https://github.com/kubernetes/kubernetes/issues/74148#issuecomment-465323588) では、このフラグが非推奨になっただけで使っていないのならば影響ないよとコメントされていますが、後のコメントでは 「[この機能自体が非推奨だよ](https://github.com/kubernetes/kubernetes/issues/74148#issuecomment-465779777)」 とされており、すでに[コンテナ化された kubelet のテスト自体も削除](https://github.com/kubernetes/test-infra/pull/11338) されてしまったようです。

## 注目機能 (Notable Features)
- **`RunAsGroup` がベータ機能に昇格し、デフォルトで有効化されました。`PodSpec` と `PodSecurityPolicy` オブジェクトを利用して、サポートされたコンテナランタイムにおいては、プライマリGIDを制御することができます。** [#73007](https://github.com/kubernetes/kubernetes/pull/73007), [@ krmayankk](https://github.com/krmayankk)
    - :pencil: これまでも `fsGroup` を指定することで補助グループを指定することはできましたが、プライマリグループを指定することはできませんでした。
- **`PodPresets` を利用した際に、init container に通常のコンテナと同じ情報が追加されるようになりました。** [#71479](https://github.com/kubernetes/kubernetes/pull/71479), [@ soggiest](https://github.com/soggiest)
    - :pencil: 注目の機能と言うよりも仕様のバグのような気がしますが、今までは init container に `PodPresets` が適用されていなかったようです。
- **CRI による pod のログディレクトリが、`/var/log/pods/UID` から `/var/log/pods/NAMESPACE_NAME_UID` に変更になりました。** [#74441](https://github.com/kubernetes/kubernetes/pull/74441), [@Random-Liu](https://github.com/Random-Liu)
    - :pencil: リリースノートからは分かりづらいですが、`/var/log/pods/${NAMESPACE_NAME}_${POD_NAME}_${POD_UID}` に変更した、と言うことです。これにより、ログの収集時などにメタデータとして Pod の名前やネームスペース名などを apiserver への問い合わせ無しでつけることができるようになります。
- **`RuntimeClass` がベータとなり、デフォルトで有効化されました。** [#75003](https://github.com/kubernetes/kubernetes/pull/75003), [@tallclair](https://github.com/tallclair)

## API の変更 (API Changes)
- **[CRI] `PodSandbox` と `PodSandboxStatus` に `runtime_handler` という Pod の RuntimeClass の情報をトラックするためのフィールドが追加されました** [#73833](https://github.com/kubernetes/kubernetes/pull/73833), [@haiyanmeng](https://github.com/haiyanmeng)
    - :pencil: `RuntimeClass` が導入された関係上、CRI の API で runtime に関する情報を取得する必要がありました。

## バグ修正や変更など (Detailed Bug Fixes And Changes)
- **`--container-runtime-endpoint` のヘルプメッセージが修正されました。Linux では unix socket しかサポートしていません。** [#74712](https://github.com/kubernetes/kubernetes/pull/74712), [@feiskyer](https://github.com/feiskyer)
    - :pencil: ヘルプメッセージには TCP エンドポイントも利用できると嘘情報が書かれていました。
- **複数のレポジトリに関連づけられている一つのタグしか持たないイメージに対するイメージガベージコレクションが失敗しなくなりました。** [#73824](https://github.com/kubernetes/kubernetes/pull/73824), [@jiayingz](https://github.com/jiayingz)
    - :pencil: なんのこっちゃという感じですが、同一のイメージに対して異なるレポジトリのイメージ名を付与すると、[kubelet によるノードディスク使用量削減のためのイメージガベージコレクションが失敗する](https://github.com/kubernetes/kubernetes/issues/70238)、という問題があったようです。
- **kubelet は Unknown ステータスなコンテナを再起動もしくは削除する前に停止を試みるようになりました。**  [#73802](https://github.com/kubernetes/kubernetes/pull/73802), [@Random-Liu](https://github.com/Random-Liu)
    - Unknown ステータスは必ずしも該当するコンテナが終了していることを意味しないので、Unknown なステータスをランタイムから受け取った後に単にそれをエラーと看做して再度コンテナの起動を試みると、同じコンテナが複数起動してしまう可能性があります。例えば kube-proxy のように一つのノードに一つのPodのみ起動する必要があるようなコンテナの場合問題が発生する可能性がありました。
- **PLEG のイベントチャンネルが満杯であった場合、イベントが破棄されるようになりました。破棄された回数は metrics として収集することができます。**
    - :pencil: PLEG とは、Pod Lifecycle Event Generator の略です。
    - :pencil: kubelet が大量の pod を処理している際に、イベントチャンネルが満杯になりメインループがブロックされてしまう問題があったようです。
- **ランタイムが dockersim の際に、ノードの IOPS が限界であった場合、予期せずノードのステータスが `NotReady` になっていた問題が修正されました。** [#74389](https://github.com/kubernetes/kubernetes/pull/74389), [@answer1991](https://github.com/answer1991)
    - :pencil: Kubelet は CNI の状態を、設定ファイルから設定を同期した後にチェックしていました。そのため、ディスクの IOPS がフルになってしまった場合 CNI の状態を返せず、結果として CNI の状態を把握することができなくなり、ノードの状態が NotReady であると判断していたようです。[修正では CNI の設定の同期を、CNIの状態確認とは別の go routine で確認](https://github.com/kubernetes/kubernetes/pull/74389/files)するようにしたようです。
- **#73264 の修正。`cpuPeriod` はアルファゲートによって無効化されていましたが、リセットされずフラグ経由で利用されていました。** [#73342](https://github.com/kubernetes/kubernetes/pull/73342), [@szuecs](https://github.com/szuecs)
    - :pencil: リリースノートを読むだけでは全く何言ってるのかわからない変更点が多いわけですが、これも特になんのこっちゃ感が高い。
    - :pencil: k8s のアルファ機能として、CFS (Completely Fair Scheduler) の CPU Quota を計算する際に利用される `cpu.cfs_period_us` を任意に指定可能とする `CustomCPUCFSQuotaPeriod` という Feature Gate があるわけですが、これが false に指定されているにも関わらず (アルファ機能なのでデフォルト false)、kubelet の引数として `--cpu-cfs-quota-period` を指定すると、その値が中途半端に使われて意図しない CPU limit がコンテナに適用されてしまっていた、というバグを修正したようです。
- **kubelet の CLI によるドキュメントと、生成されたウェブページが更新されました。**[#73256](https://github.com/kubernetes/kubernetes/pull/73256), [@deitch](https://github.com/deitch)
    - :pencil: [え、これがリリースノートに載るのか。](https://github.com/kubernetes/kubernetes/pull/73256/files)
- **`system-critical` のプライオリティを持った Pod 中のコンテナに低い `oom_score_adj` を設定するようにしました。**  [#73758](https://github.com/kubernetes/kubernetes/pull/73758), [@sjenning](https://github.com/____)
    - :pencil: Critical Pod と判定された Pod 中のコンテナに、Guaranteed な Pod と同じ `oom_score_adj` が設定されるようになったようです。
    - :pencil: ちなみに `oom_score_adj` の計算は現在の実装では以下のようになっており、高いスコアのコンテナほど OOM されやすくなります。
        - Guaranteed: `-998`
        - BestEffort: `1000`
        - Burstable: `1000 - (1000*memoryRequest)/memoryCapacity`
- **単一の `ConfigMap/Secret` を参照しているたくさんの Pod がいると kubelet がタイムアウトしてしまう問題が修正されました。** [#74755](https://github.com/kubernetes/kubernetes/pull/74755), [@liggitt](https://github.com/liggitt)
    - :pencil: go1.10/1.11 では http/2 stream が飽和するという問題があったため、kubelet における `configMapAndSecretChangeDetectionStrategy` が `kubeletconfigv1beta1.WatchChangeDetectionStrategy` から `kubeletconfigv1beta1.TTLCacheChangeDetectionStrategy` にリバートされたようです。
- **コンテナの作成、起動と停止時のイベントメッセージに、コンテナ名が含まれるようになり、またメッセージのフォーマットも一貫性のあるものになりました。** [#73892](https://github.com/kubernetes/kubernetes/pull/73892), [@smarterclayton](https://github.com/smarterclayton)
    - :pencil: 以下のようにイベントがわかりやすくなってます。
        - 変更前
        <pre>35m         Normal    Created       Pod    Created container
        35m         Normal    Started       Pod    Started container
        10m         Normal    Killing       Pod    Killing container cri-o://container_name:Need to kill Pod</pre>
        - 変更後
        <pre>35m         Normal    Created       Pod    Created container container_name
35m         Normal    Started       Pod    Started container container_name
10m         Normal    Killing       Pod    Stopping container container_name</pre>
- **kubelet における古い `OutOfDisk` conditionが削除されました。** [#72507](https://github.com/kubernetes/kubernetes/pull/72507), [@dixudx]
    - :pencil: ノードコンディションの `OutOfDisk` は 1.12 で削除されました。この変更ではさらに、古いノードオブジェクトに設定されていた `OutOfDisk` を[物理的に削除](https://github.com/kubernetes/kubernetes/pull/72507/files#diff-f653f262755f9fded98e1d4ea70bfaddR752)しています。
- **vSphere CloudProvider でノードが複数の IP アドレスを持っていた際の `NodeAddresses` の設定を修正しました。** [#70805](https://github.com/kubernetes/kubernetes/pull/70805), [@danwinship](https://github.com/danwinship)
- **docker image の削除時に dockershim が panic を起こしていた問題が修正されました。** [#75367](https://github.com/kubernetes/kubernetes/pull/75367), [@feiskyer](https://github.com/feiskyer)
    - :pencil: dockershim の実装で、[image が nil の際に今までは panic が起きる可能性があったところが修正されました](https://github.com/kubernetes/kubernetes/pull/75367/files)。
    - :pencil: そもそも[該当する docker image が存在しなかった場合は nil ではなく err を返す](https://github.com/kubernetes/kubernetes/blob/v1.14.0/pkg/kubelet/dockershim/libdocker/kube_docker_client.go#L208) はずなのでこのような状況は考えづらいのですが、issue のコメントによると [docker のアップグレードがこのような状況を引き起こす](https://github.com/kubernetes/kubernetes/pull/75367#issuecomment-473052168) ことがあるようです。
- **kubelet が終了した Pod については `ConfigMaps` と `Secrets` を監視しなくなりました。最悪なシナリオでは、この問題は kube-apiserver に対して他のリクエストを送れない状況を引き起こします。** [#74809](https://github.com/kubernetes/kubernetes/pull/74809), [@oxddr](https://github.com/oxddr)
- **新しく導入された `TaintNodesByCondition` admission plugin は新しく追加された Node オブジェクトを "not ready" として *taint* します。これは新しく追加された Node オブジェクトが "not ready" であるという状態がシステムに反映されるまでに、Pod がそのノードにスケジューリングされてしまうというレースコンディションを修正します。この admission plugin は `TaintNodesByCondition` 機能が有効化されていた場合、デフォルトで有効化されます。** [#73097](https://github.com/kubernetes/kubernetes/pull/73097), [@bsalamat](https://github.com/bsalamat)
    - :pencil: 最後の一文がわかりづらいですが、`TaintNodesByCondition` は[ベータ機能であり](https://github.com/kubernetes/kubernetes/blob/master/pkg/features/kube_features.go#L462) デフォルトで有効化されています。
    - :pencil: 新しく追加された Node オブジェクトは、通常 "not ready" な場合が多いのですが、この admission plugin を利用しない場合、ノードが追加され、"not ready" なノードであると判断し、Node オブジェクトにその状態が反映されるまで "ready" な状態があり得てしまいます。この admission plugin は、この一瞬の隙をついて Pod がスケジューリングされてしまう場合を排除するための機能です。
- **kubelet が `--system-reserved` と `--kube-reserved` オプションで `pid=<number>` をサポートするようになりました。この値を指定することでシステム全体と kubernetes のシステムデーモンで利用する process IDs を予約することができるようになりました。詳しくは[ドキュメントを参照](https://kubernetes.io/docs/tasks/administer-cluster/reserve-compute-resources/)してください。この機能を有効化するために、`SupportNodePidsLimit` feature gate を `true` に設定する必要があります。** [#73651](https://github.com/kubernetes/kubernetes/pull/73651), [@RobertKrawitz](https://github.com/RobertKrawitz)
    - :pencil: 主な変更点に記載されている Pid limiting の Node-Pod 間における Pid リソースの隔離についての PR です。

## 所感

~~誤読だと良いのですが、kubelet のコンテナ対応が非推奨になり、削除されていきそうな勢いです。(すでに e2e テストが flaky だ、という理由で削除されてしまいました。実装していた CoreOS/Red Hat が手を引いた、とissueにも書いてあり、今後 kubelet をコンテナで動かしている人たちはノードで直接 kubelet を動かさないとならなくなりそうです。個人的には kubelet が動作するのに必要なライブラリが同梱されているコンテナイメージはとても重宝しますし、もし、直接 kubelet をノードで直接実行しなければならなくなった場合、ノードのセットアップが面倒になるのでとても困ります。(例えば glusterfs を PV として利用していた場合、ノードに glusterfs のクライアントをインストールする必要があります。)~~

kubelet のコンテナ対応非推奨とは、純粋に `--containerized` フラグとその関連する機能についてで、単に kubelet をコンテナで動かす限りにおいては問題なさそうです。