You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MicroK8S部署本地镜像时出现"failed to unpack image on snapshotter overlayfs: unexpected media type text/html"错误的排查求助

MicroK8S部署本地镜像时出现"failed to unpack image on snapshotter overlayfs: unexpected media type text/html"错误的排查求助

我最近在啃Kubernetes(具体是MicroK8S),这过程断断续续的,属实有点让人头疼。下面是我遇到的问题和已经做的排查步骤,希望能得到大家的帮助:

我在开发笔记本上本地构建了一个简单的PHP Web应用镜像(用来返回请求元数据),构建命令如下:

docker build -t k8s-workload .

构建过程很顺利,完整输出:

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

之后我把镜像导出成tar包,方便传到集群节点:

docker save k8s-workload > k8s-workload.docker.tar

接着把这个tar包传到集群的主节点(我觉得传任意节点应该都行):

scp k8s-workload.docker.tar 192.168.50.251:/home/myuser/

看起来一切正常,我尝试把镜像导入集群的所有节点:

root@arran:/home/myuser# microk8s images import < k8s-workload.docker.tar

输出显示正在推送到三个节点的25000端口,看起来成功了:

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

接下来创建Deployment部署工作负载:

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错误,现在变成了ImagePullBackOff。

我先做了初步排查:检查主节点上的镜像,确认镜像确实存在:

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

但查看Pod日志也没得到新信息:

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

我本来以为所有节点都有这个镜像了,不需要拉取,结果还是出问题了。


Update 1
我本来不想在一个问题里塞太多内容,但这些都是部署这个简单工作负载的障碍,还是一起说了吧。
描述Pod的时候发现了另一个错误:

kubelet does not have ClusterDNS IP configured and cannot create Pod using "ClusterFirst" policy. Falling back to "Default" policy.

这又是个开箱没解决的问题,我用MicroK8S的方法修复了它,但这并没有解决镜像的问题,不过至少又扫清了一个障碍。

Update 2
我想验证一下导入的镜像是否有效,在主节点上用Docker加载这个tar包:

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

局域网里的其他机器用curl访问也能正常响应,说明镜像是没问题的。

Update 3
我突然想到镜像名的命名空间问题,是不是应该用docker.io/library/k8s-workload:latest而不是k8s-workload?我两种都试了,结果还是一样的错误。
现在我得到了更详细的错误信息,查看Pod事件:

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"

这个failed to unpack image错误到底是什么意思?

Update 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

Update 5
我已经把这个问题报成bug了,但还是希望能在这里得到解决办法。

Update 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命令创建Pod,指定拉取策略为Never,避免拉取问题干扰:

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

有点矛盾的是,这其实让我有点安心——毕竟手动给每个节点传镜像太麻烦了,我还是希望集群级的镜像导入能正常工作,只要解决了这个解压问题就行。

Update 7
终于发现问题了!所有节点上的tar包校验和都是一样的,没问题,但导入后有一个节点的镜像类型不对。我整理了三个节点的镜像信息(为了方便对比做了格式调整):

节点"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

节点"Yamazaki"(从节点):

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

看起来Pod总是被调度到Yamazaki节点,而这个节点的镜像明显有问题——类型是text/html,大小也只有218.4KB,和其他节点的103.5MB差远了。现在我需要重新导入这个节点的镜像,让它和其他节点一致,但不知道为什么会出现这种情况?

备注:内容来源于stack exchange,提问作者halfer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 10:13:01