我继续沿着令人沮丧的走走停停的学习 Kubernetes(特别是 MicroK8S)的道路前进。
我在开发笔记本电脑上本地构建了一个图像,如下所示:
docker build -t k8s-workload .
这是一个简单的 PHP Web 应用程序,可报告一些请求元数据。它已成功构建:
Sending build context to Docker daemon 13.82kB
Step 1/5 : FROM php:8.2-cli-alpine
---> c5f1f9770838
Step 2/5 : WORKDIR /root
---> Using cache
---> 492c997c963b
Step 3/5 : RUN apk update && apk upgrade
---> Using cache
---> f91505d5fe68
Step 4/5 : COPY src /root
---> 02bcc72dfc97
Step 5/5 : CMD ["sh", "/root/bin/start-server.sh"]
---> Running in 6bc3b72365e4
Removing intermediate container 6bc3b72365e4
---> 0c8a405b06af
Successfully built 0c8a405b06af
Successfully tagged k8s-workload:latest
我从中创建了一个 tarball,以便可以将其发送到我的三节点集群:
docker save k8s-workload > k8s-workload.docker.tar
然后我将其发送给集群中的领导者(尽管我假设它可以发送给其中任何一个):
scp k8s-workload.docker.tar 192.168.50.251:/home/myuser/
到目前为止,一切都很好。现在我想侧载将图像放入集群中的所有节点:
root@arran:/home/myuser# microk8s images import < k8s-workload.docker.tar
Pushing OCI images to 192.168.50.251:25000
Pushing OCI images to 192.168.50.135:25000
Pushing OCI images to 192.168.50.74:25000
看起来成功了,我尝试创建一个工作负载:
root@arran:/home/myuser# microk8s kubectl create deployment k8s-workload --image=k8s-workload
最后我们来获取一下这个 pod 的状态:
root@arran:/home/myuser# microk8s kubectl get pods
NAME READY STATUS RESTARTS AGE
k8s-workload-6cdfbb6b59-zvgrl 0/1 ImagePullBackOff 0 35m
好的,看起来不太好。还有一个 ErrImagePull 错误,但现在似乎已被替换。
我该如何调试图像无法启动的原因?
我发现了一种列出节点上镜像的方法。我在领导节点上找到了我新建的镜像:
root@arran:/home/myuser# microk8s ctr images list | grep workload
docker.io/library/k8s-workload:latest application/vnd.docker.distribution.manifest.v2+json sha256:725b...582b 103.5 MiB linux/amd64
因此图像可用。我可以获得有关该问题的一些日志,但它没有揭示任何我不知道的信息:
root@arran:/home/myuser# microk8s kubectl logs k8s-workload-1cdfaa6c49-zvgrl
Error from server (BadRequest): container "k8s-workload" in pod "k8s-workload-1cdfaa6c49-zvgrl" is waiting to start: trying and failing to pull image
下一步我可以尝试什么?据我所知,没有节点实际上需要拉取图像,因为它们在每个节点上都可用。
更新 1
我犹豫着是否要在一个问题中添加太多问题,但总的来说,我认为它们值得添加,因为它们都是获得一个结果的障碍:在 K8S 上成功部署一个简单的工作负载。
在描述单个部署中的单个 pod 时,我注意到它显示了这个错误:
kubelet 未配置 ClusterDNS IP,无法使用“ClusterFirst”策略创建 Pod。恢复为“默认”策略。
哎呀!又一个不能立即使用的东西。我已经使用 MicroK8S 的方式修复了这个问题这个答案虽然这并没有解决问题,但至少我正在一个接一个地清除头上的障碍。
更新 2
我想检查侧载图像是否有效,因此我在领导者上执行了此操作:
root@arran:/home/myuser# docker load < k8s-workload.docker.tar
解压很好:
bb01bd7e32b5: Loading layer [==================================================>] 7.618MB/7.618MB
e759f13eb8bc: Loading layer [==================================================>] 6.015MB/6.015MB
1a72c946ba2b: Loading layer [==================================================>] 12.29kB/12.29kB
9bbacedbd5e4: Loading layer [==================================================>] 6.144kB/6.144kB
53b5e1394bc2: Loading layer [==================================================>] 12.08MB/12.08MB
aff825926dad: Loading layer [==================================================>] 4.096kB/4.096kB
c76bce6229c6: Loading layer [==================================================>] 71.7MB/71.7MB
0503c7346508: Loading layer [==================================================>] 12.8kB/12.8kB
8c2f9e7d94bb: Loading layer [==================================================>] 65.54kB/65.54kB
7e0ad9ed4982: Loading layer [==================================================>] 10.97MB/10.97MB
b99f234d8751: Loading layer [==================================================>] 5.632kB/5.632kB
Loaded image: k8s-workload:latest
然后我在自定义端口上的领导者上运行它(即在 Docker 中,而不是 K8S 中):
root@arran:/home/myuser# docker run -p 9000:80 -it k8s-workload
正如我期望 LAN 上的另一台机器那样,它通过 cURL 做出响应。
更新 3
我突然想到,“命名空间”图像名称可能会有所不同 - 我应该指定docker.io/library/k8s-workload:latest
而不是吗k8s-workload
?我尝试了两者,发现我得到了相同的结果。
这是最新的错误:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 4m46s default-scheduler Successfully assigned default/k8s-workload-68c899df98-qhmhr to yamazaki
Normal Pulling 3m17s (x4 over 4m45s) kubelet Pulling image "k8s-workload"
Warning Failed 3m15s (x4 over 4m43s) kubelet Failed to pull image "k8s-workload": rpc error: code = NotFound desc = failed to pull and unpack image "docker.io/library/k8s-workload:latest": failed to unpack image on snapshotter overlayfs: unexpected media type text/html for sha256:e823...45c8: not found
Warning Failed 3m15s (x4 over 4m43s) kubelet Error: ErrImagePull
Warning Failed 2m52s (x6 over 4m43s) kubelet Error: ImagePullBackOff
Normal BackOff 2m37s (x7 over 4m43s) kubelet Back-off pulling image "k8s-workload"
好的,现在我了解得更详细一些了。“无法解压图像”错误到底是什么意思?
更新 4
下面的一个有用的答案表明我可能需要设置一个拉取策略来让 K8S 期望图像在每个节点上都可用,并且它不应该尝试拉取它们(它在远程任何地方都不存在)。
然而,当采取提供的建议时,虽然我得到了不同的错误代码(CreateContainerError
),但根本原因是相同的:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 64s default-scheduler Successfully assigned default/k8s-workload to yamazaki
Normal Pulled 6s (x7 over 62s) kubelet Container image "k8s-workload" already present on machine
Warning Failed 6s (x7 over 62s) kubelet Error: failed to create containerd container: error unpacking image: unexpected media type text/html for sha256:1f2c...753e1: not found
更新 5
我有将此报告为错误目前,我仍然欢迎在这里回答问题。
更新 6
基于顽强的坚持对灵魂有神奇的好处,我尝试使用ctr
子命令删除图像。这是在跟随节点上:
root@yamazaki:/home/myuser# microk8s ctr images rm docker.io/library/k8s-workload:latest
docker.io/library/k8s-workload:latest
然后使用我重新导入的相同子命令:
root@yamazaki:/home/myuser# microk8s ctr images import k8s-workload.docker.tar
unpacking docker.io/library/k8s-workload:latest (sha256:725b...582b)...done
由于这是在节点级别而不是集群级别运行,因此我对三个节点中的每一个都执行了此操作。
然后我使用了run
命令,因为这允许设置拉取策略,并且我不想将解包问题与顶部的拉取问题混为一谈。这又回到了集群领导者身上:
root@arran:/home/myuser# microk8s kubectl run k8s-workload --image=k8s-workload --image-pull-policy='Never' --port=80
pod/k8s-workload created
然后我描述生成的 pod,并收到一个熟悉的错误:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 36s default-scheduler Successfully assigned default/k8s-workload to yamazaki
Normal Pulled 6s (x5 over 35s) kubelet Container image "k8s-workload" already present on machine
Warning Failed 6s (x5 over 35s) kubelet Error: failed to create containerd container: error unpacking image: unexpected media type text/html for sha256:5f76...a3aa: not found
矛盾的是,这让人放心——向每个节点单独发送图像确实很麻烦,因此我希望集群级图像导入能够正常工作。我想,一旦我彻底解决了解包问题,它就会正常工作。
更新 7
好的,我发现了一些东西。正如人们所期望的那样,所有节点上的镜像 tarball 都具有相同的校验和。但是当导入时,一个节点报告了错误的镜像类型。为了便于比较,这些被稍微重新格式化了:
节点“Arran”:
docker.io/library/k8s-workload:latest
application/vnd.docker.distribution.manifest.v2+json
sha256:725b...582b 103.5 MiB
linux/amd64
io.cri-containerd.image=managed
节点“山崎”:
docker.io/library/k8s-workload:latest
text/html
sha256:5f76...a3aa 218.4 KiB
-
io.cri-containerd.image=managed
节点“Nikka”:
docker.io/library/k8s-workload:latest
application/vnd.docker.distribution.manifest.v2+json
sha256:725b...582b 103.5 MiB
linux/amd64
io.cri-containerd.image=managed
看起来工作负载一直被选中在 Yamazaki 上运行,而 Yamazaki 就是包含损坏映像的节点。现在重新导入映像并使其与其他映像匹配...
答案1
https://stackoverflow.com/questions/59980445/setting-image-pull-policy-using-kubectl
kubectl run
将--image-pull-policy
作为命令行参数
答案2
我最后的更新提示了这个问题——一个节点的镜像损坏了。巧合的是,这是 K8S 想要运行工作负载的节点。我要做的就是在本地重新导入镜像:
root@yamazaki:/home/myuser# microk8s ctr images import k8s-workload.docker.tar
unpacking docker.io/library/k8s-workload:latest (sha256:725b...582b)...done
根据问题更新,我通过两种方式导入了该图像,均涉及 MicroK8S:
microk8s images
执行全局集群导入microk8s ctr images import
执行每个节点的导入
我认为我可以非常肯定地说,MicroK8S 或 containerd 损坏了镜像(即不能将其归咎于 scp 或错误的文件处理)。对于每个节点的导入,我使用 验证了本地 tarball sha256sum
,它与所有其他 tarball 相同。不幸的是,我预计这不再是一个可调查的错误,因为命令的确切历史现在非常复杂,可以视为丢失。
话虽如此,我将尝试从所有 containerd 实例中清除映像,然后再次使用集群导入器。该错误可能会再次被触发。