【作者】中国农业银行研发中心 张少博
一、 引言
容器化技术是当今技术浪潮中支撑微服务和DevOps的重要推动力量。虽说Docker容器技术源自Linux内核相关技术,但微软、Docker及Kubernetes社区也在不断完善Windows操作系统对容器化的支持。自v1.14版本起,Kubernetes对Windows容器的支持进入稳定阶段。本文试从Windows容器化技术相关概念出发,对Windows .NET应用上云之路的相关问题进行探讨。
二、 Windows容器化技术
(一) Windows容器类型
相对于传统硬件虚拟化技术,容器技术更加轻量,其代价是容器中应用的运行仍一定程度上依赖于宿主机的操作系统内核提供的能力,多个容器共享宿主机的操作系统内核。也正是因为这个原因,Windows容器无法在Linux上运行,Linux容器也无法在Windows上运行。为提供容器化能力,Windows自Server 2016版开始逐渐加入了内核命名空间、控制组群、分层文件系统等内核功能,以提供类似Linux的容器化能力。
事实上,Windows支持两种类型的容器运行时:进程隔离和Hyper-V隔离。两种隔离模式可以在运行容器时以参数方式指定。
进程隔离,也称为Windows Server Containers,Windows Server上的默认隔离模式。在该模式下,宿主机上的多个容器共用该宿主机的操作系统内核,有一定的安全风险,只适用于私有云环境。同时由于共享内核,容器的内核版本应与宿主机的内核版本保持一致,即Windows Server 2019宿主机上只能运行Windows Server 2019的容器。
Hyper-V隔离,是上述模式的扩展,Windows 10上的默认隔离模式。在该模式下,每个容器独立运行于高度优化的虚拟机至上,不共享宿主机内核,因此可以运行其他版本的内核甚至是Linux内核。但需要注意的是只能运行相同或更老版本的内核,如Windows Server 2019宿主机除了可以运行Windows Server 2019容器外,还可以运行Windows Server 2016容器,而无法运行1903或者1909版本的容器。
(二) Linux容器 vs Windows容器
与Linux容器相比,Windows容器存在以下主要特点:
1、如上所述,Windows容器内核版本与宿主机内核版本存在强绑定,即使使用Hyper-V模式也只是增加了对运行更旧内核版本的容器的支持。而在Linux上,只要内核版本高于3.10,任何版本内核的容器都可以运行。
2、基础镜像较大。完整的Windows Server镜像servercore大小约为1.5G,最小化的基础镜像nanoserver约为100M,而对应的alpine Linux只有5M左右。
3、Hyper-V隔离理论上还能支持Linux容器。LCOW(Linux Containers on Windows)就是使用Hyper-V隔离支持Linux容器,在最新的Docker for Windows中可以作为一项实验功能开启。即将发布的WSL2(Windows Subsystem for Linux 2)由于使用了Hyper-V,也可以实现对Linux容器的支持。
(三) Kubernetes对Windows的局限
Kubernetes对Windows的支持还在不断成熟过程中,目前已知存在以下局限性:
1、 最低要求Windows Server 2019及Docker EE 1809。
2、 Kubeadm对纳管Windows节点的支持尚为beta阶段,目前纳管Windows的方式较繁琐。
3、 目前只支持进程隔离模式,在该模式下无法对容器内存上限作出限制。
4、 Windows支持的CNI插件极少,异构集群还需要插件同时支持Linux和Windows节点,因此Flannel成为最常用的选择。目前对Flannel的host-gw后端支持为Stable,对vxlan后端支持仍为Alpha。
5、 不支持NFS类型的存储。
三、 已有.NET应用迁移上云
(一) 测试环境搭建
目前Kubernetes对Windows节点的支持方式为作为工作节点纳管,本次测试环境为Kubernetes v1.17,Windows节点为Windows Server 2019、Docker EE 18.09,网络方案选择为Flannel的vxlan模式。Windows节点上的Flanneld和Kube-Proxy支持以Windows服务或者DaemonSet方式运行,本次选择了更为稳定的Windows服务方式,经验证节点重启后可以自动加入集群。
(二) 基础镜像选择
微软提供提供四种基础镜像供不同种类的应用选择,见下表:
其中Nano Server和Windows Server Core为最常用的选择,Nano Server的优势是仅为.NET Core构建,镜像大小相比Server Core小得多。Server Core除提供.NET Framework支持外,还内置了PowerShell、WMI等功能。
我行现有的.NET Framwork应用上云,如不考虑改造为.NET Core应用,则应选择Windows Server Core作为基础镜像。
基于Windows Server Core,微软又提供了如下镜像供选择:
根据应用种类和场景选择基础镜像后,再根据内核版本确定镜像标签,即可完成基础镜像选择。需要注意的是,微软官方仓库里的镜像每月会有更新,为保持一致性,在下载镜像时最好在tag中明确指定哪个月份的更新。
(三) 镜像制作
在本小节,我们使用iis作为基础镜像制作一个最简单的网站镜像。Dockerfile如下:
其中index.html内容为:
使用如下命令进行打包:
- docker build -t iis-site .
(四) 本地运行
使用如下命令在本地运行:
- docker run --rm -d --name iis -p 5000:80 iis-site
在浏览器中访问localhost:5000,出现如下页面证明运行成功。
可以使用命令docker exec -it iis powershell登入运行的容器,并查看.NET Framework版本为4.8,如下图。
上图中有许多功能未开启,可以使用Add-WindowsFeature在制作镜像时添加Windows功能。
和Linux容器只能看到一个进程不同,在Windows容器中可以看到除应用外的其他多个进程。
(五) 在k8s上部署
在镜像制作完成后,就可以尝试在Kubernetes上部署了,service和deployment的使用方式和Linux容器一样,这里不再赘述。由于是Linux和Windows节点共存的异构集群,需要通过类似"kubernetes.io/os": windows的nodeSelector来指定Windows容器在Windows节点上调度。
参考资料:
《Learning Windows Server Containers》 by Srikanth Machiraju
https://v1-16.docs.kubernetes.io/docs/setup/production-environment/windows/user-guide-windows-nodes/
https://docs.microsoft.com/en-us/virtualization/windowscontainers/
https://kubernetes.io/docs/setup/production-environment/windows/intro-windows-in-kubernetes/