本文已發布超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

Kubernetes StatefulSets 和 DaemonSets 更新

這篇文章討論了 Kubernetes 的 DaemonSetStatefulSet API 物件的近期更新。我們使用 Apache ZooKeeperApache Kafka StatefulSet 以及 Prometheus node exporter DaemonSet 來探索這些功能。

在 Kubernetes 1.6 中,我們將 RollingUpdate 更新策略新增至 DaemonSet API 物件。使用 RollingUpdate 策略配置您的 DaemonSet 會使 DaemonSet 控制器在您的 DaemonSet 的 spec.template 更新時,對 DaemonSet 中的 Pod 執行自動滾動更新。

在 Kubernetes 1.7 中,我們增強了 DaemonSet 控制器,以追蹤 DaemonSet 的 PodTemplateSpecs 修訂歷史記錄。這允許 DaemonSet 控制器回滾更新。我們也將 RollingUpdate 策略新增至 StatefulSet API 物件,並為 StatefulSet 控制器實作了修訂歷史記錄追蹤。此外,我們新增了 Parallel Pod 管理政策,以支援需要具有唯一身分但不需要依序建立和終止 Pod 的有狀態應用程式。

StatefulSet 滾動更新和 Pod 管理政策

首先,我們將示範如何透過部署 ZooKeeper 集群和 Kafka 叢集來使用 StatefulSet 滾動更新和 Pod 管理政策。

先決條件

若要跟著操作,您需要設定一個 Kubernetes 1.7 叢集,至少有 3 個可排程節點。每個節點需要 1 個 CPU 和 2 GiB 的可用記憶體。您還需要動態佈建器,以允許 StatefulSet 控制器佈建 6 個各 10 GiB 的持久卷 (PV),或者您需要在部署 ZooKeeper 集群或部署 Kafka 叢集之前手動佈建 PV。

部署 ZooKeeper 集群

Apache ZooKeeper 是一個強一致性的分散式系統,其他分散式系統使用它進行叢集協調和組態管理。

注意:您可以使用此 zookeeper_mini.yaml 清單檔建立 ZooKeeper 集群。您可以在 此處進一步了解如何在 Kubernetes 上執行 ZooKeeper 集群,以及在 此處更深入地解釋清單檔及其內容。

當您套用清單檔時,您會看到如下所示的輸出。

$ kubectl apply -f zookeeper\_mini.yaml

service "zk-hs" created

service "zk-cs" created

poddisruptionbudget "zk-pdb" created

statefulset "zk" created

此清單檔使用 StatefulSet (zk) 建立由三台 ZooKeeper 伺服器組成的集群;一個 Headless Service (zk-hs) 來控制集群的網域;一個 Service (zk-cs),用戶端可以使用它來連線到就緒的 ZooKeeper 實例;以及一個 PodDisruptionBugdet (zk-pdb),允許一次計劃性中斷。(請注意,雖然此集群適用於示範目的,但其大小不適合生產使用。)

如果您使用 kubectl get 在另一個終端機中監看 Pod 建立,您將會看到,與 OrderedReady 策略(實作完整版本 StatefulSet 保證的預設政策)相反,zk StatefulSet 中的所有 Pod 都會並行建立。

$ kubectl get po -lapp=zk -w

NAME           READY         STATUS        RESTARTS     AGE


zk-0           0/1             Pending      0                   0s


zk-0           0/1             Pending     0                  0s


zk-1           0/1             Pending     0                  0s


zk-1           0/1             Pending     0                  0s


zk-0           0/1             ContainerCreating      0                  0s


zk-2           0/1             Pending      0                  0s


zk-1           0/1             ContainerCreating     0                  0s


zk-2           0/1             Pending      0                  0s


zk-2           0/1             ContainerCreating      0                  0s


zk-0           0/1             Running     0                  10s


zk-2           0/1             Running     0                  11s


zk-1           0/1             Running      0                  19s


zk-0           1/1             Running      0                  20s


zk-1           1/1             Running      0                  30s


zk-2           1/1             Running      0                  30s

這是因為 zookeeper_mini.yaml 清單檔將 StatefulSet 的 podManagementPolicy 設定為 Parallel。

apiVersion: apps/v1beta1  
kind: StatefulSet  
metadata:  
   name: zk  

spec:  
   serviceName: zk-hs  

   replicas: 3  

   updateStrategy:  

       type: RollingUpdate  

   podManagementPolicy: Parallel  

 ...

許多分散式系統 (例如 ZooKeeper) 不需要依序建立和終止其程序。您可以使用 Parallel Pod 管理政策來加速管理這些系統的 StatefulSet 的建立和刪除。請注意,當使用 Parallel Pod 管理時,StatefulSet 控制器在建立 Pod 失敗時不會封鎖。當 StatefulSet 的 podManagementPolicy 設定為 OrderedReady 時,會執行依序的 Pod 建立和終止。

部署 Kafka 叢集

Apache Kafka 是一個受歡迎的分散式串流平台。Kafka 生產者將資料寫入已分割的主題,這些主題以可設定的複寫因子儲存在 Broker 叢集上。消費者從 Broker 上儲存的分割區消費生產的資料。

注意:清單檔內容的詳細資訊可以在此處找到。您可以在 此處進一步了解如何在 Kubernetes 上執行 Kafka 叢集。

若要建立叢集,您只需要下載並套用 kafka_mini.yaml 清單檔。當您套用清單檔時,您會看到如下所示的輸出

$ kubectl apply -f kafka\_mini.yaml

service "kafka-hs" created

poddisruptionbudget "kafka-pdb" created

statefulset "kafka" created

此清單檔使用 kafka StatefulSet 建立由三個 Broker 組成的叢集;一個 Headless Service (kafka-hs) 來控制 Broker 的網域;以及一個 PodDisruptionBudget (kafka-pdb),允許一次計劃性中斷。Broker 設定為使用我們在上面建立的 ZooKeeper 集群,透過 zk-cs Service 進行連線。與上面部署的 ZooKeeper 集群一樣,此 Kafka 叢集適用於示範目的,但其大小可能不適合生產使用。

如果您監看 Pod 建立,您會注意到,與上面建立的 ZooKeeper 集群一樣,Kafka 叢集使用 Parallel podManagementPolicy。

$ kubectl get po -lapp=kafka -w

NAME           READY         STATUS        RESTARTS     AGE


kafka-0     0/1             Pending      0                   0s


kafka-0     0/1             Pending      0                  0s


kafka-1     0/1             Pending      0                  0s


kafka-1     0/1             Pending      0                  0s


kafka-2     0/1             Pending      0                  0s


kafka-0     0/1             ContainerCreating     0                  0s


kafka-2     0/1             Pending      0                  0s


kafka-1     0/1             ContainerCreating     0                  0s


kafka-1     0/1             Running     0                  11s


kafka-0     0/1             Running     0                  19s


kafka-1     1/1             Running     0                  23s


kafka-0     1/1             Running     0                  32s

生產和消費資料

您可以使用 kubectl run 執行 kafka-topics.sh 指令碼來建立名為 test 的主題。

$ kubectl run -ti --image=gcr.io/google\_containers/kubernetes-kafka:1.0-10.2.1 createtopic --restart=Never --rm -- kafka-topics.sh --create \

\> --topic test \

\> --zookeeper zk-cs.default.svc.cluster.local:2181 \

\> --partitions 1 \

\> --replication-factor 3

現在您可以使用 kubectl run 執行 kafka-console-consumer.sh 指令碼來監聽訊息。

$ kubectl run -ti --image=gcr.io/google\_containers/kubnetes-kafka:1.0-10.2.1 consume --restart=Never --rm -- kafka-console-consumer.sh --topic test --bootstrap-server kafka-0.kafka-hs.default.svc.cluster.local:9093

在另一個終端機中,您可以執行 kafka-console-producer.sh 指令碼。

$kubectl run -ti --image=gcr.io/google\_containers/kubernetes-kafka:1.0-10.2.1 produce --restart=Never --rm \

\>   -- kafka-console-producer.sh --topic test --broker-list kafka-0.kafka-hs.default.svc.cluster.local:9093,kafka-1.kafka-hs.default.svc.cluster.local:9093,kafka-2.kafka-hs.default.svc.cluster.local:9093

來自第二個終端機的輸出會出現在第一個終端機中。如果您在更新叢集時繼續生產和消費訊息,您會注意到沒有訊息遺失。當個別 Broker 更新時,您可能會看到分割區領導者變更的錯誤訊息,但用戶端會重試直到訊息提交。這是由於 StatefulSet 滾動更新的依序性質,我們將在下一節中進一步探討。

更新 Kafka 叢集

StatefulSet 更新與 DaemonSet 更新類似,因為它們都是透過設定對應 API 物件的 spec.updateStrategy 來配置的。當更新策略設定為 OnDelete 時,只有在 StatefulSet 或 DaemonSet 中的 Pod 已刪除時,對應的控制器才會建立新的 Pod。當更新策略設定為 RollingUpdate 時,當 DaemonSet 或 StatefulSet 的 spec.template 欄位進行修改時,控制器將刪除並重新建立 Pod。您可以使用滾動更新來變更 StatefulSet 或 DaemonSet 中 Pod 的組態(透過環境變數或命令列參數)、資源請求、資源限制、容器映像、標籤和/或註釋。請注意,所有更新都是破壞性的,始終需要銷毀並重新建立 DaemonSet 或 StatefulSet 中的每個 Pod。StatefulSet 滾動更新與 DaemonSet 滾動更新的不同之處在於 Pod 終止和建立是有序且依序的。

您可以修補 kafka StatefulSet 以將 CPU 資源請求減少到 250m。

$ kubectl patch sts kafka --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/resources/requests/cpu", "value":"250m"}]'

statefulset "kafka" patched

如果您監看 StatefulSet 中 Pod 的狀態,您會看到每個 Pod 都以反向序數順序(從序數最大的 Pod 開始,然後到最小的 Pod)刪除並重新建立。控制器會等待每個更新的 Pod 執行並就緒,然後再更新後續的 Pod。

$kubectl get po -lapp=kafka -w

NAME           READY         STATUS       RESTARTS     AGE


kafka-0     1/1             Running     0                   13m


kafka-1     1/1             Running     0                   13m


kafka-2     1/1             Running     0                   13m


kafka-2     1/1             Terminating     0                 14m


kafka-2     0/1             Terminating     0                 14m


kafka-2     0/1             Terminating     0                 14m


kafka-2     0/1             Terminating     0                 14m


kafka-2     0/1             Pending     0                 0s


kafka-2     0/1             Pending     0                 0s


kafka-2     0/1             ContainerCreating     0                 0s


kafka-2     0/1             Running     0                 10s


kafka-2     1/1             Running     0                 21s


kafka-1     1/1             Terminating     0                 14m


kafka-1     0/1             Terminating     0                 14m


kafka-1     0/1             Terminating     0                 14m


kafka-1     0/1             Terminating     0                 14m


kafka-1     0/1             Pending     0                 0s


kafka-1     0/1             Pending     0                 0s


kafka-1     0/1             ContainerCreating     0                 0s


kafka-1     0/1             Running     0                 11s


kafka-1     1/1             Running     0                 21s


kafka-0     1/1             Terminating     0                 14m


kafka-0     0/1             Terminating     0                 14m


kafka-0     0/1             Terminating     0                 14m


kafka-0     0/1             Terminating     0                 14m


kafka-0     0/1             Pending     0                 0s


kafka-0     0/1             Pending     0                 0s


kafka-0     0/1             ContainerCreating     0                 0s


kafka-0     0/1             Running     0                 10s


kafka-0     1/1             Running     0                 22s

請注意,計劃外中斷不會在更新過程中導致意外更新。也就是說,StatefulSet 控制器始終會重新建立正確版本的 Pod,以確保保留更新的順序。如果 Pod 已刪除,且已更新,則將從 StatefulSet 的 spec.template 的更新版本建立它。如果 Pod 尚未更新,則將從 StatefulSet 的 spec.template 的先前版本建立它。我們將在以下章節中進一步探討這一點。

暫存更新

根據您的組織處理部署和組態修改的方式,您可能想要或需要先暫存 StatefulSet 的更新,然後再允許推出進度。您可以透過為 RollingUpdate 設定分割區來完成此操作。當 StatefulSet 控制器偵測到 StatefulSet 的 updateStrategy 中有分割區時,它只會將 StatefulSet 的 spec.template 的更新版本套用至序數大於或等於分割區值的 Pod。

您可以修補 kafka StatefulSet 以將分割區新增至 RollingUpdate 更新策略。如果您將分割區設定為大於或等於 StatefulSet 的 spec.replicas 的數字(如下所示),您對 StatefulSet 的 spec.template 執行的任何後續更新都將暫存以供推出,但 StatefulSet 控制器不會啟動滾動更新。

$ kubectl patch sts kafka -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'

statefulset "kafka" patched

如果您修補 StatefulSet 以將請求的 CPU 設定為 0.3,您會注意到沒有任何 Pod 更新。

$ kubectl patch sts kafka --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/resources/requests/cpu", "value":"0.3"}]'

statefulset "kafka" patched

即使您刪除 Pod 並等待 StatefulSet 控制器重新建立它,您也會注意到 Pod 是使用目前的 CPU 請求重新建立的。

$   kubectl delete po kafka-1


pod "kafka-1" deleted


$ kubectl get po kafka-1 -w

NAME           READY         STATUS                           RESTARTS     AGE


kafka-1     0/1             ContainerCreating     0                   10s


kafka-1     0/1             Running     0                 19s


kafka-1     1/1             Running     0                 21s



$ kubectl get po kafka-1 -o yaml

apiVersion: v1

kind: Pod

metadata:

   ...


       resources:


           requests:


               cpu: 250m


               memory: 1Gi

推出 Canary

通常,我們希望在全面推出映像更新或組態變更之前,先在應用程式的單一實例上驗證它。如果您將上面建立的分割區修改為 2,則 StatefulSet 控制器將推出一個 Canary,可用於驗證更新是否按預期運作。

$ kubectl patch sts kafka -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'

statefulset "kafka" patched

您可以監看 StatefulSet 控制器更新 kafka-2 Pod,並在更新完成後暫停。

$   kubectl get po -lapp=kafka -w


NAME           READY         STATUS       RESTARTS     AGE


kafka-0     1/1             Running     0                   50m


kafka-1     1/1             Running     0                   10m


kafka-2     1/1             Running     0                   29s


kafka-2     1/1             Terminating     0                 34s


kafka-2     0/1             Terminating     0                 38s


kafka-2     0/1             Terminating     0                 39s


kafka-2     0/1             Terminating     0                 39s


kafka-2     0/1             Pending     0                 0s


kafka-2     0/1             Pending     0                 0s


kafka-2     0/1             Terminating     0                 20s


kafka-2     0/1             Terminating     0                 20s


kafka-2     0/1             Pending     0                 0s


kafka-2     0/1             Pending     0                 0s


kafka-2     0/1             ContainerCreating     0                 0s


kafka-2     0/1             Running     0                 19s


kafka-2     1/1             Running     0                 22s

階段性推出

與推出 Canary 類似,您可以根據階段性進度(例如線性、幾何或指數推出)推出更新。

如果您修補 kafka StatefulSet 以將分割區設定為 1,則 StatefulSet 控制器會再更新一個 Broker。

$ kubectl patch sts kafka -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":1}}}}'

statefulset "kafka" patched

如果您將其設定為 0,則 StatefulSet 控制器會更新最後一個 Broker 並完成更新。

$ kubectl patch sts kafka -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":0}}}}'

statefulset "kafka" patched

請注意,您不必將分割區遞減一。對於較大的 StatefulSet(例如,具有 100 個副本的 StatefulSet),您可能會使用更像 100、99、90、50、0 的進度。在這種情況下,您將暫存更新、部署 Canary、推出到 10 個實例、更新百分之五十的 Pod,然後完成更新。

清除

若要刪除上面建立的 API 物件,您可以使用 kubectl delete 針對您用於建立 ZooKeeper 集群和 Kafka 叢集的兩個清單檔。

$ kubectl delete -f kafka\_mini.yaml

service "kafka-hs" deleted

poddisruptionbudget "kafka-pdb" deleted

Statefulset “kafka” deleted


$ kubectl delete -f zookeeper\_mini.yaml

service "zk-hs" deleted

service "zk-cs" deleted

poddisruptionbudget "zk-pdb" deleted

statefulset "zk" deleted

依設計,StatefulSet 控制器不會刪除任何持久卷聲明 (PVC):為 ZooKeeper 集群和 Kafka 叢集建立的 PVC 必須手動刪除。根據您叢集的儲存回收政策,您可能也需要手動刪除後端 PV。

DaemonSet 滾動更新、歷史記錄和回滾

在本節中,我們將向您展示如何在 DaemonSet 上執行滾動更新、查看其歷史記錄,然後在不良部署後執行回滾。我們將使用 DaemonSet 在叢集中的每個 Kubernetes 節點上部署 Prometheus 節點導出器。這些節點導出器會將節點指標匯出到 Prometheus 監控系統。為了簡化起見,我們在本部落格文章中省略了 Prometheus 伺服器的安裝以及用於與 DaemonSet Pod 通訊的服務。

先決條件

若要跟隨本節的部落格文章,您需要一個可運作的 Kubernetes 1.7 叢集和 kubectl 1.7 或更新版本。如果您已跟隨第一節的步驟,則可以使用相同的叢集。

DaemonSet 滾動更新。首先,準備節點導出器 DaemonSet 清單,以在叢集中的每個節點上執行 v0.13 Prometheus 節點導出器

$ cat \>\> node-exporter-v0.13.yaml \<\<EOF

apiVersion: extensions/v1beta1  
kind: DaemonSet  
metadata:  
   name: node-exporter  

spec:  
   updateStrategy:  

       type: RollingUpdate  

   template:  

       metadata:  

           labels:  

               app: node-exporter  

           name: node-exporter  

       spec:  

           containers:  

           - image: prom/node-exporter:v0.13.0  

               name: node-exporter  

               ports:  

               - containerPort: 9100  

                   hostPort: 9100  

                   name: scrape  

           hostNetwork: true  

           hostPID: true


EOF

請注意,您需要明確地將 DaemonSet .spec.updateStrategy.type 設定為 RollingUpdate,以啟用 DaemonSet 滾動更新功能。

套用此清單以建立節點導出器 DaemonSet

$ kubectl apply -f node-exporter-v0.13.yaml --record

daemonset "node-exporter" created

等待第一個 DaemonSet 部署完成

$ kubectl rollout status ds node-exporter  
daemon set "node-exporter" successfully rolled out

您應該會看到每個節點都執行了一個節點導出器 Pod 的副本

$ kubectl get pods -l app=node-exporter -o wide

若要在節點導出器 DaemonSet 上執行滾動更新,請準備一個包含 v0.14 Prometheus 節點導出器的清單

$ cat node-exporter-v0.13.yaml ```  sed "s/v0.13.0/v0.14.0/g" \> node-exporter-v0.14.yaml

然後套用 v0.14 節點導出器 DaemonSet

$ kubectl apply -f node-exporter-v0.14.yaml --record

daemonset "node-exporter" configured

等待 DaemonSet 滾動更新完成

$ kubectl rollout status ds node-exporter

...

Waiting for rollout to finish: 3 out of 4 new pods have been updated...  
Waiting for rollout to finish: 3 of 4 updated pods are available...  
daemon set "node-exporter" successfully rolled out

我們剛剛透過更新 DaemonSet 範本觸發了 DaemonSet 滾動更新。預設情況下,一次會終止一個舊的 DaemonSet Pod 並建立一個新的 DaemonSet Pod。

現在,我們將透過將映像檔更新為無效值來導致部署失敗

$ cat node-exporter-v0.13.yaml | sed "s/v0.13.0/bad/g" \> node-exporter-bad.yaml


$ kubectl apply -f node-exporter-bad.yaml --record

daemonset "node-exporter" configured

請注意,部署永遠不會完成

$ kubectl rollout status ds node-exporter   
Waiting for rollout to finish: 0 out of 4 new pods have been updated...  
Waiting for rollout to finish: 1 out of 4 new pods have been updated…

# Use ^C to exit

這是預期的行為。我們稍早提到,DaemonSet 滾動更新一次終止並建立一個 Pod。由於新的 Pod 永遠無法變成可用狀態,因此部署會停止,防止無效的規格傳播到一個以上的節點。StatefulSet 滾動更新在失敗的部署方面實作了相同的行為。不成功的更新會被封鎖,直到透過回滾或使用規格向前滾動來修正為止。

$ kubectl get pods -l app=node-exporter

NAME                                   READY         STATUS                 RESTARTS     AGE


node-exporter-f2n14     0/1             ErrImagePull     0                   3m


...


# N = number of nodes

$ kubectl get ds node-exporter  
NAME                       DESIRED     CURRENT     READY         UP-TO-DATE     AVAILABLE     NODE SELECTOR     AGE  

node-exporter     N                 N                 N-1             1                       N                     \<none\>                   46m

DaemonSet 歷史記錄、回滾和向前滾動

接下來,執行回滾。查看節點導出器 DaemonSet 部署歷史記錄

$ kubectl rollout history ds node-exporter   
daemonsets "node-exporter"  
REVISION               CHANGE-CAUSE  

1                             kubectl apply --filename=node-exporter-v0.13.yaml --record=true  

2                             kubectl apply --filename=node-exporter-v0.14.yaml --record=true


3                             kubectl apply --filename=node-exporter-bad.yaml --record=true

檢查您要回滾到的修訂版本的詳細資訊

$ kubectl rollout history ds node-exporter --revision=2  
daemonsets "node-exporter" with revision #2  
Pod Template:  
   Labels:             app=node-exporter  

   Containers:  

     node-exporter:  

       Image:           prom/node-exporter:v0.14.0  

       Port:             9100/TCP  

       Environment:               \<none\>  

       Mounts:         \<none\>  

   Volumes:           \<none\>

您可以透過 kubectl rollout history 快速回滾到您找到的任何 DaemonSet 修訂版本

# Roll back to the last revision

$ kubectl rollout undo ds node-exporter   
daemonset "node-exporter" rolled back


# Or use --to-revision to roll back to a specific revision

$ kubectl rollout undo ds node-exporter --to-revision=2  
daemonset "node-exporter" rolled back

DaemonSet 回滾是透過向前滾動完成的。因此,在回滾之後,DaemonSet 修訂版本 2 變成修訂版本 4(目前修訂版本)

$ kubectl rollout history ds node-exporter   
daemonsets "node-exporter"  
REVISION               CHANGE-CAUSE  

1                             kubectl apply --filename=node-exporter-v0.13.yaml --record=true  

3                             kubectl apply --filename=node-exporter-bad.yaml --record=true  

4                             kubectl apply --filename=node-exporter-v0.14.yaml --record=true

節點導出器 DaemonSet 現在再次恢復正常運作

$ kubectl rollout status ds node-exporter  
daemon set "node-exporter" successfully rolled out


# N = number of nodes

$ kubectl get ds node-exporter

NAME                       DESIRED     CURRENT     READY         UP-TO-DATE     AVAILABLE     NODE SELECTOR     AGE  

node-exporter     N                 N                 N                 N                       N                     \<none\>                   46m

如果在執行回滾時指定了目前的 DaemonSet 修訂版本,則會略過回滾

$ kubectl rollout undo ds node-exporter --to-revision=4  
daemonset "node-exporter" skipped rollback (current template already matches revision 4)

如果找不到 DaemonSet 修訂版本,您將會看到來自 kubectl 的此抱怨訊息

$ kubectl rollout undo ds node-exporter --to-revision=10  
error: unable to find specified revision 10 in history

請注意,kubectl rollout history 和 kubectl rollout status 也支援 StatefulSet!

清除

$ kubectl delete ds node-exporter

DaemonSet 和 StatefulSet 的下一步

滾動更新和回滾彌補了 DaemonSet 和 StatefulSet 的重要功能缺口。當我們規劃 Kubernetes 1.8 時,我們希望繼續專注於將核心控制器推進到 GA。這可能表示某些進階功能請求(例如,自動回滾、幼兒死亡偵測)將會被延後,以確保核心控制器的一致性、可用性和穩定性。我們歡迎意見回饋和貢獻,因此請隨時在 Slack 上聯繫我們、在 Stack Overflow 上提出問題,或在 GitHub 上開啟 issue 或 pull request。

  • Stack Overflow 上張貼問題(或回答問題)
  • 加入倡導者的社群入口網站 K8sPort
  • 在 Twitter 上追蹤我們 @Kubernetesio 以取得最新更新
  • Slack 上與社群聯繫
  • GitHub 上參與 Kubernetes 專案