各 Kubernetes バージョンの API バージョン対応表

:::note
最終更新は [Kubernetes v1.31.0](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.31.md) 時点での情報になります。Kubernetes v1.27 から調査方法を [minikube](https://minikube.sigs.k8s.io/docs/) から [kind](https://kind.sigs.k8s.io/docs/user/quick-start/) に切り替えました。
:::

Kubernetes の各リソース(`Pod`, `CronJob` など)は、 API のバージョン (`APIVersion`) を持っています。例えば、Kubernetes v1.22 では、`CronJob` は `batch/v1beta1` と `batch/v1` の 2 つの API バージョンがサポートされています。API のバージョンは、Alpha, Beta, Stable の 3 つの段階があり、各段階で複数のバージョンを持つこともあります(`v1beta1`, `v1beta2` など)。API バージョンニングの詳細については、下記の公式ドキュメントを参照してください。

- [API versioning#API versioning](https://kubernetes.io/docs/reference/using-api/#api-versioning)
- [Kubernetes Deprecation Policy](https://kubernetes.io/docs/reference/using-api/deprecation-policy/)

Kubernetes でサポートされるリソースの API バージョンは、Kubernetes のバージョンごとに異なっています。各 Kubernetes バージョンの [API Reference](https://kubernetes.io/docs/reference/#api-reference) を見れば、サポートされる API を知ることができますが、ある API がどのバージョンで廃止されたかを確認するのは難しいです。そのため、[kind](https://kind.sigs.k8s.io/docs/user/quick-start/) を使って、Kubernetes v1.22〜v1.31 までのデフォルトで有効な API バージョンを調べてみました。

## 対応表の注意点とメモ
- デフォルトで有効な API のみ表記しています
    - Alpha の API や Custom Resource Definition で別途定義される API は含まれていません
- deprecated の判定は [Warning ヘッダ](https://kubernetes.io/blog/2020/09/03/warnings/)を用いているため、1.19 未満では deprecated の判定はされていません
- API は `{Group}/{Version}/{Resource}` (GVR) で表記しています
    - `{"APIVersion":"apps/v1", "Kind": "Deployment"}` は `apps/v1/deployments` と表記されます
- subresource (`pods/scale` など)は記載していません
- 今までの大幅な API 削除は 1.16 と 1.22 で行われています
    - [Kubernetes 1.16](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.16.md#deprecations-and-removals): 様々なリソースの `apps/v1beta1`, `apps/v1beta2`, `extensions/v1beta1` の削除
    - [Kubernetes 1.22](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.22.md#removal-of-several-beta-kubernetes-apis): `networking.k8s.io/v1beta1` など様々なリソースの `v1beta1` 削除

## 各 Kubernetes バージョンの API バージョン対応表
Markdown の表だと見づらかったため、Google スプレッドシートの表にまとめました。

- [各 Kubernetes バージョンの API バージョン対応表 (Googleスプレッドシート)](https://docs.google.com/spreadsheets/d/14AV06J2l0r5HIbtT3e52Gm8vX8NMsDbqNCcsMzFmwKQ/edit#gid=1585704885)
    - 凡例: `A` : API が存在する, `D` :API が存在するが deprecated, `-`: API が存在しない

以下は表を画像に変換したものもです。

![k8s-api-version-matrix-v1.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100377/45dcfe0f-c9c4-bdc6-ac45-6b767b4fc839.png)


## API バージョンの調査方法

kind で各バージョンの Kubernetes クラスタを作成し、API サーバーの `/api`, `/apis` の情報から取得しました。v1.19 以上は [Warning ヘッダ](https://kubernetes.io/blog/2020/09/03/warnings/) を使って deprecated かどうかを判定しています。調査は次のスクリプトを使って、下記のように行いました。

```bash
# kind でクラスタを作り API のリストを作成
./check-apiversion-on-kind.sh

# Markdown or TSV 形式に変換
./apiversion-chart.rb
```


**kind で各バージョンのクラスタを作成して、API バージョンリスト作成するスクリプト**

```bash:check-apiversion-on-kind.sh
#! /bin/bash
set -euo pipefail

declare -a vers=(
  "1.22.17"
  "1.23.17"
  "1.24.15"
  "1.25.11"
  "1.26.6"
  "1.27.3"
  "1.28.0"
  "1.29.0"
  "1.30.0"
  "1.31.0"
)

function api_status {
  local prefix=$1
  local gvr=$2
  if kubectl get --raw "${prefix}/${gvr}" 2>&1 | grep -E "^Warning:" > /dev/null; then
    echo "${gvr} D"
  else
    echo "${gvr}"
  fi
}

function list_apiversions {
  for r in $(kubectl get --raw "/api/v1" | jq -r '.resources[].name | select (. | contains("/") | not)'); do
    api_status "/api" "v1/${r}"
  done
  for gv in $(kubectl get --raw "/apis" | jq -r '.groups[].versions[].groupVersion'); do
    for r in $(kubectl get --raw "/apis/${gv}" | jq -r '.resources[].name | select (. | contains("/") | not)'); do
      api_status "/apis" "${gv}/${r}"
    done
  done
}

for ver in "${vers[@]}"; do
  majorMinor=$(echo "$ver" | sed -E -e 's#^(1\.[0-9]+).*$#\1#g')
  kind create cluster -n api-version --image "kindest/node:v${ver}"
  list_apiversions | sort > "k8s-${majorMinor}.list"
  kind delete cluster -n api-version
done
```

**表作成**

```ruby:apiversion-chart.rb
#!/usr/bin/env ruby
require 'set'

apis = Set.new
apiTable= {}
vers = (22..31).map do |n| "1.#{n}" end

vers.each do |ver|
  apiTable[ver] = {}
  File.readlines("k8s-#{ver}.list").each do | line|
    parts = line.split(" ")
    api = parts[0]
    apis.add(api)

    if parts.length == 2 && parts[1] == "D" then
      apiTable[ver][api] = "D"
    else
      apiTable[ver][api] = "A"
    end
  end
end

# TSV
puts ["API"].concat(vers).join("\t")
apis.sort.each do |api|
  row = [api]
  vers.each do |ver|
    if apiTable[ver].has_key?(api) then
      row.append("#{apiTable[ver][api]} ")
    else
      row.append("- ")
    end
  end
  puts row.join("\t")
end
```