"所有深夜里的 Debug,都是为了黎明时那一抹翠绿的 Running。"
第一次搭网站。原本以为只是简单的 kubectl apply,却没曾想在之前没踩过坑的 K3s 和K8s的镜像拉取与数据库版本纠葛中,度过了一个漫长却充实的夜晚。
01. 序言:卡在“Sandbox”的初阵
当我按照之前正常流程操作,结果Pod 状态栏出现那一串冰冷的 ImagePullBackOff和ContainerCreating时,我估计晚上是睡不着了
由于众所周知的原因,镜像拉取一直是头疼的问题,平时在本机用梯子解决,这次在服务器上打算用了ssh NR命令,不过在腾讯云的服务器上docker拉取一直没走我设定的通路。
最后只好直接通过在服务器端开启linux的 Clash,算是能成功把镜像拉下来了。
02. 攻坚:K3s 的“内院”与“外院”
“最遥远的距离,不是镜像不存在,而是它就在我的磁盘里,K3s 却在它的‘内院’里对我摇头说:‘我没看见’。”
已经通过 sudo ctr -n k8s.io images tag 成功给镜像打了标,而且运行 sudo ctr images list 时,确实亲眼看到了 mysql:8.1 和 halohub/halo:2.10 稳稳地躺在列表里。但是,即便镜像在 ctr 列表里,Kubernetes 依然疯狂报错 ErrImageNeverPull,说明在本地找不到镜像。
为了查明真相,尝试执行了 K3s 内置的查询命令:
sudo k3s crictl images | grep -E "mysql|halo"结果输出是:完全空白。
反复折腾了几次,不断更改镜像名,跟ai进行了数轮对话,大约一个小时,悟了:
外院 (System Containerd):直接输入 ctr 命令时,它默认连接的是系统路径(比如/run/containerd/containerd.sock)。镜像虽然打进去了,但那是给普通 Docker 或系统级容器用的。
内院 (K3s Internal Containerd):K3s 为了保证环境纯净,使用了独立的 Socket 路径(/run/k3s/containerd/containerd.sock)。K3s 的 Kubelet 只会盯着这个“内院”看,对“外院”发生的任何打标、拉取都视而不见。
既然症结已经找到,我采取了经典的战术:
外院采买:利用 Docker + 代理强行拉取镜像。
跨院传送:使用
docker save | k3s ctr images import -管道,将镜像精准投喂进 K3s 的内库。身份绑定:通过 ctr images tag 给镜像打上 Pod 认准的“实名标签”。
sudo docker save halohub/halo:2.21.7 | sudo k3s ctr -n k8s.io images import -此刻,屏幕前的终端跳动着 1/1 Running。窗外或许已经有了黎明的微光。
03. 转折:H2 的告别与 MySQL 的新生
升级到 2.20+ 后,遇到了报错:MVStoreException: The write format 2 is smaller than supported format 3。
这是 H2 数据库版本跨越的阵痛,果断选择了拥抱 MySQL。
通过
kubectl patch修正环境变量。将
imagePullPolicy强行设为Never,断掉 Pod 拉取外网信息对账的机制。使用 Cluster-IP 绕过了不稳定的内部 DNS 解析。
04. 终局:2.21.7 的平滑着陆
最终,当镜像版本锁定在 2.21.7,且所有的环境变量精准指向持久化的 /data/halo 目录时,网页终于不再是 502,而是重新露出了熟悉的登录界面。
# 核心秘籍:持久化卷挂载
volumes:
- hostPath:
path: /data/halo
type: ""
name: halo-data感谢今晚的自己,没有在 ErrImagePull 面前低头。
未来,这里将记录更多的代码与生活。欢迎来到我的新世界。
Published at: 2025-12-24 Status: 🟢 Running Mode: Zen & Geek