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

生成证书

$ 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证书

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

$ 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

官方示例:

# 本示例来自官方项目示例,个人做了中文翻译(不保证准确)
# 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'

测试环境示例配置文件:

# 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

[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

配置完成以后重载:

$ systemctl daemon-reload
$ systemctl start etcd

验证

$ 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
$ 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
+--------------------+------------------+-------------+---------+----------------+-------------------+---------------------+--------------------+-------------------------------------+---------------+
|      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                  |               |
+--------------------+------------------+-------------+---------+----------------+-------------------+---------------------+--------------------+-------------------------------------+---------------+

  

posted @ 2024-02-28 17:26  陶清刚  阅读(22)  评论(0)    收藏  举报