etcd项目
etcd 是 CoreOS 团队发起的一个管理配置信息和服务发现(Service Discovery)的项目,在这一章里面,我们将基于 etcd 3.x 版本介绍该项目的目标,安装和使用,以及实现的技术
什么是 etcd
etcd 是 CoreOS 团队于 2013 年 6 月发起的开源项目,它的目标是构建一个高可用的分布式键值(key-value)数据库,基于 Go 语言实现。我们知道,在分布式系统中,各种服务的配置信息的管理分享,服务的发现是一个很基本同时也是很重要的问题。CoreOS 项目就希望基于 etcd 来解决这一问题。
etcd 目前在 github.com/etcd-io/etcd 进行维护。
受到 Apache ZooKeeper 项目和 doozer 项目的启发,etcd 在设计的时候重点考虑了下面四个要素:
-
简单:具有定义良好、面向用户的 API (gRPC)
-
安全:支持 HTTPS 方式的访问
-
快速:支持并发 10 k/s 的写操作
-
可靠:支持分布式结构,基于 Raft 的一致性算法
Apache ZooKeeper 是一套知名的分布式系统中进行同步和一致性管理的工具。
doozer 是一个一致性分布式数据库。
Raft 是一套通过选举主节点来实现分布式系统一致性的算法,相比于大名鼎鼎的 Paxos 算法,它的过程更容易被人理解,由 Stanford大学的 Diego Ongaro 和 John Ousterhout 提出。更多细节可以参考raftconsensus.github.io
一般情况下,用户使用 etcd 可以在多个节点上启动多个实例,并添加它们为一个集群。同一个集群中的 etcd 实例将会保持彼此信息的一致性
安装
参考:https://github.com/etcd-io/etcd/releases/tag/v3.4.0
etcd 基于 Go 语言实现,因此用户可以从 项目主页 下载源代码自行编译,也可以下载编译好的二进制文件,甚至直接使用制作好的 Docker 镜像文件来体验。
注意:本章节内容基于 etcd 3.4.x 版本
二进制文件方式下载
编译好的二进制文件都在 github.com/etcd-io/etcd/releases 页面,用户可以选择需要的版本,或通过下载工具下载。
例如,使用 curl 工具下载压缩包,并解压。
$ curl -L https://github.com/etcd-io/etcd/releases/download/v3.4.0/etcd-v3.4.0-linux-amd64.tar.gz -o etcd-v3.4.0-linux-amd64.tar.gz
$ tar xzvf etcd-v3.4.0-linux-amd64.tar.gz
$ cd etcd-v3.4.0-linux-amd64
解压后,可以看到文件包括
$ ls
Documentation README-etcdctl.md README.md READMEv2-etcdctl.md etcd etcdctl
其中 etcd 是服务主文件,etcdctl 是提供给用户的命令客户端,其他文件是帮助文档。
下面将 etcd etcdctl 文件放到系统可执行目录(例如 /usr/local/bin/)。
$ sudo cp etcd* /usr/local/bin/
默认 2379 端口处理客户端的请求,2380 端口用于集群各成员间的通信。启动 etcd 显示类似如下的信息:
$ etcd
...
2019-09-25 15:28:28.351833 I | embed: listening for peers on 127.0.0.1:2380
...
2019-09-25 15:28:28.948916 N | embed: serving insecure client requests on 127.0.0.1:2379, this is strongly discouraged!
2022-11-16 10:07:41.482530 N | etcdserver/membership: set the initial cluster version to 3.4
2022-11-16 10:07:41.482607 I | etcdserver/api: enabled capabilities for version 3.4
# netstat -nutlp | grep etcd
tcp 0 0 127.0.0.1:2379 0.0.0.0:* LISTEN 29640/./etcd
tcp 0 0 127.0.0.1:2380 0.0.0.0:* LISTEN 29640/./etcd
此时,可以使用 etcdctl
命令进行测试,设置和获取键值-> testkey: "hello world"
,检查 etcd 服务是否启动成功:
$ ETCDCTL_API=3 etcdctl member list
$ ETCDCTL_API=3 etcdctl put testkey "hello world"
OK
$ etcdctl get testkey
说明:etcd 服务已经成功启动了
# 完整的启动命令,所有以-initial-cluster开头的选项,在第一次运行(Bootstrap)后都被忽略
./etcd --name s1 --data-dir ./etcd-data \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://0.0.0.0:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://0.0.0.0:2380 \
--initial-cluster s1=http://0.0.0.0:2380 \
--initial-cluster-token tkn \
--initial-cluster-state new \
--log-level info \
--logger zap \
--log-outputs stderr
-
--name s1
: 设置节点的名称为 s1。 -
--data-dir /etcd-data
: 指定 etcd 存储数据的目录路径为 /etcd-data。 -
--listen-client-urls http://0.0.0.0:2379
: 指定 etcd 监听客户端请求的地址和端口号为 http://0.0.0.0:2379。这表示 etcd 将接受来自任何 IP 地址的客户端连接。 -
--advertise-client-urls http://0.0.0.0:2379
: 设置 etcd 向客户端公布的 URL。这里设置为 http://0.0.0.0:2379,表示客户端可以通过该地址与 etcd 通信。 -
--listen-peer-urls http://0.0.0.0:2380
: 指定 etcd 监听对等节点通信的地址和端口号为 http://0.0.0.0:2380。这表示 etcd 将接受来自任何 IP 地址的对等节点连接。 -
--initial-advertise-peer-urls http://0.0.0.0:2380
: 设置 etcd 向集群中其他节点公布的对等节点 URL。这里设置为 http://0.0.0.0:2380。 -
--initial-cluster s1=http://0.0.0.0:2380
: 指定初始集群配置。在这里,s1 是节点的名称,http://0.0.0.0:2380 是该节点的对等节点 URL。多个使用逗号分隔 -
--initial-cluster-token tkn
: 设置用于识别初始集群的令牌为 tkn。 -
--initial-cluster-state new
: 设置初始集群状态为 new,表示这是一个新的集群。 -
--initial-cluster-state existing
: 加入已有集群时使用 -
--log-level info
: 设置日志级别为 info,表示只记录信息级别的日志。 -
--logger zap
: 使用 zap 日志记录器。 -
--log-outputs stderr
: 将日志输出到标准错误输出。
# 客户端TLS相关参数
--client-cert-auth
--trusted-ca-file=/usr/share/ca-certificates/CA.crt
--cert-file=/opt/etcd/cert/s1.crt
--key-file=/opt/etcd/cert/s1.key
# 集群内部TLS相关参数
--peer-client-cert-auth
--peer-trusted-ca-file=/usr/share/ca-certificates/CA.crt
--peer-cert-file=/opt/etcd/cert/s1.crt
--peer-key-file=/opt/etcd/cert/s1.key
# systemctl启动文件
cat > /etc/systemd/system/etcd.service << EOF
[Unit]
Description=Etcd Server
Documentation=https://github.com/coreos/etcd
After=network.target
[Service]
User=root
Type=notify
# 这个文件特别关键,etcd使用的环境变量都需要通过环境变量文件读取
EnvironmentFile=-/etc/etcd.conf
ExecStart=/usr/local/etcd-v3.5.12-linux-amd64/etcd --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://0.0.0.0:2379 --listen-peer-urls http://0.0.0.0:2380 --initial-advertise-peer-urls http://0.0.0.0:2380 --log-level info --logger zap --log-outputs stderr
Restart=on-failure
RestartSec=10s
LimitNOFILE=40000
[Install]
WantedBy=multi-user.target
EOF
cat > /etc/etcd.conf << EOF
# 节点名称
ETCD_NAME=ghca-centos7-templet
# 数据存放位置
ETCD_DATA_DIR=/var/lib/etcd/
EOF
# systemctl daemon-reload
# systemctl start etcd
Docker 镜像方式运行
Releases · etcd-io/etcd_github.com
镜像名称为gcr.io/etcd-development/etcd
,可以通过下面的命令启动 etcd 服务监听到 2379 和 2380 端口
rm -rf /tmp/etcd-data.tmp && mkdir -p /tmp/etcd-data.tmp && \
docker rmi gcr.io/etcd-development/etcd:v3.4.0 || true && \
docker run \
-p 2379:2379 \
-p 2380:2380 \
--mount type=bind,source=/tmp/etcd-data.tmp,destination=/etcd-data \
--name etcd-gcr-v3.4.0 \
gcr.io/etcd-development/etcd:v3.4.0 \
/usr/local/bin/etcd \
--name s1 \
--data-dir /etcd-data \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://0.0.0.0:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://0.0.0.0:2380 \
--initial-cluster s1=http://0.0.0.0:2380 \
--initial-cluster-token tkn \
--initial-cluster-state new \
--log-level info \
--logger zap \
--log-outputs stderr
打开新的终端按照上一步的方法测试 etcd 是否成功启动、或者如下
docker exec etcd-gcr-v3.4.0 /bin/sh -c "/usr/local/bin/etcd --version"
docker exec etcd-gcr-v3.4.0 /bin/sh -c "/usr/local/bin/etcdctl version"
docker exec etcd-gcr-v3.4.0 /bin/sh -c "/usr/local/bin/etcdctl endpoint health"
docker exec etcd-gcr-v3.4.0 /bin/sh -c "/usr/local/bin/etcdctl put foo bar"
docker exec etcd-gcr-v3.4.0 /bin/sh -c "/usr/local/bin/etcdctl get foo"
由于gcr.io/etcd-development/etcd
镜像被和谐了,可以使用bitnami/etcd:latest
test -d /tmp/etcd-data.tmp && rm -rf /tmp/etcd-data.tmp && mkdir -p /tmp/etcd-data.tmp && \
docker run --rm \
-p 2379:2379 \
-p 2380:2380 \
--mount type=bind,source=/tmp/etcd-data.tmp,destination=/etcd-data \
--name etcd \
-e ALLOW_NONE_AUTHENTICATION=yes \
bitnami/etcd:latest
使用TLS
Etcd支持基于TLS加密的集群内部、客户端-集群通信。每个集群节点都应该拥有被共享CA签名的证书:
1、 生成 CA 证书和私钥:
首先,你需要生成一个用于签署其他证书的 CA(Certificate Authority)证书和私钥。
openssl genrsa -out ca-key.pem 2048
openssl req -new -x509 -key ca-key.pem -out ca.pem -days 365
这将生成一个 CA 证书(ca.pem)和相应的私钥(ca-key.pem),有效期为 365 天。
2、 生成 etcd 服务器证书和私钥:
接下来,你需要为 etcd 服务器生成证书和私钥。
openssl genrsa -out server-key.pem 2048
然后,创建一个证书签名请求文件(CSR):
openssl req -new -key server-key.pem -out server.csr
在这一步中,你需要提供一些与服务器相关的信息,如 Common Name(通常是服务器的主机名或域名)等。
最后,使用 CA 证书和私钥签署 CSR,生成服务器证书:
openssl x509 -req -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server.pem -days 365
这将生成一个带有 365 天有效期的 etcd 服务器证书(server.pem)。
3、 配置 etcd:
将生成的证书(ca.pem、server.pem)和私钥(server-key.pem)配置到 etcd 服务器的配置文件中,以启用 TLS 加密。
4、 可选:生成 etcd 客户端证书和私钥:
如果需要,你也可以为 etcd 客户端生成证书,方法与生成服务器证书类似,只需将 Common Name 设置为客户端的标识即可。
cfssl 生成证书
安装 cfssl 工具: cfssl 是一个用于生成 TLS 证书的工具。你可以从官方 GitHub 仓库下载并安装 cfssl 工具。
生成 CA 证书: 首先,你需要生成一个用于签署其他证书的 CA(Certificate Authority)证书和私钥。你可以使用 cfssl 工具生成:
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
其中,ca-csr.json 是一个 JSON 文件,描述了 CA 证书的配置。
生成服务器证书: 接下来,你需要为 etcd 服务器生成证书。你可以创建一个描述服务器证书配置的 JSON 文件,然后使用 cfssl 工具生成证书和私钥:
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=etcd server.json | cfssljson -bare server
其中,ca.pem 和 ca-key.pem 分别是你之前生成的 CA 证书和私钥,ca-config.json 是一个描述 CA 配置的 JSON 文件,server.json 是描述服务器证书配置的 JSON 文件。
生成客户端证书: 如果需要,你也可以为 etcd 客户端生成证书。这与生成服务器证书类似,只是配置文件和命令略有不同。
配置 etcd: 将生成的证书和私钥配置到 etcd 服务器和客户端的配置文件中,以便它们可以使用这些证书进行安全通信。
etcd 集群
下面我们使用 Docker Compose 模拟启动一个 3 节点的 etcd 集群。
编辑 docker-compose.yml 文件
version: "3.6"
services:
node1:
image: quay.io/coreos/etcd:v3.4.0
volumes:
- node1-data:/etcd-data
expose:
- 2379
- 2380
networks:
cluster_net:
ipv4_address: 172.16.238.100
environment:
- ETCDCTL_API=3
command:
- /usr/local/bin/etcd
- --data-dir=/etcd-data
- --name
- node1
- --initial-advertise-peer-urls
- http://172.16.238.100:2380
- --listen-peer-urls
- http://0.0.0.0:2380
- --advertise-client-urls
- http://172.16.238.100:2379
- --listen-client-urls
- http://0.0.0.0:2379
- --initial-cluster
- node1=http://172.16.238.100:2380,node2=http://172.16.238.101:2380,node3=http://172.16.238.102:2380
- --initial-cluster-state
- new
- --initial-cluster-token
- docker-etcd
node2:
image: quay.io/coreos/etcd:v3.4.0
volumes:
- node2-data:/etcd-data
networks:
cluster_net:
ipv4_address: 172.16.238.101
environment:
- ETCDCTL_API=3
expose:
- 2379
- 2380
command:
- /usr/local/bin/etcd
- --data-dir=/etcd-data
- --name
- node2
- --initial-advertise-peer-urls
- http://172.16.238.101:2380
- --listen-peer-urls
- http://0.0.0.0:2380
- --advertise-client-urls
- http://172.16.238.101:2379
- --listen-client-urls
- http://0.0.0.0:2379
- --initial-cluster
- node1=http://172.16.238.100:2380,node2=http://172.16.238.101:2380,node3=http://172.16.238.102:2380
- --initial-cluster-state
- new
- --initial-cluster-token
- docker-etcd
node3:
image: quay.io/coreos/etcd:v3.4.0
volumes:
- node3-data:/etcd-data
networks:
cluster_net:
ipv4_address: 172.16.238.102
environment:
- ETCDCTL_API=3
expose:
- 2379
- 2380
command:
- /usr/local/bin/etcd
- --data-dir=/etcd-data
- --name
- node3
- --initial-advertise-peer-urls
- http://172.16.238.102:2380
- --listen-peer-urls
- http://0.0.0.0:2380
- --advertise-client-urls
- http://172.16.238.102:2379
- --listen-client-urls
- http://0.0.0.0:2379
- --initial-cluster
- node1=http://172.16.238.100:2380,node2=http://172.16.238.101:2380,node3=http://172.16.238.102:2380
- --initial-cluster-state
- new
- --initial-cluster-token
- docker-etcd
volumes:
node1-data:
node2-data:
node3-data:
networks:
cluster_net:
driver: bridge
ipam:
driver: default
config:
-
subnet: 172.16.238.0/24
使用 docker-compose up
启动集群之后使用 docker exec
命令登录到任一节点测试 etcd 集群。
# etcdctl member list
daf3fd52e3583ff, started, node3, http://172.16.238.102:2380, http://172.16.238.102:2379
422a74f03b622fef, started, node1, http://172.16.238.100:2380, http://172.16.238.100:2379
ed635d2a2dbef43d, started, node2, http://172.16.238.101:2380, http://172.16.238.101:2379
使用 etcdctl
参考文档:https://yeasy.gitbooks.io/docker_practice/etcd/etcdctl.html
CoreOS项目
CoreOS 的设计是为你提供能够像谷歌一样的大型互联网公司一样的基础设施管理能力来动态扩展和管理的计算能力。
CoreOS 的安装文件和运行依赖非常小,它提供了精简的 Linux 系统。它使用 Linux 容器在更高的抽象层来管理你的服务,而不是通过常规的包管理工具 yum 或 apt 来安装包。
同时,CoreOS 几乎可以运行在任何平台:VirtualBox Amazon EC2 QEMU/KVM VMware Bare Metal 和 OpenStack 等
CoreOS 介绍
CoreOS 对 Docker 甚至容器技术的发展都带来了巨大的推动作用。其提供了运行现代基础设施的特性,支持大规模服务部署,使得在基于最小化的现代操作系统上构建规模化的计算仓库成为了可能。
CoreOS 特性
一个最小化操作系统
CoreOS 被设计成一个基于容器的最小化的现代操作系统。它比现有的 Linux 安装平均节省 40% 的 RAM(大约 114M )并允许从 PXE 或 iPXE 非常快速的启动。
无痛更新
利用主动和被动双分区方案来更新 OS,使用分区作为一个单元而不是一个包一个包的更新。这使得每次更新变得快速,可靠,而且很容易回滚。
Docker 容器
应用作为 Docker 容器运行在 CoreOS 上。容器以包的形式提供最大得灵活性并且可以在几毫秒启动。
支持集群
CoreOS 可以在一个机器上很好地运行,但是它被设计用来搭建集群。
可以通过 k8s 很容易得使应用容器部署在多台机器上并且通过服务发现把他们连接在一起。
分布式系统工具
内置诸如分布式锁和主选举等原生工具用来构建大规模分布式系统得构建模块。
服务发现
很容易定位服务在集群的那里运行并当发生变化时进行通知。它是复杂高动态集群必不可少的
CoreOS 工具介绍
CoreOS 内置了 服务发现,容器管理 工具。
服务发现
CoreOS 的第一个重要组件就是使用 etcd 来实现的服务发现。在 CoreOS 中 etcd 默认以 rkt 容器方式运行。
etcd 使用方法请查看 etcd 章节。
容器管理
第二个组件就是 Docker,它用来运行你的代码和应用。CoreOS 内置 Docker,具体使用请参考本书其他章节