在macOS中添加Windows节点用于开发调试
前提
在macOS下,已经通过UTM创建了两台Linux arm64的虚拟机
已经部署了k8s 1.28.5
想要添加一个windows节点运行负载
安装Windows虚拟机
首先下载Windows镜像
主要要选择Windows Server 2019 以后的版本(才支持Kubernetes)
这里使用了CrystalFetch下载的ISO镜像,并选择了Windows Server 23H2的版本
可以看到这里包含了Azure Stack HCI
安装系统
⚠️ UTM 安装的时候在加载镜像之后立即按ESC键,否则无法安装
安装的时候选择模拟(速度很慢) 因下载的iso镜像是X64架构的,而本机是M2的芯片是arm架构的,所以只能选择模拟
安装一路默认,选择好镜像即可
安装的时候看到这个提示尽快按下任意一个键盘(比如Enter/Esc),否则会进入UEFI启动菜单
如果没任何操作的话,是不会进入到windows 安装页面的,而是下面这个
如果已经来到这里也没事,关闭虚拟机电源再进入重来一次
由于模拟的话实在太卡了,我安装的时候选择了
AzureStackHCICore, 这样安装的话是默认没有Windows的GUI管理界面的,但是可以通过命令行管理,甚至也能远程连接
接下来的设置没啥特殊。
最后安装完成的话会有个菜单,按照提示按下4, 开启远程桌面
网络设置
网卡和端口映射
编辑此虚拟机,这里添加了两个网络,一个模式选择了Emulated VLAN,这个是用于端口映射。另一个是Shared Network, 这个是用于和其他虚拟机(k8s互通的)
首先是Emulated VlAN网络设置如下映射,这是Windows的远程桌面
远程连接
接下来用Microsoft Remote Desktop连接上去
账号是:Administrator,密码在安装的时候有设置
连接上之后按下15进入命令行模式,接下来就和SSH操作差不多了
调整K8s集群原有配置
Calico 网络配置 strict affinity
ref: https://docs.tigera.io/calico/latest/getting-started/kubernetes/windows-calico/manual-install/quickstart#configure-strict-affinity-for-clusters-using-calico-networking
Linux控制平面使用Calico网络的,为了防止Linux 节点从Windows节点借用IP地址,需要配置strict affinity
值为 true
kubectl patch ipamconfigurations default --type merge --patch='{"spec": {"strictAffinity": true}}'
关闭ipipMode
因Windows不支持此模式,所以修改ipipMode
为Never:
kubectl edit ippools.crd.projectcalico.org
回到Windows继续安装K8s所需组件
安装containerd
在Windows上需要安装各种K8s需要的组件(containerd, kubelet, kube-proxy)
以下命令可能会出现网络不顺畅,重试几次
获取containerd安装脚本
Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/microsoft/Windows-Containers/Main/helpful_tools/Install-ContainerdRuntime/install-containerd-runtime.ps1" -o install-containerd-runtime.ps1
如果上面获取失败,可以自己在网络顺畅的机器上打开链接,然后创建一个脚本并拷贝内容编辑 notepad install-containerd-runtime.ps1
保存后安装containerd, 包括nerdctl, cni二进制文件,默认安装的containerd版本为1.6.6, 可以自行修改,比如notepad install-containerd-runtime.ps1
修改$ContainerDVersion = "1.7.15"
.\install-containerd-runtime.ps1
查看当前K8s集群的配置,找一个linux的控制平面获取kubeconfig的内容,等下要用到
root@utm-debian2:~# cat ~/.kube/config
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: xxx
#server: https://apiserver.cluster.local:6443
server: https://192.168.64.12:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: xxx
client-key-data: xxx=
创建K8s的配置目录以及配置文件
mkdir c:\k
New-Item c:\k\config
notepad c:\k\config
这里打开notepad之后把上一步获取到的配置贴上并保存,注意server处可能是域名,自己替换成apiserver 的IP,比如server: https://192.168.64.12:6443
或者把域名加入到windows 的hosts文件里面,比如 C:\Windows\System32\drivers\etc\Hosts
安装 Calico(和kubelet)
获取calico的windows安装脚本,这里用的是v3.25.1版本
Invoke-WebRequest -Uri https://github.com/projectcalico/calico/releases/download/v3.25.1/install-calico-windows.ps1 -OutFile c:\k\install-calico-windows.ps1
实际上calico的脚本不但能安装calico,还能安装kubernetes的二进制文件
这里指定了版本和CIDR,可以按需修改
c:\k\install-calico-windows.ps1 -ReleaseBaseURL "https://github.com/projectcalico/calico/releases/download/v3.25.0" -ReleaseFile "calico-windows-v3.25.0.zip" -KubeVersion "1.27.1" -DownloadOnly "yes" -ServiceCidr "10.96.0.0/22" -DNSServerIPs "10.96.0.10"
or 更新的版本
c:\k\install-calico-windows.ps1 -ReleaseBaseURL "https://github.com/projectcalico/calico/releases/download/v3.27.3" -ReleaseFile "calico-windows-v3.27.3.zip" -KubeVersion "1.28.5" -DownloadOnly "yes" -ServiceCidr "10.96.0.0/22" -DNSServerIPs "10.96.0.10"
因为这里需要从多个网站下载一些依赖组件比如
https://www.powershellgallery.com/packages/7Zip4Powershel
https://github.com/Microsoft/SDN/raw/master/Kubernetes/windows/hns.psm1
https://github.com/projectcalico/calico/releases/download/v3.27.2/
是有可能失败的,可以多试几次
失败处理
最有可能失败的是7Zip4Powershell和K8s的二进制,而下载7zip其实是为了解压k8s的压缩包。
所以如果实在不行的话可以提前在网络顺畅的机器下载好,然后放在这台windows上即可规避
具体操作:
下载压缩包 https://cdn.dl.k8s.io/release/v1.27.1/kubernetes-node-windows-amd64.tar.gz
解压,得到目录kubernetes/node下若干二进制文件
复制kubernetes/node下所有文件(kube-log-runner.exe、kube-proxy.exe、kubeadm.exe、kubectl-convert.exe,kubectl.exe,kubelet.exe)到 windows机器的c:\k目录下
在Windows节点上执行
notepad c:\k\install-calico-windows.ps1
进行编辑,将InstallK8sBinaries这一句注释掉,如下所示function PrepareKubernetes() { DownloadFiles ipmo -DisableNameChecking C:\k\hns.psm1 #InstallK8sBinaries # Prepull and tag the pause image for docker if (-not (Get-IsContainerdRunning)) { #... } }
继续执行
c:\k\install-calico-windows.ps1
…即可
执行完成后会下载并安装binary到c:\k
目录下面
添加环境变量,然后安装calico插件
$ENV:CNI_BIN_DIR="c:\program files\containerd\cni\bin"
$ENV:CNI_CONF_DIR="c:\program files\containerd\cni\conf"
$ENV:CALICO_DATASTORE_TYPE="kubernetes"
c:\calicowindows\install-calico.ps1
c:\calicowindows\start-calico.ps1
耐心等待几分钟,看到下面输出说明完成
Starting Calico...
This may take several seconds if the vSwitch needs to be created.
Waiting for Calico initialisation to finish...
Waiting for Calico initialisation to finish...StoredLastBootTime , CurrentLastBootTime 5/21/2023 8:21:24 AM
Waiting for Calico initialisation to finish...StoredLastBootTime , CurrentLastBootTime 5/21/2023 8:21:24 AM
Calico initialisation finished.
Done, the Calico services are running:
Status Name DisplayName
------ ---- -----------
Running CalicoFelix Calico Windows Agent
Running CalicoNode Calico Windows Startup
接下来安装kubelet 和kube-proxy服务,
c:\calicowindows\kubernetes\install-kube-services.ps1
防火墙设置
涉及kubelet的一些操作比如kubectl logs和kubectl exec命令需要和windows nodes节点进行通信,所以这里要开放入站连接100250端口和kubelet windows 服务联通
New-NetFirewallRule -Name 'Kubelet-In-TCP' -DisplayName 'Kubelet (node)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 10250
定制kubelet的启动参数:
kubelet会选定一个网卡再启动,所以这里可以选择适当的网卡,如果有多个网卡,那就选和控制节点网络能互通的网卡。
先运行ipconfig
,查看当前网络,在powershell中也可以执行Get-NetAdapter
,获取网卡名
比如这里我获取到的是网卡名称为”vEthernet (Ethernet1)”
PS C:\Windows\system32> ipconfig
Windows IP Configuration
Ethernet adapter vEthernet (Ethernet1):
Connection-specific DNS Suffix . :
IPv6 Address. . . . . . . . . . . : 2409:8a56:3443:7c30::1009
IPv6 Address. . . . . . . . . . . : 2409:8a56:3443:7c30:4536:6e06:9675:9552
Temporary IPv6 Address. . . . . . : 2409:8a56:3443:7c30:d31:18c9:a275:57f1
Link-local IPv6 Address . . . . . : fe80::4536:6e06:9675:9552%3
IPv4 Address. . . . . . . . . . . : 192.168.2.102
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 192.168.2.1
Ethernet adapter vEthernet (Calico_ep):
Connection-specific DNS Suffix . :
Link-local IPv6 Address . . . . . : fe80::5c13:f755:55fa:86e%25
IPv4 Address. . . . . . . . . . . : 100.112.118.66
Subnet Mask . . . . . . . . . . . : 255.255.255.192
Default Gateway . . . . . . . . . : 100.112.118.65
PS C:\Windows\system32>
PS C:\Windows\system32>
PS C:\Windows\system32>
PS C:\Windows\system32> Get-NetAdapter
Name InterfaceDescription ifIndex Status MacAddress LinkSpeed
---- -------------------- ------- ------ ---------- ---------
Ethernet1 Intel(R) 82574L Gigabit Network Co...#2 13 Up 00-0C-29-6F-7E-8A 1 Gbps
vEthernet (590be6e2a68... 36 Up 00-15-5D-89-68-93 1 Gbps
vEthernet (Ethernet1) Hyper-V Virtual Ethernet Adapter 3 Up 00-0C-29-6F-7E-8A 1 Gbps
接下来用notepad或者其他编辑器打开kubelet的配置脚本 notepad c:\calicowindows\kubernetes\kubelet-service.ps1
修改默认的InterfaceName变量为相应的网卡名vEthernet (Ethernet1)
# c:\calicowindows\kubernetes\kubelet-service.ps1
Param(
[string]$NodeIp="",
[string]$InterfaceName="vEthernet (Ethernet1))"
)
另外:
- K8s 1.26以上的版本,请移除或者注释掉参数
-logtostderr=true
- K8s 1.27以上的版本,请移除或者注释掉参数
-container-runtime=remote
保存退出
最后启动Kubernetes的服务
Start-Service kubelet
Start-Service kube-proxy
错误处理以及调试指南
日志查看
如果启动不了,可以看看一些日志
比如kubelet的服务可以查看 c:\k\kubelet-error.log 以及c:\k\kubelet.out.log
containerd日志?
kube-proxy运行日志: c:\k\kube-proxy.out.log
Calico运行日志:C:\CalicoWindows\logs
例: 如果kubelet长时间未注册到集群,可以查看kubelet的日志
看到kubelet的错误:
cat c:\k\kubelet-error.log
E0324 07:45:12.792485 5936 run.go:74] "command failed" err="failed to parse kubelet flag: unknown flag: --logtostderr=true"
根据日志修正c:\calicowindows\kubernetes\kubelet-service.ps1
即可
正常来说过一会kubelet就会将当前的windows节点注册到集群,用kubectl get node就能看到
root@utm-debian2:~# kubectl get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
utm-debian2 Ready control-plane 9d v1.28.5 192.168.2.101 <none> Debian GNU/Linux 12 (bookworm) 6.1.0-13-arm64 containerd://1.6.26
win-nog6jk08mf6 Ready <none> 23m v1.28.5 192.168.2.102 <none> Azure Stack HCI 10.0.25398.1 containerd://1.7.15
修复dns fallback到Default模式
c:\calicowindows\kubernetes\kubelet-service.ps1 设置 kubelet: "--cluster-dns=10.96.0.10",`
替换google的pause镜像
另外以上方式安装的containerd默认用的sandbox镜像是k8s.gcr.io/pause:3.6
显然这个镜像是需要科学上网的,但是也可以修改默认的pause镜像
notepad "c:\Program Files\containerd\config.toml"
修改sandbox_image 为 mcr.microsoft.com/oss/kubernetes/pause:3.6
然后重启containerd服务
Stop-Service containerd
Start-Service containerd
或者自己在其他节点手动下载,然后导入其他节点下载的pause镜像
sudo ctr i pull registry.k8s.io/pause:3.6 --platform windows
sudo ctr i export pause.windows.tar registry.k8s.io/pause:3.6 --platform windows
还可以使用高版本的powershell设置代理后再拉取:
#pause镜像不替换,设置代理后手动拉一次
$env:HTTP_PROXY = "socks5://192.168.2.100:7891"
$env:HTTPS_PROXY = "socks5://192.168.2.100:7891"
ctr -n k8s.io image pull registry.k8s.io/pause:3.8
验证:
kubectl run winpod-preview --image mcr.microsoft.com/windows/server:win10-21h1-preview --overrides '{"spec": {"nodeSelector": {"kubernetes.io/os": "windows"}}}'
root@utm-debian2:~# kubectl get po
NAME READY STATUS RESTARTS AGE
winpod-preview 0/1 Running 114 (100m ago) 13h
root@utm-debian2:~#
卸载
c:\calicowindows\kubernetes\uninstall-kube-services.ps1
c:\calicowindows\uninstall-calico.ps1
c:\k\kubectl.exe delete node <node_name>
ref:
- https://docs.tigera.io/calico/latest/getting-started/kubernetes/windows-calico/manual-install/quickstart
- https://microk8s.io/docs/add-a-windows-worker-node-to-microk8s