集群 API (Cluster API) 進階

隨著 Kubernetes 逐步成為容器 orchestrator 領域的事實標準,在 Kubernetes 生態領域周邊有例如 Cluster API、Cloud Provider 等很多項目。本文介紹了 Cluster API 這個項目在 OpenStack 上的實現;同時,本文也介紹了 CoreOS 這個容器化操作系統如何在 Cluster API 上使用。


集群 API (Cluster API) 進階


Cluster API 以及 cluster-api-provider-openstack 簡介

Cluster API 是一個 Kubernetes 之上的可選項目,它使用 Kuberentes 原生方式來創建、配置和管理集群(Cluster)。本文假設讀者已經對 Cluster API 有一定了解,關於 Cluster API 使用、範圍等內容可以參考 此處 ;關於 Cluster API 的基本概念和操作可以參考這篇文章。

Cluster API 作為通用的 Kubernetes 集群管理框架,許多不同種類的雲提供商都以 Cluster API 為基礎,您可從 這裡 獲取雲提供商的完整列表。其中基於 OpenStack 的實現為 cluster-api-provider-openstack,為了簡單起見,本文使用縮寫 CAPO 代表 cluster-api-provider-openstack。

CoreOS 簡介

CoreOS 是一個基於 Linux 內核的輕量級操作系統,面向雲和集群為主,其主要的優勢是一致、安全、可靠。關於 CoreOS 具體可以參考 官方文檔

CoreOS 作為雲原生操作系統,ignition 是其很有特色以及和普通 Linux 不一樣的地方。下面這個 ignition 實例的主要目的就是將生成的公鑰注入到部署的虛擬機裡,這樣當 CoreOS 啟動之後,可以通過公鑰對應的私鑰 ssh 登錄。

<code>{
      "ignition": {
      "config": {},
      "timeouts": {},
      "version": "3.0.0"
      },
      "networkd": {},
      "passwd": {
      "users": [
      {
      "name": "core",
      "sshAuthorizedKeys": [
      "ssh-rsa ABCD..."
      ]
      }
      ]
      },
      "storage": {},
      "systemd": {
      }/<code>

OpenStack 的 ingition 可以參考該 文檔 。CAPO 使用了 ignition 來初始化 CoreOS。

CoreOS 在 CAPO 中的使用

在 CAPO 中默認主要通過如下幾個配置文件:cluster.yaml 中主要定義集群,例如集群的網絡、master IP 地址等;machines.yaml 定義所有的機器,例如規格、網絡、安全組等;provider-components.yaml 定義 role、secret 等,其中最重要的就是 worker-user-data 和 master-user-data 兩個 secret。

<code>apiVersion: "cluster.k8s.io/v1alpha1"
      kind: Cluster
      metadata:
      name: test1
      spec:
      clusterNetwork:
      services:
      cidrBlocks: ["10.96.0.0/12"]
      pods:
      cidrBlocks: ["192.168.0.0/16"]
      serviceDomain: "cluster.local"
      providerSpec:
      value:
      apiVersion: "openstackproviderconfig/v1alpha1"
      kind: "OpenstackProviderSpec"
      clusterConfiguration:
      controlPlaneEndpoint: 9.20.206.208:6443
      kubernetesVersion: 1.15.0/<code>

CAPO 邏輯上可以拆分成為 infra(也就是虛擬機和其他諸如存儲、負載均衡等相關資源)和 Kubernetes 控制和計算節點創建; 當前 Kubernetes 的創建是通過注入啟動腳本來實現的,CAPO 現在支持 Ubuntu、CentOS、CoreOS,Ubuntu 和 CentOS 使用的是 cloud-init,CoreOS 使用的是 ignition。而 cloud-init 或者 ignition 的內容就是通過上述 worker-user-data 和 master-user-data 來完成的。

如下是針對 CoreOS 和非 CoreOS 創建的區別:

<code>if [[ "$PROVIDER_OS" == "coreos" ]]; then
        cat $COREOS_COMMON_SECTION \
        | sed -e "s#\$OPENSTACK_CLOUD_PROVIDER_CONF#$OPENSTACK_CLOUD_PROVIDER_CONF#" \
        | sed -e "s#\$OPENSTACK_CLOUD_CACERT_CONFIG#$OPENSTACK_CLOUD_CACERT_CONFIG#" \
        | yq m -a - $COREOS_MASTER_SECTION  \
        > $COREOS_MASTER_USER_DATA
        cat $COREOS_COMMON_SECTION \
        | sed -e "s#\$OPENSTACK_CLOUD_PROVIDER_CONF#$OPENSTACK_CLOUD_PROVIDER_CONF#" \
        | sed -e "s#\$OPENSTACK_CLOUD_CACERT_CONFIG#$OPENSTACK_CLOUD_CACERT_CONFIG#" \
        | yq m -a - $COREOS_WORKER_SECTION  \
        > $COREOS_WORKER_USER_DATA
        else
        cat "$MASTER_USER_DATA" \
        | sed -e "s#\$OPENSTACK_CLOUD_PROVIDER_CONF#$OPENSTACK_CLOUD_PROVIDER_CONF#" \
        | sed -e "s#\$OPENSTACK_CLOUD_CACERT_CONFIG#$OPENSTACK_CLOUD_CACERT_CONFIG#" \
        > $USERDATA/$PROVIDER_OS/master-user-data.sh
        cat "$WORKER_USER_DATA" \
        | sed -e "s#\$OPENSTACK_CLOUD_PROVIDER_CONF#$OPENSTACK_CLOUD_PROVIDER_CONF#" \
        | sed -e "s#\$OPENSTACK_CLOUD_CACERT_CONFIG#$OPENSTACK_CLOUD_CACERT_CONFIG#" \
        > $USERDATA/$PROVIDER_OS/worker-user-data.sh
        Fi/<code>

通過如下命令,可以通過預先定義的模板生成最終的 ignition 文件:

<code>./generate-yaml.sh clouds.yaml openstack coreos output/<code>

當控制節點啟動的時候,ignition 會由 systemd 觸發執行,從而會完成一系列初始化動作,例如創建臨時目錄,創建需要的配置文件,然後執行其中最核心的 kubeadm 啟動腳本完成 Kubernetes 集群的創建。

當控制節點完成 Kubernetes 集群的創建之後,所有的之前在臨時集群的 Kubernetes 的對象都會被轉移到新創建的控制集群裡,之後開始創建工作節點,同控制節點一樣,工作節點也會執行 ingition,工作節點的 ignition 和控制節點的不同,主要是通過 kubeadm join 來加入控制節點。

創建 CNI 和 CRICTL:

<code>systemd:
      units:
      …
      - contents: |
      [Unit]
      Description=Unpack CNI and CRICTL into the right places.
      Before=kubelet.service
      
      [Service]
      Type=oneshot
      ExecStartPre=/usr/bin/tar -C /opt/bin -xzf /opt/kubetmp/crictl.tar.gz
      ExecStart=/usr/bin/tar -C /opt/cni/bin -xzf /opt/kubetmp/cni-plugins.tar.gz
      ExecStartPost=/usr/bin/systemctl disable unpack.service
      
      [Install]
      WantedBy=multi-user.target
      enabled: true
      name: unpack.service
      
      
      創建 Kubernetes 控制面:
      systemd:
      units:
      ….
      - contents: |-
      [Unit]
      Description=Initialise Kubernetes control plane node.
      After=kubelet.service
      Requires=coreos-metadata.service
      
      [Service]
      Type=oneshot
      Environment="PATH=/usr/bin:/usr/sbin:/opt/bin:/opt/cni/bin:/bin/sbin"
      ExecStartPre=/opt/bin/prepare.sh
      ExecStart=/opt/bin/kubeadm init --config /etc/kubernetes/kubeadm_config.yaml
      ExecStartPost=/opt/bin/kubectl --kubeconfig /etc/kubernetes/kubelet.conf annotate --overwrite node %H machine={{ .Machine.ObjectMeta.Namespace }}/{{ .Machine.ObjectMeta.Name }}
      ExecStartPost=/opt/bin/kubectl --kubeconfig /etc/kubernetes/admin.conf apply -f https://docs.projectcalico.org/v3.6/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml
      ExecStartPost=/usr/bin/systemctl disable kubeadm.service
      
      [Install]
      WantedBy=multi-user.target
      enabled: true
      name: kubeadm.service/<code>

生成 ignition 模板可以參考 這裡

多控制節點在 CAPO 中的使用

Kubernetes 通過多個控制節點來支持高可用,kubeadm 這個項目已經支持了高可用的設置,CAPO 利用了 kubeadm 的這個功能,在控制節點啟動時候決定是創建還是加入 Kubernetes 控制節點。

Opentsack 通過 octavia 項目支持負載均衡,octavia 是 OpenStack 的一個子項目,CAPO 通過 gophercloud 這個項目的 golang 接口來創建和管理負載均衡器。Octavia 的具體使用辦法可以參考 這裡

圖 1. 帶負載均衡器的 Kubernetes 集群

集群 API (Cluster API) 進階

集群 API (Cluster API) 進階

CAPO 通過大致如下步驟來完成多控制節點集群創建,具體的細節本文篇幅有限,不能詳細介紹。

  1. clusterctl 使用 kind 或者 minikube 創建一個臨時集群,創建臨時集群的目的是創建一個 Kubernetes 環境,可以把 Kubernetes 定義的對象從 yaml 定義加入到 etcd 中,這個臨時集群最終會被刪除或保留。
  2. 臨時集群 CAPO 的容器的集群控制器(Cluster Controller)觀察到需要創建負載均衡器,會通過調用 octavia 創建一個負載均衡器,這個負載均衡器會創建監聽對象等。
  3. clusterctl 根據 machines 的定義創建多個虛擬機共同組成控制面,如前所示,如果採用 CoreOS,會使用 CoreOS 的鏡像以及執行 CoreOS 的啟動腳本 (ignition)。
  4. 第一個虛擬機通過 kubeadm 創建集群控制面,當完成之後 CAPO 容器的機器控制器 (machine Controller) 會把該虛擬機加入之前創建的負載均衡器成為它的第一個成員。
  5. 此後,其他創建的虛擬機加入之前的控制面並加入負載均衡器成為其成員。
  6. 控制權從臨時集群交給創建的集群,主要的工作是把所有在臨時集群的定義通過 pivot 這個方法在新集群的 etcd 里加入 machines、cluster 等定義。
  7. 根據用戶的 Machines 定義創建工作節點,並作為 node 加入之前創建的新集群。
  8. 根據用戶的選擇(默認是刪除)刪除臨時集群。
  9. 從此用戶可以通過負載均衡器的 ip 和端口來訪問新的集群。

CAPO 加入負載均衡器的配置如下:

managedAPIServerLoadBalancer 代表創建負載均衡器與否,只有選擇 true 才會創建,否則就會創建一個單機的沒有高可用的 Kubernetes 控制面。

useOctavia 代表使用 Octavia 與否,openstack neutron lbaas 也支持負載均衡器,但 Octavia 提供更強大的功能,並且很快 neutron lbaas 也會被刪除,所以推薦使用 Octavia。

APIServerLoadBalancerFloatingIP 代表負載均衡器的 IP 地址。

<code>apiVersion: "cluster.k8s.io/v1alpha1"
kind: Cluster
metadata:
  name: test1
spec:
……
    providerSpec:
      value:
……
        managedAPIServerLoadBalancer: true
        useOctavia: true
        APIServerLoadBalancerFloatingIP: 1.2.3.4
        clusterConfiguration:
          controlPlaneEndpoint: 1.2.3.4:6443
          kubernetesVersion: 1.15.0/<code>

Cluster API 的演進和開發

Cluster API 的第一版 v1alpha1 有一些技術性的問題, 這篇文檔 有很詳細的介紹,總結如下:

  1. 單個 provider 提供基礎架構也提供 Kubernetes 會帶來很多限制,v1alpha1 中如果在一個提供商上增加新的 Kubernetes 的支持類如 Rancher、Openshift 等需要提供商提供支持。
  2. 每一個 Provider 都提供自己的配置和狀態,這個是通過 RAW 形式存在的因此沒有辦法驗證參數的有效性。
  3. 在同一個 Cluster 中不能支持不同的 provider,不能支持異構雲。

通過 v1alpha2 的演進能夠做到:

  1. 通過 Kubernetes 控制器管理(虛擬)機
  2. Bootstrap 實現可以在 provider 之間共享
  3. 支持 cloud-init、ignition 等不同的啟動引擎
  4. 在同一個 provider 上支持不同的 Kubernetes 發行版,例如原生 Kubernetes、openshift 等
  5. 儘早的驗證 provider 特定的內容符合 API 格式

CAPO 的 master 分支 正在快速跟進 Cluster API 的 v1alpha2 開發中。

結束語

本文介紹了 CoreOS 和 CAPO 的基本概念以及在 CAPO 中使用 CoreOS 的方法,以及如何在 CAPO 中使用負載均衡器創建和管理多個控制節點,最後介紹了 Cluster-API 從 v1alpha1 到 v1alpha2 的演進。


分享到:


相關文章: