Windows 容器异常排错

本章介绍 Windows 容器异常的排错方法。

RDP 登录到 Node

通常在排查 Windows 容器异常问题时需要通过 RDP 登录到 Windows Node上面查看 kubelet、docker、HNS 等的状态和日志。在使用云平台时,可以给相应的 VM 绑定一个公网 IP;而在物理机部署时,可以通过路由器上的端口映射来访问。

除此之外,还有一种更简单的方法,即通过 Kubernetes Service 对外暴露 Node 的 3389 端口(注意替换为你自己的 node-ip):

  1. # rdp.yaml
  2. apiVersion: v1
  3. kind: Service
  4. metadata:
  5. name: rdp
  6. spec:
  7. type: LoadBalancer
  8. ports:
  9. - protocol: TCP
  10. port: 3389
  11. targetPort: 3389
  12. ---
  13. kind: Endpoints
  14. apiVersion: v1
  15. metadata:
  16. name: rdp
  17. subsets:
  18. - addresses:
  19. - ip: <node-ip>
  20. ports:
  21. - port: 3389
  1. $ kubectl create -f rdp.yaml
  2. $ kubectl get svc rdp
  3. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  4. rdp LoadBalancer 10.0.99.149 52.52.52.52 3389:32008/TCP 5m

接着,就可以通过 rdp 服务的外网 IP 来登录 Node,如 mstsc.exe -v 52.52.52.52

在使用完后, 不要忘记删除 RDP 服务 kubectl delete -f rdp.yaml

Windows Pod 一直处于 ContainerCreating 状态

一般有两种可能的原因

在 Windows Server 1709 上面需要使用 1709 标签的镜像,比如

  1. * `microsoft/aspnet:4.7.2-windowsservercore-1709`
  2. * `microsoft/windowsservercore:1709`
  3. * `microsoft/iis:windowsservercore-1709`

在 Windows Server 1803 上面需要使用 1803 标签的镜像,比如

  1. * `microsoft/aspnet:4.7.2-windowsservercore-1803`
  2. * `microsoft/iis:windowsservercore-1803`
  3. * `microsoft/windowsservercore:1803`

Windows Pod 内无法解析 DNS

这是一个已知问题,有以下三种临时解决方法:

(1)Windows 重启后,清空 HNS Policy 并重启 KubeProxy 服务:

  1. Start-BitsTransfer -Source https://raw.githubusercontent.com/Microsoft/SDN/master/Kubernetes/windows/hns.psm1
  2. Import-Module .\hns.psm1
  3. Stop-Service kubeproxy
  4. Stop-Service kubelet
  5. Get-HnsNetwork | ? Name -eq l2Bridge | Remove-HnsNetwork
  6. Get-HnsPolicyList | Remove-HnsPolicyList
  7. Start-Service kubelet
  8. Start-Service kubeproxy

(2)是为 Pod 直接配置 kube-dns Pod 的地址:

  1. $adapter=Get-NetAdapter
  2. Set-DnsClientServerAddress -InterfaceIndex $adapter.ifIndex -ServerAddresses 10.244.0.4,10.244.0.6
  3. Set-DnsClient -InterfaceIndex $adapter.ifIndex -ConnectionSpecificSuffix "default.svc.cluster.local"

(3)更简单的为每个 Windows Node 多运行一个 Pod,即保证每台 Node 上面至少有两个 Pod 在运行。此时,DNS 解析也是正常的。

如果 Windows Node 运行在 Azure 上面,并且部署 Kubernetes 时使用了自定义 VNET,那么需要为该 VNET 添加路由表

  1. #!/bin/bash
  2. # KubernetesSubnet is the name of the vnet subnet
  3. # KubernetesCustomVNET is the name of the custom VNET itself
  4. rt=$(az network route-table list -g acs-custom-vnet -o json | jq -r '.[].id')
  5. az network vnet subnet update -n KubernetesSubnet \
  6. -g acs-custom-vnet \
  7. --vnet-name KubernetesCustomVNET \
  8. --route-table $rt

如果 VNET 在不同的 ResourceGroup 里面,那么

  1. rt=$(az network route-table list -g RESOURCE_GROUP_NAME_KUBE -o json | jq -r '.[].id')
  2. az network vnet subnet update \
  3. -g RESOURCE_GROUP_NAME_VNET \
  4. --route-table $rt \
  5. --ids "/subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP_NAME_VNET/providers/Microsoft.Network/VirtualNetworks/KUBERNETES_CUSTOM_VNET/subnets/KUBERNETES_SUBNET"

Remote endpoint creation failed: HNS failed with error: The switch-port was not found

这个错误发生在 kube-proxy 为服务配置负载均衡的时候,需要安装 KB4089848

  1. Start-BitsTransfer http://download.windowsupdate.com/d/msdownload/update/software/updt/2018/03/windows10.0-kb4089848-x64_db7c5aad31c520c6983a937c3d53170e84372b11.msu
  2. wusa.exe windows10.0-kb4089848-x64_db7c5aad31c520c6983a937c3d53170e84372b11.msu
  3. Restart-Computer

重启后确认更新安装成功:

  1. PS C:\k> Get-HotFix
  2. Source Description HotFixID InstalledBy InstalledOn
  3. ------ ----------- -------- ----------- -----------
  4. 27171k8s9000 Update KB4087256 NT AUTHORITY\SYSTEM 3/22/2018 12:00:00 AM
  5. 27171k8s9000 Update KB4089848 NT AUTHORITY\SYSTEM 4/4/2018 12:00:00 AM

安装更新后,如果 DNS 解析还是有问题,可以按照上一节中的方法(1) 重启 kubelet 和 kube-proxy。

Windows Pod 内无法访问 ServiceAccount Secret

这是老版本 Windows 的已知问题,升级 Windows 到 1803 即可解决,升级步骤见这里

Windows Pod 内无法访问 Kubernetes API

如果使用了 Hyper-V 隔离容器,需要开启 MAC spoofing 。

Windows Node 内无法访问 Service ClusterIP

这是个当前 Windows 网络协议栈的已知问题,只有在 Pod 内才可以访问 Service ClusterIP。

Kubelet 无法启动

使用 Docker 18.03 版本和 Kubelet v1.12.x 时,Kubelet 无法正常启动报错:

  1. Error response from daemon: client version 1.38 is too new. Maximum supported API version is 1.37

解决方法是为 Windows 上面的 Docker 设置 API 版本的环境变量:

  1. [System.Environment]::SetEnvironmentVariable('DOCKER_API_VERSION', '1.37', [System.EnvironmentVariableTarget]::Machine)

参考文档