一文講透Cluster API的前世、此生與將來

Cluster API是一個Kubernetes項目,它將聲明式Kubernetes風格的API用於集羣的建立、配置和管理。它經過使用時CustomResourceDefinitions(CRDs)來擴展被Kubernetes API Server暴露的API來實現這些功能,從而容許用戶建立新資源,例如集羣(指Kubernetes集羣)和Machine(指組成集羣的節點的Machine)。而後每一個資源的控制器負責對這些資源的更改作出反應,以啓動集羣。API的設計可讓不一樣的基礎架構提供程序能夠與其集成,進而提供針對其環境的特定邏輯。html

Cluster API項目仍處於早期階段,可是當前的狀況已經證實了它能帶來強大的功能。這篇文章的目的是總結迄今爲止該項目的功能,並展望後續版本的功能。node

過去、如今和將來

撰寫這篇文章的時候,Cluster API最新發布的版本實現了v1alpha2。在這裏,咱們將討論該API的轉換以及提供程序如何與之集成。nginx

過去:v1alpha1

最初,Cluster API的v1alpha1實現要求提供程序須要在其項目中包含Cluster API控制器代碼,並實現actuator(接口)以處理其環境的特定邏輯(例如,對雲提供程序API的調用)。該代碼做爲特定於某個提供程序的管理器二進制文件運行,該二進制文件能夠爲管理集羣所需的每一個資源管理一個控制器。git

如今:v1alpha2

使用Cluster API 的v1alpha1方法存在一個痛點,即它要求每一個提供程序都實現必定數量的bootstrap boilerplate code,即代碼不靈活而且冗長。爲了解決這個問題,v1alpha2引入了bootstrap provider,它們負責生成將Machine轉變爲Kubernetes節點所需的數據。Kubeadm bootstrap provider則經過使用kubedam在全部環境中處理此任務。它的默認行爲是爲每臺Machine生成一個可用於bootstrap節點的cloud-config腳本。github

v1alpha2引入的另外一個更改是,提供程序再也不須要將Cluster API控制器代碼包含在其項目中。並且Cluster API提供了對核心類型負責的獨立控制器。有關這些更改的更多信息,請參閱Github上的信息json

對於此版本,如今須要部署3個管理器(而不是此前的1個):bootstrap

  • Cluster API manager:用於管理核心v1alpha2資源api

  • Bootstrap provider manager:用於管理資源以生成將Machine轉變爲Kubernetes節點的數據bash

  • Infrastructure provider manager:用於管理提供運行集羣所需基礎架構的資源網絡

例如,若是我想使用kubedam在配置好的GCP上建立一個集羣,我應該部署Cluster API manager(用於調和核心資源,例如集羣和Machine資源),kubeadm bootstrap provider(例如,用於調和KubeadmConfig資源)以及GCP infrastructure provider(用於調和環境的特定資源,如GCPClusters和GCPMachines)。

爲了瞭解如何應用這些資源,咱們將使用我編寫的Kubernetes基礎架構提供程序實現來進行集羣部署,即由Kubernetes自己提供基礎架構的提供程序。Kubernetes節點使用kind鏡像做爲Kubernetes Pod運行。

首先,咱們須要建立一個基礎集羣來爲咱們的Cluster API集羣提供基礎架構。咱們將使用GKE。如下命令假定你已安裝gcloud和GCP項目並設置了賬戶。

警告:gcloud命令將產生一些花費,你也能夠考慮使用GCP免費套餐。

Calico將做爲Cluster API集羣的CNI解決方案。在配置GKE集羣以路由IPv4封裝的數據包時,須要一些特殊的配置。爲了避免分散本文關於Cluster API行爲的描述,咱們將在此處直接運行它們,不作詳細解釋。有關詳細信息,能夠參考Kubernetes基礎架構提供程序代碼庫

gcloud container clusters create management-cluster --cluster-version=1.14 --image-type=UBUNTU
CLUSTER_CIDR=$(gcloud container clusters describe management-cluster --format="value(clusterIpv4Cidr)")
gcloud compute firewall-rules create allow-management-cluster-pods-ipip --source-ranges=$CLUSTER_CIDR --allow=ipip
kubectl apply -f <(cat <<EOF
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: forward-ipencap
  namespace: kube-system
  labels:
    app: forward-ipencap
spec:
  selector:
    matchLabels:
      name: forward-ipencap
  template:
    metadata:
      labels:
        name: forward-ipencap
    spec:
      hostNetwork: true
      initContainers:
      - name: forward-ipencap
        command:
        - sh
        - -c
        - |
          apk add iptables
          iptables -C FORWARD -p ipencap -j ACCEPT || iptables -A FORWARD -p ipencap -j ACCEPT
        image: alpine:3.11
        securityContext:
          capabilities:
            add: ["NET_ADMIN"]
      containers:
      - name: sleep-forever
        image: alpine:3.11
        command: ["tail"]
        args: ["-f", "/dev/null"]
EOF
)

配置了GKE集羣后,咱們如今能夠開始部署必要的管理器(manager)。

# Install cluster api manager
kubectl apply -f https://github.com/kubernetes-sigs/cluster-api/releases/download/v0.2.8/cluster-api-components.yaml

# Install kubeadm bootstrap provider
kubectl apply -f https://github.com/kubernetes-sigs/cluster-api-bootstrap-provider-kubeadm/releases/download/v0.1.5/bootstrap-components.yaml

# Install kubernetes infrastructure provider
kubectl apply -f https://github.com/dippynark/cluster-api-provider-kubernetes/releases/download/v0.2.1/provider-components.yaml

# Allow cluster api controller to interact with kubernetes infrastructure resources
# If the kubernetes provider were SIG-sponsored this would not be necesarry ;)
# https://cluster-api.sigs.k8s.io/providers/v1alpha1-to-v1alpha2.html#the-new-api-groups
kubectl apply -f https://github.com/dippynark/cluster-api-provider-kubernetes/releases/download/v0.2.1/capi-kubernetes-rbac.yaml

如今,咱們能夠部署咱們的集羣。

kubectl apply -f <(cat <<EOF
apiVersion: infrastructure.lukeaddison.co.uk/v1alpha2
kind: KubernetesCluster
metadata:
  name: example
spec:
  controlPlaneServiceType: LoadBalancer
---
apiVersion: cluster.x-k8s.io/v1alpha2
kind: Cluster
metadata:
  name: example
spec:
  clusterNetwork:
    services:
      cidrBlocks: ["172.16.0.0/12"]
    pods:
      cidrBlocks: ["192.168.0.0/16"]
    serviceDomain: "cluster.local"
  infrastructureRef:
    apiVersion: infrastructure.lukeaddison.co.uk/v1alpha2
    kind: KubernetesCluster
    name: example
EOF
)

在這裏,咱們定義了特定於環境的KubernetesCluster資源。這將爲運行Kubernetes集羣提供必要的基礎架構組件。例如,GCPCluster可能會提供VPC、防火牆規則和負載均衡器以訪問API Server。而咱們的KubernetesCluster只爲API Server設置了LoadBalancer類型的Kubernetes服務。咱們能夠查詢KubernetesCluster來查看其狀態。

$ kubectl get kubernetescluster
NAME      PHASE         HOST             PORT   AGE
example   Provisioned   35.205.255.206   443    51s

咱們從核心集羣資源中引用特定於提供程序的集羣資源,該資源提供了集羣的網絡詳細信息。KubernetesCluster將被修改成由集羣資源所擁有。

如今,咱們準備部署咱們的Machine。在這裏,咱們建立一個controller Machine,它引用infrastructure provider中特定的KubernetesMachine資源以及bootstrap provider中特定的KubeadmConfig資源。

kubectl apply -f <(cat <<EOF
apiVersion: bootstrap.cluster.x-k8s.io/v1alpha2
kind: KubeadmConfig
metadata:
  name: controller
spec:
  initConfiguration:
    nodeRegistration:
      kubeletExtraArgs:
        eviction-hard: nodefs.available<0%,nodefs.inodesFree<0%,imagefs.available<0%
        cgroups-per-qos: "false"
        enforce-node-allocatable: ""
  clusterConfiguration:
    controllerManager:
      extraArgs:
        enable-hostpath-provisioner: "true"
---
apiVersion: infrastructure.lukeaddison.co.uk/v1alpha2
kind: KubernetesMachine
metadata:
  name: controller
---
apiVersion: cluster.x-k8s.io/v1alpha2
kind: Machine
metadata:
  name: controller
  labels:
    cluster.x-k8s.io/cluster-name: example
    cluster.x-k8s.io/control-plane: "true"
spec:
  version: "v1.17.0"
  bootstrap:
    configRef:
      apiVersion: bootstrap.cluster.x-k8s.io/v1alpha2
      kind: KubeadmConfig
      name: controller
  infrastructureRef:
    apiVersion: infrastructure.lukeaddison.co.uk/v1alpha2
    kind: KubernetesMachine
    name: controller
EOF
)

kubeadm bootstrap provider將KubeadmConfig資源轉換爲cloud-config腳本,Kubernetes infrastructure provider使用該腳原本bootstrap Kubernetes Pod以造成新集羣的控制平面。

Kubernetes infrastructure provider經過依靠systemd(它做爲kind鏡像的一部分運行)來實現這一目的。而後從cloud-config腳本生成一個bash腳本,以建立和運行指定的文件和命令。使用Kubernetes Secret將腳本安裝到Pod中,當containerd socket可使用以後,就使用systemd路徑單元觸發該腳本。你能夠到controller pod中執行,並運行journalctl -u cloud-init來查看此腳本的輸出。cat /opt/cloud-init/bootstrap.sh將顯示完整腳本。

Kubelet運行以後,它將經過在etcd中建立controller Node對象(也在controller Pod上運行)向集羣註冊本身。

如今,咱們能夠部署咱們的worker Machine了。這看起來與controller Machine 配置很是相似,但咱們還會利用MachineDeployment、KubeadmConfigTemplate和KubernetesMachineTemplate來請求worker節點的多個副本。

kubectl apply -f <(cat <<EOF
apiVersion: infrastructure.lukeaddison.co.uk/v1alpha2
kind: KubernetesMachineTemplate
metadata:
  name: worker
spec:
  template:
    spec: {}
---
apiVersion: bootstrap.cluster.x-k8s.io/v1alpha2
kind: KubeadmConfigTemplate
metadata:
  name: worker
spec:
  template:
    spec:
      joinConfiguration:
        nodeRegistration:
          kubeletExtraArgs:
            eviction-hard: nodefs.available<0%,nodefs.inodesFree<0%,imagefs.available<0%
            cgroups-per-qos: "false"
            enforce-node-allocatable: ""
---
apiVersion: cluster.x-k8s.io/v1alpha2
kind: MachineDeployment
metadata:
  name: worker
  labels:
    cluster.x-k8s.io/cluster-name: example
    nodepool: default
spec:
  replicas: 3
  selector:
    matchLabels:
      cluster.x-k8s.io/cluster-name: example
      nodepool: default
  template:
    metadata:
      labels:
        cluster.x-k8s.io/cluster-name: example
        nodepool: default
    spec:
      version: "v1.17.0"
      bootstrap:
        configRef:
          apiVersion: bootstrap.cluster.x-k8s.io/v1alpha2
          kind: KubeadmConfigTemplate
          name: worker
      infrastructureRef:
        apiVersion: infrastructure.lukeaddison.co.uk/v1alpha2
        kind: KubernetesMachineTemplate
        name: worker
EOF
)

MachineDeployments與Kubernetes Deployment工做方式十分類似,由於它們管理MachineSets,後者還管理所需數量的Machines副本。

如今,咱們應該可以查詢已經配置的Machine,以查看其狀態。

$ kubectl get machines
NAME                      PROVIDERID                                          PHASE
controller                kubernetes://871cde5a-3159-11ea-a1c6-42010a840084   provisioning
worker-6c498c48db-4grxq                                                       pending
worker-6c498c48db-66zk7                                                       pending
worker-6c498c48db-k5kkp                                                       pending

咱們還能夠看到相應的KubernetesMachines。

$ kubectl get kubernetesmachines
NAME           PROVIDER-ID                                         PHASE          AGE
controller     kubernetes://871cde5a-3159-11ea-a1c6-42010a840084   Provisioning   53s
worker-cs95w                                                       Pending        35s
worker-kpbhm                                                       Pending        35s
worker-pxsph                                                       Pending        35s

不久,全部KubernetesMachines都應處於運行狀態。

$ kubectl get kubernetesmachines
NAME           PROVIDER-ID                                         PHASE     AGE
controller     kubernetes://871cde5a-3159-11ea-a1c6-42010a840084   Running   2m
worker-cs95w   kubernetes://bcd10f28-3159-11ea-a1c6-42010a840084   Running   1m
worker-kpbhm   kubernetes://bcd4ef33-3159-11ea-a1c6-42010a840084   Running   1m
worker-pxsph   kubernetes://bccd1af4-3159-11ea-a1c6-42010a840084   Running   1m

咱們還能夠看到與你的KubernetesMachines相對應的Pod。

$ kubectl get pods
NAME           READY   STATUS    RESTARTS   AGE
controller     1/1     Running   0          2m11s
worker-cs95w   1/1     Running   0          111s
worker-kpbhm   1/1     Running   0          111s
worker-pxsph   1/1     Running   0          111s

Cluster API manager生成一個kubeconfig並將其保存爲一個Kubernetes Secret,名爲<clusterName>-kubeconfig。咱們能夠檢索它並訪問集羣。

$ kubectl get secret example-kubeconfig -o jsonpath='{.data.value}' | base64 --decode > example-kubeconfig
$ export KUBECONFIG=example-kubeconfig
$ kubectl get nodes
NAME           STATUS     ROLES    AGE     VERSION
controller     NotReady   master   3m16s   v1.17.0
worker-cs95w   NotReady   <none>   2m34s   v1.17.0
worker-kpbhm   NotReady   <none>   2m32s   v1.17.0
worker-pxsph   NotReady   <none>   2m34s   v1.17.0

最後,能夠應用咱們的Calico CNI解決方案。節點應該很快就準備就緒。

$ kubectl apply -f https://docs.projectcalico.org/v3.11/manifests/calico.yaml
$ kubectl get nodes
NAME           STATUS   ROLES    AGE     VERSION
controller     Ready    master   5m8s    v1.17.0
worker-cs95w   Ready    <none>   4m26s   v1.17.0
worker-kpbhm   Ready    <none>   4m24s   v1.17.0
worker-pxsph   Ready    <none>   4m26s   v1.17.0

如今,咱們能夠在全新的集羣上運行工做負載:

kubectl run nginx --image=nginx --replicas=3

對於其餘基礎設施提供程序,流程相似。你還能夠在Cluster API文檔中的快速入門部分找到許多其餘示例。

將來:v1alpha3以及更高級的版本

咱們僅僅是根據當前的狀況進行延展,探討Cluster API可能提供的功能。此外,咱們還將討論roadmap上的其餘一些有趣的事情。

機器健康檢查(MachineHealthCheck)

在v1alpha2中,特定於基礎架構的Machine能夠將其自身標記爲故障,而且狀態將上升到owning Machine,可是owning MachineSet不執行任何操做。這樣作是由於,除了MachineSet以外的其餘資源均可以擁有Machine,所以將Machine修復邏輯與MachineSet分離是有意義的。

MachineHealthCheck是一種建議的資源,用於描述節點的故障狀況並在發生故障時刪除相應的Machine。這將觸發適當的刪除行爲(例如,驅散)和任何控制資源來啓動替換Machine。

Kubeadm控制平面(KubeadmControlPlane)

當前,建立一個高可用控制平面並管理它一般須要使用正確的bootstrap配置(須要以正確的順序啓動)仔細配置獨立的controller Machine。v1alpha3則但願經過初始的kubeadm控制平面實現來支持控制平臺提供程序。從infrastructure provider的角度來看,這機會不須要進行任何更改,可是將容許用戶管理控制平面的實例化和彈性伸縮,而無需手動建立相應的Machine。關於此功能,你能夠查看Github上相關頁面獲取更多信息。

與MachineHealthChecks一塊兒使用,可使用Cluster API進行控制平面自動修復。

集羣自動伸縮(Cluster Autoscaler)

Cluster Autoscaler是能夠利用Cluster API的項目的一個示例。當前的實現要求每一個受支持的雲提供程序都實現擴展其環境中的實例組所需的CloudProvider和NodeGroup接口。隨着Cluster API的出現,能夠經過與Cluster API資源交互而不是直接與提供程序特定的API交互,來實現自動彈性伸縮邏輯,而且沒有廠商鎖定。

總 結

咱們已經對Cluster API的當前功能以及不久的未來進行了深刻的研究。該項目看起來十分強大而且完整,這使人激動。做爲一個與Kubernetes相關的開源項目,Cluster API也是十分開放的,你能夠經過各類渠道提出建議或是作出本身的貢獻。

相關文章
相關標籤/搜索