etcd 是一个强一致、分布式的键值存储系统,常用于保存分布式系统的关键配置数据与服务发现信息(Kubernetes 即以其作为唯一的状态存储)。完成本教程后,您将能够:
- 在任意一台 Linux 主机上以容器方式运行单节点 etcd 并完成读写验证;
- 在三台主机上引导一个具备容错能力的 etcd 生产集群;
- 对集群进行健康检查、数据持久化、快照备份与故障排查。
重要 **本教程中的命令以 etcd **v3.6.12 为例(撰写时的最新稳定版)。生产环境请务必固定到具体的版本标签(如
v3.6.12),不要使用latest标签——latest可能指向非预期版本。
目录
- 先决条件
- 安装 Docker 引擎
- 准备 etcd 镜像
- 单节点快速入门
- 部署三节点生产集群
- 安全加固(TLS 与鉴权)
- 数据持久化与快照备份
- 故障排除
- 清理资源
- 后续步骤
1. 先决条件
在开始之前,请确认您的环境满足以下条件。
1.1 操作系统与硬件
| 资源 | 最低要求 | 推荐(生产) |
|---|---|---|
| 操作系统 | Ubuntu 20.04+ / CentOS 7+(含 Stream、Rocky、Alma)/ CTyunOS | 同左 |
| vCPU | 2 | 4 及以上 |
| 内存 | 2 GB | 8 GB 及以上 |
| 磁盘 | 20 GB(SSD) | 50 GB 及以上(SSD/NVMe) |
| 节点数(集群) | — | 3(或 3 的奇数倍,如 5) |
注意etcd 对磁盘 I/O 延迟非常敏感。生产环境强烈建议使用本地 SSD 或 NVMe 盘,避免使用网络存储,否则会显著拖慢写入与领导者选举。
1.2 网络与端口
| 端口 | 用途 | 访问范围 |
|---|---|---|
| 2379/TCP | 客户端访问(client API) | 仅对应用与运维网段开放 |
| 2380/TCP | 集群节点间通信(peer) | 仅对 etcd 集群成员开放 |
请确保安全组(云平台)与主机防火墙(ufw / firewalld)已放行上述端口,且节点间可双向通信。例如:
# Ubuntu (ufw)
sudo ufw allow 2379/tcp
sudo ufw allow 2380/tcp
# CentOS / CTyunOS (firewalld)
sudo firewall-cmd --permanent --add-port=2379/tcp
sudo firewall-cmd --permanent --add-port=2380/tcp
sudo firewall-cmd --reload
1.3 账户与工具
- **拥有 **
sudo或root权限的账户; - 节点间时间同步(NTP/chrony),etcd 依赖一致的系统时间;
- 三台主机之间可通过主机名或 IP 互通(部署集群时)。
2. 安装 Docker 引擎
etcd 的容器运行依赖 Docker 引擎。请根据您的操作系统选择对应章节。
2.1 Ubuntu
# 1. 更新包索引并安装依赖
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg lsb-release
# 2. 添加 Docker 官方 GPG 密钥
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# 3. 添加 Docker 软件源
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 4. 安装 Docker 引擎及相关组件
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
# 5. 将当前用户加入 docker 组(免 sudo 运行 docker,需重新登录生效)
sudo usermod -aG docker $USER
2.2 CentOS / RHEL
适用于 CentOS 7/8、CentOS Stream、Rocky Linux、AlmaLinux 等 RHEL 系发行版。
# 1. 卸载可能冲突的旧版本
sudo yum remove -y docker \
docker-client docker-client-latest \
docker-common docker-latest docker-latest-logrotate \
docker-logrotate docker-engine
# 2. 安装 yum-utils 并添加 Docker 源
sudo yum install -y yum-utils
sudo yum-config-manager \
--add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 3. 安装 Docker 引擎
sudo yum install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
# 4. 启动并设置开机自启
sudo systemctl enable --now docker
2.3 CTyunOS
**CTyunOS(天翼云云操作系统)基于 openEuler,使用 **dnf 作为包管理器。openEuler 官方源自带 docker-engine 包,可一键安装;若需要较新的 Docker CE,则需额外配置 CentOS 8 兼容源。
方式 A:使用系统自带 docker-engine(最简单)
sudo dnf install -y docker
sudo systemctl enable --now docker
注意 **openEuler/CTyunOS 官方源提供的 **
docker-engine版本相对较旧(如 18.09)。如对功能或兼容性有更高要求,请使用方式 B。
方式 B:安装最新版 Docker CE
# 1. 若已安装 docker-engine,先卸载以避免包冲突
sudo dnf remove -y docker docker-engine
# 2. 安装 Docker CE
sudo dnf install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
# 3. 启动并设置开机自启
sudo systemctl enable --now docker
2.4 验证安装
无论使用哪种操作系统,安装完成后均执行以下命令验证:
docker --version
docker run hello-world
**若终端出现 **Hello from Docker! 的提示信息,说明 Docker 引擎已正确安装并运行。
2.5(可选)配置镜像加速
国内从 Docker Hub 拉取镜像可能较慢,可配置镜像加速器:
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json > /dev/null <<'EOF'
{
"registry-mirrors": ["https://<您的镜像加速器地址>"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
注意
registry-mirrors仅对 Docker Hub 生效。gcr.io与quay.io上的 etcd 镜像若拉取缓慢或失败,可:(1) 自建 pull-through 缓存代理;(2) 使用可访问的第三方镜像源预先拉取后通过docker save/load传入节点;(3) 在网络可达的跳板机上拉取后传输。
3. 准备 etcd 镜像
拉取固定版本的 etcd 镜像:
docker pull quay.io/coreos/etcd:v3.6.12
注意etcd 官方提供两个内容一致的镜像仓库:
- 首选:
gcr.io/etcd-development/etcd- 备选:
quay.io/coreos/etcd(本教程统一使用此仓库)**二者可任选其一。请始终固定到具体的版本标签(如 **
v3.6.12)。
验证镜像与内置工具:
docker run --rm quay.io/coreos/etcd:v3.6.12 /usr/local/bin/etcd --version
docker run --rm quay.io/coreos/etcd:v3.6.12 /usr/local/bin/etcdctl version
4. 单节点快速入门
本节在一台主机上部署单节点 etcd,适合学习、开发与测试。
4.1 启动容器
docker run -d \
--name etcd \
--restart=always \
-p 2379:2379 \
-p 2380:2380 \
-v etcd-data:/etcd-data \
quay.io/coreos/etcd:v3.6.12 \
/usr/local/bin/etcd \
--name etcd-single \
--data-dir /etcd-data \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://127.0.0.1:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://127.0.0.1:2380 \
--initial-cluster etcd-single=http://127.0.0.1:2380 \
--initial-cluster-state new \
--initial-cluster-token etcd-single-token
参数说明:
| 参数 | 含义 |
|---|---|
--name |
当前节点名称,集群内需唯一 |
--data-dir |
数据目录(已挂载到命名卷etcd-data) |
--listen-client-urls |
监听客户端请求的地址 |
--advertise-client-urls |
对外通告的客户端地址(客户端据此连接) |
--listen-peer-urls |
监听集群伙伴请求的地址 |
--initial-advertise-peer-urls |
对外通告的伙伴地址(其他节点据此连接) |
--initial-cluster |
初始集群成员列表 |
--initial-cluster-state |
new表示全新集群,existing表示加入已有集群 |
--initial-cluster-token |
集群令牌,用于区分不同集群 |
4.2 验证读写
# 查看容器状态与日志
docker ps
docker logs etcd
# 查看集群成员
docker exec etcd /usr/local/bin/etcdctl \
--endpoints=http://127.0.0.1:2379 member list
# 写入与读取一个键值
docker exec etcd /usr/local/bin/etcdctl \
--endpoints=http://127.0.0.1:2379 put foo bar
docker exec etcd /usr/local/bin/etcdctl \
--endpoints=http://127.0.0.1:2379 get foo
预期输出:put 返回 OK,get 返回 foo 与 bar 两行,表示 etcd 已可正常读写。
注意自 etcd v3.4 起,
etcdctl默认使用 v3 API,无需再显式设置ETCDCTL_API=3。
5. 部署三节点生产集群
**生产环境应部署多节点集群以保证高可用。etcd 采用 Raft 协议,建议使用 **3 个节点(可容忍 1 个节点故障)或 5 个节点(可容忍 2 个故障)。本节部署一个三节点集群。
5.1 节点规划
准备三台主机,规划如下(请将 IP 替换为您的实际地址):
| 节点名 | 主机 IP | 客户端端口 | 对等端口 |
|---|---|---|---|
| etcd-1 | 10.0.0.11 | 2379 | 2380 |
| etcd-2 | 10.0.0.12 | 2379 | 2380 |
| etcd-3 | 10.0.0.13 | 2379 | 2380 |
重要多节点集群中,
--advertise-client-urls与--initial-advertise-peer-urls必须使用其他节点可访问的真实 IP,不能使用127.0.0.1,否则节点间无法建立连接。
5.2 启动节点
提示 **本节使用 **
--network host模式:容器直接使用宿主机网络栈,容器内监听地址即为宿主机地址,无需端口映射,最适合跨主机的 etcd 集群。
在节点 1(10.0.0.11)上执行:
docker run -d \
--name etcd \
--restart=always \
--network host \
-v /var/lib/etcd:/etcd-data \
quay.io/coreos/etcd:v3.6.12 \
/usr/local/bin/etcd \
--name etcd-1 \
--data-dir /etcd-data \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://10.0.0.11:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://10.0.0.11:2380 \
--initial-cluster etcd-1=http://10.0.0.11:2380,etcd-2=http://10.0.0.12:2380,etcd-3=http://10.0.0.13:2380 \
--initial-cluster-state new \
--initial-cluster-token etcd-prod-cluster
在节点 2(10.0.0.12)上执行:
docker run -d \
--name etcd \
--restart=always \
--network host \
-v /var/lib/etcd:/etcd-data \
quay.io/coreos/etcd:v3.6.12 \
/usr/local/bin/etcd \
--name etcd-2 \
--data-dir /etcd-data \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://10.0.0.12:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://10.0.0.12:2380 \
--initial-cluster etcd-1=http://10.0.0.11:2380,etcd-2=http://10.0.0.12:2380,etcd-3=http://10.0.0.13:2380 \
--initial-cluster-state new \
--initial-cluster-token etcd-prod-cluster
在节点 3(10.0.0.13)上执行:
docker run -d \
--name etcd \
--restart=always \
--network host \
-v /var/lib/etcd:/etcd-data \
quay.io/coreos/etcd:v3.6.12 \
/usr/local/bin/etcd \
--name etcd-3 \
--data-dir /etcd-data \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://10.0.0.13:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://10.0.0.13:2380 \
--initial-cluster etcd-1=http://10.0.0.11:2380,etcd-2=http://10.0.0.12:2380,etcd-3=http://10.0.0.13:2380 \
--initial-cluster-state new \
--initial-cluster-token etcd-prod-cluster
重要三台节点上的
--initial-cluster、--initial-cluster-token、--initial-cluster-state必须完全一致,仅--name与各 advertise 地址随节点变化。三台节点需同时启动(或在彼此--initial-cluster-state=new的引导窗口内启动),集群才能成功组建。
5.3 验证集群
在任意一台节点上执行:
# 查看成员列表
docker exec etcd /usr/local/bin/etcdctl \
--endpoints=http://10.0.0.11:2379,http://10.0.0.12:2379,http://10.0.0.13:2379 \
member list --write-out=table
# 检查各端点健康状态(应为 3 个 healthy)
docker exec etcd /usr/local/bin/etcdctl \
--endpoints=http://10.0.0.11:2379,http://10.0.0.12:2379,http://10.0.0.13:2379 \
endpoint health --write-out=table
# 查看端点状态(含 leader、raft term、DB 大小)
docker exec etcd /usr/local/bin/etcdctl \
--endpoints=http://10.0.0.11:2379,http://10.0.0.12:2379,http://10.0.0.13:2379 \
endpoint status --write-out=table
**预期 **member list 列出 3 个成员,endpoint health 全部显示 healthy,endpoint status 中有且仅有一个节点标记为 true(即 leader)。
5.4 容错验证
停止某一节点(例如节点 3),观察集群是否仍可正常读写:
# 在节点 3 上停止容器
docker stop etcd
# 在节点 1 上读写,集群应仍可正常工作(容忍 1 节点故障)
docker exec etcd /usr/local/bin/etcdctl \
--endpoints=http://10.0.0.11:2379 put ha-test ok
docker exec etcd /usr/local/bin/etcdctl \
--endpoints=http://10.0.0.11:2379 get ha-test
验证完成后恢复节点 3:
# 在节点 3 上重新启动
docker start etcd
6. 安全加固(TLS 与鉴权)
重要默认配置下 etcd 的客户端与伙伴通信均为明文,且无鉴权。生产环境****必须启用 TLS 与访问控制,否则任何可达 2379 端口的主机都可读写您的数据。
6.1 启用 TLS
**为客户端(client)与节点间(peer)通信分别启用 TLS,需准备 CA 证书与各节点证书(证书生成属独立主题,可使用 **cfssl 或 openssl,本节假定证书已就绪并放置于宿主机 /etc/etcd/ssl)。
**在原有 **docker run 命令中追加挂载与以下参数:
-v /etc/etcd/ssl:/etc/etcd/ssl:ro \
... \
# 客户端 TLS
--client-cert-auth \
--trusted-ca-file /etc/etcd/ssl/ca.pem \
--cert-file /etc/etcd/ssl/server.pem \
--key-file /etc/etcd/ssl/server-key.pem \
# 节点间 TLS
--peer-client-cert-auth \
--peer-trusted-ca-file /etc/etcd/ssl/ca.pem \
--peer-cert-file /etc/etcd/ssl/peer.pem \
--peer-key-file /etc/etcd/ssl/peer-key.pem
启用后,etcdctl 也需携带证书:
docker exec etcd /usr/local/bin/etcdctl \
--endpoints=https://10.0.0.11:2379 \
--cacert /etc/etcd/ssl/ca.pem \
--cert /etc/etcd/ssl/client.pem \
--key /etc/etcd/ssl/client-key.pem \
member list
6.2 启用鉴权
启用基于角色的访问控制(RBAC),创建 root 用户与角色:
# 创建 root 用户
docker exec etcd /usr/local/bin/etcdctl --endpoints=http://127.0.0.1:2379 \
user add root
# 授予 root 角色
docker exec etcd /usr/local/bin/etcdctl --endpoints=http://127.0.0.1:2379 \
user grant-role root root
# 启用鉴权
docker exec etcd /usr/local/bin/etcdctl --endpoints=http://127.0.0.1:2379 \
auth enable
警告 **启用鉴权后,所有后续操作都必须携带 **
--user root:<密码>参数。请妥善保管 root 密码,丢失将导致无法管理集群。
7. 数据持久化与快照备份
7.1 持久化
- **单节点示例已通过命名卷 **
etcd-data持久化; - **集群示例已将宿主机 **
/var/lib/etcd挂载到容器内,数据直接落盘宿主机。
容器删除重建后,只要挂载路径不变,数据即可恢复。
7.2 快照备份
定期对 etcd 做快照是灾难恢复的关键。在任意健康节点上执行:
# 1. 生成快照(保存到挂载目录内)
docker exec etcd /usr/local/bin/etcdctl \
--endpoints=http://10.0.0.11:2379 \
snapshot save /etcd-data/snapshot.db
# 2. 将快照拷贝到宿主机(建议进一步转存到对象存储)
docker cp etcd:/etcd-data/snapshot.db ./etcd-snapshot.db
# 3. 验证快照完整性
docker exec etcd /usr/local/bin/etcdctl \
snapshot status /etcd-data/snapshot.db --write-out=table
提示 **建议将快照备份纳入定时任务(如 cron),并异地保存。从快照恢复属于独立的运维流程,可参考 etcd 官方文档的 **disaster recovery 章节。
8. 故障排除
| 现象 | 可能原因与处理 |
|---|---|
| 节点启动后集群一直无法选主 | 三节点的--initial-cluster/--initial-cluster-token不一致;或 advertise 地址不可达。请逐项核对,并确认使用的是真实可达 IP 而非127.0.0.1。 |
| 节点重启后无法重新加入 | 首次引导后再次启动时--initial-cluster-state仍设为new。集群组建后,节点重启应使用existing。 |
| 拉取镜像超时 / TLS handshake timeout | gcr.io/quay.io在部分网络不可达。参见第 2.5 节「配置镜像加速」,或通过跳板机docker save/load离线传入镜像。 |
etcdctl报版本不匹配 |
宿主机安装的etcdctl与集群大版本差异过大。建议统一使用容器内自带的etcdctl(版本与集群一致)。 |
connection refused/ 无法访问 2379 |
安全组或防火墙未放行端口;或--listen-client-urls未包含0.0.0.0。 |
| 写入延迟很高、频繁切主 | 磁盘 I/O 抖动(常见于共享/网络存储)。改用本地 SSD,并检查是否有其他 I/O 密集进程争用。 |
查看实时日志以辅助排查:
docker logs -f etcd
9. 清理资源
完成测试后,可按需清理。
9.1 单节点
docker rm -f etcd
docker volume rm etcd-data
9.2 集群(在三台节点上分别执行)
docker rm -f etcd
sudo rm -rf /var/lib/etcd
警告
rm -rf /var/lib/etcd会永久删除该节点的所有 etcd 数据,操作前请确认无需保留或已完成快照备份。
10. 后续步骤
- 监控:etcd 在
/metrics暴露 Prometheus 指标,可接入 Prometheus + Grafana 监控领导者变更、提交延迟、DB 大小等关键指标。 - 压缩与碎片整理:定期执行
etcdctl compact与etcdctl defrag,控制历史版本与磁盘占用。 - 成员管理:学习使用
member add/member remove在线扩缩容集群。 - 灾难恢复:熟悉从快照恢复集群的完整流程,制定灾备预案。
- 生产加固:参见 etcd 官方文档的 hardware、security 与 tuning 章节进行生产调优。
参考
- etcd 官方文档:https://etcd.io/docs/
- etcd GitHub Releases:https://github.com/etcd-io/etcd/releases
- Docker 官方安装指南:https://docs.docker.com/engine/install/
- openEuler 容器(Docker)文档:https://docs.openeuler.org/zh/docs/22.03_LTS/docs/Container/docker-container.html