环境信息

最少三个及以上奇数个节点

名称

IP

etcd-1

10.20.13.10

etcd-2

10.20.13.11

etcd-3

10.20.13.12

etcd集群节点数量的相关说明:

etcd 是基于 raft算法的分布式键值数据库,生来就为集群化而设计的,由于Raft算法在做决策时需要超半数节点的投票,所以etcd集群一般推荐奇数节点,如3、5或者7个节点构成一个集群。

etcd官方推荐3、5、7个节点,虽然raft算法也是半数以上投票才能有 leader,但奇数只是推荐,其实偶数也是可以的。如 2、4、8个节点。下面分情况说明:

  • 1 个节点:就是单实例,没有集群概念,不做讨论

  • 2 个节点:是集群,但没人会这么配,这里说点废话:双节点的etcd能启动,启动时也能有主,可以正常提供服务,但是一台挂掉之后,就选不出主了,因为他只能拿到1票,剩下的那台也无法提供服务,也就是双节点无容错能力,不要使用。

  • 3 节点:标准的3 节点etcd 集群只能容忍1台机器宕机,挂掉 1 台此时等于2个节点的情况,如果再挂 1 台,就和 2节点的情形一致了,一直选,一直增加任期,但就是选不出来,服务也就不可用了

  • 4 节点:最大容忍1 台 服务器宕机

  • 5 节点:最大容忍 2 台 服务器宕机

  • 6 节点:最大容忍 2 台 服务器宕机

  • 7和8个节点,最大容忍3台 服务器宕机

以此类推,9和10个节点,最大容忍4台 服务器宕机,总结以上可以得出结论:偶数节点虽然多了一台机器,但是容错能力是一样的,也就是说,你可以设置偶数节点,但没增加什么能力,还浪费了一台机器。同时etcd 是通过复制数据给所有节点来达到一致性,因此偶数的多一台机器增加不了性能,反而会拉低写入速度。

部署etcd集群(三台节点)

部署etcd

下载地址:Releases · etcd-io/etcd (github.com)

解压
tar zxvf etcd-v3.5.13-linux-amd64.tar.gz
添加到环境变量目录
cd etcd-v3.5.13-linux-amd64
mv etcd etcdctl etcdutl /usr/local/bin/
创建配置文件目录与数据目录
mkdir -p /etc/etcd
mkdir -p /data/etcd
mkdir -p /etc/etcd/pki
注册系统服务
vim /etc/systemd/system/etcd.service
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
​
[Service]
Type=notify
EnvironmentFile=/etc/etcd/etcd.conf
ExecStart=/usr/local/bin/etcd --config-file=/etc/etcd/etcd.conf
Restart=on-failure
LimitNOFILE=65536
​
[Install]
WantedBy=multi-user.target

修改配置文件

etcd-1节点
# 节点名称
name: "etcd-1"
# 数据存储目录
data-dir: "/data/etcd"
# 对外公告的该节点客户端监听地址,这个值会告诉集群中其他节点
advertise-client-urls: "https://10.20.13.10:2379"
# 监听客户端请求的地址列表
listen-client-urls: "https://10.20.13.10:2379,http://127.0.0.1:2379"
# 监听URL,用于节点之间通信监听地址
listen-peer-urls: "https://10.20.13.10:2380"
# 服务端之间通讯使用的地址列表,该节点同伴监听地址,这个值会告诉集群中其他节点
initial-advertise-peer-urls: "https://10.20.13.10:2380"
# etcd启动时,etcd集群的节点地址列表
initial-cluster: "etcd-1=https://10.20.13.10:2380,etcd-2=https://10.20.13.11:2380,etcd-3=https://10.20.13.12:2380"
# etcd集群的初始集群令牌
initial-cluster-token: 'etcd-cluster'
# etcd集群初始化的状态,new代表新建集群,existing表示加入现有集群
initial-cluster-state: 'new'
# 日志配置
logger: zap
​
# 客户端加密
client-transport-security:
  cert-file: "/etc/etcd/pki/etcd.pem"
  key-file: "/etc/etcd/pki/etcd-key.pem"
  client-cert-auth: True
  trusted-ca-file: "/etc/etcd/pki/ca.pem"
​
# 节点加密
peer-transport-security:
  cert-file: "/etc/etcd/pki/etcd.pem"
  key-file: "/etc/etcd/pki/etcd-key.pem"
  client-cert-auth: True
  trusted-ca-file: "/etc/etcd/pki/ca.pem"
etcd-2节点
# 节点名称
name: "etcd-2"
# 数据存储目录
data-dir: "/data/etcd"
# 对外公告的该节点客户端监听地址,这个值会告诉集群中其他节点
advertise-client-urls: "https://10.20.13.11:2379"
# 监听客户端请求的地址列表
listen-client-urls: "https://10.20.13.11:2379,https://127.0.0.1:2379"
# 监听URL,用于节点之间通信监听地址
listen-peer-urls: "https://10.20.13.11:2380"
# 服务端之间通讯使用的地址列表,该节点同伴监听地址,这个值会告诉集群中其他节点
initial-advertise-peer-urls: "https://10.20.13.11:2380"
# etcd启动时,etcd集群的节点地址列表
initial-cluster: "etcd-1=https://10.20.13.10:2380,etcd-2=https://10.20.13.11:2380,etcd-3=https://10.20.13.12:2380"
# etcd集群的初始集群令牌
initial-cluster-token: 'etcd-cluster'
# etcd集群初始化的状态,new代表新建集群,existing表示加入现有集群
initial-cluster-state: 'new'
# 日志配置
logger: zap
​
# 客户端加密
client-transport-security:
  cert-file: "/etc/etcd/pki/etcd.pem"
  key-file: "/etc/etcd/pki/etcd-key.pem"
  client-cert-auth: True
  trusted-ca-file: "/etc/etcd/pki/ca.pem"
​
# 节点加密
peer-transport-security:
  cert-file: "/etc/etcd/pki/etcd.pem"
  key-file: "/etc/etcd/pki/etcd-key.pem"
  client-cert-auth: True
  trusted-ca-file: "/etc/etcd/pki/ca.pem"
etcd-3节点
# 节点名称
name: "etcd-3"
# 数据存储目录
data-dir: "/data/etcd"
# 对外公告的该节点客户端监听地址,这个值会告诉集群中其他节点
advertise-client-urls: "https://10.20.13.12:2379"
# 监听客户端请求的地址列表
listen-client-urls: "https://10.20.13.12:2379,https://127.0.0.1:2379"
# 监听URL,用于节点之间通信监听地址
listen-peer-urls: "https://10.20.13.12:2380"
# 服务端之间通讯使用的地址列表,该节点同伴监听地址,这个值会告诉集群中其他节点
initial-advertise-peer-urls: "https://10.20.13.12:2380"
# etcd启动时,etcd集群的节点地址列表
initial-cluster: "etcd-1=https://10.20.13.10:2380,etcd-2=https://10.20.13.11:2380,etcd-3=https://10.20.13.12:2380"
# etcd集群的初始集群令牌
initial-cluster-token: 'etcd-cluster'
# etcd集群初始化的状态,new代表新建集群,existing表示加入现有集群
initial-cluster-state: 'new'
# 日志配置
logger: zap
​
# 客户端加密
client-transport-security:
  cert-file: "/etc/etcd/pki/etcd.pem"
  key-file: "/etc/etcd/pki/etcd-key.pem"
  client-cert-auth: True
  trusted-ca-file: "/etc/etcd/pki/ca.pem"
​
# 节点加密
peer-transport-security:
  cert-file: "/etc/etcd/pki/etcd.pem"
  key-file: "/etc/etcd/pki/etcd-key.pem"
  client-cert-auth: True
  trusted-ca-file: "/etc/etcd/pki/ca.pem"

先不启动,准备证书文件,如果不需要证书认证,在配置文件删除上方加密证书的配置启动。跳转到最下方测试即可。

部署TLS加密集群

安装cfssl

下载地址:Releases · cloudflare/cfssl (github.com)

mv cfssl_1.6.5_linux_amd64 /usr/bin/cfssl
mv cfssljson_1.6.5_linux_amd64 /usr/bin/cfssljson
chmod +x /usr/bin/{cfssl,cfssljson}

创建默认配置文件(可选,下一步会替换)

cfssl print-defaults config > ca-config.json
cfssl print-defaults csr > ca-csr.json

创建CA证书

修改ca-config

各个组件都需要配置证书,并且依赖 CA 证书来签发证书,所以首先要生成好 CA 证书以及后续的签发配置文件

cat > ca-config.json <<EOF
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "Etcd": {
        "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ],
        "expiry": "87600h"
      }
    }
  }
}
EOF

ca-config.json:可以定义多个 profiles,分别指定不同的过期时间、使用场景等参数;后续在签名证书时使用某个 profile; signing:表示该证书可用于签名其它证书;生成的 ca.pem 证书中 CA=TRUE; server auth:表示 client 可以用该 CA 对 server 提供的证书进行验证; client auth:表示 server 可以用该 CA 对 client 提供的证书进行验证;

配置证书请求
cat > ca-csr.json <<EOF
{
    "CN": "Etcd",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "BeiJing",
            "ST": "BeiJing",
            "O": "Etcd",
            "OU": "System"
        }
    ]
}
EOF

生成ca证书

cfssl gencert -initca ca-csr.json | cfssljson -bare ca -

CN:Common Name,kube-apiserver 从证书中提取该字段作为请求的用户名 (User Name),浏览器使用该字段验证网站是否合法; O:Organization,kube-apiserver 从证书中提取该字段作为请求用户所属的组 (Group); kube-apiserver 将提取的 User、Group 作为 RBAC 授权的用户标识;

创建客户端与对等证书请求文件

注意hosts字段需要加上etcd全部节点的IP/主机名信息及127.0.0.1

cat > etcd-csr.json <<EOF
{
    "CN": "etcd",
    "hosts": [
      "127.0.0.1",
      "10.20.13.10",
      "10.20.13.11",
      "10.20.13.12"
    ],
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "beijing",
            "ST": "BeiJing",
            "O": "ETCD",
            "OU": "System"
        }
    ]
}
EOF
生成证书和私钥
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=Etcd etcd-csr.json | cfssljson -bare etcd

拷贝密钥到etcd节点

cp *.pem /etc/etcd/pki/
scp /etc/etcd/pki/* 10.20.13.11:/etc/etcd/pki/
scp /etc/etcd/pki/* 10.20.13.12:/etc/etcd/pki/

设置开机自启并启动

systemctl daemon-reload
systemctl enable etcd --now

测试

etcdctl --endpoints=https://10.20.13.10:2379 \
--cacert=/etc/etcd/pki/ca.pem \
--cert=/etc/etcd/pki/etcd.pem \
--key=/etc/etcd/pki/etcd-key.pem \
endpoint status --cluster -w table

如果没有使用证书,用下方命令测试

etcdctl endpoint status --cluster -w table

测试读写

在第一台节点上写入

第二台节点上读取

第三台节点上读取