Files
Deploy-Laboratory/docs/01-07-双控制节点ha.md
2026-03-29 09:08:01 +08:00

146 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 01-07-双控制节点HA安装与准备
## TL;DR
- **自动化验收(基线)**`./ansible/bin/verify.sh run 01-07`只做集群可达性基线HA 加入/切换需按本文手工演练)
- **你需要准备**:第二个 server、外部 datastore、**面向 `6443` 的负载均衡**(双主控硬前提);**仅两台主控、不想单独跑 HAProxy/nginx 时,优先 [kube-vip](https://kube-vip.io/)L2/ARP VIP见下节、维护窗口与备份
- **成功判据**:能按本文完成外部 datastore 与 LB 的准备清单;并在 `03-08` 中完成加入/切换演练
- **失败排障**见本文「排障」小节datastore/LB/tls-san/6443
> 本文只讲双控制节点 HA 的安装前准备与基础环境搭建。
> 具体集群参数切换、server 加入与迁移步骤见 `03-08-k3s-ha-集群配置与切换.md`。
## 前置条件
- 已完成 `01-01-k3s-控制节点含traefik.md`
- 已完成 `01-02-k3s-工作节点.md`
- 当前集群运行稳定,可执行维护窗口
## 目标与边界
- 目标:控制平面单点故障时仍可管理集群
- 边界:家庭网关(如 OpenWrt可能仍是整体单点
## 双主控与负载均衡
**双主控 = 要对 Kubernetes API 做负载均衡。** 至少一个 **稳定对外的入口地址**(或域名),其背后把 **`6443` 流量**落到**多个** `k3s server` 上(多活分摊或主备切换均可),这样 kubelet、kubectl、`K3S_URL` 与证书 `--tls-san` 才能始终指向同一逻辑端点,控制面才算 HA。
**HAProxy 不是唯一选项但「LB 这一层」不能省。** 常见实现:
| 做法 | 说明 |
|------|------|
| **HAProxy / nginx stream** 等 | 典型 **四层 LB**TCP 轮询/最少连接等到各 server 的 `6443` |
| **云厂商 / 硬件 LB** | 托管型四层 LB同上 |
| **kube-vip、Keepalived + VIP** | 常做成 **apiserver VIP**(对外仍是一个 IP背后与多 master 协同;语义上仍是「单入口 + 高可用后端」) |
**`01-06-openwrt-haproxy.md`** 的区别:**01-06** 的 HAProxy 面向 **HTTP/HTTPS80/443→ Traefik 应用入口****01-07 / 03-08** 要解决的是 **API Server6443的负载均衡**。可在同一台 OpenWrt 上同时部署,但须 **两套监听与后端**,不要与 01-06 的 `18080/18443` 配置混用。
### 推荐:只有两台主控、不用独立 HAProxy / nginx
目标:**不增加**专门跑 HAProxy、nginx stream 的第四台机器,只在 **两个 `k3s server` 节点**上解决「对外一个稳定 `6443` 地址」。
**首选 [kube-vip](https://kube-vip.io/)Layer 2 / ARP 模式Control Plane VIP**
| 项 | 说明 |
|----|------|
| 做什么 | 在**每个**主控节点上跑 kube-vip常见为 **static pod** 或与 k3s 集成的部署方式),在同网段申请一个 **VIP**(如 `192.168.2.60`VIP 随节点存活 **漂移**,客户端始终访问 `https://<VIP>:6443`。 |
| 为何适合双主控 | **不依赖**外部 HAProxy/nginx VM组件只落在主控上与「仅两台 server」拓扑一致。 |
| 网络前提 | 两主控与 VIP 须在 **同一二层广播域**家庭局域网通常满足VIP 需在网段内 **未被占用**。 |
| 与「多活轮询」 | 常见是 **主备式 VIP**(同一时刻由一台承接 `6443`),故障后漂到另一台;对双主控 HA **足够**。若要 **多活同时分摊** API 连接,才更偏向独立四层 LB。 |
| k3s 侧 | `--tls-san` / 证书须包含 **该 VIP**(及若使用则包含域名);`K3S_URL``kubeconfig` 的 server 地址指向 **VIP:6443**。具体安装与清单以官方与 `03-08` 演练为准。 |
**备选(仍无 HAProxy/nginx**:两节点 **Keepalived + VIP**,自行维护 `vrrp` 与脚本,语义与 kube-vip 类似,集成度略低。
**云上**:若无 L2 条件,可改用 **托管四层 LB** 指到各主控 `6443`(仍属负载均衡,只是不在你自己机器上跑进程)。
## 安装准备清单
1. 新增第二个 server 节点(示例 `192.168.2.63`
2. 准备外部数据存储MySQL/PostgreSQL/etcd
3. 准备 **`6443` 负载均衡****仅双主控、无独立 LB 机器时优先 kube-vipL2 VIP**;否则可选 HAProxy、nginx stream、云 LB 等
4. 备份现有 token 与关键配置
### 免费 PostgreSQL实验室推荐
k3s 的外部 datastore 只需 **兼容的 PostgreSQL****PostgreSQL 本体开源**[PostgreSQL License](https://www.postgresql.org/about/licence/)),无商业版授权问题,下列均为 **$0** 落地方式:
| 方式 | 适合场景 | 说明 |
|------|----------|------|
| **发行版软件包** | 有一台 **独立于 k3s 控制面** 的 Linux如工作机、ARM 小主机、虚拟机) | Fedora/RHEL`dnf install postgresql-server``postgresql-setup --initdb``systemctl enable --now postgresql`Debian/Ubuntu`apt install postgresql`。建库 `k3s`、用户与密码,在 `pg_hba.conf` 放行 k3s server 网段。 |
| **官方容器镜像 [postgres](https://hub.docker.com/_/postgres)** | 想快速起实例、少动系统包 | `docker` / `podman` 一行起库,例如:`podman run -d --name k3s-pg -e POSTGRES_USER=k3s -e POSTGRES_PASSWORD=strong-password -e POSTGRES_DB=k3s -p 5432:5432 docker.io/library/postgres:16`(版本号可按需调整)。数据卷请挂到持久目录。 |
| **托管免费档(容量/用量有限制)** | 不想自建、可接受 **公网** 与厂商条款 | 常见:**[Neon](https://neon.tech/)**Serverless Postgres免费档对 **存储、分支、计算时长** 等有限额,适合轻量/实验);**[Supabase](https://supabase.com/pricing)**(免费档含托管 Postgres**数据库容量、API 调用、带宽** 等受限)。另有各云「试用/免费层」Postgres均以 **官网当期配额** 为准。k3s 连接串一般需 **`sslmode=require`**(或厂商文档要求);**家庭实验室**须保证各 `k3s server` 能访问云库主机出口、防火墙、TLS。**仅免费档不宜当生产唯一 datastore**(易触顶、休眠策略、合规以厂商为准)。 |
**注意**datastore 建议与 **两个 k3s server 网络互通**、且 **不要** 只跑在「即将整体下线的那一台」唯一节点上,否则 datastore 单点与迁移成本更高。
### 双控 + datastore 还能不能「数据库集群」?
**可以。** 双主控解决的是 **Kubernetes API6443** 高可用;**外部 PostgreSQL** 这一层同样可以做成 **高可用/集群**,与双控 **不冲突**
- **k3s 侧**`--datastore-endpoint` 里填的仍是 **一个** 连接目标(`host` 多为 **VIP、LB 虚拟地址、托管库提供的单一 endpoint、或始终解析到当前主的 DNS**。k3s 只按 PostgreSQL 协议访问,不关心背后是单进程还是多节点。
- **数据库侧**:常见做法包括 **云托管多可用区 Postgres**RDS、Cloud SQL、Aurora 兼容端等)、**Patroni + etcd/Consul**、**repmgr** 等;由它们负责 **主备、故障转移**;对 k3s 必须保证故障转移后 **仍连到可写主库**(不要把 endpoint 指到 **只读副本**)。
- **取舍**PG 集群能消掉 **datastore 单点**,但 **运维复杂度**明显高于「单实例 Postgres」家庭实验室可先单库跑通双控再按需上 PG HA。
### 外部 datastore 与 k3s server 最小示例
以下只给出一个“最小可参考”的 PostgreSQL + k3s server 参数示意,具体地址/账号请按你自己的环境调整:
- **若采用 01-01 的数据盘方案**:在 server 参数中增加 `--data-dir=/storage`,与首节点一致(第二个 server 安装时同样需要)。
```bash
# 假设外部 PostgreSQL 已创建数据库与账号:
# host=192.168.2.50 dbname=k3s user=k3s password=strong-password
# 在首个 server例如 192.168.2.61)上,默认数据目录:
sudo k3s server \
--datastore-endpoint="postgres://k3s:strong-password@192.168.2.50:5432/k3s?sslmode=disable" \
--tls-san 192.168.2.61 \
--tls-san 192.168.2.62 \
--tls-san 192.168.2.63 \
--tls-san 192.168.2.60 # 这里示例为 LB IP
# 若使用数据盘方案,增加 --data-dir=/storage例如
# sudo k3s server --data-dir=/storage \
# --datastore-endpoint="postgres://..." --tls-san ...
```
> 说明:上面的命令仅作为参数示意,实际部署时建议改用 systemd unit 或官方安装脚本的额外参数(`INSTALL_K3S_EXEC=...`),并结合 `03-08-k3s-ha-集群配置与切换.md` 中的步骤执行。
### 从现有 worker 升级为第二控制节点(推荐路径)
在家庭实验室环境中,第二个控制节点通常可以直接复用一台已有的 worker 节点。整体思路是:
1. **确认 worker 节点健康**
- 已按 `01-02-k3s-工作节点.md` 正常加入集群;
- 无关键 Pod 仅运行在该节点(可先用 `kubectl drain` 或手动迁移工作负载)。
2. **在 `01-07` 阶段完成外部 datastore 与 LB 准备**
- 不要立即改动现有 server/worker 的 systemd 配置,只确保 datastore/LB 均已就绪。
3. **在 `03-08` 中按步骤将该 worker 替换为 server**
- 停止该节点上的 `k3s-agent` 服务(或执行官方卸载脚本);
- 使用与首个 server 相同的 token/datastore/LB 地址重新以 `server` 角色安装 k3s
- 最终形成“2 个 server + 若干 worker”的目标拓扑。
> 具体切换命令与顺序详见:`03-08-k3s-ha-集群配置与切换.md` 中的操作步骤。
## 基础验证
```bash
kubectl get nodes -o wide
kubectl get pods -A
```
## 风险提示
- 这是高级改造,建议在业务稳定后执行
- 执行前务必做完整备份
## 下一步
- `03-08-k3s-ha-集群配置与切换.md`:加入第二个 server、切换与演练
## 排障
- **LB 6443 不通**:先在客户端 `curl -k https://<lb_ip>:6443/ping`;再在各 server 检查监听与防火墙放行。
- **加入第二个 server 后 kubeconfig 指向错误地址**:确认 `--tls-san` 包含 LB IP/域名与各 server IP并更新 kubeconfig server 地址。
- **外部 datastore 连接失败**:检查连接串、网络 ACL、防火墙、账号权限在 server 上用 `psql/mysql` 先手工连通再跑 k3s 参数。