高可用配置:Raft 与 Consul 存储后端

说到 Vault 的高可用,我个人觉得最绕不开的就是存储后端的选择。Vault 本身不保存数据,所有加密信息都搁在后端存储里。高可用说白了就是让多个 Vault 实例共享同一个存储后端,并且能自动切主。我早年搭第一套生产环境时,选了 Consul,后来换成了 Raft,踩了不少坑。下面把我的经验掰开揉碎讲给你听。

Raft vs Consul:核心差异

这两个方案都支持高可用,但底子完全不同。

对比项Raft 集成存储(集成存储)Consul 存储后端
依赖组件无外部依赖,Vault 自带 Raft 一致性算法需要独立部署 Consul 集群(至少 3 节点)
数据持久化Vault 节点本地磁盘Consul 的 KV Store(内存+快照)
一致性协议RaftRaft(Consul 内部实现)
故障转移方式自动 Leader 选举,对客户端透明自动 Leader 选举,但依赖 Consul 集群健康
运维复杂度低,一个 Vault 进程搞定中,需要额外维护 Consul 集群
性能中等,写操作需半数以上节点确认较高,但受 Consul 性能瓶颈影响
网络要求节点间延迟低,推荐同一机房同左,但 Consul 本身对网络抖动更敏感
我的经验: 如果你刚开始搭建 Vault 生产环境,且团队不熟悉 Consul,优先选 Raft 集成存储。少一个运维对象就少一个故障点。我在第一家公司因为 Consul 集群脑裂导致 Vault 不可用,后来全切成了 Raft。

搭建案例:Raft 模式集群

直接上命令,我习惯用 vault operator init 和 vault operator raft join 这条线。

1. 启动第一个节点(Leader)

vault server -config=/etc/vault/config.hcl

config.hcl 里必须启用 raft 存储:

storage "raft" {
  path = "/opt/vault/data"
  node_id = "node1"
}

listener "tcp" {
  address     = "0.0.0.0:8200"
  tls_disable = true
}

api_addr = "http://192.168.1.10:8200"
cluster_addr = "http://192.168.1.10:8201"
disable_mlock = true
ui = true

启动后初始化并解封:

export VAULT_ADDR='http://192.168.1.10:8200'
vault operator init -key-shares=5 -key-threshold=3
vault operator unseal # 输入3个key

2. 加入第二个、第三个节点

在节点2和节点3上执行:

vault server -config=/path/to/node2-config.hcl

然后从任意已初始化的节点执行加入命令:

vault operator raft join http://192.168.1.10:8200

重复解封流程。等节点都加入后,用 vault operator raft list-peers 确认集群状态。

注意: Raft 集群至少需要 3 个节点才能容忍一个节点故障。我曾经图省事只搭了 2 个节点,结果一台宕机后整个集群就没了写入能力——Raft 要求多数派存活,2 节点的多数派是 2,挂一个就只剩 1 个,够不成多数派。

搭建案例:Consul 后端模式

Consul 后端需要先建好 Consul 集群,这个我就不展开了。Vault 配置里写:

storage "consul" {
  address = "127.0.0.1:8500"
  path    = "vault/"
  service = "vault"
}

注意 Consul 的 ACL 开启时,Vault 需要具备读写 KV 的 。我踩过的坑:Consul 的 ACL 过期后,Vault 看似正常,但写入失败时会报 500。建议配置时加 health check。

故障转移机制

Raft 模式下,故障转移非常自然。Leader 挂了后,剩余节点重新选举,通常几秒内完成。客户端只要配置了多个 VAULT_ADDR 或使用负载均衡器指向所有节点,就能自动重试到新 Leader。

Consul 模式下,Vault 主节点实际上是一个 Consul 的 session,当主节点挂掉后,Consul 检测到 session 失效,其他 Vault 实例会抢夺锁,谁拿到谁成为新主。这个过程依赖 Consul 的健康检查间隔(默认 10 秒),所以故障切换可能比 Raft 慢一些。

核心区别: Raft 是 Vault 自己管理一致性,Consul 是委托给外部。Raft 的切换速度由你配置的 raft_trailing_logs 和心跳间隔决定,我一般设置 retry_join 时心跳超时为 3 秒,切换基本在 5 秒内完成。

下面这张图直观对比两种架构的差距:

Raft 集成存储 vs Consul 后端的架构对比 Raft 集成存储 Vault-1 (Leader) Vault-2 (Follower) Vault-3 (Follower) • 无外部依赖 • 数据存在本地磁盘(/opt/vault/data) • Leader 故障 → 自动选举新 Leader Consul 存储后端 Vault-A Vault-B Vault-C Consul-1 Consul-2 Consul-3 • 需要独立 Consul 集群(至少 3 节点) • Vault 通过 API 读写 Consul KV • Consul session 失效 → 其他 Vault 抢锁

避坑指南

我之前在几个项目里攒了一些教训,列出来你参考:

  1. Raft 节点数量一定要是奇数。 3 或 5 个最佳。偶数节点(比如 4)容错能力不增反降,因为多数派还是要求超过半数,4 节点的多数派是 3,跟 3 节点一样只能坏 1 个,何必多花钱。
  2. Consul 后端千万别用单节点。 曾经有个同事图省事只用了一个 Consul,结果 Consul 挂了 Vault 直接变成只读。后来我们强制要求 Consul 至少 3 个节点,并且用 systemd 守护。
  3. Raft 的 retry_join 要写对。 启动时 retry_join 指向 Leader 地址,如果你写的是 Follower,节点会一直重试直到 Leader 出现。但如果你写的是负载均衡器地址,最好确认负载均衡能指向当前 Leader(推荐用主动健康检查)。
  4. 网络分区:Raft 集群出现网络隔离时,被隔离的节点会变成 Candidate,不断发起选举,可能导致磁盘 IO 飙升。我在 AWS 遇到过一次跨可用区延迟过高导致频繁选举,后来把节点全放到同一个可用区解决了。
我的小建议: 不管选 Raft 还是 Consul,日常要监控 vault.raft.leader 和 vault.core.unsealed 指标。一旦发现 Leader 切换频繁,第一时间检查网络和磁盘延迟。我曾经因为一台机器磁盘 IO 打满,导致 Raft 心跳超时,集群反复切主,服务抖动了好几分钟。

好了,这就是我个人对 Vault 高可用的理解。两种方案没有的好坏,关键是匹配你的团队运维能力。如果你只有 3 台机器,我推荐 Raft;如果你已经有一个健康的 Consul 集群,复用它会减少额外运维负担。记住:生产环境永远先测试再上线,别像我当年那样直接对着业务集群搞实验。