删除了 traefik,重启后它又回来了
目标
在真实的 k3s 上确认 k3s 服务器把 manifests 目录中的文件作为 AddOn 应用,并把 traefik 作为 HelmChart 安装的结构。 记录用 kubectl 删除、重启、.skip、--disable、HelmChartConfig,以及配置文件与 CLI 标志的优先级,各自会改变什么、又会保留什么。
为什么重要
k3s 用一行安装命令,就提供包含 Ingress、DNS、指标在内的集群。这种便利来自“k3s 每次启动时都会重写并应用默认组件的清单”这一设计。 因此,像在托管集群中那样用 kubectl 删除组件,下次重启时它会悄无声息地复活;反过来,即使删除清单文件,集群中的对象也会保留。 关闭靠 --disable,只忽略文件靠 .skip,只改值靠 HelmChartConfig。如果分不清这三者的区别,在升级或重启之后就得去追查“是谁把它又装上了”。 配置文件也一样:如果不知道安装脚本写入服务单元的标志优先于 config.yaml,就找不到修改后的值没有生效的原因。
步骤
- 在
/root/k3s-pkg/inventory.json中写入version(节点的 kubeletVersion)、addons(kube-system 中 AddOn 名称排序后的数组)、helmcharts(kube-system 中 HelmChart 名称排序后的数组)、manifest_files(manifests 目录下文件的相对路径排序后的数组)。 - 在
/var/lib/rancher/k3s/server/manifests/lab-banner.yaml中写入 Namespacek3s-pkg和 ConfigMapbanner(命名空间 k3s-pkg,msg: v1),作为 AddOn 部署。用 kubectl 删除生成的 ConfigMap,等待 20 秒,确认它没有回来,然后把文件中的值改为msg: v2,让它重新生成。在/root/k3s-pkg/banner.json中写入deleted_uid(被删除那个的 UID)、restored_uid(重新生成那个的 UID)、returned_before_edit(在修改文件之前它是否回来了,布尔值)。 - 用 kubectl 删除 kube-system 中的 HelmChart
traefik,并等待 traefik Deployment 消失(此时先不要重启)。在/root/k3s-pkg/gone.json中写入deleted_at(删除的时刻,UTC RFC3339,例如:2026-01-01T00:00:00Z)、manifest_still_there(traefik.yaml 文件是否仍然存在,布尔值)、release_left(剩余的 traefik release Secret 数量,整数)。 - 用
systemctl restart k3s重启 k3s,并等待 traefik Deployment 再次变为 Available。在/root/k3s-pkg/revive.json中写入helmchart_uid(重新生成的 HelmChart traefik 的 UID)、helmchart_created(它的 creationTimestamp)、revived(Deployment 是否恢复了,布尔值)。 - 用
/var/lib/rancher/k3s/server/manifests/lab-pinned.yaml部署 ConfigMappinned(命名空间 k3s-pkg,v: "1")。确认它生成之后,在同一目录中创建lab-pinned.yaml.skip,把文件中的值改为v: "2",并等待 20 秒。在/root/k3s-pkg/skip.json中写入file_value(文件中写的值)、live_value(集群 ConfigMap 中的值)、addon_still_exists(AddOn lab-pinned 是否仍然存在,布尔值)。 - 保持
/etc/rancher/k3s/config.yaml不变,创建/etc/rancher/k3s/config.yaml.d/50-disable.yaml来关闭 metrics-server。local-storage 必须保持关闭。写完文件后,先确认 metrics-server 在 20 秒内保持原样,然后重启 k3s。在/root/k3s-pkg/disable.json中写入changed_before_restart(重启之前它是否消失了,布尔值)、removed_addons(因重启而消失的 AddOn 名称排序后的数组)、files_left(manifests/metrics-server 下剩余的文件数,整数)。 - 在
/etc/rancher/k3s/config.yaml中保留原有的 disable 列表,并加入write-kubeconfig-mode: "0600",然后重启 k3s。查看/etc/rancher/k3s/k3s.yaml的权限变成了什么,并在/root/k3s-pkg/precedence.json中写入config_value(config.yaml 中写的值,字符串)、effective_mode(重启后 k3s.yaml 的八进制权限,字符串,例如:"640")、winner(cli或config)、flag_file(写有胜出值的文件的绝对路径)。 - 不重启,在
/var/lib/rancher/k3s/server/manifests/traefik-config.yaml中放置 HelmChartConfigtraefik(kube-system),把 traefik 的日志级别改为 DEBUG(logs.general.level)。在/root/k3s-pkg/hcc.json中写入revision_before(应用前 traefik release 的最大 revision,整数)、revision_after(应用后,整数)、log_arg(traefik 容器参数中完整的日志级别参数)。 - 在
/root/k3s-pkg/report.json中写入needs_restart(对象:manifest_file、skip_file、helmchartconfig、config_dropin各自是否需要重启才生效,布尔值)、revived_by_restart(第 3、4 步中因重启而复活的 HelmChart 名称)、disable_deletes_files(布尔值)、skip_removes_resources(布尔值)、current_addons(当前 kube-system 中 AddOn 名称排序后的数组)、traefik_revision(当前 traefik release 的最大 revision,整数)。
参考
- VM 中有一台 k3s v1.35.8+k3s1。配方通过 config.yaml 只关闭了 local-storage,并向安装脚本传入了
--write-kubeconfig-mode 644。 - 重启的命令是
systemctl restart k3s。API 大约 5 秒后恢复,traefik 大约 20 秒后恢复(实测)。 - 查看 AddOn:
kubectl -n kube-system get addon -o custom-columns=NAME:.metadata.name,SOURCE:.spec.source - 常见错误:在 drop-in 中使用
disable:。最后的值会胜出,config.yaml 中的 local-storage 会被重新安装。 - 常见错误:直接修改默认组件的清单文件(traefik.yaml 等)。它们会在启动时被重写,修改会消失。
- Managing Packaged Components · Helm · Configuration Options
哪些东西是作为 AddOn 安装的
在 /root/k3s-pkg/inventory.json 中写入 version(节点的 kubeletVersion)、addons(kube-system 中 AddOn 名称排序后的数组)、helmcharts(kube-system 中 HelmChart 名称排序后的数组)、manifest_files(manifests 目录下文件的相对路径排序后的数组)。
AddOn 是 k3s.cattle.io 组的 CRD,一个文件对应一个 AddOn。子目录中的文件也各自成为一个 AddOn。local-storage 已经在配方的 config.yaml 中关闭了,所以它不在列表中才是正常的。
用 kubectl 删除的 ConfigMap 何时会回来
在 /var/lib/rancher/k3s/server/manifests/lab-banner.yaml 中写入 Namespace k3s-pkg 和 ConfigMap banner(命名空间 k3s-pkg,msg: v1),作为 AddOn 部署。用 kubectl 删除生成的 ConfigMap,等待 20 秒,确认它没有回来,然后把文件中的值改为 msg: v2,让它重新生成。在 /root/k3s-pkg/banner.json 中写入 deleted_uid(被删除那个的 UID)、restored_uid(重新生成那个的 UID)、returned_before_edit(在修改文件之前它是否回来了,布尔值)。
部署控制器在文件发生变化时以及 k3s 启动时进行应用。集群中的对象被删除这一事实,并不是触发应用的时机。AddOn 会记住文件的校验和,所以像 touch 这样内容相同的变更也不会成为触发时机。
用 kubectl 删除了 traefik
用 kubectl 删除 kube-system 中的 HelmChart traefik,并等待 traefik Deployment 消失(此时先不要重启)。在 /root/k3s-pkg/gone.json 中写入 deleted_at(删除的时刻,UTC RFC3339,例如:2026-01-01T00:00:00Z)、manifest_still_there(traefik.yaml 文件是否仍然存在,布尔值)、release_left(剩余的 traefik release Secret 数量,整数)。
HelmChart 上带有 helm-controller 的终结器(finalizer),删除时 helm-delete Job 会先删除 release。Helm release 会以带有 owner=helm,name=traefik 标签的 Secret 形式保留在 kube-system 中。即使删除集群对象,manifests 目录也不会被触动。
重启之后 traefik 又复活了
用 systemctl restart k3s 重启 k3s,并等待 traefik Deployment 再次变为 Available。在 /root/k3s-pkg/revive.json 中写入 helmchart_uid(重新生成的 HelmChart traefik 的 UID)、helmchart_created(它的 creationTimestamp)、revived(Deployment 是否恢复了,布尔值)。
k3s 每次启动时都会把默认组件的清单重新写入磁盘并应用。如果没有由文件创建的 HelmChart,就会重新创建,随后 helm-install Job 再次运行。从 API 就绪到 traefik 启动之间,大约相差 20 秒。
.skip 不会删除,只是装作没看见
用 /var/lib/rancher/k3s/server/manifests/lab-pinned.yaml 部署 ConfigMap pinned(命名空间 k3s-pkg,v: "1")。确认它生成之后,在同一目录中创建 lab-pinned.yaml.skip,把文件中的值改为 v: "2",并等待 20 秒。在 /root/k3s-pkg/skip.json 中写入 file_value(文件中写的值)、live_value(集群 ConfigMap 中的值)、addon_still_exists(AddOn lab-pinned 是否仍然存在,布尔值)。
.skip 文件只看是否存在,不看内容。已经应用的 AddOn 以及它所创建的对象保持原样,此后对该文件的变更会被忽略。
用一个 drop-in 关闭 metrics-server
保持 /etc/rancher/k3s/config.yaml 不变,创建 /etc/rancher/k3s/config.yaml.d/50-disable.yaml 来关闭 metrics-server。local-storage 必须保持关闭。写完文件后,先确认 metrics-server 在 20 秒内保持原样,然后重启 k3s。在 /root/k3s-pkg/disable.json 中写入 changed_before_restart(重启之前它是否消失了,布尔值)、removed_addons(因重启而消失的 AddOn 名称排序后的数组)、files_left(manifests/metrics-server 下剩余的文件数,整数)。
drop-in 按名称顺序读取,如果多个文件中有相同的键,则以最后一个值为准。要追加到列表中,就在键名末尾加上 +。--disable 不仅会移除 AddOn,还会删除原文件。配置文件在 k3s 启动时读取。
修改了 config.yaml,权限却没变
在 /etc/rancher/k3s/config.yaml 中保留原有的 disable 列表,并加入 write-kubeconfig-mode: "0600",然后重启 k3s。查看 /etc/rancher/k3s/k3s.yaml 的权限变成了什么,并在 /root/k3s-pkg/precedence.json 中写入 config_value(config.yaml 中写的值,字符串)、effective_mode(重启后 k3s.yaml 的八进制权限,字符串,例如:"640")、winner(cli 或 config)、flag_file(写有胜出值的文件的绝对路径)。
如果配置文件和 CLI 参数中有相同的键,CLI 优先。传给安装脚本的 INSTALL_K3S_EXEC 会作为参数保存在 systemd 单元的 ExecStart 中。请用 systemctl cat k3s 查看。
不重启,只修改 traefik 的值
不重启,在 /var/lib/rancher/k3s/server/manifests/traefik-config.yaml 中放置 HelmChartConfig traefik(kube-system),把 traefik 的日志级别改为 DEBUG(logs.general.level)。在 /root/k3s-pkg/hcc.json 中写入 revision_before(应用前 traefik release 的最大 revision,整数)、revision_after(应用后,整数)、log_arg(traefik 容器参数中完整的日志级别参数)。
HelmChartConfig 的名称和命名空间必须与目标 HelmChart 相同。valuesContent 优先于 HelmChart 的 valuesContent,但弱于 spec.set。由于 helm-controller 会运行 helm upgrade,release Secret 会增加一个(sh.helm.release.v1.traefik.vN)。
把删除、忽略、覆盖整理成一张表
在 /root/k3s-pkg/report.json 中写入 needs_restart(对象:manifest_file、skip_file、helmchartconfig、config_dropin 各自是否需要重启才生效,布尔值)、revived_by_restart(第 3、4 步中因重启而复活的 HelmChart 名称)、disable_deletes_files(布尔值)、skip_removes_resources(布尔值)、current_addons(当前 kube-system 中 AddOn 名称排序后的数组)、traefik_revision(当前 traefik release 的最大 revision,整数)。
依据前面步骤留下的 json 和当前集群来填写。评分器会从集群和记录文件中重新计算同样的值。