只有挂载 VPN 配置,它才能在容器重建后保留下来
在运行中的容器里直接编辑的文件位于会消失的层。比较绑定挂载、卷和机密,然后重建容器并核对四件事。
你在运行中的容器里编辑 WireGuard 配置,它工作正常,而下一次镜像更新会把它抹掉。配置并没有写错。这个文件位于容器的可写层,而该层只为这一个容器实例存在。真正要比较的不是用哪个工具,而是你的部署声明了哪些输入。凡是手工改过的东西,都是部署并不知道的输入。
两种状态,其中一种是一次性的
容器有一个用于运行时改动的可写层,容器被替换时这层会被丢弃。它不是配置仓库,也不是备份。镜像加上已声明的输入,才是运行内容的完整定义。
问一问:哪些 VPN 文件是声明过的输入,哪些只是意外:
docker diff wg-vpn
docker inspect --format '{{json .Mounts}}' wg-vpndiff 会列出可写层里改了什么,那正是将要消失的东西。挂载列表则显示什么会留下。把两者一比,就能在丢失之前得到答案。
绑定挂载、命名卷还是机密:各自保护什么
三者都能存放 VPN 配置,区别在于谁有权限读取,以及替换时会发生什么。
| Mechanism | Survives recreation | Who can read it |
|---|---|---|
| Writable layer | No | Anyone with container access, until it is gone |
| Bind mount | Yes, while the host path exists | Whatever the host permissions allow |
| Named volume | Yes, until the volume is removed | Managed by the runtime |
| Secret | Yes, as a declared input | The container process, by design |
绑定挂载会映射主机路径,因此文件的保护程度取决于该路径,可见范围取决于主机的权限。命名卷由运行时管理,容器删除后仍然存在,因此对于部署所拥有的状态,它是更安全的默认选择。机密机制用于你不希望放进镜像或环境变量的材料。
不要把每个环境变量和每个主机文件都当成同等强度的保护,它们并不是。
在容器内部编辑就是陷阱
陷阱不在工具,而在改动方向。在运行中的容器里做的改动对部署不可见,于是下一次重建会悄悄把它回滚,症状看起来像镜像里的回归。若必须在那里改动以排查问题,请立即复制出来并放进已声明的输入。然后再重建,证明部署能复现它。
配置可能包含私钥和账户材料,因此备份该文件属于机密处理工作,而不是文件拷贝。把属主和读取权限限制在容器的实际进程上,而不是为了消掉权限错误就放宽主机目录。
这种放宽正是容器里的便利变成主机暴露的方式。
有意识地重建,然后核对四件事
记录镜像版本、所需设备和能力、网络接入以及持久输入。设备与能力清单对 VPN 容器尤其重要,因为隧道需要网络设备以及配置它的权限。
确认哪些生成的运行时状态应当重建而不是保存。隧道首次启动时生成的密钥属于状态,保留还是重新生成,会影响每一个知道旧公钥的对端。
受控重建之后,核对身份、路由、DNS 以及必需的失败阻断。一个没有报错就启动的进程,并不能证明这四项中的任何一项。要在隧道运行期间检查一次,停止之后再检查一次,因为失败阻断只在隧道消失时才显现。
在容器之外保留恢复副本
在容器之外保留一份独立的恢复副本,并按照文档流程测试恢复。未经测试的 VPN 配置备份只是一种希望,尤其是当恢复路径涉及容器进程所需的权限时。
如果持有 VPN 的容器被替换,要在运行时支持的生命周期内协调共享其网络栈的应用。
这种协调就是重启与中断的区别。部署应当说明配置从哪里来,而卷文档正是核对运行时真正保留了什么的地方。