Kubernetes 使用配置文件對Kubernetes對象進行聲明式管理

2022-06-11 15:34 更新

使用配置文件對 Kubernetes 對象進行聲明式管理

你可以通過在一個目錄中存儲多個對象配置文件、并使用 ?kubectl apply? 來遞歸地創(chuàng)建和更新對象來創(chuàng)建、更新和刪除 Kubernetes 對象。 這種方法會保留對現(xiàn)有對象已作出的修改,而不會將這些更改寫回到對象配置文件中。 ?kubectl diff? 也會給你呈現(xiàn) ?apply ?將作出的變更的預(yù)覽。

在開始之前

安裝 kubectl。

你必須擁有一個 Kubernetes 的集群,同時你的 Kubernetes 集群必須帶有 kubectl 命令行工具。 建議在至少有兩個節(jié)點的集群上運行本教程,且這些節(jié)點不作為控制平面主機。 如果你還沒有集群,你可以通過 Minikube 構(gòu)建一個你自己的集群,或者你可以使用下面任意一個 Kubernetes 工具構(gòu)建:

要檢查版本,請輸入 ?kubectl version?。

權(quán)衡取舍 

?kubectl ?工具能夠支持三種對象管理方式:

  • 指令式命令
  • 指令式對象配置
  • 聲明式對象配置

概覽 

聲明式對象管理需要用戶對 Kubernetes 對象定義和配置有比較深刻的理解。 

以下是本文檔中使用的術(shù)語的定義:

  • 對象配置文件/配置文件:一個定義 Kubernetes 對象的配置的文件。 本主題展示如何將配置文件傳遞給 ?kubectl apply?。 配置文件通常存儲于類似 Git 這種源碼控制系統(tǒng)中。
  • 現(xiàn)時對象配置/現(xiàn)時配置:由 Kubernetes 集群所觀測到的對象的現(xiàn)時配置值。 這些配置保存在 Kubernetes 集群存儲(通常是 etcd)中。
  • 聲明式配置寫者/聲明式寫者:負責更新現(xiàn)時對象的人或者軟件組件。 本主題中的聲明式寫者負責改變對象配置文件并執(zhí)行 ?kubectl apply? 命令 以寫入變更。

如何創(chuàng)建對象

使用 ?kubectl apply? 來創(chuàng)建指定目錄中配置文件所定義的所有對象,除非對應(yīng)對象已經(jīng)存在:

kubectl apply -f <目錄>/

此操作會在每個對象上設(shè)置 ?kubectl.kubernetes.io/last-applied-configuration: '{...}'? 注解。注解值中包含了用來創(chuàng)建對象的配置文件的內(nèi)容。

Note: 添加 ?-R? 標志可以遞歸地處理目錄。

下面是一個對象配置文件示例:

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

執(zhí)行 ?kubectl diff? 可以打印出將被創(chuàng)建的對象:

kubectl diff -f https://k8s.io/examples/application/simple_deployment.yaml
Note:
?diff ?使用服務(wù)器端試運行(Server-side Dry-run) 功能特性;而該功能特性需要在 ?kube-apiserver? 上啟用。
由于 ?diff ?操作會使用試運行模式執(zhí)行服務(wù)器端 apply 請求,因此需要為 用戶配置 ?PATCH?、?CREATE ?和 ?UPDATE ?操作權(quán)限。

使用 ?kubectl apply? 來創(chuàng)建對象:

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

使用 ?kubectl get? 打印其現(xiàn)時配置:

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

輸出顯示注解 ?kubectl.kubernetes.io/last-applied-configuration? 被寫入到 現(xiàn)時配置中,并且其內(nèi)容與配置文件相同:

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? 來更新某個目錄中定義的所有對象,即使那些對象已經(jīng)存在。 這一操作會隱含以下行為:

  1. 在現(xiàn)時配置中設(shè)置配置文件中出現(xiàn)的字段;
  2. 在現(xiàn)時配置中清除配置文件中已刪除的字段。
kubectl diff -f <目錄>/
kubectl apply -f <目錄>/

Note: 使用 ?-R? 標志遞歸處理目錄。

下面是一個配置文件示例:

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? 來創(chuàng)建對象:

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

Note: 出于演示的目的,上面的命令引用的是單個文件而不是整個目錄。

使用 ?kubectl get? 打印現(xiàn)時配置:

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

輸出顯示,注解 ?kubectl.kubernetes.io/last-applied-configuration? 被寫入到 現(xiàn)時配置中,并且其取值與配置文件內(nèi)容相同。

kind: Deployment
metadata:
  annotations:
    # ...
    # 此為 simple_deployment.yaml 的 JSON 表示
    # 在對象創(chuàng)建時由 kubectl 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:
  # ...
  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? 命令直接更新現(xiàn)時配置中的 ?replicas ?字段。 這一命令沒有使用 ?kubectl apply?:

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

使用 ?kubectl get? 來打印現(xiàn)時配置:

kubectl get deployment nginx-deployment -o yaml

輸出顯示,?replicas ?字段已經(jīng)被設(shè)置為 2,而 ?last-applied-configuration? 注解中 并不包含 ?replicas ?字段。

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # 注意注解中并不包含 replicas
    # 這是因為更新并不是通過 kubectl apply 來執(zhí)行的
    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
      # ...

現(xiàn)在更新 ?simple_deployment.yaml? 配置文件,將鏡像文件從 ?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

應(yīng)用對配置文件所作更改:

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

使用 ?kubectl get? 打印現(xiàn)時配置:

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

輸出顯示現(xiàn)時配置中發(fā)生了以下更改:

  • 字段 ?replicas ?保留了 ?kubectl scale? 命令所設(shè)置的值:2; 之所以該字段被保留是因為配置文件中并沒有設(shè)置 ?replicas?。
  • 字段 ?image ?的內(nèi)容已經(jīng)從 ?nginx:1.14.2? 更改為 ?nginx:1.16.1?。
  • 注解 ?last-applied-configuration? 內(nèi)容被更改為新的鏡像名稱。
  • 字段 ?minReadySeconds ?被移除。
  • 注解 ?last-applied-configuration? 中不再包含 ?minReadySeconds ?字段。
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # 注解中包含更新后的鏡像 nginx 1.16.1
    # 但是其中并不包含更改后的 replicas 值 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 # 由 `kubectl scale` 設(shè)置,被 `kubectl apply` 命令忽略
  # minReadySeconds 被 `kubectl apply` 清除
  # ...
  selector:
    matchLabels:
      # ...
      app: nginx
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.16.1 # 由 `kubectl apply` 設(shè)置
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

Warning: 將 ?kubectl apply? 與指令式對象配置命令 ?kubectl create? 或 ?kubectl replace? 混合使用是不受支持的。這是因為 ?create ?和 ?replace ?命令都不會保留 ?kubectl apply? 用來計算更新內(nèi)容所使用的 ?kubectl.kubernetes.io/last-applied-configuration? 注解值。

如何刪除對象 

有兩種方法來刪除 ?kubectl apply? 管理的對象。

建議操作:kubectl delete -f <文件名> 

使用指令式命令來手動刪除對象是建議的方法,因為這種方法更為明確地給出了 要刪除的內(nèi)容是什么,且不容易造成用戶不小心刪除了其他對象的情況。

kubectl delete -f <文件名>

替代方式:kubectl apply -f <目錄名稱/> --prune -l your=label 

只有在充分理解此命令背后含義的情況下才建議這樣操作。

Warning: ?kubectl apply --prune? 命令本身仍處于 Alpha 狀態(tài),在后續(xù)發(fā)布版本中可能會 引入一些向后不兼容的變化。

Warning: 在使用此命令時必須小心,這樣才不會無意中刪除不想刪除的對象。

作為 ?kubectl delete? 操作的替代方式,你可以在目錄中對象配置文件被刪除之后, 使用 ?kubectl apply? 來辯識要刪除的對象。 帶 ?--prune? 標志的 ?apply ?命令會首先查詢 API 服務(wù)器,獲得與某組標簽相匹配 的對象列表,之后將返回的現(xiàn)時對象配置與目錄中的對象配置文件相比較。 如果某對象在查詢中被匹配到,但在目錄中沒有文件與其相對應(yīng),并且其中還包含 ?last-applied-configuration? 注解,則該對象會被刪除。

kubectl apply -f <directory/> --prune -l <labels>

Warning: 帶剪裁(prune)行為的 ?apply ?操作應(yīng)在包含對象配置文件的目錄的根目錄運行。 如果在其子目錄中運行,可能導(dǎo)致對象被不小心刪除。 因為某些對象可能與 ?-l <標簽>? 的標簽選擇算符匹配,但其配置文件不在當前 子目錄下。

如何查看對象 

你可以使用 ?kubectl get? 并指定 ?-o yaml? 選項來查看現(xiàn)時對象的配置:

kubectl get -f <文件名 | URL> -o yaml

apply 操作是如何計算配置差異并合并變更的? 

Caution: patch 是一種更新操作,其作用域為對象的一些特定字段而不是整個對象。 這使得你可以更新對象的特定字段集合而不必先要讀回對象。

?kubectl apply? 更新對象的現(xiàn)時配置,它是通過向 API 服務(wù)器發(fā)送一個 patch 請求 來執(zhí)行更新動作的。 所提交的補丁中定義了對現(xiàn)時對象配置中特定字段的更新。 ?kubectl apply? 命令會使用當前的配置文件、現(xiàn)時配置以及現(xiàn)時配置中保存的 ?last-applied-configuration? 注解內(nèi)容來計算補丁更新內(nèi)容。

合并補丁計算 

?kubectl apply? 命令將配置文件的內(nèi)容寫入到 ?kubectl.kubernetes.io/last-applied-configuration? 注解中。 這些內(nèi)容用來識別配置文件中已經(jīng)移除的、因而也需要從現(xiàn)時配置中刪除的字段。 用來計算要刪除或設(shè)置哪些字段的步驟如下:

  1. 計算要刪除的字段,即在 ?last-applied-configuration? 中存在但在 配置文件中不再存在的字段。
  2. 計算要添加或設(shè)置的字段,即在配置文件中存在但其取值與現(xiàn)時配置不同的字段。

下面是一個例子。假定此文件是某 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 對象的現(xiàn)時配置如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    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
  # ...
  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? 將執(zhí)行的合并計算:

  1. 通過讀取 ?last-applied-configuration并將其與配置文件中的值相比較, 計算要刪除的字段。 對于本地對象配置文件中顯式設(shè)置為空的字段,清除其在現(xiàn)時配置中的設(shè)置, 無論這些字段是否出現(xiàn)在 ?last-applied-configuration? 中。 在此例中,?minReadySeconds ?出現(xiàn)在 ?last-applied-configuration? 注解中,但 并不存在于配置文件中。 動作: 從現(xiàn)時配置中刪除 ?minReadySeconds ?字段。
  2. 通過讀取配置文件中的值并將其與現(xiàn)時配置相比較,計算要設(shè)置的字段。 在這個例子中,配置文件中的 ?image ?值與現(xiàn)時配置中的 ?image ?不匹配。 動作:設(shè)置現(xiàn)時配置中的 ?image ?值。
  3. 設(shè)置 ?last-applied-configuration? 注解的內(nèi)容,使之與配置文件匹配。
  4. 將第 1、2、3 步驟得出的結(jié)果合并,構(gòu)成向 API 服務(wù)器發(fā)送的補丁請求內(nèi)容。

下面是此合并操作之后形成的現(xiàn)時配置:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    # ...
    # 注解中包含更新后的 image,nginx 1.11.9,
    # 但不包含更新后的 replicas
    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
  # minReadySeconds  此字段被清除
  # ...
  template:
    metadata:
      # ...
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.16.1
        # ...
        name: nginx
        ports:
        - containerPort: 80
        # ...
      # ...
    # ...
  # ...

不同類型字段的合并方式

配置文件中的特定字段與現(xiàn)時配置合并時,合并方式取決于字段類型。 字段類型有幾種:

  • 基本類型:字段類型為 ?string?、?integer ?或 ?boolean ?之一。 例如:?image ?和 ?replicas ?字段都是基本類型字段。動作: 替換。
  • map:也稱作 object。類型為 ?map ?或包含子域的復(fù)雜結(jié)構(gòu)。例如,?labels?、 ?annotations?、?spec ?和 ?metadata ?都是 map。動作: 合并元素或子字段。
  • list:包含元素列表的字段,其中每個元素可以是基本類型或 map。 例如,?containers?、?ports ?和 ?args ?都是 list。動作: 不一定。

當 ?kubectl apply? 更新某個 map 或 list 字段時,它通常不會替換整個字段,而是會 更新其中的各個子元素。例如,當合并 Deployment 的 ?spec ?時,?kubectl ?并不會 將其整個替換掉。相反,實際操作會是對 ?replicas ?這類 ?spec ?的子字段來執(zhí)行比較和更新。

合并對基本類型字段的更新 

基本類型字段會被替換或清除。

Note: - 表示的是“不適用”,因為指定數(shù)值未被使用。

字段在對象配置文件中 字段在現(xiàn)時對象配置中 字段在 last-applied-configuration 中 動作
- 將配置文件中值設(shè)置到現(xiàn)時配置上。
- 將配置文件中值設(shè)置到現(xiàn)時配置上。
- 從現(xiàn)時配置中移除。
- 什么也不做。保持現(xiàn)時值。

合并對 map 字段的變更

用來表示映射的字段在合并時會逐個子字段或元素地比較:

Note: - 表示的是“不適用”,因為指定數(shù)值未被使用。

鍵存在于對象配置文件中 鍵存在于現(xiàn)時對象配置中 鍵存在于 last-applied-configuration 中 動作
- 比較子域取值。
- 將現(xiàn)時配置設(shè)置為本地配置值。
- 從現(xiàn)時配置中刪除鍵。
- 什么也不做,保留現(xiàn)時值。

合并 list 類型字段的變更

對 list 類型字段的變更合并會使用以下三種策略之一:

  • 如果 list 所有元素都是基本類型則替換整個 list。
  • 如果 list 中元素是復(fù)合結(jié)構(gòu)則逐個元素執(zhí)行合并操作。
  • 合并基本類型元素構(gòu)成的 list。

策略的選擇是基于各個字段做出的。

如果 list 中元素都是基本類型則替換整個 list 

將整個 list 視為一個基本類型字段?;蛘哒麄€替換或者整個刪除。 此操作會保持 list 中元素順序不變

示例: 使用 ?kubectl apply? 來更新 Pod 中 Container 的 ?args ?字段。此操作會 將現(xiàn)時配置中的 ?args ?值設(shè)為配置文件中的值。 所有之前添加到現(xiàn)時配置中的 ?args ?元素都會丟失。 配置文件中的 ?args ?元素的順序在被添加到現(xiàn)時配置中時保持不變。

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

# 配置文件值
    args: ["a", "c"]

# 現(xiàn)時配置
    args: ["a", "b", "d"]

# 合并結(jié)果
    args: ["a", "c"]

解釋: 合并操作將配置文件中的值當做新的 list 值。

如果 list 中元素為復(fù)合類型則逐個執(zhí)行合并

此操作將 list 視為 map,并將每個元素中的特定字段當做其主鍵。 逐個元素地執(zhí)行添加、刪除或更新操作。結(jié)果順序無法得到保證。

此合并策略會使用每個字段上的一個名為 ?patchMergeKey ?的特殊標簽。 Kubernetes 源代碼中為每個字段定義了 ?patchMergeKey?: types.go 當合并由 map 組成的 list 時,給定元素中被設(shè)置為 ?patchMergeKey ?的字段會被 當做該元素的 map 鍵值來使用。

例如: 使用 ?kubectl apply? 來更新 Pod 規(guī)約中的 ?containers ?字段。 此操作會將 ?containers ?列表視作一個映射來執(zhí)行合并,每個元素的主鍵為 ?name?。

# last-applied-configuration 值
    containers:
    - name: nginx
      image: nginx:1.16
    - name: nginx-helper-a # 鍵 nginx-helper-a 會被刪除
      image: helper:1.3
    - name: nginx-helper-b # 鍵 nginx-helper-b 會被保留
      image: helper:1.3

# 配置文件值
    containers:
    - name: nginx
      image: nginx:1.16
    - name: nginx-helper-b
      image: helper:1.3
    - name: nginx-helper-c # 鍵 nginx-helper-c 會被添加
      image: helper:1.3

# 現(xiàn)時配置
    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"]        # 字段會被保留
    - name: nginx-helper-d # 鍵 nginx-helper-d 會被保留
      image: helper:1.3

# 合并結(jié)果
    containers:
    - name: nginx
      image: nginx:1.16
      # 元素 nginx-helper-a 被刪除
    - name: nginx-helper-b
      image: helper:1.3
      args: ["run"]        # 字段被保留
    - name: nginx-helper-c # 新增元素
      image: helper:1.3
    - name: nginx-helper-d # 此元素被忽略(保留)
      image: helper:1.3

解釋:

  • 名為 "nginx-helper-a" 的容器被刪除,因為配置文件中不存在同名的容器。
  • 名為 "nginx-helper-b" 的容器的現(xiàn)時配置中的 ?args ?被保留。 ?kubectl apply? 能夠辯識出現(xiàn)時配置中的容器 "nginx-helper-b" 與配置文件 中的容器 "nginx-helper-b" 相同,即使它們的字段值有些不同(配置文件中未給定 ?args ?值)。這是因為 ?patchMergeKey ?字段(name)的值在兩個版本中都一樣。
  • 名為 "nginx-helper-c" 的容器是新增的,因為在配置文件中的這個容器尚不存在 于現(xiàn)時配置中。
  • 名為 "nginx-helper-d" 的容器被保留下來,因為在 last-applied-configuration 中沒有與之同名的元素。

合并基本類型元素 list

在 Kubernetes 1.5 中,尚不支持對由基本類型元素構(gòu)成的 list 進行合并。

Note: 選擇上述哪種策略是由源碼中給定字段的 ?patchStrategy ?標記來控制的: types.go 如果 list 類型字段未設(shè)置 ?patchStrategy?,則整個 list 會被替換掉。

默認字段值 

API 服務(wù)器會在對象創(chuàng)建時其中某些字段未設(shè)置的情況下在現(xiàn)時配置中為其設(shè)置默認值。

下面是一個 Deployment 的配置文件。文件未設(shè)置 ?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? 創(chuàng)建對象:

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

使用 ?kubectl get? 打印現(xiàn)時配置:

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

輸出顯示 API 在現(xiàn)時配置中為某些字段設(shè)置了默認值。 這些字段在配置文件中并未設(shè)置。

apiVersion: apps/v1
kind: Deployment
# ...
spec:
  selector:
    matchLabels:
      app: nginx
  minReadySeconds: 5
  replicas: 1           # API 服務(wù)器所設(shè)默認值
  strategy:
    rollingUpdate:      # API 服務(wù)器基于 strategy.type 所設(shè)默認值
      maxSurge: 1
      maxUnavailable: 1
    type: RollingUpdate # API 服務(wù)器所設(shè)默認值
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.14.2
        imagePullPolicy: IfNotPresent    # API 服務(wù)器所設(shè)默認值
        name: nginx
        ports:
        - containerPort: 80
          protocol: TCP       # API 服務(wù)器所設(shè)默認值
        resources: {}         # API 服務(wù)器所設(shè)默認值
        terminationMessagePath: /dev/termination-log    # API 服務(wù)器所設(shè)默認值
      dnsPolicy: ClusterFirst       # API 服務(wù)器所設(shè)默認值
      restartPolicy: Always         # API 服務(wù)器所設(shè)默認值
      securityContext: {}           # API 服務(wù)器所設(shè)默認值
      terminationGracePeriodSeconds: 30        # API 服務(wù)器所設(shè)默認值
# ...

在補丁請求中,已經(jīng)設(shè)置了默認值的字段不會被重新設(shè)回其默認值,除非 在補丁請求中顯式地要求清除。對于默認值取決于其他字段的某些字段而言, 這可能會引發(fā)一些意想不到的行為。當所依賴的其他字段后來發(fā)生改變時, 基于它們所設(shè)置的默認值只能在顯式執(zhí)行清除操作時才會被更新。

為此,建議在配置文件中為服務(wù)器設(shè)置默認值的字段顯式提供定義,即使所 給的定義與服務(wù)器端默認值設(shè)定相同。這樣可以使得辯識無法被服務(wù)器重新 基于默認值來設(shè)置的沖突字段變得容易。

示例:

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

# 配置文件
spec:
  strategy:
    type: Recreate   # 更新的值
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

# 現(xiàn)時配置
spec:
  strategy:
    type: RollingUpdate    # 默認設(shè)置的值
    rollingUpdate:         # 基于 type 設(shè)置的默認值
      maxSurge : 1
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

# 合并后的結(jié)果 - 出錯!
spec:
  strategy:
    type: Recreate     # 更新的值:與 rollingUpdate 不兼容
    rollingUpdate:     # 默認設(shè)置的值:與 "type: Recreate" 沖突
      maxSurge : 1
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

解釋:

  1. 用戶創(chuàng)建 Deployment,未設(shè)置 ?strategy.type?。
  2. 服務(wù)器為 ?strategy.type? 設(shè)置默認值 ?RollingUpdate?,并為 ?strategy.rollingUpdate? 設(shè)置默認值。
  3. 用戶改變 ?strategy.type? 為 ?Recreate?。字段 ?strategy.rollingUpdate? 仍會取其 默認設(shè)置值,盡管服務(wù)器期望該字段被清除。 如果 ?strategy.rollingUpdate? 值最初于配置文件中定義,則它們需要被清除 這一點就更明確一些。
  4. ?apply ?操作失敗,因為 ?strategy.rollingUpdate? 未被清除。 ?strategy.rollingupdate? 在 ?strategy.type? 為 ?Recreate ?不可被設(shè)定。

建議:以下字段應(yīng)該在對象配置文件中顯式定義:

  • 如 Deployment、StatefulSet、Job、DaemonSet、ReplicaSet 和 ReplicationController 這類負載的選擇算符和 ?PodTemplate ?標簽
  • Deployment 的上線策略

如何清除服務(wù)器端按默認值設(shè)置的字段或者被其他寫者設(shè)置的字段

沒有出現(xiàn)在配置文件中的字段可以通過將其值設(shè)置為 ?null ?并應(yīng)用配置文件來清除。 對于由服務(wù)器按默認值設(shè)置的字段,清除操作會觸發(fā)重新為字段設(shè)置新的默認值。

如何將字段的屬主在配置文件和直接指令式寫者之間切換

更改某個對象字段時,應(yīng)該采用下面的方法:

  • 使用 ?kubectl apply?。
  • 直接寫入到現(xiàn)時配置,但不更改配置文件本身,例如使用 ?kubectl scale?。

將屬主從直接指令式寫者更改為配置文件

將字段添加到配置文件。針對該字段,不再直接執(zhí)行對現(xiàn)時配置的修改。 修改均通過 ?kubectl apply? 來執(zhí)行。

將屬主從配置文件改為直接指令式寫者

在 Kubernetes 1.5 中,將字段的屬主從配置文件切換到某指令式寫者需要手動 執(zhí)行以下步驟:

  • 從配置文件中刪除該字段;
  • 將字段從現(xiàn)時對象的 ?kubectl.kubernetes.io/last-applied-configuration? 注解 中刪除。

更改管理方法 

Kubernetes 對象在同一時刻應(yīng)該只用一種方法來管理。 從一種方法切換到另一種方法是可能的,但這一切換是一個手動過程。

Note: 在聲明式管理方法中使用指令式命令來刪除對象是可以的。

從指令式命令管理切換到聲明式對象配置

從指令式命令管理切換到聲明式對象配置管理的切換包含以下幾個手動步驟:

  1. 將現(xiàn)時對象導(dǎo)出到本地配置文件:
  2. kubectl get <kind>/<name> -o yaml > <kind>_<name>.yaml
    
  3. 手動移除配置文件中的 ?status ?字段。
  4. Note: 這一步驟是可選的,因為 ?kubectl apply? 并不會更新 status 字段,即便 配置文件中包含 status 字段。

  5. 設(shè)置對象上的 ?kubectl.kubernetes.io/last-applied-configuration? 注解:
  6. kubectl replace --save-config -f <kind>_<name>.yaml
    
  7. 更改過程,使用 ?kubectl apply? 專門管理對象。

從指令式對象配置切換到聲明式對象配置

  1. 在對象上設(shè)置 ?kubectl.kubernetes.io/last-applied-configuration? 注解:
  2. kubectl replace -save-config -f <kind>_<name>.yaml
    
  3. 自此排他性地使用 ?kubectl apply? 來管理對象。

定義控制器選擇算符和 PodTemplate 標簽

Warning: 強烈不建議更改控制器上的選擇算符。

建議的方法是定義一個不可變更的 PodTemplate 標簽,僅用于控制器選擇算符且 不包含其他語義性的含義。

示例:

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


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號