使用組態檔宣告式管理 Kubernetes 物件

Kubernetes 物件可以透過在目錄中儲存多個物件組態檔,並使用 kubectl apply 遞迴地建立和更新這些物件來建立、更新和刪除,視需要而定。此方法保留對即時物件所做的寫入,而不會將變更合併回物件組態檔。kubectl diff 也可讓您預覽 apply 將進行的變更。

開始之前

安裝 kubectl

您需要有一個 Kubernetes 叢集,並且必須設定 kubectl 命令列工具以與您的叢集通訊。建議在至少有兩個節點且不充當控制平面主機的叢集上執行本教學課程。如果您還沒有叢集,可以使用 minikube 建立一個,或者您可以使用以下 Kubernetes playground 之一

若要檢查版本,請輸入 kubectl version

權衡

kubectl 工具支援三種物件管理類型

  • 命令式命令
  • 命令式物件組態
  • 宣告式物件組態

請參閱 Kubernetes 物件管理 以取得關於每種物件管理優缺點的討論。

總覽

宣告式物件組態需要對 Kubernetes 物件定義和組態有紮實的理解。如果您尚未閱讀並完成以下文件

以下是本文檔中使用的術語定義

  • 物件組態檔 / 組態檔:定義 Kubernetes 物件組態的檔案。本主題說明如何將組態檔傳遞給 kubectl apply。組態檔通常儲存在來源控制系統中,例如 Git。
  • 即時物件組態 / 即時組態:Kubernetes 叢集觀察到的物件即時組態值。這些值保存在 Kubernetes 叢集儲存區中,通常是 etcd。
  • 宣告式組態寫入器 / 宣告式寫入器:對即時物件進行更新的人員或軟體元件。本主題中提到的即時寫入器會變更物件組態檔並執行 kubectl apply 以寫入變更。

如何建立物件

使用 kubectl apply 建立指定目錄中組態檔定義的所有物件,但已存在的物件除外

kubectl apply -f <directory>

這會在每個物件上設定 kubectl.kubernetes.io/last-applied-configuration: '{...}' 註解。該註解包含用於建立物件的物件組態檔內容。

以下是物件組態檔的範例

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

執行 kubectl diff 以列印將建立的物件

kubectl diff -f https://k8s.io/examples/application/simple_deployment.yaml

使用 kubectl apply 建立物件

kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml

使用 kubectl get 列印即時組態

kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml

輸出顯示 kubectl.kubernetes.io/last-applied-configuration 註解已寫入即時組態,並且與組態檔相符

kind: Deployment
metadata:
  annotations:
    # ...
    # This is the json representation of simple_deployment.yaml
    # It was written by kubectl apply when the object was created
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
  # ...
spec:
  # ...
  minReadySeconds: 5
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

如何更新物件

您也可以使用 kubectl apply 更新目錄中定義的所有物件,即使這些物件已存在。此方法完成以下操作

  1. 在即時組態中設定組態檔中顯示的欄位。
  2. 清除即時組態中從組態檔中移除的欄位。
kubectl diff -f <directory>
kubectl apply -f <directory>

以下是範例組態檔

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

使用 kubectl apply 建立物件

kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml

使用 kubectl get 列印即時組態

kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml

輸出顯示 kubectl.kubernetes.io/last-applied-configuration 註解已寫入即時組態,並且與組態檔相符

kind: Deployment
metadata:
  annotations:
    # ...
    # This is the json representation of simple_deployment.yaml
    # It was written by kubectl apply when the object was created
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
  # ...
spec:
  # ...
  minReadySeconds: 5
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

使用 kubectl scale 直接更新即時組態中的 replicas 欄位。這不使用 kubectl apply

kubectl scale deployment/nginx-deployment --replicas=2

使用 kubectl get 列印即時組態

kubectl get deployment nginx-deployment -o yaml

輸出顯示 replicas 欄位已設定為 2,且 last-applied-configuration 註解不包含 replicas 欄位

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # note that the annotation does not contain replicas
    # because it was not updated through apply
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
  # ...
spec:
  replicas: 2 # written by scale
  # ...
  minReadySeconds: 5
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        # ...
        name: nginx
        ports:
        - containerPort: 80
      # ...

更新 simple_deployment.yaml 設定檔,將 image 從 nginx:1.14.2 變更為 nginx:1.16.1,並刪除 minReadySeconds 欄位

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16.1 # update the image
        ports:
        - containerPort: 80

套用對設定檔所做的變更

kubectl diff -f https://k8s.io/examples/application/update_deployment.yaml
kubectl apply -f https://k8s.io/examples/application/update_deployment.yaml

使用 kubectl get 列印即時組態

kubectl get -f https://k8s.io/examples/application/update_deployment.yaml -o yaml

輸出顯示對即時設定的以下變更

  • replicas 欄位保留了 kubectl scale 設定的值 2。這是可行的,因為它已從設定檔中省略。
  • image 欄位已從 nginx:1.14.2 更新為 nginx:1.16.1
  • last-applied-configuration 註解已使用新的 image 更新。
  • minReadySeconds 欄位已被清除。
  • last-applied-configuration 註解不再包含 minReadySeconds 欄位。
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # The annotation contains the updated image to nginx 1.16.1,
    # but does not contain the updated replicas to 2
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.16.1","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
    # ...
spec:
  replicas: 2 # Set by `kubectl scale`.  Ignored by `kubectl apply`.
  # minReadySeconds cleared by `kubectl apply`
  # ...
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.16.1 # Set by `kubectl apply`
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

如何刪除物件

有兩種方法可以刪除由 kubectl apply 管理的物件。

建議使用命令式指令手動刪除物件,因為這樣更明確地說明了要刪除的內容,並且不太可能導致使用者意外刪除某些東西

kubectl delete -f <filename>

替代方案:kubectl apply -f <directory> --prune

作為 kubectl delete 的替代方案,您可以使用 kubectl apply 在物件的 manifest 從本機檔案系統中的目錄移除後,識別要刪除的物件。

在 Kubernetes 1.32 中,kubectl apply 中有兩種可用的修剪模式

  • 許可清單式修剪:此模式自 kubectl v1.5 以來就已存在,但由於其設計在可用性、正確性和效能方面存在問題,因此仍處於 alpha 階段。基於 ApplySet 的模式旨在取代它。
  • 基於 ApplySet 的修剪:apply set 是一個伺服器端物件(預設情況下為 Secret),kubectl 可以使用它來準確有效地追蹤跨 apply 操作的集合成員資格。此模式在 kubectl v1.27 中以 alpha 階段引入,作為許可清單式修剪的替代方案。

功能狀態: Kubernetes v1.5 [alpha]

若要使用許可清單式修剪,請將以下標記添加到您的 kubectl apply 調用中

  • --prune:刪除先前已套用但不在傳遞給目前調用的集合中的物件。
  • --prune-allowlist:要考慮修剪的 group-version-kinds (GVK) 清單。此標記是選用的,但強烈建議使用,因為其預設值是命名空間範圍和叢集範圍類型的不完整清單,這可能會導致令人驚訝的結果。
  • --selector/-l:使用標籤選擇器來限制為修剪選擇的物件集合。此標記是選用的,但強烈建議使用。
  • --all:使用此標記代替 --selector/-l 以明確選擇所有先前已套用且屬於許可清單類型的物件。

許可清單式修剪會向 API 伺服器查詢所有符合給定標籤(如果有的話)的許可清單 GVK 物件,並嘗試將傳回的即時物件組態與物件 manifest 檔案進行比對。如果物件符合查詢,並且在目錄中沒有 manifest,並且具有 kubectl.kubernetes.io/last-applied-configuration 註解,則會將其刪除。

kubectl apply -f <directory> --prune -l <labels> --prune-allowlist=<gvk-list>

功能狀態: Kubernetes v1.27 [alpha]

若要使用基於 ApplySet 的修剪,請設定 KUBECTL_APPLYSET=true 環境變數,並將以下標記添加到您的 kubectl apply 調用中

  • --prune:刪除先前已套用但不在傳遞給目前調用的集合中的物件。
  • --applyset:kubectl 可以用來準確有效地追蹤跨 apply 操作的集合成員資格的物件名稱。
KUBECTL_APPLYSET=true kubectl apply -f <directory> --prune --applyset=<name>

預設情況下,使用的 ApplySet 父物件類型為 Secret。但是,ConfigMap 也可以使用以下格式:--applyset=configmaps/<name>。當使用 Secret 或 ConfigMap 時,如果物件尚不存在,kubectl 將會建立該物件。

也可以使用自訂資源作為 ApplySet 父物件。若要啟用此功能,請使用以下標籤標記定義您要使用的資源的自訂資源定義 (CRD):applyset.kubernetes.io/is-parent-type: true。然後,建立您要用作 ApplySet 父物件的物件(kubectl 不會自動為自訂資源執行此操作)。最後,在 applyset 標記中按如下方式參考該物件:--applyset=<resource>.<group>/<name>(例如,widgets.custom.example.com/widget-name)。

使用基於 ApplySet 的修剪時,kubectl 會在將集合中的每個物件傳送到伺服器之前,將 applyset.kubernetes.io/part-of=<parentID> 標籤新增至每個物件。基於效能考量,它還會收集集合包含的資源類型和命名空間清單,並將這些資訊新增至即時父物件上的註解中。最後,在套用操作結束時,它會向 API 伺服器查詢屬於該集合的那些類型、那些命名空間(或在叢集範圍內,如適用)的物件,如 applyset.kubernetes.io/part-of=<parentID> 標籤所定義。

注意事項和限制

  • 每個物件最多只能是一個集合的成員。
  • 當使用任何命名空間父物件(包括預設的 Secret)時,必須使用 --namespace 標記。這表示跨越多個命名空間的 ApplySet 必須使用叢集範圍的自訂資源作為父物件。
  • 為了安全地將基於 ApplySet 的修剪與多個目錄一起使用,請為每個目錄使用唯一的 ApplySet 名稱。

如何檢視物件

您可以使用帶有 -o yamlkubectl get 來檢視即時物件的組態

kubectl get -f <filename|url> -o yaml

apply 如何計算差異並合併變更

kubectl apply 更新物件的即時組態時,它是透過向 API 伺服器發送 patch 請求來完成的。patch 定義了範圍限定於即時物件組態的特定欄位的更新。kubectl apply 命令使用設定檔、即時組態和儲存在即時組態中的 last-applied-configuration 註解來計算此 patch 請求。

合併 patch 計算

kubectl apply 命令將設定檔的內容寫入 kubectl.kubernetes.io/last-applied-configuration 註解。這用於識別已從設定檔中移除且需要從即時組態中清除的欄位。以下是用於計算應刪除或設定哪些欄位的步驟

  1. 計算要刪除的欄位。這些是存在於 last-applied-configuration 中但設定檔中遺失的欄位。
  2. 計算要新增或設定的欄位。這些是存在於設定檔中但其值與即時組態不符的欄位。

這是一個範例。假設這是 Deployment 物件的設定檔

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.16.1 # update the image
        ports:
        - containerPort: 80

此外,假設這是同一個 Deployment 物件的即時組態

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # note that the annotation does not contain replicas
    # because it was not updated through apply
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"minReadySeconds":5,"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.14.2","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
  # ...
spec:
  replicas: 2 # written by scale
  # ...
  minReadySeconds: 5
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        # ...
        name: nginx
        ports:
        - containerPort: 80
      # ...

以下是 kubectl apply 將執行的合併計算

  1. 透過從 last-applied-configuration 讀取值並將其與設定檔中的值進行比較,來計算要刪除的欄位。清除在本機物件設定檔中明確設定為 null 的欄位,無論它們是否出現在 last-applied-configuration 中。在此範例中,minReadySeconds 出現在 last-applied-configuration 註解中,但未出現在設定檔中。動作: 從即時組態中清除 minReadySeconds
  2. 透過從設定檔讀取值並將其與即時組態中的值進行比較,來計算要設定的欄位。在此範例中,設定檔中 image 的值與即時組態中的值不符。動作: 在即時組態中設定 image 的值。
  3. last-applied-configuration 註解設定為與設定檔的值相符。
  4. 將步驟 1、2、3 的結果合併到對 API 伺服器的單個 patch 請求中。

這是合併結果的即時組態

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # The annotation contains the updated image to nginx 1.16.1,
    # but does not contain the updated replicas to 2
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"apps/v1","kind":"Deployment",
      "metadata":{"annotations":{},"name":"nginx-deployment","namespace":"default"},
      "spec":{"selector":{"matchLabels":{"app":nginx}},"template":{"metadata":{"labels":{"app":"nginx"}},
      "spec":{"containers":[{"image":"nginx:1.16.1","name":"nginx",
      "ports":[{"containerPort":80}]}]}}}}      
    # ...
spec:
  selector:
    matchLabels:
      # ...
      app: nginx
  replicas: 2 # Set by `kubectl scale`.  Ignored by `kubectl apply`.
  # minReadySeconds cleared by `kubectl apply`
  # ...
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.16.1 # Set by `kubectl apply`
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

不同類型的欄位如何合併

設定檔中的特定欄位如何與即時組態合併取決於欄位的類型。欄位有幾種類型

  • primitive:字串、整數或布林類型欄位。例如,imagereplicas 是 primitive 欄位。動作: 取代。

  • map,也稱為 object:map 類型或包含子欄位的複雜類型欄位。例如,labelsannotationsspecmetadata 都是 map。動作: 合併元素或子欄位。

  • list:包含項目清單的欄位,這些項目可以是 primitive 類型或 map。例如,containersportsargs 都是 list。動作: 各有不同。

kubectl apply 更新 map 或 list 欄位時,它通常不會取代整個欄位,而是更新個別子元素。例如,當合併 Deployment 上的 spec 時,不會取代整個 spec。而是比較和合併 spec 的子欄位,例如 replicas

合併對 primitive 欄位的變更

Primitive 欄位會被取代或清除。

物件設定檔中的欄位即時物件組態中的欄位last-applied-configuration 中的欄位動作
-將即時值設定為設定檔值。
-將即時值設定為本機組態。
-從即時組態中清除。
-不執行任何動作。保留即時值。

合併對 map 欄位的變更

代表 map 的欄位透過比較 map 的每個子欄位或元素來合併

物件設定檔中的鍵即時物件組態中的鍵last-applied-configuration 中的欄位動作
-比較子欄位值。
-將即時值設定為本機組態。
-從即時組態中刪除。
-不執行任何動作。保留即時值。

合併 list 類型欄位的變更

合併 list 的變更使用三種策略之一

  • 如果 list 的所有元素都是 primitive,則取代該 list。
  • 合併複雜元素 list 中的個別元素。
  • 合併 primitive 元素 list。

策略的選擇是根據每個欄位而定。

如果 list 的所有元素都是 primitive,則取代該 list

將 list 視為與 primitive 欄位相同。取代或刪除整個 list。這樣可以保留順序。

範例: 使用 kubectl apply 更新 Pod 中 Container 的 args 欄位。這會將即時組態中 args 的值設定為設定檔中的值。先前已新增至即時組態的任何 args 元素都會遺失。設定檔中定義的 args 元素的順序會保留在即時組態中。

# last-applied-configuration value
    args: ["a", "b"]

# configuration file value
    args: ["a", "c"]

# live configuration
    args: ["a", "b", "d"]

# result after merge
    args: ["a", "c"]

說明: 合併使用設定檔值作為新的 list 值。

合併複雜元素 list 的個別元素

將 list 視為 map,並將每個元素的特定欄位視為鍵。新增、刪除或更新個別元素。這不會保留順序。

此合併策略在每個欄位上使用一個稱為 patchMergeKey 的特殊標籤。patchMergeKey 在 Kubernetes 原始碼中為每個欄位定義:types.go 當合併 map 的 list 時,指定為給定元素的 patchMergeKey 的欄位會像該元素的 map 鍵一樣使用。

範例: 使用 kubectl apply 更新 PodSpec 的 containers 欄位。這會合併 list,就好像它是一個 map,其中每個元素都以 name 作為鍵。

# last-applied-configuration value
    containers:
    - name: nginx
      image: nginx:1.16
    - name: nginx-helper-a # key: nginx-helper-a; will be deleted in result
      image: helper:1.3
    - name: nginx-helper-b # key: nginx-helper-b; will be retained
      image: helper:1.3

# configuration file value
    containers:
    - name: nginx
      image: nginx:1.16
    - name: nginx-helper-b
      image: helper:1.3
    - name: nginx-helper-c # key: nginx-helper-c; will be added in result
      image: helper:1.3

# live configuration
    containers:
    - name: nginx
      image: nginx:1.16
    - name: nginx-helper-a
      image: helper:1.3
    - name: nginx-helper-b
      image: helper:1.3
      args: ["run"] # Field will be retained
    - name: nginx-helper-d # key: nginx-helper-d; will be retained
      image: helper:1.3

# result after merge
    containers:
    - name: nginx
      image: nginx:1.16
      # Element nginx-helper-a was deleted
    - name: nginx-helper-b
      image: helper:1.3
      args: ["run"] # Field was retained
    - name: nginx-helper-c # Element was added
      image: helper:1.3
    - name: nginx-helper-d # Element was ignored
      image: helper:1.3

說明

  • 名為 "nginx-helper-a" 的容器被刪除,因為設定檔中未出現名為 "nginx-helper-a" 的容器。
  • 名為 "nginx-helper-b" 的容器保留了即時組態中對 args 的變更。kubectl apply 能夠識別出即時組態中的 "nginx-helper-b" 與設定檔中的 "nginx-helper-b" 是相同的,即使它們的欄位具有不同的值(設定檔中沒有 args)。這是因為 patchMergeKey 欄位值(name)在兩者中是相同的。
  • 名為「nginx-helper-c」的容器已新增,因為在即時配置中未出現具有該名稱的容器,但在設定檔中出現了一個具有該名稱的容器。
  • 名為「nginx-helper-d」的容器已保留,因為在上次套用的配置中未出現具有該名稱的元素。

合併基本元素列表

從 Kubernetes 1.5 開始,不支援合併基本元素列表。

預設欄位值

如果物件在建立時未指定某些欄位,API 伺服器會在即時配置中將這些欄位設定為預設值。

以下是 Deployment 的設定檔。該檔案未指定 strategy

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

使用 kubectl apply 建立物件

kubectl apply -f https://k8s.io/examples/application/simple_deployment.yaml

使用 kubectl get 列印即時組態

kubectl get -f https://k8s.io/examples/application/simple_deployment.yaml -o yaml

輸出顯示 API 伺服器在即時配置中將多個欄位設定為預設值。這些欄位在設定檔中未指定。

apiVersion: apps/v1
kind: Deployment
# ...
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  replicas: 1 # defaulted by apiserver
  strategy:
    rollingUpdate: # defaulted by apiserver - derived from strategy.type
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate # defaulted by apiserver
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        imagePullPolicy: IfNotPresent # defaulted by apiserver
        name: nginx
        ports:
        - containerPort: 80
          protocol: TCP # defaulted by apiserver
        resources: {} # defaulted by apiserver
        terminationMessagePath: /dev/termination-log # defaulted by apiserver
      dnsPolicy: ClusterFirst # defaulted by apiserver
      restartPolicy: Always # defaulted by apiserver
      securityContext: {} # defaulted by apiserver
      terminationGracePeriodSeconds: 30 # defaulted by apiserver
# ...

在修補程式請求中,預設欄位不會重新預設,除非它們在修補程式請求中被明確清除。這可能會導致根據其他欄位的值預設的欄位出現非預期的行為。當其他欄位稍後變更時,除非明確清除,否則從它們預設的值將不會更新。

因此,建議在設定檔中明確定義伺服器預設的某些欄位,即使所需的值與伺服器預設值相符也一樣。這使得更容易識別不會被伺服器重新預設的衝突值。

範例

# last-applied-configuration
spec:
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

# configuration file
spec:
  strategy:
    type: Recreate # updated value
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

# live configuration
spec:
  strategy:
    type: RollingUpdate # defaulted value
    rollingUpdate: # defaulted value derived from type
      maxSurge : 1
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

# result after merge - ERROR!
spec:
  strategy:
    type: Recreate # updated value: incompatible with rollingUpdate
    rollingUpdate: # defaulted value: incompatible with "type: Recreate"
      maxSurge : 1
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

說明

  1. 使用者建立一個 Deployment,但未定義 strategy.type
  2. 伺服器將 strategy.type 預設為 RollingUpdate,並預設 strategy.rollingUpdate 值。
  3. 使用者將 strategy.type 變更為 Recreatestrategy.rollingUpdate 值仍保持其預設值,儘管伺服器期望它們被清除。如果 strategy.rollingUpdate 值最初已在設定檔中定義,則會更清楚地表明它們需要被刪除。
  4. 套用失敗,因為 strategy.rollingUpdate 未被清除。strategy.rollingupdate 欄位不能與 strategy.typeRecreate 一起定義。

建議:這些欄位應在物件設定檔中明確定義

  • 工作負載(例如 Deployment、StatefulSet、Job、DaemonSet、ReplicaSet 和 ReplicationController)上的選取器和 PodTemplate 標籤
  • Deployment 部署策略

如何清除伺服器預設欄位或由其他寫入器設定的欄位

設定檔中未出現的欄位可以透過將其值設定為 null,然後套用設定檔來清除。對於伺服器預設的欄位,這會觸發重新預設值。

如何在設定檔和直接命令式寫入器之間變更欄位的擁有權

這些是您應該用來變更個別物件欄位的唯一方法

  • 使用 kubectl apply
  • 直接寫入即時配置而不修改設定檔:例如,使用 kubectl scale

將擁有者從直接命令式寫入器變更為設定檔

將欄位新增至設定檔。對於該欄位,停止不透過 kubectl apply 直接更新即時配置。

將擁有者從設定檔變更為直接命令式寫入器

從 Kubernetes 1.5 開始,將欄位的擁有權從設定檔變更為命令式寫入器需要手動步驟。

  • 從設定檔中移除該欄位。
  • 從即時物件上的 kubectl.kubernetes.io/last-applied-configuration 註解中移除該欄位。

變更管理方法

Kubernetes 物件應一次僅使用一種方法進行管理。從一種方法切換到另一種方法是可能的,但這是一個手動過程。

從命令式命令管理遷移到宣告式物件配置

從命令式命令管理遷移到宣告式物件配置涉及多個手動步驟。

  1. 將即時物件匯出到本機設定檔

    kubectl get <kind>/<name> -o yaml > <kind>_<name>.yaml
    
  2. 從設定檔中手動移除 status 欄位。

  3. 在物件上設定 kubectl.kubernetes.io/last-applied-configuration 註解

    kubectl replace --save-config -f <kind>_<name>.yaml
    
  4. 變更程序以專門使用 kubectl apply 來管理物件。

從命令式物件配置遷移到宣告式物件配置

  1. 在物件上設定 kubectl.kubernetes.io/last-applied-configuration 註解

    kubectl replace --save-config -f <kind>_<name>.yaml
    
  2. 變更程序以專門使用 kubectl apply 來管理物件。

定義控制器選取器和 PodTemplate 標籤

建議的方法是定義一個單一、不可變的 PodTemplate 標籤,該標籤僅供控制器選取器使用,而沒有其他語義含義。

範例

selector:
  matchLabels:
      controller-selector: "apps/v1/deployment/nginx"
template:
  metadata:
    labels:
      controller-selector: "apps/v1/deployment/nginx"

下一步

上次修改時間:2023 年 8 月 24 日下午 6:38 PST:Use code_sample shortcode instead of code shortcode (e8b136c3b3)