MENU

k3s踩坑之凭证失效

• January 3, 2026 • Read: 160 • 默认分类

最近在使用 Docker + K3s 搭建 GZCTF 平台时,遇到了一个后端服务无限重启的问题。经过一番排查,发现是 K8s 配置文件(kubeconfig)凭证失效导致的。特此记录一下排查过程和原理解析。

1. 问题现象

环境配置如下:

  • GZCTF: 使用 Docker Compose 部署
  • Kubernetes: 使用 K3s 作为集群后端
  • 架构: GZCTF 容器通过挂载宿主机的 kube-config.yaml 文件来连接 K3s 集群

服务正常运行了相当一段时间后,忽然有一天, GZCTF 的后台页面、比赛页面进不去了,一直卡在加载。

于是我把服务重启了一下,注意到 GZCTF 容器不断重启,查看日志发现后端一直报错,提示无法连接到 K8s API Server,状态码为 401 Unauthorized

容器日志 (docker compose logs):

gzctf-1 | [ERR] KubernetesProvider: K8s 初始化失败,请检查相关配置是否正确 (https://x.x.x.x:6443)
gzctf-1 | k8s.Autorest.HttpOperationException: Operation returned an invalid status code 'Unauthorized', response body 
gzctf-1 | {"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Unauthorized","reason":"Unauthorized","code":401}

2. 排查过程

最初怀疑是网络问题或配置路径错误,但 Unauthorized 明确指向了身份验证失败

为了验证是否是配置文件的问题,我在宿主机上直接使用该配置文件尝试连接集群:

root@hostname:/path/to/GZCTF# kubectl --kubeconfig ./kube-config.yaml get nodes

E1221 21:38:50.168514   18214 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: the server has asked for the client to provide credentials"

E1221 21:38:50.176447   18214 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: the server has asked for the client to provide credentials"

E1221 21:38:50.184038   18214 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: the server has asked for the client to provide credentials"

E1221 21:38:50.196097   18214 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: the server has asked for the client to provide credentials"

E1221 21:38:50.205985   18214 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: the server has asked for the client to provide credentials"

error: You must be logged in to the server (the server has asked for the client to provide credentials)

对比测试:
随后我使用 K3s 系统默认的配置文件进行测试:

# 使用 K3s 系统源文件测试
kubectl --kubeconfig /etc/rancher/k3s/k3s.yaml get nodes

结果成功:输出了节点列表,状态为 Ready

结论: 宿主机系统里的 K3s 是一切正常的,问题出在我复制到项目目录下的 kube-config.yaml 文件内容已经失效了。

3. 解决方案

解决办法非常简单:用“原件”覆盖“复印件”,并修正 IP 地址。

第一步:复制最新配置

将 K3s 系统自动生成的最新配置文件复制到项目目录:

# 备份旧文件
mv ./kube-config.yaml ./kube-config.yaml.bak

# 复制最新文件
cp /etc/rancher/k3s/k3s.yaml ./kube-config.yaml
chmod 644 ./kube-config.yaml

第二步:修改 Server IP

K3s 默认生成的配置中,Server 地址是 https://127.0.0.1:6443
但 GZCTF 运行在 Docker 容器内部,容器内的 127.0.0.1 指向容器自己,而非宿主机。因此必须将其修改为宿主机的 IP。

打开 ./kube-config.yaml 修改:

apiVersion: v1
clusters:
- cluster:
    # 修改前: server: https://127.0.0.1:6443
    server: https://xxx.xx.xx.xx:6443  # <--- 修改为宿主机真实IP
    certificate-authority-data: ...

第三步:重启服务

docker compose down -v
docker compose up -d

重启后日志显示 KubernetesProvider 初始化成功,服务恢复正常。

4. 深入解析:为什么凭证会失效?

排查完问题后,产生了一个疑问:为什么 /etc/rancher/k3s/k3s.yaml 永远是最新的,而我复制出来的文件过一段时间就不能用了?

于是我对比了一下原文件和最新的配置文件:

2026-01-03T10:10:31.png

起初我甚至以为是服务器硬盘出现了硬件错误(0E了),因为刚开始没用 010Editor ,看着凭据的开头和末尾都长一样。

进一步观察才发现,俩文件并非一样,头尾都一样但中间不同(诶k3s怎么这么坏

最终查资料发现,这涉及到了 K8s 的安全机制。

  1. 证书轮换 (Certificate Rotation)
    出于安全考虑,K3s 会定期(一般是一年)重置集群的 TLS 证书和密钥。
  2. 静态副本 vs 动态原件
    /etc/rancher/k3s/k3s.yaml (动态原件):这是由 K3s 守护进程直接管理的。只要 K3s 在运行,它就会确保这个文件里包含的是最新的凭据。
    ./kube-config.yaml (静态副本):这是我之前手动复制出来的文件。当 K3s 进行了证书轮换后,系统里的凭据换了,但我手里的这一份并不会自动更新。

5. 一句话总结

K3s守护进程会定期更换集群的TLS证书和密钥,我在部署使复制出来的配置并不会自动更新,所以GZCTF对集群的访问出现了401未授权,需要管理员定期维护k8s配置文件。

Archives QR Code Tip
QR Code for this page
Tipping QR Code