最近在跟着高塔老师的教程用二进制的方式搭建k8s
kubernetes v1.20.0 我没有使用最新的版本,是因为内部网络问题。
containerd v1.5.2 之前并没有使用过,但对docker比较熟悉
我所处的环境是一个内网环境,无法连接互联网,更无法连接国际互联网,
内网环境下部署了Harbor(private registry),用作镜像仓库来使用,是以http形式来进行服务的,即 insecure registry,ip地址为192.168.1.8
还有6台虚拟机节点,分为 3台主节点(master)和3台工作节点(worker),而192.168.1.1为网关路由器地址,所以从2开始,2-4为master,5-7为worker
192.168.1.2/192.168.1.3/192.168.1.4/192.168.1.5/192.168.1.6/192.168.1.7
在第12步骤部署CoreDNS部分出现了containerd无法拉取私库里面的镜像的问题。
首先我在自己的私库Harbor是存在沙箱镜像pause:3.2 ,我使用docker能正常拉取,说明我的Harbor是没有问题的。docker是由/etc/docker/daemon.json insecure-registries :["192.168.1.8"]进行配置的。
当我安装高塔老师的步骤执行到:
$ kubectl get pods -l k8s-app=kube-dns -n kube-system --kubeconfig=admin.kubeconfig
一直会出现容器正在创建的状态,于是通过describe看一下具体问题。
执行如下命令后,具体错误为:
$ kubectl describe pod coredns-xxxx-xxx -n kube-system --kubeconfig=admin.kubeconfig
第一个问题: 出现了kubelet去k8s.gcr.io/pause:3.5拉取镜像了,并没有去私库拉取镜像,导致沙箱镜像无法下载,也就是无法运行coreDNS镜像。
而我在内网的harbor pause镜像地址为: 192.168.1.8/kubernetes/pause:3.2
那如何解决这个问题呢?
我一开始以为是出现的错误是由于kubelet的配置所在,所以重新找到高塔老师的文档,又看了一遍,没有发现蛛丝马迹。
然后又找到了containerd的官方文档,发现在默认生成的/etc/containerd/config.toml中包含了要拉取sandbox_image地址,也就是说containerd告诉kubelet去gcr.io拉取镜像,我们通过修改这个地址来让kubelet去我们的私库拉取镜像。
$ containerd config default > /etc/containerd/config.toml
[plugins]
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image="k8s.gcr.io/pause:3.5"
下面是修改后的配置,然后重启三个worker节点的containerd
[plugins]
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image="192.168.1.8/kubernetes/pause:3.2"
$ systemctl restart containerd
第二个问题:我继续通过kubectl descirbe命令来查看情况,这次的结果是地址确实变化了,但是还是没有从私库上拉取下来。
我找了很多文档,包括github的issues和discussions有不少人都遇到了这个问题,但是都没有一个详细的解决办法,尤其是看了这篇手册https://github.com/containerd/containerd/blob/release/1.5/docs/cri/registry.md,按照手册配置了半天,没有任何效果,有点浪费时间。
总结一下:无外乎就是修改config.toml里面的 insecure_skip_verify及在[plugins."io.containerd.grpc.v1.cri".registry]新增mirrors、auths或configs,但结果都是无效的。
并且issues的人 说ctr无法使用cri的config,也就是说config.toml是cri的配置,可以通过:
$ ctr images pull --plain-http 192.168.1.8/kubernetes/pause:3.2
进行拉取,但是kubelet并不认识ctr,是因为ctr没有实现cri接口,具体表现为:
$ ctr images pull --plain-http 192.168.1.8/kubernetes/pause:3.2
$ ctr images ls //我们发现就有了这个镜像,但是当我们执行
$ crictl images //并没有发现刚刚拉取下来的pause:3.2镜像
也就是还是无法让kubelet从私库拉取pause:3.2镜像的问题,都是如下错误:
Failed CreatePodSandBox 7s(x22 over 4m42s) kubelet Failed to create pod sandbox: rpc error: code=Unknown desc = failed to get sandbox image "192.168.1.8/kubernetes/pause:3.2" :failed to pull image "192.168.1.8/kubernetes/pause:3.2": failed to pull and unpack image "192.168.1.8/kubernetes/pause:3.2": failed to resolve reference "192.168.1.8/kubernetes/pause:3.2": failed to do request: Head "https://192.168.1.8/v2/kubernetes/pause/manifests/3.2": dial tcp 192.168.1.8:443: connect:connection refused
我重新又找文档,又鏖战了一天的时间,发现在containerd:配置hosts 中有一个Bypass TLS Verification Example,我按照教程立刻配了一下,问题立刻解决。
解决方法为:
$ tree /etc/containerd/certs.d
/etc/containerd/certs.d
└── docker.io
└── hosts.toml
$ cat /etc/containerd/certs.d/docker.io/hosts.toml
server = "https://docker.io"
[host."http://192.168.1.8:80"]
capabilities = ["pull", "resolve","push"]
skip_verify = true
还有就是修改你的config.toml中的192.168.1.8为docker.io ,对,你没看错,一定要修改这里。
[plugins]
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image="docker.io/kubernetes/pause:3.2"
这是因为containerd已经设置了hosts,你可以理解为拦截器,将访问docker.io的链接替换为上面咱们hosts.toml里面设置的私库地址。
以后你的所有的私库中的镜像地址都不是 192.168.1.8/repo/image:version ,而是docker.io/repo/image:version
也就是说更改的是你的yaml文件里面image镜像地址,改为docker.io/repo/image:version ,但是harbor不用任何更改。
$ systemctl restart containerd
别忘重启所有worker节点。
参考链接:
1.高塔老师:kubernetes the hard way
2.containerd: 配置registry
https://github.com/containerd/containerd/blob/release/1.5/docs/cri/registry.md
3.containerd:配置hosts
https://github.com/containerd/containerd/blob/release/1.5/docs/hosts.md