这个站(包括二维码平台和在线工具箱)跑在一台云服务器上。不是买不起第二台,而是想清楚了一件事:对个人项目来说,多副本带来的可用性提升,远不如把单机的持久化、备份和恢复做扎实来得实在。
下面记录这套环境的选型过程、落地结构,以及踩过的坑。
为什么是 k3s 而不是 k8s 或 docker compose
三个选项摆在一起比较:
- docker compose:最简单,但没有健康检查自动恢复、没有声明式的滚动更新,进程挂了得自己发现。
- 标准 Kubernetes:能力最全,但对单节点来说是杀鸡用牛刀,光控制面就要吃掉 1–2 GB 内存。
- k3s:单个二进制、内置 Traefik 做 Ingress、默认用 SQLite 也能换外部存储,控制面开销小,而且是 CNCF 认证的发行版,命令和 kubectl 完全一致。
最后选了 k3s。它把”我想用 kubectl 和 YAML 管一切”和”我只有一台 4C8G 的机器”这两件事调和了。
落地结构
节点是 vm-20-8-ubuntu,跑 k3s v1.32.1+k3s1。环境隔离用命名空间而不是用两台机器:
prod命名空间对外是www.mazter.cn,beta对外是beta.mazter.cn。- 两个命名空间跑同一套镜像,差异只在 ConfigMap 和 Ingress host。
- 数据库、Redis 这种有状态服务也各部署一份,靠库名和 db 编号隔离(
wordpress_prod/wordpress_beta,Redis db0 / db1)。
这样改配置不会污染生产,发布前先在 beta 验一遍,确认没问题再推 prod。
存储的硬边界
单节点上所有卷都落在本地磁盘(hostPath / 本地 PVC)。这带来一个必须记住的限制:
单节点卷没法被另一个节点挂载,所以任何 Deployment 的副本数都只能是 1。
这不是配置疏忽,是物理限制。想要多副本,就得先解决分布式存储(NFS、Longhorn、云盘),而那会把事情复杂好几倍。对个人项目来说,接受”单点”这个事实,然后把备份和恢复做扎实,是更划算的选择。
两个值得记的命令行坑
第一个是 KUBECONFIG 必须用绝对路径。用相对路径且路径写错时,kubectl 不会报”找不到 kubeconfig”,而是静默回落到默认的 http://localhost:8080,于是你看到的是:
Unable to connect to the server: dial tcp 127.0.0.1:8080: connect: connection refused
这看起来像”集群挂了”,实际上是”配置文件没读到”。排查方向会完全跑偏。
第二个是本机可能同时配了多个集群的 context,默认 context 未必是你想操作的那个。每次执行前显式指定能省掉很多麻烦:
export KUBECONFIG=/path/to/key-house/k3s-master-cn.yaml
kubectl config current-context # 确认一下再动手
什么时候这套方案不合适
这套结构的前提是”能接受短暂不可用”。如果要做的是需要 99.9% SLA 的业务,或者数据丢了会出事,那单节点就不该出现在选项里。
对个人作品站、工具类站点来说,它不是妥协,是清醒。