第12章 Kubernetes开发中的新功能
12.1 对Windows容器的支持
12.1.1 Windows Node部署
12.1.2 Windows容器支持的Kubernetes特性和发展趋势
12.2 对GPU的支持
12.2.1 环境准备
12.2.2 在容器中使用GPU资源
12.2.3 发展趋势
12.3 Pod的垂直扩缩容
12.3.1 前提条件
12.3.2 安装Vertical Pod Autoscaler
12.3.3 为Pod设置垂直扩缩容
12.3.4 注意事项
12.4 Kubernetes的演进路线和开发模式
本章对Kubernetes开发中的一些新功能进行介绍,包括对Windows容器的支持、对GPU的支持、Pod的垂直扩缩容,并讲解Kubernetes的演进路线(Roadmap)和开发模式。
12.1 对Windows容器的支持
Kubernetes从1.5版本开始,就引入了管理基于Windows Server 2016操作系统的Windows容器的功能。
随着Windows Server version 1709的发布,Kubernetes 1.9对Windows容器的支持提升为Beta版,Kubernetes 1.14对Windows容器的支持提升为GA稳定版。
目前Windows Server的最新版本是2019,与Kubernetes的对接更加成熟。
目前Windows Server可以作为Node加入Kubernetes集群中,集群的Master仍需在Linux环境中运行。
在Kubernetes上改进了Windows容器的一些关键功能,包括:
对Pod网络模型的支持,可为一个Pod内的多个容器设置共享的网络命名空间(共享kernel模式);
为每个Pod都设置了单个网络Endpoint,以降低网络复杂性;
使用Windows Server的Virtual Filtering Platform (VFP) Hyper-v Switch Extension技术,实现了类似于Linux iptables的负载均衡器;
Pod支持容器运行时接口(CRI)和Node的统计信息;
支持使用kubeadm命令将Windows Server节点添加到集群中。
下面对Windows Node部署,以及Kubernetes支持的Windows容器特性和发展趋势进行讲解。
12.1.1 Windows Node部署
需要在Windows Server上安装的Kubernetes Node相关组件包括Docker、kubelet、kube-proxy和kubectl。
Docker版本要求在18.03及以上,推荐使用最新版本。
可参考官方文档https://docs.docker.com/install/windows/docker-ee/#use-a-script-to-install-docker-ee在Windows Server上安装Docker。
从Kubernetes的版本发布页面(https://github.com/kubernetes/kubernetes/releases)下载Windows Node相关文件,
例如Kubernetes Windows Node 1.14的下载页面为https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.14.md#node-binaries,
在该页面下载kubernetes-node-windows-amd64.tar.gz文件,将其解压缩后得到可执行文件kubelet.exe、kube-proxy.exe、kubectl.exe和kubeadm.exe,如图12.1所示。
下面介绍如何在Windows Server 2019上搭建Kubernetes Node,
详细的操作文档请参考https://docs.microsoft.com/en-us/virtualization/windowscontainers/kubernetes/getting-startedkubernetes-windows。
1)制作kubelet运行容器所需的pause镜像。
下载Microsoft提供的nanoserver镜像(需要与Windows Server的版本相匹配):
C:\> docker pull mcr.microsoft.com/windows/nanoserver:1809
将该镜像重命名为microsoft/nanoserver:latest:
C:\> docker tag mcr.microsoft.com/windows/nanoserver:1809 microsoft.com/nanoserver:latest
编写Dockerfile:
FROM microsoft.com/nanoserver
CMD cmd /c ping -t localhost
运行docker build命令制作pause镜像,并将镜像名设置为kubeletwin/pause:
C:\> docker build -t kubeletwin/pause
2)将Kubernetes Windows Node的压缩包文件解压缩到C:\k目录下,得到kubelet.exe、kube-proxy.exe和kubectl.exe文件。
3)将连接Kubernetes Master所需的kubeconfig文件和SSL安全证书文件从Linux Node复制到C:\k目录下,将文件名改为config。
可以使用kubectl.exe命令验证能否访问Master:
[Environment]::SetEnvironmentVariable("KUBECONFIG","C:\k\config",[EnvironmentVariableTarget]::User)
C:\k> kubectl config view
4)选择一个容器网络方案,目前支持的网络方案有如下3种:
(1)基于3层路由的网络方案。
需要Top of Rack(机柜上面安装的)交换机或路由器的支持,Windows节点的容器IP池应由该交换机或路由器管理。
在Windows节点上需要创建一个虚拟的l2bridge网桥,用于连通Pod IP与物理机之间的网络。
ToR交换机或路由器负责Pod的IP地址分配,并负责设置Pod IP与其他物理机联通的静态路由规则。
如图12.2所示为基于3层路由的容器网络方案,这种网络方案与Linux的直接路由方案比较相似,但是对交换机或路由器的要求较高。
在图12.2中,物理机网络为10.127.132.*,Linux Master的IP地址为10.127.132.128,Linux Node的IP地址为10.127.132.129,Windows Node的IP地址为10.127.132.213。
Linux Node上的容器网络IP范围为 10.10.187.0/26,Windows Node上的容器网络IP范围为10.10.187.64/26,
要求ToR交换机或路由器管理Windows容器IP地址的分配并设置到其他主机的路由规则。
(2)基于Open vSwitch的网络方案。
这种方案依赖Open vSwitch,部署流程比较复杂。如图12.3所示为通用的网络部署架构。
(3)基于Flannel的网络方案。
在Linux上为Kubernetes搭建CNI网络的Flannel系统时,要求Linux的Kubernetes环境也使用Flannel网络,能够实现Windows容器网络与Linux容器网络的互联互通。
5)下载Windows Node的部署脚本和配置文件并修改配置。
目前Kubernetes在Windows Node上的部署脚本和CNI网络插件可以从GitHub代码库(https://github.com/Microsoft/SDN/tree/master/Kubernetes)下载,
将该代码库windows子目录的文件下载并保存到C:\k目录下,再从另外几个目录下载CNI网络插件相关的文件,例如flannel、wincni等,如图12.4所示。
6)以Flannel为例配置CNI网络的关键信息。
下载https://github.com/Microsoft/SDN/tree/master/Kubernetes/flannel中的文件并将其保存到C:\k目录。
还需要将Flannel的可执行文件flanneld.exe保存到C:\flannel目录下。
start-kubelet.ps1脚本中的关键网络配置参数如下:
Param(
[parameter(Mandatory = $false)] $clusterCIDR="10.244.0.0/16",
[parameter(Mandatory = $false)] $KubeDnsServiceIP="169.169.0.100",
[parameter(Mandatory = $false)] $serviceCIDR="169.169.0.0/16",
[parameter(Mandatory = $false)] $KubeDnsSuffix="svc.cluster.local",
[parameter(Mandatory = $false)] $InterfaceName="Ethernet",
[parameter(Mandatory = $false)] $LogDir="C:\k\logs",
[ValidateSet("process","hyperv")] $IsolationType="process",
$NetworkName = "cbr0",
[switch] $RegisterOnly
)
对于以下参数,可以在执行start.ps1时用命令行参数指定,也可以直接修改start-kubelet.ps1脚本进行设置。
clusterCIDR:用于设置Flannel的容器IP池,需要与kube-controller-manager的--cluster-cidr保持一致。
KubeDnsServiceIP:将其设置为Kubernetes集群DNS服务的ClusterIP,例如169.169.0.100。
serviceCIDR:将其设置为Kubernetes集群Service的ClusterIP池,例如169.169.0.0/16。
InterfaceName:Windows主机的网卡名,例如Ethernet。
LogDir:日志目录,例如C:\k\logs。
在Update-CNIConfig函数内设置Nameservers(DNS服务器)的IP地址,例如169.169.0.100:
function Update-CNIConfig($podCIDR){
...
}
7)运行start.ps1脚本,将Windows Node加入Kubernetes集群:
.\tart.ps1 -ManagementIP "192.168.18.9" -ClusterCIDR "10.244.0.0/16" -ServiceCIDR "169.169.0.0/16" -KubeDnsServiceIP "169.169.0.100"
将其中的-ManagementIP参数设置为Windows Node的主机IP地址。
该脚本的启动过程如下。
(1)创建一个名为External、类型为L2Bridge的HNSNetwork虚拟网卡,其管理IP为Windows主机IP,如图12.5所示。
(2)启动flanneld程序,创建一个名为cbr0、类型为L2Bridge的虚拟网卡(HNSNetwork),将其作为容器网络的网桥,之后flanneld正常退出,如图12.6所示。
(3)在名为cbr0的虚拟网卡创建成功后,在一个新的powershell窗口启动kubelet,如图12.7所示。
(4)在一个新的powershell窗口启动kube-proxy,如图12.8所示。
(5)在脚本启动成功之后,可以在Master上查看新加入的Windows Node:
# kubectl get nodes
查看这个Node的Label,可以看到其包含“kubernetes.io/os=windows”的Label,与Linux Node有所区分(Linux Node的标签为“kubernetes.io/os=linux”):
# kubectl get no --show-labels
8)在Windows Node上部署容器应用。
现在,我们可以像在Linux Node上部署容器应用一样,在Windows Node上部署Windows容器应用。
下面是一个Web服务示例,可以从https://github.com/Microsoft/SDN/blob/master/Kubernetes/flannel/l2bridge/manifests/simpleweb.yml获得YAML配置文件,
其中容器镜像使用的是mcr.microsoft.com/windows/servercore:1809,并通过powershell命令行启动了一个Web服务。
在Deployment的配置中需要设置nodeSelector为“kubernetes.io/os: windows”,以将Windows容器调度到Windows Node上:
用kubectl命令完成部署:
# kubectl apply -f simpleweb.yml
在Pod创建成功后,查看Pod的状态:
# kubectl get pod -o wide
查看Service的信息:
# kubectl get svc win-webserver
下面在Linux环境中访问Windows容器的服务。
使用容器IP访问Windows容器的服务:
# curl 10.244.2.20:80
使用服务IP访问Windows容器的服务:
# curl 169.169.219.15:80
对于类型为NodePort的服务,通过Windows Server的IP和NodePort也能访问Windows容器的服务:
# curl 192.168.18.9:40001
在Windows环境中使用容器IP或服务IP也能访问Windows容器的服务:
C:\> curl -UseBasicParsing 10.244.2.20:80
12.1.2 Windows容器支持的Kubernetes特性和发展趋势
Kubernetes在1.14版本中对Windows容器的支持达到GA稳定版,要求Windows Server的版本为Windows Server 2019,
支持的功能特性包括:
支持将Secret或ConfigMap挂载为环境变量或文件;
Volume存储卷支持emptyDir和hostPath;
支持的持久化存储卷PV类型包括FlexVolume(SMB+iSCSI类型)、AzureFile和AzureDisk;
支持livenessProbe和readinessProbe健康检查机制;
支持容器的postStart和preStop命令;
支持CRI类型为Dockershim;
支持的控制器包括ReplicaSet、ReplicationController、Deployments、StatefulSets、DaemonSet、Job和CronJob;
支持Service的类型包括NodePort、ClusterIP、LoadBalancer、ExternalName和Headless Service;
支持CPU和内存的资源限制;
支持Resource Quotas;
支持基于任意指标数据的HPA机制;
支持的CNI网络插件包括Azure-CNI、OVN-Kubernetes和Flannel(VxLAN和Host-Gateway模式)。
kubelet.exe和kube-proxy.exe可以以Windows服务的形式运行。
已知的功能限制包括:
不支持容器以特权模式运行;
不支持hostNetwork网络模式;
不支持CSI插件;
不支持NFS类型的存储卷;
在挂载存储卷时无法设置subpath;
Windows容器内的OS版本必须与宿主机OS的版本一致,否则容器无法启动。
Windows容器在Kubernetes上计划完成的功能包括:
支持更多的Overlay网络方案,包括Calico CNI插件;
支持更多的CRI容器运行时;
支持通过kubeadm安装Windows Node;
支持基于Hyper-V虚拟化技术在1个Pod中包含多个容器(目前在1个Pod中只能有1个容器);
支持设置terminationGracePeriodSeconds实现对Pod的优雅删除;
支持设置run_as_username以自定义用户名运行容器内的程序。
可以预见,在不久的将来,Kubernetes能完善Windows容器和Linux容器的混合管理,实现跨平台的容器云平台。
12.2 对GPU的支持
随着人工智能和机器学习的迅速发展,基于GPU的大数据运算越来越普及。
在Kubernetes的发展规划中,GPU资源有着非常重要的地位。
用户应该能够为其工作任务请求GPU资源,就像请求CPU或内存一样,而Kubernetes将负责调度容器到具有GPU资源的节点上。
目前Kubernetes对NVIDIA和AMD两个厂商的GPU进行了实验性的支持。
Kubernetes对NVIDIA GPU的支持是从1.6版本开始的,对AMD GPU的支持是从1.9版本开始的,并且都在快速发展。
Kubernetes从1.8版本开始,引入了Device Plugin(设备插件)模型,为设备提供商提供了一种基于插件的、无须修改kubelet核心代码的外部设备启用方式,
设备提供商只需在计算节点上以DaemonSet方式启动一个设备插件容器供kubelet调用,即可使用外部设备。
目前支持的设备类型包括GPU、高性能NIC卡、FPGA、InfiniBand等,
关于设备插件的说明详见官方文档https://kubernetes.io/docs/concepts/extend-kubernetes/computestorage-net/device-plugins。
下面对如何在Kubernetes中使用GPU资源进行说明。
12.2.1 环境准备
(1)在Kubernetes的1.8和1.9版本中,需要在每个工作节点上都为kubelet服务开启--feature-gates="DevicePlugins=true"特性开关。
该特性开关从Kubernetes 1.10版本开始默认启用,无须手动设置。
(2)在每个工作节点上都安装NVIDIA GPU或AMD GPU驱动程序,如下所述。
使用NVIDIA GPU的系统要求包括:
NVIDIA驱动程序的版本为361.93及以上;
nvidia-docker的版本为2.0及以上;
配置Docker默认使用NVIDIA运行时;
Kubernetes的版本为1.11及以上。
Docker使用NVIDIA运行时的配置示例(通常配置文件为/etc/docker/daemon.json)如下:
...
NVIDIA设备驱动的部署YAML文件可以从NVIDIA的GitHub代码库https://github.com/NVIDIA/k8s-device-plugin/blob/v1.11/nvidia-device-plugin.yml获取:
...
使用AMD GPU的系统要求包括:
服务器支持ROCm(Radeon Open Computing platform);
ROCm kernel驱动程序或AMD GPU Linux驱动程序为最新版本;
Kubernetes的版本为1.10及以上。
AMD设备驱动的部署YAML文件可以从NVIDIA的GitHub代码库(https://github.com/RadeonOpenCompute/k8s-device-plugin/blob/master/k8s-ds-amdgpu-dp.ya ml)获取:
...
在完成上述配置后,容器应用就能使用GPU资源了。
12.2.2 在容器中使用GPU资源
GPU资源在Kubernetes中的名称为nvidia.com/gpu(NVIDIA类型)或amd.com/gpu(AMD类型),可以对容器进行GPU资源请求的设置。
在下面的例子中为容器申请1个GPU资源:
...
目前对GPU资源的使用配置有如下限制:
GPU资源请求只能在limits字段进行设置,系统将默认设置requests字段的值等于limits字段的值,不支持只设置requests而不设置limits;
在多个容器之间或者在多个Pod之间不能共享GPU资源;
每个容器只能请求整数个(1个或多个)GPU资源,不能请求1个GPU的部分资源。
如果在集群中运行着不同类型的GPU,则Kubernetes支持通过使用Node Label(节点标签)和Node Selector(节点选择器)将Pod调度到合适的GPU所属的节点。
1.为Node添加合适的Label标签
对于NVIDIA类型的GPU,可以使用kubectl label命令为Node设置不同的标签:
# kubectl label nodes <node-with-k80> accelerator=nvidia-tesla-k80
# kubectl label nodes <node-with-p100> accelerator=nvidia-tesla-p100
对于AMD类型的GPU,可以使用AMD开发的Node Labeller工具自动为Node设置合适的Label。
Node Labeller以DaemonSet的方式部署,可以从https://github.com/RadeonOpenCompute/k8s-device-plugin/blob/master/k8s-ds-amdgpu-labeller.yaml下载YAML配置文件。
在Node Labeller的启动参数中可以设置不同的Label以表示不同的GPU信息。
目前支持的Label如下:
(1)Device ID,启动参数为-device-id。
(2)VRAM Size,启动参数为-vram。
(3)Number of SIMD,启动参数为-simd-count。
(4)Number of Compute Unit,启动参数为-cu-count。
(5)Firmware and Feature Versions,启动参数为-firmware。
(6)GPU Family, in two letters acronym,启动参数为-family,family类型以两个字母缩写表示,完整的启动参数为family.SI、family.CI等。
其中,SI的全称为Southern Islands;CI的全称为Sea Islands;KV的全称为Kaveri;VI的全称为Volcanic Islands;CZ的全称为Carrizo;AI的全称为Arctic Islands;RV的全称为Raven。
通过Node Labeller工具自动为Node设置的Label示例如下:
# kubectl describe node cluster-node-23
2.设置Node Selector指定调度Pod到目标Node上
以NVIDIA GPU为例:
...
上面的配置可确保将Pod调度到含有“accelerator=nvidia-tesla-k80”Label的节点运行。
12.2.3 发展趋势
发展趋势如下:
GPU和其他设备将像CPU那样成为Kubernetes系统的原生计算资源类型,以Device Plugin的方式供kubelet调用。
目前的API限制较多,Kubernetes未来会有功能更丰富的API,能支持以可扩展的形式进行GPU等硬件加速器资源的供给、调度和使用。
Kubernetes将能自动确保使用GPU的应用程序达到最佳性能。
12.3 Pod的垂直扩缩容
Kubernetes在1.9版本中加入了对Pod的垂直扩缩容(简称为VPA)支持,
这一功能使用CRD的方式为Pod定义垂直扩缩容的规则,根据Pod的运行行为来判断Pod的资源需求,从而更好地为Pod提供调度支持。
该项目的地址为https://github.com/kubernetes/autoscaler,其中包含了三个不同的工具,分别是:
能够在AWS、Azure和GCP上提供集群节点扩缩容的ClusterAutoScaler,已经进入GA阶段;
提供Pod垂直扩缩容的Vertical Pod Autoscaler,目前处于Beta阶段;
Addon Resizer,是Vertical Pod Autoscaler的简化版,能够根据节点数量修改Deployment资源请求,目前处于Beta阶段。
12.3.1 前提条件
垂直扩缩容目前的版本为0.4,需要在Kubernetes 1.11以上版本中运行。
该组件所需的运行指标由Metrics Server提供,因此在安装Autoscaler前要先启动Metrics Server。
12.3.2 安装Vertical Pod Autoscaler
首先使用Git获取Autoscaler的源码:
# git clone https://github.com/kubernetes/autoscaler.git
下载结束之后,执行如下脚本,启动VPA:
# autoscaler/vertical-pod-autoscaler/hack/vpa-up.sh
可以看到,在安装过程中生成了常见的Deployment、Secret、Service及RBAC内容,还生成了两个CRD,接下来会用新生成的CRD设置Pod的垂直扩缩容。
12.3.3 为Pod设置垂直扩缩容
在下载的Git代码中包含一个子目录example,可以使用其中的redis.yaml来尝试使用VPA功能。
查看其中的redis.yaml文件,可以看到VPA的定义:
# cat autoscaler/vertical-pod-autoscaler/examples/redis.yaml
...
该定义非常简短:对名称为redis-master的Deployment进行自动垂直扩缩容。
在https://git.io/fhAeY页面可以找到该对象的完整定义,除了包括targetRef,还包括如下内容:
(1)UpdatePolicy:用于指定监控资源需求时的操作策略。
UpdateMode:默认值为Auto。
Off:仅监控资源状况并提出建议,不进行自动修改。
Initial:在创建Pod时为Pod指派资源。
Recreate:在创建Pod时为Pod指派资源,并且在Pod的生命周期中可以通过删除、重建Pod,将其资源数量更新为Pod申请的数量。
Auto:目前相当于Recreate。
(2)ResourcePolicy:用于指定资源计算的策略,如果这一字段被省略,则将会为在targetRef中指定的控制器生成的所有Pod的容器进行资源测算并根据UpdatePolicy的定义进行更新。
ContainerName:容器名称,如果为“*”,则对所有没有设置资源策略的容器都生效。
Mode:为Auto时,表示为指定容器启用VPA;为Off时,表示关闭指定容器的VPA。
MinAllowed:最小允许的资源值。
MaxAllowed:最大允许的资源值。
通过kubectl将测试文件提交到集群上运行:
# kubectl apply -f autoscaler/vertical-pod-autoscaler/examples/redis.yaml
在创建结束之后,VPA会监控资源状况,大约5分钟后重新获取VPA对象的内容:
# kubectl describe vpa redis-vpa
可以看到,在VPA对象中已经有了新的推荐设置。
接下来查看Redis的Pod资源请求:
# kubectl describe pod redis-master-xxx
不难看出,Pod的资源状况和Deployment中的原始定义已经不同,和VPA中的推荐数量一致。
12.3.4 注意事项
注意事项如下:
VPA对Pod的更新会造成Pod的重新创建和调度。
对于不受控制器支配的Pod,VPA仅能在其创建时提供支持。
VPA的准入控制器是一个Webhook,可能会和其他同类Webhook存在冲突,从而导致无法正确执行。
VPA无法和使用CPU、内存指标的HPA共用。
VPA能够识别多数内存不足的问题,但并非全部。
尚未在大规模集群上测试VPA的性能。
如果多个VPA对象都匹配同一个Pod,则会造成不可预知的后果。
VPA目前不会修改limits字段的内容。
12.4 Kubernetes的演进路线和开发模式
Kubernetes将每个版本的待开发功能由SIG-Release小组进行文档管理和发布,
网址为https://github.com/kubernetes/sig-release,可以跟踪每个大版本的功能列表,如图12.9所示。
以release-1.14为例,从release-1.14.md文档中可以查看这个版本的详细信息,如图12.10所示。
版本发布的详细时间表如图12.11所示。
单击页面链接“Enhancements Tracking Sheet”,可以查看该版本所包含的全部功能列表,按开发阶段分为Alpha、Beta和Stable三个类别,可以直观地看到各功能模块的实现阶段。
每个功能都有HTTP链接,可以单击该链接跳转至GitHub中的相关issue页面,进一步查看该功能的详细信息。
在WIP Features by Release表中还可以看到各功能特性在Kubernetes各版本中的开发过程,如图12.12所示。
每个版本中的每个Feature都由一个特别兴趣小组(Special Interest Group,SIG)负责开发和维护,
各SIG小组的介绍可以在https://github.com/kubernetes/community/blob/master/sig-list.md找到,如图12.13所示。
目前已经成立的SIG小组有30个,涵盖了安全、自动扩缩容、大数据、AWS云、文档、网络、存储、调度、UI、Windows容器等方方面面,为完善Kubernetes的功能群策群力,共同开发。
有兴趣、有能力的读者可以申请加入感兴趣的SIG小组,并可以通过Slack聊天频道与来自世界各地的开发组成员开展技术探讨和解决问题。
同时,可以参加SIG小组的周例会,共同参与一个功能模块的开发工作。