Featured image of post etcd集群部署

etcd集群部署

etcd集群部署

  • 部署形态

    • 单点

    • 集群

      • http通信集群

      • https通信集群

        • 单证书部署(集群节点证书相同)

        • 多证书部署(集群节点证书不同)

上面几种,单点和http集群没啥好说的,单证书部署的操作请参考我全手动部署kubernetes (h2c.tech) ,本文主要说的是多证书的情形。

下载etcd

访问 Releases · etcd-io/etcd (github.com) 下载etcd

下载cfssl

访问 Releases · cloudflare/cfssl (github.com) 下载cfssl,别问我为啥不直接用openssl,问就是懒。下载下面这三个:

  • cfssl

  • cfssl-certinfo

  • cfssljson

生成证书

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
$ mkdir {ca,cfssl_conf,node_cert}
$ cat > cfssl-conf/ca-config.json<<EOF
{
    "signing": {
        "default": {
            "expiry": "168h"
        },
        "profiles": {
            "server": {
                "expiry": "87600h",
                "usages": [
                    "signing",
                    "key encipherment",
                    "server auth"
                ]
            },
            "client": {
                "expiry": "87600h",
                "usages": [
                    "signing",
                    "key encipherment",
                    "client auth"
                ]
            },
            "peer": {
                "expiry": "87600h",
                "usages": [
                    "signing",
                    "key encipherment",
                    "server auth",
                    "client auth"
                ]
            }
        }
    }
}
EOF

$ cat > cfssl-conf/ca-csr.json<<EOF
{
    "CN": "etcd CA",
    "key": {
        "algo": "rsa",
        "size": 4096
    },
    "names": [
        {
            "C": "CN",
            "ST": "Hubei",
            "L": "Wuhan"
        }
    ]
}
EOF

$ node0=172.15.110.84;node1=172.15.110.85;node2=172.15.110.86;node3=172.15.110.87;
for i in {0..3};do
cat > cfssl-conf/infra$i-csr.json<<EOF
{
    "CN": "infra$i",
    "hosts": [
      "$(eval echo \$node$i)"
    ],
    "names": [
        {
            "C":  "CN",
            "ST": "Hubei",
            "L":  "Wuhan",
            "O":  "h2c.tech",
            "CN": "infra$i.h2c.tech"
        }
    ]
}
EOF
done

$ cfssl gencert -initca cfssl-conf/ca-csr.json | cfssljson -bare ca/ca -
$ for i in `seq 0 4`;do
cfssl gencert \
      -ca=cfssl-conf/ca.pem \
      -ca-key=cfssl-conf/ca-key.pem \
      -config=ca-config.json \
      -profile=peer \
      infra$i-csr.json | cfssljson -bare node_cert/infra$i;
done

上面用到了一个小技巧,用$(eval echo \$node$i)来 Evaluation 获取变量值,避免直接展开成字符串,如果你直接写$(node$i)那就会获取不到。

解析:cfssl gencert -initca cfssl-conf/ca-csr.json | cfssljson -bare ca/ca -

  1. cfssl gencert -initca cfssl-conf/ca-csr.json 这部分是生成自签名的根CA证书和私钥。它使用-initca标志表示这是一个CA根证书,并从cfssl-conf/ca-csr.json文件读取证书签名请求配置。
  2. | 管道符用于将前一个命令的输出作为后一个命令的输入。
  3. cfssljson -bare ca/ca 这个部分将从管道输入解析出证书和私钥,并以ca为前缀输出到ca/下。即会生成ca/ca.pem证书文件和ca/ca-key.pem私钥文件。
  4. -符号表示输出到标准输出,也就是终端屏幕。

另外一个类似,只有一个区别就是它指定了profile使用peer这个。

生成完成以后分发到各个节点,指定一个固定的路径给它存放,我是放到了/etc/etcd/etcd-cert/node-cert/

etcdctl证书

我还习惯单独给客户端发一个证书:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ cat > cfssl-conf/client-csr.json<<EOF
{
    "CN": "client",
    "hosts": [
      "0.0.0.0"
    ],
    "names": [
        {
            "C":  "CN",
            "ST": "Hubei",
            "L":  "Wuhan",
            "O":  "h2c.tech",
            "CN": "client.h2c.tech"
        }
    ]
}

$ cfssl gencert \
        -ca=cfssl-conf/ca.pem \
        -ca-key=cfssl-conf/ca-key.pem \
        -config=ca-config.json \
        -profile=peer \
        client-csr.json | cfssljson -bare node_cert/client;

配置etcd

官方示例:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# 本示例来自官方项目示例,个人做了中文翻译(不保证准确)
# etcd节点的人类可读名称
name: 'default'

# 数据目录的路径
data-dir:

# 专用WAL目录的路径
wal-dir:

# 触发将快照写入磁盘的已提交事务数  
snapshot-count: 10000

# 心跳间隔时间(毫秒)
heartbeat-interval: 100

# 选举超时时间(毫秒) 
election-timeout: 1000

# 当后端大小超过给定配额时发出警报。0表示使用默认配额
quota-backend-bytes: 0

# 用于对等流量的监听URL列表,用逗号分隔  
listen-peer-urls: http://localhost:2380

# 用于客户端流量的监听 URL 列表,用逗号分隔
listen-client-urls: http://localhost:2379

# 要保留的最大快照文件数(0 为无限制)
max-snapshots: 5

# 要保留的最大 WAL 文件数(0 为无限制)
max-wals: 5

# 逗号分隔的CORS(跨域资源共享)的域白名单
cors:

# 此成员的对等URL列表,用于向集群其余部分通告
initial-advertise-peer-urls: http://localhost:2380

# 此成员的客户端 URL 列表,用于向公众通告  
advertise-client-urls: http://localhost:2379

# 用于引导集群的发现 URL
discovery:

# 有效值为“exit”、“proxy”
discovery-fallback: 'proxy'

# 用于访问发现服务的流量的 HTTP 代理
discovery-proxy:

# 引导初始集群的使用的 DNS 域
discovery-srv:

# 引导初始集群配置的字符串
# 例如: "infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380"
initial-cluster:

# etcd 集群引导过程中的初始集群令牌
initial-cluster-token: 'etcd-cluster'

# 初始集群状态(“新建”或“现有”)  
initial-cluster-state: 'new'

# 拒绝会导致法定人数丢失的重新配置请求
strict-reconfig-check: false

# 通过 HTTP 服务器启用运行时性能分析数据
enable-pprof: true

# 有效值为 “开启”、“只读”、“关闭”
proxy: 'off'

# 端点将持续失败状态的时间(毫秒) 
proxy-failure-wait: 5000

# 端点刷新间隔的时间(毫秒)
proxy-refresh-interval: 30000

# 拨号超时的时间(毫秒)
proxy-dial-timeout: 1000

# 写入超时的时间(毫秒)
proxy-write-timeout: 5000

# 读取超时的时间(毫秒)  
proxy-read-timeout: 0

# 客户端传输安全配置
client-transport-security:
  # 客户端服务器 TLS 证书文件的路径  
  cert-file:

  # 客户端服务器 TLS 密钥文件的路径
  key-file:

  # 启用客户端证书验证  
  client-cert-auth: false

  # 客户端服务器 TLS 受信任 CA 证书文件的路径  
  trusted-ca-file:

  # 使用生成的证书的客户端 TLS
  auto-tls: false

# 对等服务器传输安全配置
peer-transport-security:
  # 对等服务器 TLS 证书文件的路径  
  cert-file:

  # 对等服务器 TLS 密钥文件的路径
  key-file:

  # 启用对等客户端证书验证
  client-cert-auth: false

  # 对等服务器 TLS 受信任的 CA 证书文件的路径
  trusted-ca-file:

  # 使用生成的证书的对等 TLS  
  auto-tls: false

# 自签名证书的有效期,单位为年
self-signed-cert-validity: 1

# 为 etcd 启用调试级别的日志记录
log-level: debug

# 指定“stdout”或“stderr”可跳过 journald 日志记录,即使在 systemd 下运行也是如此。  
log-outputs: [stderr]

# 强制创建一个新的单成员集群
force-new-cluster: false

# 自动压缩模式  
auto-compaction-mode: periodic

# 自动压缩保留期 
auto-compaction-retention: "1"

# 将 etcd 限制在一组特定的 TLS 加密套件中
cipher-suites: [
  TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
  TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
]

# 将 etcd 限制在特定的 TLS 协议版本
tls-min-version: 'TLS1.2'
tls-max-version: 'TLS1.3'

测试环境示例配置文件:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# etcd节点的人类可读名称
name: infra0

# 数据目录的路径
data-dir: /var/lib/etcd/default.etcd

# 专用WAL目录的路径
wal-dir: /var/lib/etcd/default.etcd.wal

# 触发将快照写入磁盘的已提交事务数
snapshot-count: 10000

# 心跳间隔时间(毫秒)
heartbeat-interval: 100

# 选举超时时间(毫秒)
election-timeout: 1000

# 当后端大小超过给定配额时发出警报。0表示使用默认配额
quota-backend-bytes: 0

# 用于对等流量的监听URL列表,用逗号分隔
listen-peer-urls: https://172.15.110.84:2380

# 用于客户端流量的监听 URL 列表,用逗号分隔
listen-client-urls: https://localhost:2379,https://172.15.110.84:2379

# 要保留的最大快照文件数(0 为无限制)
max-snapshots: 5

# 要保留的最大 WAL 文件数(0 为无限制)
# max-wals: 5

# 逗号分隔的CORS(跨域资源共享)的域白名单
# cors:

# 此成员的对等URL列表,用于向集群其余部分通告
initial-advertise-peer-urls: https://172.15.110.84:2380

# 此成员的客户端 URL 列表,用于向公众通告
advertise-client-urls: https://172.15.110.84:2379

# 用于引导集群的发现 URL
discovery:

# 有效值为“exit”、“proxy”
discovery-fallback: 'proxy'

# 用于访问发现服务的流量的 HTTP 代理
discovery-proxy:

# 引导初始集群的使用的 DNS 域
discovery-srv:

# 引导初始集群配置的字符串
# 例如: "infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11iiinfra0,infra2=http://10.0.1.12:2380"
initial-cluster: "infra0=https://172.15.110.84:2380,infra1=https://172.15.110.85:2380,infra2=https://172.15.110.86:2380,infra3=https://172.15.110.87:2380"

# etcd 集群引导过程中的初始集群令牌
initial-cluster-token: 'etcd-cluster-k8s'

# 初始集群状态(“新建”或“现有”)
initial-cluster-state: 'new'

# 拒绝会导致法定人数丢失的重新配置请求
strict-reconfig-check: false

# 通过 HTTP 服务器启用运行时性能分析数据
enable-pprof: true

# 有效值为 “开启”、“只读”、“关闭”
proxy: 'off'

# 端点将持续失败状态的时间(毫秒)
proxy-failure-wait: 5000

# 端点刷新间隔的时间(毫秒)
proxy-refresh-interval: 30000

# 拨号超时的时间(毫秒)
proxy-dial-timeout: 1000

# 写入超时的时间(毫秒)
proxy-write-timeout: 5000

# 读取超时的时间(毫秒)
proxy-read-timeout: 0

# 客户端传输安全配置
client-transport-security:
  # 客户端服务器 TLS 证书文件的路径
  cert-file: '/etc/etcd/etcd-cert/node-cert/infra0.pem'

  # 客户端服务器 TLS 密钥文件的路径
  key-file: '/etc/etcd/etcd-cert/node-cert/infra0-key.pem'

  # 启用客户端证书验证
  client-cert-auth: true

  # 客户端服务器 TLS 受信任 CA 证书文件的路径
  trusted-ca-file: '/etc/etcd/etcd-cert/ca/ca.pem'

  # 使用生成的证书的客户端 TLS
  auto-tls: true

# 对等服务器传输安全配置
peer-transport-security:
  # 对等服务器 TLS 证书文件的路径
  cert-file: '/etc/etcd/etcd-cert/node-cert/infra0.pem'

  # 对等服务器 TLS 密钥文件的路径
  key-file: '/etc/etcd/etcd-cert/node-cert/infra0-key.pem'

  # 启用对等客户端证书验证
  client-cert-auth: true

  # 对等服务器 TLS 受信任的 CA 证书文件的路径
  trusted-ca-file: '/etc/etcd/etcd-cert/ca/ca.pem'

  # 使用生成的证书的对等 TLS
  auto-tls: true

# 自签名证书的有效期,单位为年
self-signed-cert-validity: 1

# 为 etcd 启用调试级别的日志记录
log-level: debug

# 指定“stdout”或“stderr”可跳过 journald 日志记录,即使在 systemd 下运行也是如此。
log-outputs: [stderr]

# 强制创建一个新的单成员集群
force-new-cluster: false

# 自动压缩模式
auto-compaction-mode: periodic

# 自动压缩保留期
auto-compaction-retention: "1"

# 将 etcd 限制在一组特定的 TLS 加密套件中
#cipher-suites: [
#  TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
#  TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
#]

# 将 etcd 限制在特定的 TLS 协议版本
#tls-min-version: 'TLS1.2'
#tls-max-version: 'TLS1.3'

上面的配置文件用户主要需要关注的是:

  • name

  • data-dir

  • wal-dir

  • listen-peer-urls

  • listen-client-urls

  • initial-advertise-peer-urls

  • advertise-client-urls

  • initial-cluster

  • client-transport-security.cert-file

  • client-transport-security.key-file

  • client-transport-security.trusted-ca-file

  • peer-transport-security.cert-file

  • peer-transport-security.key-file

  • peer-transport-security.trusted-ca-file

其他节点与上面节点不同,需要修改的内容为:

  • name: infra0:infra0改成对应的节点名

  • listen-peer-urls: https://172.15.110.84:2380:172.15.110.84 改成对应机器的IP或者域名

  • advertise-client-urls: https://172.15.110.84:2379:172.15.110.84 改成对应机器的IP或者域名

  • cert-file: '/etc/etcd/etcd-cert/node-cert/infra0.pem':节点公钥修改成自己对应节点的公钥

  • key-file: '/etc/etcd/etcd-cert/node-cert/infra0-key.pem':节点私钥修改成自己对应节点的私钥

配置systemd

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[Unit]
Description=etcd service
Documentation=https://coreos.com/etcd/docs/latest/
After=network.target

[Service]
Type=notify
ExecStart=/usr/local/bin/etcd --config-file=/etc/etcd/etcd.conf
Restart=on-failure
RestartSec=10
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
Alias=etcd3.service

配置完成以后重载:

1
2
$ systemctl daemon-reload
$ systemctl start etcd

验证

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ export ETCDCTL_API=3 \
HOST_1=172.15.110.84 \
HOST_2=172.15.110.85 \
HOST_3=172.15.110.86 \
HOST_4=172.15.110.87 \
ENDPOINTS=$HOST_1:2379,$HOST_2:2379,$HOST_3:2379,$HOST_4:2379
$ etcdctl --endpoints=$ENDPOINTS \
          --cacert="/etc/etcd/etcd-cert/ca/ca.pem" \
          --cert="/etc/etcd/etcd-cert/node-cert/client.pem" \
          --key="/etc/etcd/etcd-cert/node-cert/client-key.pem" \
          member list --write-out=table
1
2
3
4
5
6
7
8
+------------------+----------+---------+----------------------------+----------------------------+-------------------+
|        ID        |  STATUS  |  NAME   |         PEER ADDRS         |       CLIENT ADDRS         |   IS LEARNER      |
+------------------+--- ------+---------+----------------------------+----------------------------+--------=----------+
| 29a6b7b89a53ff4  | started  |  etcd4  | https://172.15.110.87:2380 | https://172.15.110.87:2379 |      false        |
| 2b8e9ab68dcdd2d5 | started  |  etcd2  | https://172.15.110.85:2380 | https://172.15.110.85:2379 |      false        |
| 667eeb25771855b7 | started  |  etcd1  | https://172.15.110.84:2380 | https://172.15.110.84:2379 |      false        |
| b7487f18e8d35925 | started  |  etcd3  | https://172.15.110.86:2380 | https://172.15.110.86:2379 |      false        |
+------------------+----------+---------+----------------------------+----------------------------+-------------------+
1
2
3
4
5
$ etcdctl --endpoints=$ENDPOINTS \
          --cacert="/etc/etcd/etcd-cert/ca/ca.pem" \
          --cert="/etc/etcd/etcd-cert/node-cert/client.pem" \
          --key="/etc/etcd/etcd-cert/node-cert/client-key.pem" \
          endpoint status --write-out=table
1
2
3
4
5
6
7
8
+--------------------+------------------+-------------+---------+----------------+-------------------+---------------------+--------------------+-------------------------------------+---------------+
|      ENDPOINT      |           ID     |    VERSION  | DB SIZE |    IS LEADER   |     IS LEARNER    |      RAFT TERM      |      RAFT INDEX    |          RAFT APPLIED INDEX         |     ERRORS    |
+--------------------+------------------+-------------+---------+----------------+-------------------+---------------------+--------------------+-------------------------------------+---------------+
| 172.15.110.84:2379 | 667eeb25771855b7 |    3.5.11   |   20 kB |     false      |      false        |         3           |         21         |                 21                  |               |
| 172.15.110.85:2379 | 2b8e9ab68dcdd2d5 |    3.5.11   |   20 kB |      true      |      false        |         3           |         21         |                 21                  |               |
| 172.15.110.86:2379 | b7487f18e8d35925 |    3.5.11   |   20 kB |     false      |      false        |         3           |         21         |                 21                  |               |
| 172.15.110.87:2379 | 29a6b7b89a53ff4  |    3.5.11   |   20 kB |     false      |      false        |         3           |         21         |                 21                  |               |
+--------------------+------------------+-------------+---------+----------------+-------------------+---------------------+--------------------+-------------------------------------+---------------+