在了解virtual-Kubelet之前,我們先了解下什么是Kubelet。
Kubelet 是在每個Node節點上運行的主要 “節點代理”。在Kubernetes集群中每個節點都會啟動一個kubelet進程,kubelet基于PodSpec來工作。每個Pod Spec是一個描述Pod的YAML或JSON對象。Kubelet接受通過各種機制(主要是通過Apiserver)提供的一組Pod Spec,并確保這些Pod Spec中描述的容器處于運行狀態且運行狀況良好。同時Kubelet還通過cAdvisor監控容器和節點資源,定期向上報當前節點的健康狀態以及資源使用情況,可以把Kubelet理解成[Server-Agent]架構中的Agent。
Virtual-Kubelet是基于Kubelet的典型特性實現,向上偽裝成Kubelet,從而模擬出Node對象,對接Kubernetes的原生資源對象;向下提供API,可對接其他資源管理平臺提供的Provider。不同的平臺通過實現Virtual-Kubelet定義的方法,允許節點由其對應的Provider提供(如ACI,AWS Fargate,IoT Edge,Tensile Kube等)支持,實現Serverless,或者將其擴展到如Docker Swarm、Openstack Zun等容器平臺中,也可以通過Provider納管其他Kubernetes集群,甚至是原生的IaaS層平臺(VMware、zstack、openstack)。
最好的描述是Kubernetes API on top,programmable back。
Virtual-Kubelet如何管理虛擬機是本文討論重點。
Virutal-Kubelet的架構
Virtual-Kubelet 模擬了Node資源對象,并負責對Pod調度到Virtual-Kubelet偽裝的虛擬節點之后,對Pod進行生命周期管理。
當前支持原生Kubernetes特性:
- 創建,刪除和更新Pod
- Container的日志,管理和監控
- 獲取單個Pod或多個Pod狀態
- 節點地址,節點容量,節點守護程序端點
- 管理操作系統
- 攜帶私有虛擬網絡
Virtual-Kubelet如何管理虛擬機?
虛擬機生命周期管理
Virtual-Kubelet在虛擬機調度和操作方面可以復用Kubernetes原生的資源對象,但Pod在Kubelet管理下的生命周期僅存在創建、運行和銷毀,實際對于虛擬機的開關機、備份和遷移等操作無法實現映射關系,因此對于復雜的生命周期管理,需要通過自定義CRD方式支持不同類型的IaaS平臺,每一個VM-CR對應一個IaaS層VM實例。
對于VM-CR操作主要可以分為兩類:
- 對VM運行狀態變更
- 創建和銷毀:可以對應一個VM-CR的create/delete
- VM啟停操作對應VM-CR replicas數量的變更:開機0→1關機1→0
- VM規格變更:修改VM-CR Spec資源定義
- kubectl logs/exec VM-pod:實現對Pod的訪問
- 對VM進行備份/遷移
- VM備份采用創建對應Backup-Job對象,通過與VM-CR實例pod親和方式,將Backup-Job調度置VM實際節點所運行的Virtual-Kubelet節點上,備份狀態與Job執行狀態一致
- VM遷移采用Kubernetes原生的節點調度方式,IaaS平臺每一個負載VM的物理機對應一個Kubernetes集群內的Virtual-Kubelet,VM-CR實例Pod的調度由Kubernetes控制面管理
虛擬機存儲管理
由于Virtual-Kubelet中Pod僅作為邏輯概念,IaaS層存儲無法與Kubernetes集群公用,但可抽象為Kubernetes原生定義的PV/PVC,PV的access mode能力依賴IaaS層能力,并需要實現對應平臺和底層存儲的Provider和Provisioner。
Virtual-Kubelet如何實現容器與虛擬機交互
容器和虛擬機互通
- Virtual-Kubelet對應的Node會上報節點上Pod的Endpoint,假定Kubernetes集群和IaaS層平臺部署在同一個二層網絡下,則集群內容器Pod可以訪問VM-Pod,但容器Pod對于VM-Pod不可見;
- 針對上一點可以通過Macvlan等網絡插件,將容器-Pod,降維至二層網絡上,實現容器-Pod和虛擬機互通,有一定硬件要求。
如何實現一套集群下虛擬機與容器的混合調度與資源隔離
- Virtual-Kubelet提供的是一個虛擬節點用來向Kubernetes上報Node對象和Pod的狀態和資源情況,虛擬機資源和集群內節點資源完全隔離;
- 在引入Virtual-Kubelet的情況下,需要對Virtual-Kubelet節點配置Taint和Tolerations,保證容器-Pod和VM-Pod調度分離。
服務發現
Virtual-Kubelet,通過Provider實現的API將IaaS層VM信息抽象成對應Pod對象的信息的方式來上報Endpoints,可以通過給CR添加no selector Service,待VM-Pod拉起后補充address至對應的Service。
Virutal-Kubelet適用場景
適用場景
Virtual-Kuberlet適合在已有IaaS層管理平臺和Kubernetes集群環境下進行二者的打通,實現在Kubernetes集群上統一管理容器和非容器平臺,同時由于Virtual-Kubelet在Serverless和納管其他已有容器平臺(Openstack Zun,Docker Swarm)方面也具有很高適配性,Virtual-Kubelet可以提供一套統一的API,方便開發者打通全流程。
Virtual-Kubelet的優缺點
優點
- 一個開源的Kubelet實現,使用Kubernetes源語,使構建、部署更簡單
- 提供Kubelet典型特性接口,Provider僅需實現對應服務管理平臺資源到Node和Pod對象特性的實現,不需要考慮如何訪問Kubernetes
- 靈活性高,Severless實踐、對接現有容器平臺、對接現有IaaS平臺均有一定前景
- Virtual-Kubelet設計將virtual-kubelet和Provider高度分離,Virtual-Kubelet使對于異構服務平臺具有很高的兼容性(不同架構如:ARM、S390x,不同CRI如:Kata、PodMan),不光是可以納關IaaS平臺對于其他Kubernetes集群也可以實現管理
缺點
- 將非集群內資源抽象成Node和Pod對象對資源使用上有一定局限性,很難提供超出原有kubelet和IaaS平臺能力范疇,IaaS深度整合需要自行實現CRD
- 僅能作為轉換器,用于容器和虛擬機統一管理時還是需要依托已有的平臺能力,無法像Kubevirt等方案作為一個單獨的Iaas管理平臺使用
Virtual-Kubelet開發及部署
開發自定義的Provider
Virtual-Kubelet項目本身并不提供Provider,而是提供一系列定義Kubelet典型操作的接口,開發者需要根據應用場景實現對應的Provider。使Kubernetes可以進行按需和幾乎即時的Container的計算、調度,而無需管理VM基礎結構,同時仍可利用可移植的KubernetesAPI。
實現遵循以下三個準則:
- 提供必要的后端管道(back-end plumbing),以在Kubernetes的Context中支持Pods,Containers和相關資源的的生命周期管理
- 符合Virtual-Kubelet當前提供的API
- 沒有訪問Kubernetes APIServer的權限,通過實現具有定義良好的回調機制來獲取Secrets或Configmap之類的數據
創建一個新的Provider主要需要通過調用Virtual-Kubelet提供的庫實現如下三個接口:
- PodLifecylceHandler:用于Pod生命周期的管理
type PodLifecycleHandler interface {
// CreatePod takes a Kubernetes Pod and deploys it within the provider.
CreatePod(ctx context.Context, pod *corev1.Pod) error
// UpdatePod takes a Kubernetes Pod and updates it within the provider.
UpdatePod(ctx context.Context, pod *corev1.Pod) error
// DeletePod takes a Kubernetes Pod and deletes it from the provider.
DeletePod(ctx context.Context, pod *corev1.Pod) error
// GetPod retrieves a pod by name from the provider (can be cached).
GetPod(ctx context.Context, namespace, name string) (*corev1.Pod, error)
// GetPodStatus retrieves the status of a pod by name from the provider.
GetPodStatus(ctx context.Context, namespace, name string) (*corev1.PodStatus, error)
// GetPods retrieves a list of all pods running on the provider (can be cached).
GetPods(context.Context) ([]*corev1.Pod, error)
}
- PodNotifier:該接口允許Provider提供異步通知Virtual-Kubelet有關Pod狀態更新的信息,如未實現該接口的話,Virtual-Kubelet會定期檢查所有Pod的狀態,在計劃運行大量Pod的場景中強烈推薦實現該接口
type PodNotifier interface {
// NotifyPods instructs the notifier to call the passed in function when
// the pod status changes.
//
// NotifyPods should not block callers.
NotifyPods(context.Context, func(*corev1.Pod))
}
- NodeProvider:NodeProvider負責通知虛擬小程序有關節點狀態更新的信息。Virtual-Kubelet將定期檢查節點的狀態并相應地更新Kubernetes,如果不打算額外定義Node特性,可以直接使用Virtual-Kubelet提供的NativeNodeProvider
type NodeProvider interface {
// Ping checks if the node is still active.
// This is intended to be lightweight as it will be called periodically as a
// heartbeat to keep the node marked as ready in Kubernetes.
Ping(context.Context) error
// NotifyNodeStatus is used to asynchronously monitor the node.
// The passed in callback should be called any time there is a change to the
// node's status.
// This will generally trigger a call to the Kubernetes API server to update
// the status.
//
// NotifyNodeStatus should not block callers.
NotifyNodeStatus(ctx context.Context, cb func(*corev1.Node))
}
- API Endpoints:用于實現kubectl logs和kubectl exec
部署
Provider部署簡單僅需要在要添加目標集群的主機中添加二進制程序并根據IaaS層配置啟動即可:
./bin/virtual-kubelet --provider="hc-vmware-provider" --exsi="X.X.X.X"