警告:前方有用的警告
作為 Kubernetes 維護者,我們一直在尋找在保持相容性的同時提高可用性的方法。在開發功能、分類錯誤和回答支援問題時,我們積累了對 Kubernetes 使用者有幫助的資訊。過去,分享這些資訊僅限於釋出說明、公告電子郵件、文件和部落格文章等帶外方法。除非有人知道要尋找這些資訊並設法找到它,否則他們將無法從中受益。
在 Kubernetes v1.19 中,我們添加了一項功能,允許 Kubernetes API 伺服器向 API 客戶端傳送警告。警告使用標準 `Warning` 響應頭傳送,因此它不會以任何方式更改狀態碼或響應正文。這允許伺服器輕鬆地向任何 API 客戶端傳送警告,同時與以前的客戶端版本保持相容。
警告由 `kubectl` v1.19+ 在 `stderr` 輸出中顯示,並由 `k8s.io/client-go` 客戶端庫 v0.19.0+ 在日誌輸出中顯示。`k8s.io/client-go` 行為可以按程序或按客戶端覆蓋。
廢棄警告
我們使用此新功能的第一個方式是傳送有關使用廢棄 API 的警告。
Kubernetes 是一個龐大、快速發展的專案。即使對於全職從事該專案的人來說,跟上每個版本中的變化也可能令人望而生畏。一種重要的變化型別是 API 廢棄。隨著 Kubernetes 中的 API 畢業到 GA 版本,預釋出 API 版本被廢棄並最終刪除。
儘管有延長廢棄期,並且廢棄包含在釋出說明中,但它們仍然難以追蹤。在廢棄期內,預釋出 API 仍然可用,允許幾個版本過渡到穩定的 API 版本。然而,我們發現使用者通常直到升級到停止提供該 API 的版本才意識到他們依賴於廢棄的 API 版本。
從 v1.19 開始,每當對廢棄的 REST API 發出請求時,都會隨 API 響應返回警告。此警告包含有關 API 將不再可用的版本以及替換 API 版本的詳細資訊。
由於警告源自伺服器,並在客戶端級別被攔截,因此它適用於所有 kubectl 命令,包括 `kubectl apply` 等高階命令和 `kubectl get --raw` 等低階命令
這有助於受廢棄影響的人知道他們正在發出的請求已被廢棄,他們有多少時間來解決問題,以及他們應該使用哪個 API。當用戶應用他們未建立的清單時,這尤其有用,這樣他們就有時間聯絡作者以請求更新版本。
我們還意識到,使用廢棄 API 的人通常與負責升級叢集的人不是同一個人,因此我們添加了兩個面向管理員的工具,以幫助跟蹤廢棄 API 的使用並確定何時可以安全升級。
指標
從 Kubernetes v1.19 開始,當向廢棄的 REST API 端點發出請求時,`kube-apiserver` 程序中的 `apiserver_requested_deprecated_apis` 儀表指標設定為 `1`。此指標具有 API `group`、`version`、`resource` 和 `subresource` 的標籤,以及一個 `removed_release` 標籤,該標籤指示 API 將不再提供的 Kubernetes 版本。
這是一個使用 `kubectl`、prom2json 和 jq 查詢的示例,用於確定已從 API 伺服器的當前例項請求了哪些廢棄 API
kubectl get --raw /metrics | prom2json | jq '
.[] | select(.name=="apiserver_requested_deprecated_apis").metrics[].labels
'
輸出
{
"group": "extensions",
"removed_release": "1.22",
"resource": "ingresses",
"subresource": "",
"version": "v1beta1"
}
{
"group": "rbac.authorization.k8s.io",
"removed_release": "1.22",
"resource": "clusterroles",
"subresource": "",
"version": "v1beta1"
}
這表明在此伺服器上已請求廢棄的 `extensions/v1beta1` Ingress 和 `rbac.authorization.k8s.io/v1beta1` ClusterRole API,並將在 v1.22 中刪除。
我們可以將該資訊與 `apiserver_request_total` 指標結合起來,以獲取有關對這些 API 發出的請求的更多詳細資訊
kubectl get --raw /metrics | prom2json | jq '
# set $deprecated to a list of deprecated APIs
[
.[] |
select(.name=="apiserver_requested_deprecated_apis").metrics[].labels |
{group,version,resource}
] as $deprecated
|
# select apiserver_request_total metrics which are deprecated
.[] | select(.name=="apiserver_request_total").metrics[] |
select(.labels | {group,version,resource} as $key | $deprecated | index($key))
'
輸出
{
"labels": {
"code": "0",
"component": "apiserver",
"contentType": "application/vnd.kubernetes.protobuf;stream=watch",
"dry_run": "",
"group": "extensions",
"resource": "ingresses",
"scope": "cluster",
"subresource": "",
"verb": "WATCH",
"version": "v1beta1"
},
"value": "21"
}
{
"labels": {
"code": "200",
"component": "apiserver",
"contentType": "application/vnd.kubernetes.protobuf",
"dry_run": "",
"group": "extensions",
"resource": "ingresses",
"scope": "cluster",
"subresource": "",
"verb": "LIST",
"version": "v1beta1"
},
"value": "1"
}
{
"labels": {
"code": "200",
"component": "apiserver",
"contentType": "application/json",
"dry_run": "",
"group": "rbac.authorization.k8s.io",
"resource": "clusterroles",
"scope": "cluster",
"subresource": "",
"verb": "LIST",
"version": "v1beta1"
},
"value": "1"
}
輸出顯示,只對這些 API 發出了讀取請求,並且對觀察廢棄的 Ingress API 的請求最多。
您還可以透過以下 Prometheus 查詢找到該資訊,該查詢返回有關對將在 v1.22 中刪除的廢棄 API 發出的請求的資訊
apiserver_requested_deprecated_apis{removed_release="1.22"} * on(group,version,resource,subresource)
group_right() apiserver_request_total
審計註釋
度量是檢查是否正在使用廢棄的 API 以及使用率的快速方法,但它們不包含足夠的資訊來識別特定的客戶端或 API 物件。從 Kubernetes v1.19 開始,對廢棄 API 的請求的審計事件包含一個審計註釋 `"k8s.io/deprecated":"true"`。管理員可以使用這些審計事件來識別需要更新的特定客戶端或物件。
自定義資源定義(Custom Resource Definitions)
除了 API 伺服器能夠警告廢棄 API 的使用外,從 v1.19 開始,CustomResourceDefinition 可以指示它定義的資源的特定版本已廢棄。當對自定義資源的廢棄版本發出 API 請求時,將返回警告訊息,與內建 API 的行為匹配。
CustomResourceDefinition 的作者還可以根據需要為每個版本自定義警告。這允許他們在需要時提供指向遷移指南或其他資訊的指標。
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
name: crontabs.example.com
spec:
versions:
- name: v1alpha1
# This indicates the v1alpha1 version of the custom resource is deprecated.
# API requests to this version receive a warning in the server response.
deprecated: true
# This overrides the default warning returned to clients making v1alpha1 API requests.
deprecationWarning: "example.com/v1alpha1 CronTab is deprecated; use example.com/v1 CronTab (see http://example.com/v1alpha1-v1)"
...
- name: v1beta1
# This indicates the v1beta1 version of the custom resource is deprecated.
# API requests to this version receive a warning in the server response.
# A default warning message is returned for this version.
deprecated: true
...
- name: v1
...
准入 Webhook
准入 Webhook 是將自定義策略或驗證與 Kubernetes 整合的主要方式。從 v1.19 開始,准入 Webhook 可以返回警告訊息,這些訊息會傳遞給請求的 API 客戶端。警告可以隨允許或拒絕的准入響應一起返回。
例如,為了允許請求但警告配置已知無法正常工作,准入 Webhook 可以傳送此響應
{
"apiVersion": "admission.k8s.io/v1",
"kind": "AdmissionReview",
"response": {
"uid": "<value from request.uid>",
"allowed": true,
"warnings": [
".spec.memory: requests >1GB do not work on Fridays"
]
}
}
如果您正在實現返回警告訊息的 Webhook,這裡有一些提示
- 不要在訊息中包含“Warning:”字首(這由客戶端在輸出時新增)
- 使用警告訊息描述發出 API 請求的客戶端應更正或注意的問題
- 簡明扼要;如果可能,將警告限制在 120 個字元以內
准入 Webhook 有很多方法可以使用此新功能,我期待看到人們會提出什麼。這裡有一些想法可以幫助您入門
- Webhook 實現新增“抱怨”模式,它們返回警告而不是拒絕,以便在開始強制執行策略之前嘗試策略以驗證其是否按預期工作
- “lint”或“vet”風格的 Webhook,檢查物件並在不遵循最佳實踐時顯示警告
自定義客戶端處理
使用 `k8s.io/client-go` 庫發出 API 請求的應用程式可以自定義如何處理從伺服器返回的警告。預設情況下,警告會在收到時記錄到 stderr,但此行為可以按程序或按客戶端自定義。
此示例演示如何使您的應用程式表現得像 `kubectl`,在程序範圍內覆蓋訊息處理以消除重複警告,並在支援的情況下使用彩色輸出突出顯示訊息
import (
"os"
"k8s.io/client-go/rest"
"k8s.io/kubectl/pkg/util/term"
...
)
func main() {
rest.SetDefaultWarningHandler(
rest.NewWarningWriter(os.Stderr, rest.WarningWriterOptions{
// only print a given warning the first time we receive it
Deduplicate: true,
// highlight the output with color when the output supports it
Color: term.AllowsColorOutput(os.Stderr),
},
),
)
...
下一個示例演示如何構建忽略警告的客戶端。這對於操作所有資源型別元資料(在執行時使用發現 API 動態發現)的客戶端非常有用,並且不會從有關特定資源被廢棄的警告中受益。不建議需要使用特定 API 的客戶端抑制廢棄警告。
import (
"k8s.io/client-go/rest"
"k8s.io/client-go/kubernetes"
)
func getClientWithoutWarnings(config *rest.Config) (kubernetes.Interface, error) {
// copy to avoid mutating the passed-in config
config = rest.CopyConfig(config)
// set the warning handler for this client to ignore warnings
config.WarningHandler = rest.NoWarnings{}
// construct and return the client
return kubernetes.NewForConfig(config)
}
Kubectl 嚴格模式
如果您想確保儘快注意到廢棄並開始解決它們,`kubectl` 在 v1.19 中添加了 `--warnings-as-errors` 選項。使用此選項呼叫時,`kubectl` 會將從伺服器收到的所有警告視為錯誤並以非零退出程式碼退出
這可以在 CI 任務中用於將清單應用到當前伺服器,並且要求以零退出程式碼透過才能使 CI 任務成功。
未來可能性
現在我們有了一種以上下文方式向用戶傳達有用資訊的方式,我們已經在考慮其他可以利用此功能來改善 Kubernetes 使用者體驗的方法。我們接下來關注的幾個領域是警告已知的問題值(由於相容性原因我們無法直接拒絕),以及警告使用廢棄欄位或欄位值(例如使用 beta os/arch 節點標籤的選擇器,在 v1.14 中已廢棄)。我很高興看到這方面的進展,繼續讓 Kubernetes 更易於使用。