前言



环境和部分软件已经配置好了,接着要部署一个Etcd集群。Etcd 通常是和master部署在一起,也有人会将 etcd独立于 k8s集群之外,以便于更好地扩展etcd集群。而此次是部署在3个master上。



下面是关于Etcd的一些问题及答案:

Etcd节点数:
etcd 是基于raft算法的分布式键值数据库,在做决策时需要超半数节点的投票,所以 etcd集群 一般推荐奇数节点(3,5,7);etcd是高可用的,3节点etcd集群,最大容忍1台机器宕机。根据网上的资料:设置偶数节点也是可以的,但是会拉低写入速度。节点数越多,性能越差。



限制Etcd性能的因素:
单机的容量限制,内存和磁盘(这基本上是大部分服务的主要限制因素之一。可使用ionice调高etcd进程的IO优先级;部署etcd集群使用性能较高,内存较大的服务器,如果是云服务器可选择高性能云盘)

ionice -c2 -n0 -p `pgrep etcd`

Etcd配置的容量上限(Etcd默认配置的容量上限较小。当ETCD的存储使用超过了空间配额,ETCD 将发起集群范围的警告,并使集群进入维护模式,仅接收键的读取和删除,从而影响平台的正常运行。因此需要部署时调整ETCD 容量上限)


网络开销(每次 Raft 操作都需要所有节点参与。每一次写操作需要集群中大多数节点将日志落盘成功后,Leader节点才能修改内部状态,并将结果返回给客户端。频繁的交互,对网络的要求较高。因此通常会将 etcd 集群规划在一个网络环境中(同地域/同机房),并且使用tc提高带宽和优先级)

tc qdisc add dev eth0 root handle 1: prio bands 3 
tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip sport 2380 0xffff flowid 1:1 
tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip dport 2380 0xffff flowid 1:1 
tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip sport 2739 0xffff flowid 1:1 
tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip dport 2739 0xffff flowid 1:1




ETCD部署



本次使用的源码包部署一个外部的ETCD集群



生成证书



以下操作在 etcd1(即master01)机器执行



<1>下载证书生成工具

curl -o /usr/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
curl -o /usr/bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
curl -o /usr/bin/cfssl-certinfo https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
chmod +x /usr/bin/cfssl*


<2>创建证书etcd目录



mkdir -p /etc/kubernetes/pki/etcd
cd /etc/kubernetes/pki/etcd

根据需求创建目录,实际建议etcd证书放到其他位置(当证书放到/etc/kubernetes时,虽然便于统一管理,但kubeadm reset后,etcd的证书也会丢失。如不想重新配置etcd,建议证书放到其他位置)

先进入目录再生成证书,否则证书比较散乱



<3>创建 CA 配置文件(ca-config.json)

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

or
使用命令生成,然后对其进行修改
cfssl print-defaults config > ca-config.json


备注:

"ca-config.json":  可以定义多个profiles,分别指定不同的过期时间、使用场景等参数
"signing":         表示该证书可用于签名其它证书
"expiry":          表示证书的有效时间(876000h=100年),根据需求配置
"key encipherment":密钥加密
"server auth":     表示client可以用该 CA 对server提供的证书进行验证
"client auth":     表示server可以用该CA对client提供的证书进行验证


<4>创建 CA 证书签名请求(ca-csr.json)

cat >ca-csr.json <<EOF
{
  "CN": "etcd",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "shanghai",
      "L": "shanghai",
      "O": "etcd",
      "OU": "System"
    }
  ]
}
EOF

or
使用命令生成,然后对其进行修改
cfssl print-defaults csr > ca-csr.json


备注:

"CN":   etcd会从证书中提取该字段作为请求的用户名,根据需求起名字
"O":    etcd 从证书中提取该字段作为请求用户所属的组

"C":    国家编码
"ST":   省份
"L":    市/区
"O":    公司名称
"OU":   部门名称
随意填即可


<5>生成 CA 证书和私钥


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

生成下面3个文件
ca.pem      根证书公钥文件,用于签发后续其他的证书文件
ca-key.pem  根证书私钥文件
ca.csr      证书签名请求,用于交叉签名或重新签名


<6>以上操作可写脚本,简便一些


简洁型ca脚本:

#!/bin/bash


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


cat >ca-csr.json <<EOF
{
  "CN": "etcd",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "shanghai",
      "L": "shanghai",
      "O": "etcd",
      "OU": "System"
    }
  ]
}
EOF

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


<7>创建etcd的TLS认证证书

#创建 etcd证书签名请求(etcd-csr.json)

cat > etcd-csr.json <<EOF
{
  "CN": "etcd",
  "hosts": [
    "192.168.1.1", 
    "192.168.1.2", 
    "192.168.1.3",
    "k8s-master01",
    "k8s-master02",
    "k8s-master03"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "shanghai",
      "L": "shanghai",
      "O": "etcd",
      "OU": "System"
    }
  ]
}
EOF


备注:

"hosts": 指定授权使用该证书的IP和域名列表(即指定了etcd集群各个节点的IP/域名)


<8>生成 etcd证书和私钥

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=etcd etcd-csr.json | cfssljson -bare etcd

生成下面3个文件
etcd.csr
etcd.pem
etcd-key.pem



<9>etcd证书拷贝


本次etcd部署在master上,且由于在初始化阶段,master间进行了免密认证,直接推送即可。
重点在于将前面生成的证书拷贝到其他节点。



rsync -aP  /etc/kubernetes  root@k8s-master02:/etc/
rsync -aP  /etc/kubernetes  root@k8s-master03:/etc/


<10>以上操作可写脚本,简便一些

简洁型etcd证书脚本:

#!/bin/bash

cat > etcd-csr.json <<EOF
{
  "CN": "etcd",
  "hosts": [
    "192.168.1.1", 
    "192.168.1.2", 
    "192.168.1.3",
    "k8s-master01",
    "k8s-master02",
    "k8s-master03"
  ],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "ST": "shanghai",
      "L": "shanghai",
      "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

rsync -aP  /etc/kubernetes  root@k8s-master02:/etc/
rsync -aP  /etc/kubernetes  root@k8s-master03:/etc/


Etcd安装配置



以下操作在各个etcd节点,修改参数后再执行



<1>创建etcd数据目录
(统一的数据目录,可便于管理)

mkdir -p /data/etcd
chmod -R 777 /data/etcd
ln -s /data/etcd /var/lib/etcd


<2>下载etcd源码包


版本建议选择3.4及其以上,3.4存储容量做了提升,降低了读写延迟;且3.3以下等版本存在数据不一致的bug


#选择合适版本和方式下载即可

export ETCD_VERSION=v3.4.4
curl -sSL https://github.com/coreos/etcd/releases/download/${ETCD_VERSION}/etcd-${ETCD_VERSION}-linux-amd64.tar.gz | tar -xzv --strip-components=1 -C /usr/local/bin/

or 
wget https://github.com/coreos/etcd/releases/download/v3.4.4/etcd-v3.4.4-linux-amd64.tar.gz


<3>创建etcd环境配置文件



ETCD3.4版本会自动读取环境变量的参数,所以EnvironmentFile文件中有的参数,不需要再次在ExecStart启动参数中添加



#!/bin/bash

#PEER_NAME指定本节点的主机名称/域名,
#PRIVATE_IP指定本节点的IP(用于后面配置文件的生成)
#ETCD_CLUSTER群集列表,是所有节点信息(内容格式: 各节点名称=https://ip:端口  名称任意但要有标识性)
#ETCD_INITIAL_CLUSTER_TOKEN为该etcd集群Token,同一集群token一致

#需将此操作在每个etcd节点执行,前2个变量执行时需分别配置为 当前节点的 信息,意思是如果是


cat > /etc/etcd.env <<EOF
PEER_NAME=k8s-master01 
PRIVATE_IP=192.168.1.1
ETCD_CLUSTER="k8s-master01=https://192.168.1.1:2380,k8s-master02=https://192.168.1.2:2380,k8s-master03=https://192.168.1.3:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster-1"
EOF


cat > /etc/systemd/system/etcd.service  <<EOF
[Unit]
Description=etcd
Documentation=https://github.com/coreos/etcd
Conflicts=etcd.service
Conflicts=etcd2.service

[Service]
EnvironmentFile=/etc/etcd.env
Type=notify
Restart=always
RestartSec=5s
LimitNOFILE=65536
TimeoutStartSec=0

ExecStart=/usr/local/bin/etcd --name ${PEER_NAME} \
    --data-dir /var/lib/etcd \
    --listen-client-urls https://${PRIVATE_IP}:2379 \
    --advertise-client-urls https://${PRIVATE_IP}:2379 \
    --listen-peer-urls https://${PRIVATE_IP}:2380 \
    --initial-advertise-peer-urls https://${PRIVATE_IP}:2380 \
    --cert-file=/etc/kubernetes/pki/etcd/etcd.pem \
    --key-file=/etc/kubernetes/pki/etcd/etcd-key.pem \
    --client-cert-auth \
    --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem \
    --peer-cert-file=/etc/kubernetes/pki/etcd/etcd.pem \
    --peer-key-file=/etc/kubernetes/pki/etcd/etcd-key.pem \
    --peer-client-cert-auth \
    --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.pem \
    --initial-cluster ${ETCD_CLUSTER} \
    --initial-cluster-token etcd-cluster-1 \
    --initial-cluster-state new

[Install]
WantedBy=multi-user.target

EOF


需注意内容:
2379是提供给外部端口,2380是内部集群通讯端口
EnvironmentFile          指定环境变量文件
ExecStart                指定启动文件
--data-dir               指定数据目录
--listen-client-urls     对外提供服务的地址
--listen-peer-urls       和成员之间通信的地址
--initial-cluster-token  创建集群的 token,这个值每个集群保持唯一
--client-cert-auth       启用客户端证书验证
--peer-client-cert-auth  启用对等客户端证书验证
--initial-cluster-state  集群状态,默认为new(初始时建议设置为new。当一个节点故障后恢复时,该节点调整为existing,etcd将尝试使其加入现有群集)



下列参数皆为指定密钥文件,就不具体介绍了
--cert-file
--key-file
--client-cert-auth
--trusted-ca-file
--peer-cert-file
--peer-key-file
--peer-client-cert-auth
--peer-trusted-ca-file



调优



(1s=1000ms)

下列参数可写入配置文件,也可用命令调整
当开启证书验证,如果需要使用命令调整参数,需要加上证书,否则无法执行

--heartbeat-interval     心跳间隔的时间(以毫秒为单位)默认100   
应该被设置为节点之间网络往返时间,节点网络延迟较高时,可适当调高(跨机房/地域,通常最高为5s)

--election-timeout       选举超时的时间(以毫秒为单位)默认1000  
不均匀的网络性能或者常规的网络延迟和丢失,会引起多次网络重试,延迟过大可调高超时时间最高值应该是50s
调参命令:etcd --heartbeat-interval=100 --election-timeout=500

--max-snapshots          要保留的最大快照文件数(0表示不受限制)默认5

--snapshot-count         触发快照到磁盘的已提交事务数。默认100000   
当参数累积到一定的数量时,Etcd 才会创建快照文件。如果 Etcd的内存使用和磁盘使用过高,可调低快照触发的阈值5000 
调参命令:etcd --snapshot-count=5000

--auto-compaction-retention  自动压缩,默认为0不开启(默认小时为单位)。etcd会存储多版本数据,随着写入的主键增加,历史版本将会越来越多,并且默认不清理。可根据需求,设置压缩时间间隔。
调参命令:etcd --auto-compaction-retention=1

--max-request-bytes      服务器将接受的最大客户端请求大小(字节)默认1572864,1.5M  
官方推荐的是10M,建议根据需求自行调整

--quota-backend-bytes    当后端db数据大小超过给定配额时,引发警报并不允许写入,空间释放足够的空间之后,警告可以被解除,而集群将恢复正常运作,默认是2G   
官方推荐是8G配置,也可根据需求配置100G,并不是越大越好,key存储越多性能越差
调参命令:etcd --max-request-bytes=$((32*1024*1024)) --quota-backend-bytes=$((8*1024*1024*1024))


<5>启动etcd集群

systemctl daemon-reload
systemctl start etcd
systemctl enable etcd
systemctl status etcd -l

如果启动失败,检测一下当前节点是否存在etcd证书


<6>配置脚本,获取etcd集群服务的信息

cat etcd_healthy.sh

#!/bin/bash

HOST1=192.168.1.1
HOST2=192.168.1.2
HOST3=192.168.1.3
ENDPOINTS=$HOST1:2379,$HOST2:2379,$HOST3:2379
#因为开启了证书验证,因此执行命令需加上证书
KEY="--cacert=/etc/kubernetes/pki/etcd/ca.pem \
--cert=/etc/kubernetes/pki/etcd/etcd.pem \
--key=/etc/kubernetes/pki/etcd/etcd-key.pem"


#etcd集群健康信息
etcdctl --endpoints=$ENDPOINTS $KEY endpoint health

#etcd集群状态信息
etcdctl --endpoints=$ENDPOINTS $KEY --write-out=table endpoint status

#etcd集群成员信息
etcdctl --endpoints=$ENDPOINTS $KEY member list -w table


以下为实际环境执行时得到的,因此ip与文档不一致



172.22.57.184:2379 is healthy: successfully committed proposal: took = 10.085925ms
172.22.57.185:2379 is healthy: successfully committed proposal: took = 10.220026ms
172.22.57.187:2379 is healthy: successfully committed proposal: took = 11.350372ms
+--------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
|      ENDPOINT      |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+--------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| 172.22.57.184:2379 | 4fdbc756dda5ffbb |   3.4.4 |  1.6 MB |     false |      false |        94 |     289210 |             289210 |        |
| 172.22.57.187:2379 | c6c78a8f420b5599 |   3.4.4 |  1.6 MB |      true |      false |        94 |     289210 |             289210 |        |
| 172.22.57.185:2379 | 3067cb577abc7d54 |   3.4.4 |  1.6 MB |     false |      false |        94 |     289210 |             289210 |        |
+--------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
+------------------+---------+---------+----------------------------+----------------------------+------------+
|        ID        | STATUS  |  NAME   |         PEER ADDRS         |        CLIENT ADDRS        | IS LEARNER |
+------------------+---------+---------+----------------------------+----------------------------+------------+
| 3067cb577abc7d54 | started | master3 | https://172.22.57.185:2380 | https://172.22.57.185:2379 |      false |
| 4fdbc756dda5ffbb | started | master1 | https://172.22.57.184:2380 | https://172.22.57.184:2379 |      false |
| c6c78a8f420b5599 | started | master2 | https://172.22.57.187:2380 | https://172.22.57.187:2379 |      false |
+------------------+---------+---------+----------------------------+----------------------------+------------+



<7>配置脚本,有需要时释放空间

cat etcd_clean.sh

#!/bin/bash

#说明:
#由于配置了endpoints,在任意节点执行一次即可清理ETCD各节点空间
#如需清理单个节点,不加endpoints即可
#碎片整理会阻塞对etcd的读写操作,数据较大时defrag建议逐台进行

HOST1=192.168.1.1
HOST2=192.168.1.2
HOST3=192.168.1.3
ENDPOINTS=$HOST1:2379,$HOST2:2379,$HOST3:2379
#因为开启了证书验证,因此执行命令需加上证书
KEY="--cacert=/etc/kubernetes/pki/etcd/ca.pem \
--cert=/etc/kubernetes/pki/etcd/etcd.pem \
--key=/etc/kubernetes/pki/etcd/etcd-key.pem"


#获取当前历史修订版本
rev=$(ETCDCTL_API=3 etcdctl --endpoints=$ENDPOINTS $KEY endpoint status --write-out="json" | egrep -o '"revision":[0-9]*' | egrep -o '[0-9].*')

#压缩到指定的修订版本
##数据压缩并不是清理现有数据,只是对给定版本之前的历史版本进行清理,清理后数据的历史版本将不能访问,不会影响现有最新数据的访问压缩
#示例:ETCDCTL_API=3 etcdctl --endpoints=${ENDPOINTS} ${KEY} compact 5
ETCDCTL_API=3 etcdctl --endpoints=${ENDPOINTS} ${KEY} compact $rev

# 反碎片化(碎片整理,释放空间)
ETCDCTL_API=3 etcdctl --endpoints=${ENDPOINTS} ${KEY} defrag

# 解除警报
ETCDCTL_API=3 etcdctl --endpoints=${ENDPOINTS} ${KEY} alarm disarm
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐