Kubernetes 1.20: SIG-API Machineryの変更内容

# はじめに

Kubernetes 1.20がリリースされました :tada:

今回のリリースでは数年前のKubeConで発表のあったリクエストの処理に優先度をつけるAPI priority/Fairness([KEP-1040](https://github.com/kubernetes/enhancements/tree/master/keps/sig-api-machinery/1040-priority-and-fairness))がbetaになったり、api-serverに識別子を付与するkube-apiserver identity([KEP-1965](https://github.com/kubernetes/enhancements/blob/master/keps/sig-api-machinery/1965-kube-apiserver-identity))の変更が入っているためか、api-server周りの変更が多い印象です。アップグレード前の注意点もいくつかあるので要チェックです。あと個人的にはHPAがPodではなくContainerごとに設定できるようになったのは嬉しい変更です。

それでは、今回もAPI周りを担当するSIG-API Machineryの変更点を[CHANGELOG](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.20.md#v1200)からピックアップします。(:pencil: がついた文章は、CHANGELOGの公式内容ではなく筆者の補足です)

# :warning: Urgent Upgrade Notes (アップグレード前の注意点)

- API priority/Fairness(APF)はbetaに昇格しました。APFを有効にしたv1.19のAPIサーバはv1.20+のサーバと共に動かさないでください。 ([#96527](https://github.com/kubernetes/kubernetes/pull/96527/files))
- v1.10で非推奨となったAPIサーバでinsecureポートを公開する機能が削除されました。insecureアドレスの`--address`フラグと、`--insecure-bind-address`もAPIサーバでは利用できなくなります。フラグ自体の削除はv1.24予定です。また、`--port`と`--insecure-port`フラグは0のみ設定可能で、こちらもv1.24で削除されます。([#95856](https://github.com/kubernetes/kubernetes/pull/95856))
- dual-stack Service(アルファ)が追加されました。alpha APIへの破壊的な変更となります。この変更では、dual-stack APIのwrt Serivceにおいて、1フィールドのみの`ipFamily`から、以下のの3フィールドになりました。 デフォルト値をハンドリングするため多くのユーザはこれに伴う変更は必要ありません。ユーザがdual-stackを要求しない限り、Serviceはsingle-stackです。また、これらの機能はfeature gateの`IPv6DualStack`から切り替えられます。 ([#91824](https://github.com/kubernetes/kubernetes/pull/91824))
 - `ipFamilyPolicy`(SingleStack, PreferDualStack, RequireDualStack)
 - `ipFamilies`(アサインするfamilyのリスト)
 - `clusterIPs`
- TokenRequestとTokenRequestProjectionがGAになりました。この機能では、Podのライフタイムに沿ったSecretから参照できないservice account tokenを生成できます。詳細は、[こちら](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#service-account-token-volume-projection)を参照してください。また、TokenRequestとTokenRequestProjectionのfeature gatesはv1.21に削除されます。この変更に伴い、APIサーバの以下のフラグが必須値となります。([#95896](https://github.com/kubernetes/kubernetes/pull/95896))
    - `--service-account-issuer`: クラスタのライフタイムに渡ってService Account Tokenの発行者を識別するための識別子。
    - `--service-account-key-file`: 1つ以上の公開鍵を含んだファイルを設定します。
    - `--service-account-signing-key-file`: Service Account Tokenの署名に利用する、秘密鍵を含んだファイルを設定します。kube-controller-managerの`--service-account-private-key-file`と同じファイルを設定できます。

- GCコントローラが不正なownerReferenceを受け取ったときの非決定論的な挙動を解決しました。今後はchildとownerオブジェクトのnamespaceが一致しない場合、`OwnerRefInvalidNamespace`をreasonに持つEventへ記録します。`kubectl-check-ownerrefefrences`ツールを利用すると、アップグレード前にも不正なownerReferenceが存在しないかチェックできます。([#92743](https://github.com/kubernetes/kubernetes/pull/92743))
  - 名前空間スコープのオブジェクトのownerReferenceが、同じ名前空間に存在しない場合オブジェクトのuidを参照していた場合、ownerが存在しないものとしてそのchildオブジェクトは削除されます。
  - クラスタスコープのオブジェクトのownerRefefrenceが、名前空間スコープのオブジェクトuidを参照していた場合、ownerが解決できないとしてそのchildオブジェクトはGCによって無視されます。
        - :memo: 該当のツールはkubernetes-sigsで管理されている[kubectl-check-ownerreference](https://github.com/kubernetes-sigs/kubectl-check-ownerreferences)です。

```bash
$ git clone https://github.com/kubernetes-sigs/kubectl-check-ownerreferences.git && \
  cd kubectl-check-ownerreferences && \
  make install
Cloning into 'kubectl-check-ownerreferences'...
...

$ kubectl-check-ownerreferences
No invalid ownerReferences found

# ~~適当にinvalidなownerreferenceを持ったobject作成~~

$ kubectl-check-ownerreferences
GROUP   RESOURCE   NAMESPACE   NAME                    OWNER_UID                              LEVEL   MESSAGE
        pods       default     hello-7d8df5b78-d64d6   a27035d1-7e84-41ef-92fd-5cbac4fafc0c   Error   no object found for uid
1 error, 0 warnings
```

# :wastebasket: Deprecation (非推奨になったAPI)

- EgressSelectorConfiguration APIのEgressSelectionタイプとして、`controlplane`がサポートされました。`Master`は非推奨となり、v1.22で削除される予定です。 ([#95235](https://github.com/kubernetes/kubernetes/pull/95235))
- v1alpha1 PodPreset APIとそのadmissionプラグインは削除されました。Pod作成時にPodの設定を書き換えたい場合は、Admission webhookを使ってください。 ([#94090](https://github.com/kubernetes/kubernetes/pull/94090))

# :earth_asia: API Changes (API周りの変更)

- Serviceのタイプが既存のフィールドを必要としないものに変更されたとき、自動的にクリアされるようになりました。例えば、`type=LoadBalancer`から`type=ClusterIP`に変更した場合、NodePortのアサインがクリアされます。これにより、ユーザは不要な値のクリーンアップに注意する必要がなくなります。 ([#95196](https://github.com/kubernetes/kubernetes/pull/95196))
    - :memo: Serviceのtypeを変えることは頻繁にないと思いますが、稀だからこそ気にすることが少なくなるのは嬉しい変更。
- EndpointSliceに`NodeName`フィールドが追加されました。この機能は、feature gateの`EndpointSliceNodeName`から有効にできます。 ([#96528](https://github.com/kubernetes/kubernetes/pull/96528))
    - 将来のリリースにおいてEndpointSlice topologyフィールドが非推奨となります。
    - EndpointSliceの"IP" addressタイプは、v1.17の非推奨を経て正式に削除されます。
    - `discovery.k8s.io/v1alpha1`APIは非推奨となりました。v1.21で削除されます。
        - :memo: EndpointSliceによる大規模クラスタのボトルネック解消話は2020 KubeCon Euroの発表が面白かったのでおすすめ
            - ref: [Scaling Kubernetes Networking Beyond 100k Endpoints](https://kccnceu20.sched.com/event/Zeta/scaling-kubernetes-networking-beyond-100k-endpoints-rob-scott-minhan-xia-google)
- `BoundServiceAccountTokenVolume`を有効にした場合、クラスタ管理者は`serviceaccount_stale_tokens_total`メトリクスから長期間のトークンに依存しているワークロード数をモニタリングできます。もしそのようなワークロードが存在しない場合、APIサーバに`--service-account-extend-token-expiration=false`フラグを設定することで、長期間のトークンを無効化できます。([#96273](https://github.com/kubernetes/kubernetes/pull/96273))
    - :memo: v1.13からalphaで入っている機能。最近はDay2意識してか運用に便利なメトリクスも追加されたり、新機能とセットで入ったりして便利ですね。
        - ref. [BoundServiceAccountVolumeを有効にしてみる](https://qiita.com/hiyosi/items/35c22507b2a85892c707)
- HPAが、コンテナのリソース使用量に基づいてスケールできるようになりました。([#90691](https://github.com/kubernetes/kubernetes/pull/90691))
    - :memo: 前回の[KubeCon Europeで発表のあった機能](https://speakerdeck.com/ladicle/kubecon-plus-cloudnativecon-europe-2020-overview?slide=14)で、v1.19でギリギリ入らずv1.20でのリリースとなりました。 いままではPod単位のリソース消費量しか指定できなかったため、コンテナごとにリソースの消費傾向が違うとうまくスケールできないという問題点がありましたが、これが解決した形です。
- kube-apiserverは、kube-apiserverの期限切れLeaseオブジェクトを削除するようになりました。この機能はfeature gateの`APIServerIdentity`から有効にできます。これに伴い、kube-apiserverに`identity-lease-garbage-collection-check-period-seconds`フラグが追加されました。 ([#95895](https://github.com/kubernetes/kubernetes/pull/95895))
    - :memo: 今回のchangelogにはこれ関係の変更が多いapiserver identity。現在は生存apiserverのリストをkubernetes endpointsのIPで識別していますが、これが有効になるとLearseオブジェクトで識別子が管理されるようになります。
- kube-controller-manager: volume pluginで、localとloopbackアドレスからのアクセスを制限できるようになりました。この設定は` --volume-host-allow-local-loopback=false`フラグを設定するか、`--volume-host-cidr-denylist`フラグで拒否するCIDRの範囲を指定することで有効にできます。(例: `--volume-host-cidr-denylist=127.0.0.1/28,feed::/16`) ([#91785](https://github.com/kubernetes/kubernetes/pull/91785))
- scheduler, controller-manager, cloud-controller-managerがLeaseLockを使うように修正しました。 ([#94603](https://github.com/kubernetes/kubernetes/pull/94603))
    - :memo: これらコントローラは今まで、`endpointsleases`をresource lockに利用していました。
- DNS-1123エラーメッセージにおいて、RFC 1123準拠ではないことを明示するようになりました。([#94182](https://github.com/kubernetes/kubernetes/pull/94182))
    - :memo: この変更では、小文字のみを許可している旨をエラーメッセージに追加しています。
- 注意: "failure-domain.beta.kubernetes.io/zone"と"failure-domain.beta.kubernetes.io/region"ラベルは非推奨になりました。代わりに"topology.kubernetes.io/zone"と"topology.kubernetes.io/region"を利用してください。プレフィックスの`failure-domain.beta`を`topology`に変更すれば大丈夫です。([#96033](https://github.com/kubernetes/kubernetes/pull/96033))
- Server Side ApplyがLabelSelectorフィールドをアトミックとして処理するようになりました。つまり、Selector全体は単一のwriterもしくはupdaterによって管理されることになります。([#93901](https://github.com/kubernetes/kubernetes/pull/93901))
- 一つのLoadBalancer Serviceに対して、複数のprotocol値を設定できるようになります。この機能はデフォルト無効で、feature gateの`MixedProtocolLBService`から切り替えられます。 ([#93130](https://github.com/kubernetes/kubernetes/pull/93130))
- CSIDriverSpecに2つのフィールドを追加するため、feature gateに`CSIServiceAccountToken`をが加わりました。([#93130](https://github.com/kubernetes/kubernetes/pull/93130))
- ユーザはfeature gateを設定することで、cronjob controller v2を利用できます。このコントローラは、将来的なリリースでデフォルトのコントローラになります。([#93370](https://github.com/kubernetes/kubernetes/pull/93370))
    - :memo: cronjobのGAに向けてコントローラv2がきましたね。全貌は[KEP-19](https://github.com/kubernetes/enhancements/blob/master/keps/sig-apps/19-Graduate-CronJob-to-Stable/README.md)参照

# :sparkle: Features (機能追加)

- APIサーバが書き込みリクエストを処理する前に、storageversionsを更新する`StorageVersionAPI`がfeature gateに追加されました。この機能では、storage migratorによるビルドインリソースのバージョン移行が可能になります。この機能を利用するためには、internal.apiserver.k8s.io/v1alpha1 APIの有効かと、APIServerIdentityのfeature gateの有効化も必要です。 ([#93873](https://github.com/kubernetes/kubernetes/pull/93873))
- CRD: structural schemasにおいて、nullableになっていないmapフィールドがドロップされるようになりました。デフォルト値が設定されている場合はその値が設定されます。同じく、nullableではないリスト内にnullアイテムが存在している場合は、バリデーションに失敗します。([#95423](https://github.com/kubernetes/kubernetes/pull/95423))
    - :memo: structural schemasの変更も着々と進んでいます。まだschemaを生成できてない(or違反している)プロジェクトがあれば修正を勧めたほうが良さそうです。
- client-goのcredentialプラグインでは、現在のクラスタ情報を`KUBERNETES_EXEC_INFO`環境変数経由で渡せるようになりました。([#95489](https://github.com/kubernetes/kubernetes/pull/95489))
- `api-extensions`カテゴリが導入されました。このカテゴリでは、kubectl getなどでmutating admission configやvalidation admission config, CRDやAPIServiceを取得できます。 ([#95603](https://github.com/kubernetes/kubernetes/pull/95603))
    - :memo: こんなかんじ

```bash
$ kubectl get api-extensions
NAME                                                                     SERVICE   AVAILABLE   AGE
apiservice.apiregistration.k8s.io/v1.                                    Local     True        3m1s
apiservice.apiregistration.k8s.io/v1.admissionregistration.k8s.io        Local     True        3m1s
apiservice.apiregistration.k8s.io/v1.apiextensions.k8s.io                Local     True        3m1s
...
```
- kube-apiserverが自身を識別するためにLease objectを維持するようになりました。この機能はfeature gateの`APIServerIdentity`から切り替えられます。これに伴い、identity-lease-duration-secondsとidentity-lease-renew-interval-secondsの2つのフラグがkube-apiserverに追加されました。([#95533](https://github.com/kubernetes/kubernetes/pull/95533))
- kube-apiserver: etcdのhealth checkのタイムアウト値を変更できるようになりました。今までと同じ動きとなるように、デフォルト値は2秒になっています。([#93244](https://github.com/kubernetes/kubernetes/pull/93244))
- kube-apiserver: ローテートしたauditログファイルを圧縮するために、`--audit-log-compress`フラグが追加されました。([#94066](https://github.com/kubernetes/kubernetes/pull/94066))
    - :memo: 有効にした場合gzipで圧縮されます。
- 現在ベータの`RootCAConfigMap` feature gateがデフォルトで有効になりました。これにより、kube-controller-managerが"kube-root-ca.crt`を各namespaceのConfigMapとして公開するようになります。このConfigMapには、kube-apiserverとの接続を検証するためのCA bundleが含まれています。 ([#96197](https://github.com/kubernetes/kubernetes/pull/96197))

# :bug: Bug or Regression (バグやリグレッションの修正)

- PVC StorageClassがツリー外のプロビジョナーによって既に更新されていた場合、ボリュームの拡張コントローラがPVCへの`volume.kubernetes.io/storage-resizer`アノテーション付与を妨げる問題が解決しました。([#94489](https://github.com/kubernetes/kubernetes/pull/94489))
- タイムアウトパラメータの処理は、既存クライアントの下位互換性を損なうため、1.20.0-beta.2でrevertされました。([#96727](https://github.com/kubernetes/kubernetes/pull/96727))
- eventsのwatch cacheが無効化されました。([#96052](https://github.com/kubernetes/kubernetes/pull/96052))
    - :memo: eventに対してwatchのcacheが有効になっていると性能に影響がでるため無効化されました
- Dual-stack: dual-stackのfeature gateがデフォルト有効になった時に、nodeipamが既存のsingle-stackクラスタで互換性を持つように修正されました。 ([#90439](https://github.com/kubernetes/kubernetes/pull/90439))
- create/update/patchリクエストのowner referenceエントリに重複があった場合、APIレスポンスのヘッダに警告を載せるようになりました。クライアントは、このような重複したowner referenceを持つリクエストの送信をやめなければなりません。このようなリクエストは、早ければv1.24でリジェクトされます。([#96185](https://github.com/kubernetes/kubernetes/pull/96185))
- SubjectAccessReviewクライアントのDelegatingAuthorizationOptionsにデフォルトタイムアウトが設定されるようになりました。([#95725](https://github.com/kubernetes/kubernetes/pull/95725))
- JSON pathパーサがrangeがからの時にエラーになるバグが修正されました。([#95933](https://github.com/kubernetes/kubernetes/pull/95933))
- client-goのprometheus metricsが正しくAPI pathを公開できるように修正されました。([#74363](https://github.com/kubernetes/kubernetes/pull/74363))
- kube-apiserverによってレポートされる`etcd_object_counts`メトリクスが修正されました。([#94773](https://github.com/kubernetes/kubernetes/pull/94773))
- CRDオブジェクトに関するkube-apiserverメトリクスで、verbsが間違って報告されていた問題を修正しました。([#93523](https://github.com/kubernetes/kubernetes/pull/93523))
- `k8s.io/apimachinery/pkg/api/meta.SetStatusCondition`更新時にObservedGenerationを更新するように修正されました。([#95961](https://github.com/kubernetes/kubernetes/pull/95961))
- CRDでarray typeに`x-kubernetes-preserve-unknown-fields`が付与されているschemaがSchemaErrorになる問題が修正されました。([#94888](https://github.com/kubernetes/kubernetes/pull/94888))
- 時間が前後する場合、kube-apiserverがメモリリークする問題が修正されました。([#96266](https://github.com/kubernetes/kubernetes/pull/96266))
- client-goにおいて、カスタマイズされたDial, Proxy, GetCert configを持つ新しいクライアントが、古いHTTP transportsを取得する可能性がある問題が修正されました。([#95427](https://github.com/kubernetes/kubernetes/pull/95427))
- 1.17.0-1.18.5のAPIサーバが"Too large resource version"エラーから復帰しないreflectorのバグが修正されました。([#94316](https://github.com/kubernetes/kubernetes/pull/94316))
- ポートを指定しなくてもipv6のPodにプロキシされる問題を修正しました。([#94834](https://github.com/kubernetes/kubernetes/pull/94834))
- クラスタスコープのsubresource用のfake clientを生成するときのバグが修正されました。([#946586](https://github.com/kubernetes/kubernetes/pull/96586))
- HTTP/2のconnection health checkは全Kubernetes clientにおいてデフォルトで有効になっています。必要に応じて`HTTP2_READ_IDLE_TIMEOUT_SECONDS`および、`HTTP2_PING_TIMEOUT_SECONDS`環境変数から設定を変更してください。`HTTP2_READ_IDLE_TIMEOUT_SECONDS`が0に設定されている場合、この機能は無効になります。([#95981](https://github.com/kubernetes/kubernetes/pull/95981))
- ユーザが不正なタイムアウトをリクエストURLで指定した場合、そのリクエストはHTTP 400として中止されます。
    - ユーザが指定したタイムアウトがapiserverが許可する最大値を超える場合、このリクエストもHTTP 400になります。([#96061](https://github.com/kubernetes/kubernetes/pull/96061))
- K8s.io/apimachinery: runtime.DefaultUnstructuredConverter.FromUnstructuredは、integerフィールドから型付きfloat値への変換を処理するようになりました。([#93250](https://github.com/kubernetes/kubernetes/pull/93250))
- kube-apiserverはGA時に削除されるはずだったnon-alphaレベルのAPIを停止します。alphaレベルのAPIは、CIが壊れないよう提供を続けます。([#96525](https://github.com/kubernetes/kubernetes/pull/96525))
- デフォルトのetcdサーババージョンが3.4.13に更新されました。([#94287](https://github.com/kubernetes/kubernetes/pull/94287))

# :microscope: Other (その他の修正)

- Namespace APIオブジェクトの作成のため送信されていたAdmissionReviewオブジェクトは、常に`namespace`属性へ挿入されるようになりました。(以前は、Namespace作成のPOSTリクエストにおいて、`namespace`属性は空になっていました。また、server-side-applyのPATCHリクエストによってNamespace生成時に挿入されていました。) ([#95012](https://github.com/kubernetes/kubernetes/pull/95012))
- debian-iptables:buster-v1.3.0に更新しました。([#94733](https://github.com/kubernetes/kubernetes/pull/94733))
    - iptableは1.8.5を利用します
    - ベースイメージはdebian-base:buster-v1.2.0に更新しました
    - cluster/images/etcd: etcd:3.4.13-1のイメージをビルドします
        - 利用するイメージはdebian-base:buster-v1.2.0です。
- client-goヘッダのログに(ログレベル9以上)マスクされた`Authorization`ヘッダがのるようになりました。([#95316](https://github.com/kubernetes/kubernetes/pull/95316))
- kube-apiserverにおいて、(1.16で非推奨になった)SelfLinkの伝搬を停止しました。([#94397](https://github.com/kubernetes/kubernetes/pull/94397))
- etcdのクライアントをv3.4.13に更新しました。([#94259](https://github.com/kubernetes/kubernetes/pull/94259))
- kubectl get ingressのデフォルトではnetworking.k8s.io/v1が返るようになりました。(以前返っていたのはv1.14で非推奨になったextensions/v1beta1です)非推奨になったリソースを取得するには、`kubectl get ingress.v1beta1.extensions`のように明示的なバージョン指定が必要です。