这里的混合云是指公有云和私有云同时拿来部署集群的

本文仅记录本人踩坑和解决方案,不一定能完全当作万能解决方案

警惕一切snap电信诈骗,它让你干什么都不要信!!!

Containerd

网络访问问题

在一些特定的地区由于当地的网络环境可能没法正常使用containerd拉取镜像,可以使用代理或者镜像来解决,不过都有需要注意的地方

使用代理

推荐是有代理就用代理

containerd作为systemd服务启动,不会继承终端环境变量,需要在/etc/environment或者/etc/systemd/system/containerd.service.d/http-proxy.conf(文件名随意)中添加,这样containerd就会使用http/https代理拉取镜像

使用镜像

使用镜像要保证kubeadm init命令的--image-repository 参数要和containerd配置文件指定的镜像仓库的一致,例如在containerd指定镜像仓库为reg.liteyuki.icu后,在--image-repository指定镜像前也要加上镜像站的域,否则kubeadm init仍然会尝试从默认仓库拉去,网络无法连通就拉不下来

Docker安装的containerd导致的问题

使用包管理器安装docker时,containerd作为其容器运行时,便会自动安装和配置好,但是这个配置在后续安装Kubernetes(kubeadm init)时会引发一些问题,例如它默认禁用了CRI(Container Runtime Interface)插件,而kubelet和容器运行时通过此接口进行通信。因此需要启用CRI插件,即从disabled_plugins数组中移除。

CGroup配置问题

具体表现为卡在[api-check] Waiting for a healthy API server. This can take up to 4m0s 这一步很久,然后出现类似以下报错

[api-check] The API server is not healthy after 4m0.000097985s
Unfortunately, an error has occurred:
        context deadline exceeded
This error is likely caused by:
        - The kubelet is not running
        - The kubelet is unhealthy due to a misconfiguration of the node in some way (required cgroups disabled)
If you are on a systemd-powered system, you can try to troubleshoot the error with the following commands:
        - 'systemctl status kubelet'
        - 'journalctl -xeu kubelet'
Additionally, a control plane component may have crashed or exited when started by the container runtime.
To troubleshoot, list all containers using your preferred container runtimes CLI.
Here is one example how you may list all running Kubernetes containers by using crictl:
        - 'crictl --runtime-endpoint unix:///var/run/containerd/containerd.sock ps -a | grep kube | grep -v pause'
        Once you have found the failing container, you can inspect its logs with:
        - 'crictl --runtime-endpoint unix:///var/run/containerd/containerd.sock logs CONTAINERID'
error execution phase wait-control-plane: could not initialize a Kubernetes cluster
To see the stack trace of this error execute with --v=5 or higher

根据错误原因来看,可能是The kubelet is unhealthy due to a misconfiguration of the node in some way (required cgroups disabled) 于是在查阅后发现要在containerd配置中启用SystemdCgroup。

这里我们直接使用containerd生成默认配置文件来覆盖包管理器的配置文件,然后在此基础上修改

containerd config default > /etc/containerd/config.toml

找到disabled_plugins,确保CRI插件不在里面,找到SystemdCgroup,设置为true

综上,containerd的问题解决。

节点访问问题

在我们安装完CNI插件(例如calico)后,如果节点们都在一个局域网,那很就可以很轻松地使用kubeadm join配置好集群。本文提到的场景是混合云,通常是家里云和云服务商混合着来的,节点之间有办法联通,但是不在一个网段,直接修改join命令的地址尝试加入,会被kubeadm init时自动生成的controlPlaneEndpoint坑死。

例如我的家庭局域网网段是192.168.1.1/24,我的控制平面节点位于192.168.1.15,其余几个家里云节点都分别在192.168.1.21,192.168.1.22,192.168.1.23,他们使用join命令可以正常连接,因为默认的控制平面地址也是192.168.1.15。

倘若我们现在和机房之间用了wireguard组网,有一个虚拟网络接口,控制平面节点分到的IP是10.0.0.12,另一个待加入的工作节点的IP是10.0.0.44。这时候如果我们改掉join命令中的地址为10.0.0.12,它首先是可以正常访问的,然后控制平面下发给它的api终结点是192.168.1.15。这就会导致api不可用的问题。

网上参考了一些方法,例如calico启用ipip等。最后感觉还是自定义域名好使,我们只需要使用配置文件启动,新建一个yaml文件,内容如下

apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
controlPlaneEndpoint: "k8s.liteyuki.icu:6443"
apiServer:
  certSANs:
    - "k8s.liteyuki.icu"  # 为域名生成证书

没有购买域名也没有关系,这些在本地改改hosts就能用,例如在192段的机器上,我们可以在路由器网关添加自定义hosts,让k8s.liteyuki.icu指向192.168.1.15,在10段的机器上指向10.0.0.12,同时配置自签证书的生成,可以保证SSL不出问题。然后使用kubeadm init --config=config.yaml 初始化控制平面节点即可,此时它生成的join命令就是这个域名了,我们便可以在10段的工作节点上使用域名api结点加入集群

在跨网段或者特殊组网的环境中,请在join时也指定--apiserver-advertise-address ,防止节点地址变成默认路由地址而无法到达,或者使用DNAT+SNAT转发(麻烦)

BGP 配置问题

在安装完Calico CNI后几个calico-node的pods一直处于Ready 0/1状态,这显然是不正常的。kubectl describe之后

Readiness probe failed: calico/node is not ready: BIRD is not ready: Error querying BIRD: unable to connect to BIRDv4 socket: dial unix /var/run/calico/bird.ctl

在我这边是因为calico配置中的IP_AUTODETECTION_METHOD 没有指定网络接口导致,我们手动指定后使用kubectl apply -f calico.yaml应用配置

- name: IP_AUTODETECTION_METHOD
  value: "interface=eth0,enp41s0,enp46s0"  # 可以指定多个,每个节点上的网络接口,也可用正则匹配

此后所有pods正常

参考:https://github.com/projectcalico/calico/issues/2042