k8s纳管windows节点

460 阅读10分钟

Windows 基本知识

检测管道是否存在

检测命令管道是否存在;在 PowerShell 中,命名管道路径使用 \.\pipe 作为命名空间的前缀。

if (-not(Test-Path "//./pipe/containerd-containerd")) {
    Write-Error "ContainerD service was not detected - please install and start containerD before calling PrepareNode.ps1 with -ContainerRuntime containerD"
    exit 1
}

添加环境变量

这是查看系统级别的环境变量
[Environment]::GetEnvironmentVariable("PATH", [EnvironmentVariableTarget]::Machine)

这是查看当前用户级别下的环境变量
$env:path 

[Environment]::SetEnvironmentVariable("PATH", $newPath, [EnvironmentVariableTarget]::Machine)

查看监听端口

查看 netstat -ano windows 机器的监听端口
netstat -ano | select-string "10248"  这里面的 selec-string 就类似于 grep 的用法

辅助设置

安装 gvim

  1. 下载 github.com/vim/vim-win…

  2. 设置环境变量,参考:windows10安装配置vim_windows vim配置-CSDN博客

安装 OpenSSH

参考:Get started with OpenSSH for Windows

需要先安装 ssh-server

windows 安装 ssh-server

步骤如下:

  1. Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*' 查看windows server是否安装
Name  : OpenSSH.Client~~~~0.0.1.0
State : NotPresent

Name  : OpenSSH.Server~~~~0.0.1.0
State : NotPresent                    代表未安装
  1. 安装 OpenSSH Server(安装可能比较耗时,耐心等待)
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

输出如下即代表安装成功

Path          :
Online        : True
RestartNeeded : False

  1. 启动 sshd 服务
Start-Service sshd

配置免密登录

Windows 免密登录有两种方式:分为公钥放在用户家目录下或者管理员目录下

方法一:放在用户家目录下

步骤如下

  1. 将公钥复制到 \UsersAdmin.ssh\authorized_keys 文件下(这里要登录哪个用户就放在哪个用户下)
  2. 请务必检查 C:\ProgramData\ssh下(首次启动sshd后会生成该文件夹),打开 sshd_config 文件;检查下面几项
请务必确保下面这个 PubkeyAuthentication 被注释掉或者值是yes,因为默认值也是Yes
PubkeyAuthentication yes

确保以下2条有注释掉 重点,这两行要注释
#Match Group administrators
#       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
  1. 重启 sshd 服务 Restart-Service sshd
  2. ssh admin@hostIP 远程登录,注意这里是 admin 用户

方法二:放在管理员家目录下

  1. 将公钥复制到 C:\ProgramData\ssh\administrators_authorized_keys 这个文件下
  2. 检查 C:\ProgramData\ssh\sshd_config 文件,确保下面的这个不能被注释
Match Group administrators
       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
  1. 重启 sshd 服务 Restart-Service sshd

如果SSH一直连接不上,记得在 sshd_config 文件里面把日志打开,则对应的日志就会输出到 C:\ProgramData\ssh\logs\sshd.log

 # Logging
 #SyslogFacility AUTH
 #LogLevel INFO
 # 添加日志打印
 SyslogFacility LOCAL0
 LogLevel DEBUG3

前置知识

HostProcess

Windows HostProcess 容器让你能够在 Windows 主机上运行容器化负载。 这类容器以普通的进程形式运行,但能够在具有合适用户特权的情况下, 访问主机网络名字空间、存储和设备。 HostProcess 容器可用来在 Windows 节点上部署网络插件、存储配置、设备插件、kube-proxy 以及其他组件, 同时不需要配置专用的代理或者直接安装主机服务

ssm

安装组件总览

image.png

安装 Containerd

目的

安装 runitme,也可使用 docker

安装命令

我们下面使用的安装命令是windows官方的安装脚本;containerd 官方也有一份专门的安装脚本(前者就是把后者包装了一层)参考链接如下

# Download and extract desired containerd Windows binaries
$Version="1.6.4"
curl.exe -L https://github.com/containerd/containerd/releases/download/v $Version /containerd- $Version -windows-amd64 .tar.gz -o containerd -windows-amd64 .tar.gz
tar.exe xvf .\containerd -windows-amd64 .tar.gz

# Copy and configure
Copy-Item -Path ".\bin" -Destination "$Env:ProgramFiles\containerd" -Recurse -Container:$false -Force
cd $Env:ProgramFiles\containerd\
.\containerd.exe config default | Out-File config.toml -Encoding ascii

# Review the configuration. Depending on setup you may want to adjust:
# - the sandbox_image (Kubernetes pause image)
# - cni bin_dir and conf_dir locations
Get-Content config.toml

# Register and start service
.\containerd.exe --register-service
Start-Service containerd

从上面的安装配置也可以看出,只是安装了 cotainerd,但是并没有对系统做任何检查任务比如是否支持容器运行等这些

windows 提供的脚本会有一些额外的检查信息,更加全面

Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/microsoft/Windows-Containers/Main/helpful_tools/Install-ContainerdRuntime/install-containerd-runtime.ps1" -o install-containerd-runtime.ps1

.\install-containerd-runtime.ps1

安装过程解析

安装完成之后查看 containerd 的配置文件

cat 'C:\Program Files\containerd\config.toml'

  [plugins."io.containerd.grpc.v1.cri"]
    device_ownership_from_security_context = false
    disable_apparmor = false
    disable_cgroup = false
    disable_hugetlb_controller = false
    disable_proc_mount = false
    disable_tcp_service = true
    enable_selinux = false
    enable_tls_streaming = false
    enable_unprivileged_icmp = false
    enable_unprivileged_ports = false
    ignore_image_defined_volumes = false
    max_concurrent_downloads = 3
    max_container_log_line_size = 16384
    netns_mounts_under_state_dir = false
    restrict_oom_score_adj = false
sandbox_image = "k8s.gcr.io/pause:3.6"    观察到puase镜像的版本
    selinux_category_range = 0

验证

ctr image pull mcr.microsoft.com/windows/nanoserver:ltsc2022-amd64

安装 CNI

目的

与 docker 不同,containerd 不会将 pod 直接附属到某个网络空间上;containerd 使用 CNI 插件来设置网络

这里我们手动来创建一个网络的CNI plugin,集群里面的配置还是建议使用 Calico 或者 flannel 这样通用的第三方插件机制

安装命令

curl.exe -LO https://raw.githubusercontent.com/microsoft/SDN/master/Kubernetes/windows/hns.psm1
ipmo ./hns.psm1

$subnet="10.0.0.0/16"     
$gateway="10.0.0.1"
New-HNSNetwork -Type Nat -AddressPrefix $subnet -Gateway $gateway -Name "nat"

@"
{
    "cniVersion": "0.3.0",
    "name": "nat",
    "type": "nat",
    "master": "Ethernet",
    "ipam": {
        "subnet": "$subnet",
        "routes": [
            {
                "gateway": "$gateway"
            }
        ]
    },
    "capabilities": {
        "portMappings": true,
        "dns": true
    }
}
"@ | Set-Content "C:\Program Files\containerd\cni\conf\0-containerd-nat.conf" -Force
  1. 下载 ctrictl 安装工具,方便后续排查问题,也方便后续本机运行 pod

安装命令如下

curl.exe -LO https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.24.2/crictl-v1.24.2-windows-amd64.tar.gz                          
tar xvf crictl-v1.24.2-windows-amd64.tar.gz

# crictl.yaml 跟crictl二进制放一起(这个务必请放在一起,因为crictl运行会读取这个yaml的配置)
@"
runtime-endpoint: npipe://./pipe/containerd-containerd
image-endpoint: npipe://./pipe/containerd-containerd
timeout: 10
#debug: true
"@ | Set-Content "crictl.yaml" -Force

验证

PS C:> .\crictl.exe info -q
{
  "status": {
    "conditions": [
      {
        "type": "RuntimeReady",
        "status": true,
        "reason": "",
        "message": ""
      },
      {
        "type": "NetworkReady",
        "status": false,
        "reason": "NetworkPluginNotReady",
        "message": "Network plugin returns error: cni plugin not initialized"
      }
    ]
  }
}

安装 kubelet

安装

注意事项:

  • kubeadm 的版本建议要和集群使用的 kubeadm version 的版本一致
  • hostNetwork 是 k8s 1.26 才 alpha 支持的配置,所以 kubelet 使用1.26+版本
curl.exe -LO https://raw.githubusercontent.com/kubernetes-sigs/sig-windows-tools/master/hostprocess/PrepareNode.ps1

修改下面的高亮部分,我们手动设置 kubeadm 的版本用来 join 集群

<#
.SYNOPSIS
Assists with preparing a Windows VM prior to calling kubeadm join

.DESCRIPTION
This script assists with joining a Windows node to a cluster.
- Downloads Kubernetes binaries (kubelet, kubeadm) at the version specified
- Registers wins as a service in order to run kube-proxy and cni as DaemonSets.
- Registers kubelet as an nssm service. More info on nssm: https://nssm.cc/

.PARAMETER KubernetesVersion
Kubernetes version to download and use

.PARAMETER HostnameOverride
Overrides the hostname for kubeadm. Defaults to the value determined by the hostname command.

 . PARAMETER KubeadmVersion
KubeadmVersion version to for join k8s cluster

.EXAMPLE
PS> .\PrepareNode.ps1 -KubernetesVersion v1.25.3

#>

Param(
    [parameter(Mandatory = $true, HelpMessage="Kubernetes version to use")]
    [string] $KubernetesVersion,
    [parameter(HelpMessage="kubeadm version for join k8s cluster")]
    [string] $KubeadmVersion,
    [parameter(HelpMessage="Hostname override for kubeadm")]
    [string] $HostnameOverride = "$(hostname)"
)
$ErrorActionPreference = 'Stop'

function DownloadFile($destination, $source) {
    Write-Host("Downloading $source to $destination")
    curl.exe --silent --fail -Lo $destination $source

    if (!$?) {
        Write-Error "Download $source failed"
        exit 1
    }
}

if (-not(Test-Path "//./pipe/containerd-containerd")) {
    Write-Error "ContainerD service was not detected - please install and start containerD before calling PrepareNode.ps1 with -ContainerRuntime containerD"
    exit 1
}

if (!$KubernetesVersion.StartsWith("v")) {
    $KubernetesVersion = "v" + $KubernetesVersion
}
Write-Host "Using Kubernetes version: $KubernetesVersion"
$global:Powershell = (Get-Command powershell).Source
$global:PowershellArgs = "-ExecutionPolicy Bypass -NoProfile"
$global:KubernetesPath = "$env:SystemDrive\k"
$global:StartKubeletScript = "$global:KubernetesPath\StartKubelet.ps1"
$global:NssmInstallDirectory = "$env:ProgramFiles\nssm"
$kubeletBinPath = "$global:KubernetesPath\kubelet.exe"

mkdir -force "$global:KubernetesPath"
$env:Path += ";$global:KubernetesPath"
[Environment]::SetEnvironmentVariable("Path", $env:Path, [System.EnvironmentVariableTarget]::Machine)

DownloadFile $kubeletBinPath https://dl.k8s.io/$KubernetesVersion/bin/windows/amd64/kubelet.exe
DownloadFile "$global:KubernetesPath\kubeadm.exe" https://dl.k8s.io/$KubeadmVersion/bin/windows/amd64/kubeadm.exe

$kubeletLogPath = "C:\var\log\kubelet"
mkdir -force $kubeletLogPath
mkdir -force C:\var\lib\kubelet\etc\kubernetes
mkdir -force C:\etc\kubernetes\pki
mkdir -Force c:\etc\kubernetes\manifests
New-Item -path C:\var\lib\kubelet\etc\kubernetes\pki -type SymbolicLink -value C:\etc\kubernetes\pki\

# dockershim related flags (--image-pull-progress-deadline=20m and --network-plugin=cni)  are removed in k8s v1.24
# Link to changelog: https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.24.md

$cmd_commands=@("C:\k\kubelet.exe ", '$global:KubeletArgs ', '--cert-dir=$env:SYSTEMDRIVE\var\lib\kubelet\pki ', "--config=/var/lib/kubelet/config.yaml ", "--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf ", "--kubeconfig=/etc/kubernetes/kubelet.conf ", "--hostname-override=$HostnameOverride ", '--pod-infra-container-image=`"mcr.microsoft.com/oss/kubernetes/pause:3.6`" ', "--enable-debugging-handlers ", "--cgroups-per-qos=false ", '--enforce-node-allocatable=`"`" ', '--resolv-conf=`"`" ')
[version]$CurrentVersion = $($KubernetesVersion.Split("v") | Select -Index 1)
[version]$V1_24_Version = '1.24'
if ($CurrentVersion -lt $V1_24_Version) {
    $cmd_commands = $cmd_commands + "--network-plugin=cni " + "--image-pull-progress-deadline=20m "
}
[version]$V1_26_Version = '1.26'
if ($CurrentVersion -lt $V1_26_Version) {
    $cmd_commands += ("--log-dir=/var/log/kubelet ", "--logtostderr=false ")
}

$StartKubeletFileContent = '$FileContent = Get-Content -Path "/var/lib/kubelet/kubeadm-flags.env"
$global:KubeletArgs = $FileContent.TrimStart(''KUBELET_KUBEADM_ARGS='').Trim(''"'')

$cmd = "' + $cmd_commands + '"
Invoke-Expression $cmd'
Set-Content -Path $global:StartKubeletScript -Value $StartKubeletFileContent

Write-Host "Installing nssm"
$arch = "win32"
if ([Environment]::Is64BitOperatingSystem) {
    $arch = "win64"
}

mkdir -Force $global:NssmInstallDirectory
DownloadFile nssm.zip https://k8stestinfrabinaries.blob.core.windows.net/nssm-mirror/nssm-2.24.zip
tar C $global:NssmInstallDirectory -xvf .\nssm.zip --strip-components 2 */$arch/*.exe
Remove-Item -Force .\nssm.zip

$env:path += ";$global:NssmInstallDirectory"
$newPath = "$global:NssmInstallDirectory;" +
[Environment]::GetEnvironmentVariable("PATH", [EnvironmentVariableTarget]::Machine)

[Environment]::SetEnvironmentVariable("PATH", $newPath, [EnvironmentVariableTarget]::Machine)

Write-Host "Registering kubelet service"
nssm install kubelet $global:Powershell $global:PowershellArgs $global:StartKubeletScript
nssm set kubelet AppStdout $kubeletLogPath\kubelet.out.log
nssm set kubelet AppStderr $kubeletLogPath\kubelet.err.log

# Configure online file rotation.
nssm set kubelet AppRotateFiles 1
nssm set kubelet AppRotateOnline 1
# Rotate once per day.
nssm set kubelet AppRotateSeconds 86400
# Rotate after 10MB.
nssm set kubelet AppRotateBytes 10485760

nssm set kubelet DependOnService containerd

New-NetFirewallRule -Name kubelet -DisplayName 'kubelet' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 10250

$repoUrl='https://raw.githubusercontent.com/kubernetes-sigs/sig-windows-tools/master'

Write-Output "Please remember that after you have joined the node to the cluster, that you have to apply the cni daemonset/service and the kube-proxy"
Write-Output "Also remember that for kube-proxy you have to change the its version from the name of the image in the kube-proxy.yml to that of your kubernetes version `n"
# rancher commands
Write-Output "In case you use rancher, use the following commands:"
Write-Output "For Windows you can use the following command: "
Write-Output "curl.exe -LO $repoUrl/kubeadm/kube-proxy/kube-proxy.yml"
Write-Output "(Get-Content `"kube-proxy.yml`") -Replace 'VERSION', '$KubernetesVersion' | Set-Content `"kube-proxy.yml`" `n"
Write-Output "For Linux, you can use the following command: "
Write-Output "curl -LO $repoUrl/kubeadm/kube-proxy/kube-proxy.yml"
Write-Output "sed -i 's/VERSION/$KubernetesVersion/g' `kube-proxy.yml`n"
# flannel commands
Write-Output "In case you use flannel, use the following commands:"
Write-Output "For Windows you can use the following command: "
Write-Output "curl.exe -LO $repoUrl/hostprocess/flannel/kube-proxy/kube-proxy.yml"
Write-Output "(Get-Content `"kube-proxy.yml`") -Replace 'image: (.*):(.*)-(.*)-(.*)$', 'image: `$1:$KubernetesVersion-`$3-`$4' | Set-Content `"kube-proxy.yml`" `n"
Write-Output "For Linux, you can use the following command: "
Write-Output "curl -LO $repoUrl/hostprocess/flannel/kube-proxy/kube-proxy.yml"
Write-Output "sed -i -E 's/image: (.*):(.*)-(.*)-(.*)$/image: \1:$KubernetesVersion-\3-\4/g' `kube-proxy.yml`n"
# calico commands
Write-Output "In case you use calico, use the following commands:"
Write-Output "For Windows you can use the following command: "
Write-Output "curl.exe -LO $repoUrl/hostprocess/calico/kube-proxy/kube-proxy.yml"
Write-Output "(Get-Content `"kube-proxy.yml`") -Replace 'image: (.*):(.*)-(.*)-(.*)$', 'image: `$1:$KubernetesVersion-`$3-`$4' | Set-Content `"kube-proxy.yml`" `n"
Write-Output "For Linux, you can use the following command: "
# - image: sigwindowstools/kube-proxy:v1.24.2-flannel-hostprocess
Write-Output "curl -LO $repoUrl/hostprocess/calico/kube-proxy/kube-proxy.yml"
Write-Output "sed -i -E 's/image: (.*):(.*)-(.*)-(.*)$/image: \1:$KubernetesVersion-\3-\4/g' `kube-proxy.yml`n"

查看k8s版本信息

执行安装命令

.\PrepareNode.ps1 -KubernetesVersion v1.26.0 -KubeadmVersion v1.23.8 -HostnameOverride windows-test

验证

ctr image pull mcr.microsoft.com/windows/nanoserver:ltsc2022-amd64

Notes:

安装完成如果 Get-Service kubelet 命令显示服务 stopped

去 C:\var\log\kubelet 查看 kubelet 的具体日志信息

原因可能如下:这一步创建的文件 C:\k\StartKubelet.ps1

$FileContent = Get-Content -Path  "/var/lib/kubelet/kubeadm-flags.env" 
$global:KubeletArgs = $FileContent.TrimStart('KUBELET_KUBEADM_ARGS=').Trim('"')

$cmd = "C:\k\kubelet.exe  $global:KubeletArgs  --cert-dir=$env:SYSTEMDRIVE\var\lib\kubelet\pki  --config=/var/lib/kubelet/config.yaml  --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf  --kubeconfig=/etc/kubernetes/kubelet.conf  --hostname-override=windows-test  --pod-infra-container-image=`"mcr.microsoft.com/oss/kubernetes/pause:3.6`"  --enable-debugging-handlers  --cgroups-per-qos=false  --enforce-node-allocatable=`"`"  --resolv-conf=`"`" "
Invoke-Expression $cmd^M

第一行的 kubeadm-flags.env 文件要等下面的 kubeadm join 进集群之后才会有这个对应的文件产生

Join 进集群

生成 join 所需配置信息

生成 kubeadm-join-config 文件(使用 kubeadm token create --print-join-command 获取下面的参数)

apiVersion: kubeadm.k8s.io/v1beta2
discovery:
  bootstrapToken:
    apiServerEndpoint: 10.37.18.97:6443
    caCertHashes:
    - sha256:eeb50ccc2c8006ab075038ba66ff7fb7322dec8cf187bccd93bcb99f65694a24
    token: sevwfh.8rgsadgvtrpzdu07
kind: JoinConfiguration
nodeRegistration:
  criSocket: npipe:////./pipe/containerd-containerd
  kubeletExtraArgs:
    read-only-port: "10255"

Join 集群

使用 kubeadm join 命令直接 join 即可

kubeadm join phase preflight --ignore-preflight-errors="DirAvailable--etc-kubernetes-manifests,Swap" --node-name=window-test --config=./kubeadm-join-config.yaml -v5

kubeadm join phase kubelet-start --node-name=windows-test --config=./kubeadm-join-config.yaml -v5

查看 node 信息,状态为 Ready 代表 join 成功

~ k get node
NAME           STATUS   ROLES                  AGE    VERSION
n37-018-097    Ready    control-plane,master   204d   v1.23.8
windows-test   Ready    <none>                 19s    v1.26.0

验证

我们通过下发一个 windows 的 pod 来判断 windows 节点是否能支持调度并运行 pod

apiVersion: apps/v1
kind: Deployment
metadata:
  name: windows-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      nodeSelector:
        kubernetes.io/os: windows
      containers:
        - name: windows-container
          image: mcr.microsoft.com/windows/nanoserver:ltsc2022-amd64
          command: ["cmd", "/C"]
          args: ["ping", "-t", "8.8.8.8"]

查看调度结果和容器日志显示调度成功

~ k get pod
NAME                                  READY   STATUS    RESTARTS   AGE
windows-deployment-58d4474759-fvw2t   1/1     Running   0          111s

➜  ~ k logs windows-deployment-58d4474759-fvw2t
Pinging 8.8.8.8 with 32 bytes of data:
Reply from 8.8.8.8: bytes=32 time=98ms TTL=51
Reply from 8.8.8.8: bytes=32 time=115ms TTL=51
Reply from 8.8.8.8: bytes=32 time=97ms TTL=51
Reply from 8.8.8.8: bytes=32 time=98ms TTL=51
Reply from 8.8.8.8: bytes=32 time=98ms TTL=51
Reply from 8.8.8.8: bytes=32 time=101ms TTL=51
Reply from 8.8.8.8: bytes=32 time=97ms TTL=51

域名解析不通(TODO)

进入上面的容器 crictl.exe exec -it 12a2d2a817964 "cmd"

结果如下

C:>ping 163.com
Ping request could not find host 163.com. Please check the name and try again

尝试使用域名解析:修改上面的yaml里的CMD命令如下

查看 coredns日志,发现报错

➜  ~ k logs coredns-56547797df-gn6w6 -n kube-system
.:53
[INFO] plugin/reload: Running configuration MD5 = db32ca3650231d74073ff4cf814959a7
CoreDNS-1.8.6
linux/amd64, go1.17.1, 13a9191
[ERROR] plugin/errors: 2 7512992285510408604.3472123971709177314. HINFO: read udp 172.16.8.209:47656->10.199.34.255:53: i/o timeout
[ERROR] plugin/errors: 2 7512992285510408604.3472123971709177314. HINFO: read udp 172.16.8.209:46804->10.199.35.253:53: i/o timeout
[ERROR] plugin/errors: 2 7512992285510408604.3472123971709177314. HINFO: read udp 172.16.8.209:49876->10.199.35.253:53: i/o timeout

172.16.8.209 和 10.199.35.253 分别为 core-dns 的地址和本地的 dns-server 地址

~ k get pod -A -owide | grep -i dns
kube-system   coredns-56547797df-gn6w6   1/1     Running     0     6m56s   172.16.8.209   n37-018-097    <none>       <none>~ cat /etc/resolv.conf
domain byted.org
nameserver 10.199.34.255
nameserver 10.199.35.253

踩坑

节点 join 报错

PS C:> kubeadm join phase preflight --ignore-preflight-errors="DirAvailable--etc-kubernetes-manifests,Swap" --node-name=window-test --config=./kubeadm-join-config.yaml -v5
I0112 09:08:00.581431   20808 joinconfiguration.go:76] loading configuration from "./kubeadm-join-config.yaml"
[preflight] Running pre-flight checks
I0112 09:08:00.631252   20808 preflight.go:92] [preflight] Running general checks
I0112 09:08:00.732791   20808 checks.go:283] validating the existence of file \etc\kubernetes\kubelet.conf
I0112 09:08:00.733313   20808 checks.go:283] validating the existence of file \etc\kubernetes\bootstrap-kubelet.conf
I0112 09:08:00.733836   20808 checks.go:107] validating the container runtime
I0112 09:08:01.290672   20808 checks.go:521] running all checks
I0112 09:08:03.369554   20808 checks.go:404] checking whether the given node name is valid and reachable using net.LookupHost
        [WARNING Hostname]: hostname "window-test" could not be reached
        [WARNING Hostname]: hostname "window-test": lookup window-test: no such host
I0112 09:08:06.099025   20808 checks.go:620] validating kubelet version
I0112 09:08:06.711145   20808 checks.go:133] validating if the "kubelet" service is enabled and active
I0112 09:08:06.713323   20808 checks.go:206] validating availability of port 10250
I0112 09:08:06.715177   20808 checks.go:283] validating the existence of file C:/etc/kubernetes/pki/ca.crt
I0112 09:08:06.715681   20808 checks.go:433] validating if the connectivity type is via proxy or direct
[preflight] Some fatal errors occurred:
        [ERROR CRI]: container runtime is not running: output: time="2024-01-12T09:08:01+08:00" level=fatal msg="getting status of runtime: invalid character 'P' in string escape code"

发现 crictl 也有同样的报错信息

PS C:> crictl info
time="2024-01-12T09:09:27+08:00" level=fatal msg="getting status of runtime: invalid character 'P' in string escape code"

解决方案:重新安装 containerd

安装参考下面两篇文章

eviatargerzi.medium.com/installing-…

github.com/containerd/…