关键内容:配置自签发的SSL证书
目录
- 配置虚拟机 1-10
- 配置根证书 11-15
- 配置etcd 16-23
一、虚拟机
这里使用KVM生成三台测试机,你也可以使用virtualBox或者VMware。操作系统请选择 CentOS-7.6.18.10
virt-clone --connect qemu:///system --original newbie --name etcd-1 --file /home/kvm/disk/etcd-1.img
virt-clone --connect qemu:///system --original newbie --name etcd-2 --file /home/kvm/disk/etcd-2.img
virt-clone --connect qemu:///system --original newbie --name etcd-3 --file /home/kvm/disk/etcd-3.img
二、集群机器
- etcd-1: 192.168.0.34
- etcd-2: 192.168.0.35
- etcd-3: 192.168.0.36
注意:
- 需要在所有机器上执行本文档的初始化命令;
- 需要使用 root 账号执行这些命令;
- 如果没有特殊指明,本文档的所有操作均在
etcd-1
节点上执行,然后远程分发文件和执行命令;
三、主机名
设置永久主机名称,然后重新登录(三个节点都执行):
[root@etcd-1 ~]# hostnamectl set-hostname etcd-1 # 将 etcd-1 替换为当前主机名
设置的主机名保存在 /etc/hostname 文件中;
如果 DNS 不支持解析主机名称,则需要修改每台机器的 /etc/hosts 文件,添加主机名和 IP 的对应关系:
cat >> /etc/hosts <<EOF
192.168.0.34 etcd-1
192.168.0.35 etcd-2
192.168.0.36 etcd-3
EOF
四、无密码 ssh 登录其它节点
如果没有特殊指明,本文档的所有操作均在 etcd-1 节点上执行,然后远程分发文件和执行命令,所以需要添加该节点到其它节点的 ssh 信任关系。
设置 etcd-1 的 root 账户可以无密码登录所有节点:
[root@etcd-1 ~]# ssh-keygen -t rsa
[root@etcd-1 ~]# ssh-copy-id root@etcd-1
[root@etcd-1 ~]# ssh-copy-id root@etcd-2
[root@etcd-1 ~]# ssh-copy-id root@etcd-3
验证是否配置成功
[root@etcd-1 ~]# ssh root@etcd-1 hostname
etcd-1
[root@etcd-1 ~]# ssh root@etcd-2 hostname
etcd-2
[root@etcd-1 ~]# ssh root@etcd-3 hostname
etcd-3
五、更新 PATH 变量
将可执行文件目录添加到 PATH 环境变量中(三个节点都执行):
echo 'PATH=/opt/k8s/bin:$PATH' >>/root/.bashrc
source /root/.bashrc
六、安装依赖包
在每台机器上安装依赖包(三个节点都执行):
yum install -y epel-release
yum install -y ntpdate ntp jq iptables curl sysstat wget
七、关闭防火墙
在每台机器上关闭防火墙,清理防火墙规则,设置默认转发策略(三个节点都执行):
systemctl stop firewalld
systemctl disable firewalld
八、设置系统时区
三个节点都执行
## 调整系统 TimeZone
timedatectl set-timezone Asia/Shanghai
## 将当前的 UTC 时间写入硬件时钟
timedatectl set-local-rtc 0
## 重启依赖于系统时间的服务
systemctl restart rsyslog
systemctl restart crond
九、创建相关目录
三个节点都执行
mkdir -p /opt/k8s/{bin,work} /etc/etcd/cert
十、分发集群配置参数脚本
后续使用的环境变量都定义在文件 environment.sh中,
cat >> /opt/k8s/binenvironment.sh <<EOF
#!/usr/bin/bash
# 生成 EncryptionConfig 所需的加密 key
export ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)
# 集群各机器 IP 数组
export NODE_IPS=(192.168.0.34 192.168.0.35 192.168.0.36)
# 集群各 IP 对应的主机名数组
export NODE_NAMES=(etcd-1 etcd-2 etcd-3)
# etcd 集群服务地址列表
export ETCD_ENDPOINTS="https://192.168.0.34:2379,https://192.168.0.35:2379,https://192.168.0.36:2379"
# etcd 集群间通信的 IP 和端口
export ETCD_NODES="etcd-1=https://192.168.0.34:2380,etcd-2=https://192.168.0.35:2380,etcd-3=https://192.168.0.36:2380"
# 节点间互联网络接口名称
export IFACE="eth0"
# etcd 数据目录
export ETCD_DATA_DIR="/data/k8s/etcd/data"
# etcd WAL 目录,建议是 SSD 磁盘分区,或者和 ETCD_DATA_DIR 不同的磁盘分区
export ETCD_WAL_DIR="/data/k8s/etcd/wal"
# 将二进制目录 /opt/k8s/bin 加到 PATH 中
export PATH=/opt/k8s/bin:$PATH
EOF
请根据自己的机器、网络情况修改。然后,把它拷贝到所有节点的 /opt/k8s/bin
目录:
source environment.sh
for node_ip in ${NODE_IPS[@]}
do
echo ">>> ${node_ip}"
scp environment.sh root@${node_ip}:/opt/k8s/bin/
ssh root@${node_ip} "chmod +x /opt/k8s/bin/*"
done
十一、安装 cfssl 工具集
sudo mkdir -p /opt/k8s/cert && cd /opt/k8s
wget -c https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
mv cfssl_linux-amd64 /opt/k8s/bin/cfssl
wget -c https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
mv cfssljson_linux-amd64 /opt/k8s/bin/cfssljson
wget -c https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
mv cfssl-certinfo_linux-amd64 /opt/k8s/bin/cfssl-certinfo
chmod +x /opt/k8s/bin/*
十二、创建根证书 (CA)
CA 证书是集群所有节点共享的,只需要创建一个 CA 证书,后续创建的所有证书都由它签名。
十三、创建证书配置文件
CA 配置文件用于配置根证书的使用场景 (profile) 和具体参数 (usage,过期时间、服务端认证、客户端认证、加密等),后续在签名其它证书时需要指定特定场景。
cd /opt/k8s/work
cat > ca-config.json <<EOF
{
"signing": {
"default": {
"expiry": "87600h"
},
"profiles": {
"kubernetes": {
"usages": [
"signing",
"key encipherment",
"server auth",
"client auth"
],
"expiry": "87600h"
}
}
}
}
EOF
- signing:表示该证书可用于签名其它证书,生成的 ca.pem 证书中 CA=TRUE;
- server auth:表示 client 可以用该该证书对 server 提供的证书进行验证;
- client auth:表示 server 可以用该该证书对 client 提供的证书进行验证;
十四、创建证书签名请求文件
cd /opt/k8s/work
cat > ca-csr.json <<EOF
{
"CN": "kubernetes",
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "4Paradigm"
}
],
"ca": {
"expiry": "876000h"
}
}
EOF
- CN:Common Name,kube-apiserver 从证书中提取该字段作为请求的用户名 (User Name),浏览器使用该字段验证网站是否合法;
- O:Organization,kube-apiserver 从证书中提取该字段作为请求用户所属的组 (Group);
- kube-apiserver 将提取的 User、Group 作为 RBAC 授权的用户标识;
十五、生成 CA 证书和私钥
cd /opt/k8s/work
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
ls ca*
分发证书文件
cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
do
echo ">>> ${node_ip}"
ssh root@${node_ip} "mkdir -p /etc/kubernetes/cert"
scp ca*.pem ca-config.json root@${node_ip}:/etc/kubernetes/cert
done
十六、下载和分发 etcd 二进制文件
cd /opt/k8s/work
wget -c https://github.com/coreos/etcd/releases/download/v3.3.13/etcd-v3.3.13-linux-amd64.tar.gz
tar -xvf etcd-v3.3.13-linux-amd64.tar.gz
分发二进制文件到集群所有节点:
cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
do
echo ">>> ${node_ip}"
scp etcd-v3.3.13-linux-amd64/etcd* root@${node_ip}:/opt/k8s/bin
ssh root@${node_ip} "chmod +x /opt/k8s/bin/*"
done
十七、创建 etcd 证书和私钥
创建证书签名请求:
cd /opt/k8s/work
cat > etcd-csr.json <<EOF
{
"CN": "etcd",
"hosts": [
"127.0.0.1",
"192.168.0.34",
"192.168.0.35",
"192.168.0.36"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "4Paradigm"
}
]
}
EOF
- hosts 字段指定授权使用该证书的 etcd 节点 IP 或域名列表,需要将 etcd 集群的三个节点 IP 都列在其中;
生成证书和私钥:
cd /opt/k8s/work
cfssl gencert -ca=/opt/k8s/work/ca.pem \
-ca-key=/opt/k8s/work/ca-key.pem \
-config=/opt/k8s/work/ca-config.json \
-profile=kubernetes etcd-csr.json | cfssljson -bare etcd
ls etcd*pem
分发生成的证书和私钥到各 etcd 节点:
cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
do
echo ">>> ${node_ip}"
ssh root@${node_ip} "mkdir -p /etc/etcd/cert"
scp etcd*.pem root@${node_ip}:/etc/etcd/cert/
done
十八、创建 etcd 的 systemd unit 模板文件
cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
cat > etcd.service.template <<EOF
[Unit]
Description=Etcd Server
After=network.target
After=network-online.target
Wants=network-online.target
Documentation=https://github.com/coreos
[Service]
Type=notify
WorkingDirectory=${ETCD_DATA_DIR}
ExecStart=/opt/k8s/bin/etcd \\
--data-dir=${ETCD_DATA_DIR} \\
--wal-dir=${ETCD_WAL_DIR} \\
--name=##NODE_NAME## \\
--cert-file=/etc/etcd/cert/etcd.pem \\
--key-file=/etc/etcd/cert/etcd-key.pem \\
--trusted-ca-file=/etc/kubernetes/cert/ca.pem \\
--peer-cert-file=/etc/etcd/cert/etcd.pem \\
--peer-key-file=/etc/etcd/cert/etcd-key.pem \\
--peer-trusted-ca-file=/etc/kubernetes/cert/ca.pem \\
--peer-client-cert-auth \\
--client-cert-auth \\
--listen-peer-urls=https://##NODE_IP##:2380 \\
--initial-advertise-peer-urls=https://##NODE_IP##:2380 \\
--listen-client-urls=https://##NODE_IP##:2379,http://127.0.0.1:2379 \\
--advertise-client-urls=https://##NODE_IP##:2379 \\
--initial-cluster-token=etcd-cluster-0 \\
--initial-cluster=${ETCD_NODES} \\
--initial-cluster-state=new \\
--auto-compaction-mode=periodic \\
--auto-compaction-retention=1 \\
--max-request-bytes=33554432 \\
--quota-backend-bytes=6442450944 \\
--heartbeat-interval=250 \\
--election-timeout=2000
Restart=on-failure
RestartSec=5
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
- WorkingDirectory、--data-dir:指定工作目录和数据目录为 ${ETCD_DATA_DIR},需在启动服务前创建这个目录;
- --wal-dir:指定 wal 目录,为了提高性能,一般使用 SSD 或者和 --data-dir 不同的磁盘;
- --name:指定节点名称,当 --initial-cluster-state 值为 new 时,--name 的参数值必须位于 --initial-cluster 列表中;
- --cert-file、--key-file:etcd server 与 client 通信时使用的证书和私钥;
- --trusted-ca-file:签名 client 证书的 CA 证书,用于验证 client 证书;
- --peer-cert-file、--peer-key-file:etcd 与 peer 通信使用的证书和私钥;
- --peer-trusted-ca-file:签名 peer 证书的 CA 证书,用于验证 peer 证书;
十九、为各节点创建和分发 etcd systemd unit 文件
替换模板文件中的变量,为各节点创建 systemd unit 文件:
cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for (( i=0; i < 3; i++ ))
do
sed -e "s/##NODE_NAME##/${NODE_NAMES[i]}/" -e "s/##NODE_IP##/${NODE_IPS[i]}/" etcd.service.template > etcd-${NODE_IPS[i]}.service
done
ls *.service
- NODE_NAMES 和 NODE_IPS 为相同长度的 bash 数组,分别为节点名称和对应的 IP;
分发生成的 systemd unit 文件:
cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
do
echo ">>> ${node_ip}"
scp etcd-${node_ip}.service root@${node_ip}:/etc/systemd/system/etcd.service
done
二十、启动 etcd 服务
cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
do
echo ">>> ${node_ip}"
ssh root@${node_ip} "mkdir -p ${ETCD_DATA_DIR} ${ETCD_WAL_DIR}"
ssh root@${node_ip} "systemctl daemon-reload && systemctl enable etcd && systemctl restart etcd " &
done
- 必须先创建 etcd 数据目录和工作目录;
- etcd 进程首次启动时会等待其它节点的 etcd 加入集群,命令 systemctl start etcd 会卡住一段时间,为正常现象;
二十一、检查启动结果
cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
do
echo ">>> ${node_ip}"
ssh root@${node_ip} "systemctl status etcd|grep Active"
done
确保状态为 active (running),否则查看日志,确认原因:
journalctl -u etcd
验证服务状态
cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
do
echo ">>> ${node_ip}"
ETCDCTL_API=3 /opt/k8s/bin/etcdctl \
--endpoints=https://${node_ip}:2379 \
--cacert=/etc/kubernetes/cert/ca.pem \
--cert=/etc/etcd/cert/etcd.pem \
--key=/etc/etcd/cert/etcd-key.pem endpoint health
done
预期输出:
>>> 192.168.0.34
https://192.168.0.34:2379 is healthy: successfully committed proposal: took = 14.896891ms
>>> 192.168.0.35
https://192.168.0.35:2379 is healthy: successfully committed proposal: took = 17.176835ms
>>> 192.168.0.36
https://192.168.0.36:2379 is healthy: successfully committed proposal: took = 20.758029ms
输出均为 healthy 时表示集群服务正常。
二十二、查看当前的 leader
source /opt/k8s/bin/environment.sh
ETCDCTL_API=3 /opt/k8s/bin/etcdctl \
-w table --cacert=/etc/kubernetes/cert/ca.pem \
--cert=/etc/etcd/cert/etcd.pem \
--key=/etc/etcd/cert/etcd-key.pem \
--endpoints=${ETCD_ENDPOINTS} endpoint status
输出:
+-----------------------------+------------------+---------+---------+-----------+-----------+------------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
+-----------------------------+------------------+---------+---------+-----------+-----------+------------+
| https://172.27.137.240:2379 | bdda68fa64a34210 | 3.3.13 | 20 kB | false | 2 | 8 |
| https://172.27.137.239:2379 | 3405e3220d380204 | 3.3.13 | 20 kB | true | 2 | 8 |
| https://172.27.137.238:2379 | beee77fb1e3915cc | 3.3.13 | 20 kB | false | 2 | 8 |
+-----------------------------+------------------+---------+---------+-----------+-----------+------------+
- 可见,当前的 leader 为 172.27.137.239。
二十三、结束
大多数情况,如果能看到这,说明你已经成功安装etcd了。😁
如果把etcd-1重启一次,它就会马上失去leader的地位了
+---------------------------+------------------+---------+---------+-----------+-----------+------------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | RAFT TERM | RAFT INDEX |
+---------------------------+------------------+---------+---------+-----------+-----------+------------+
| https://192.168.0.34:2379 | 4dfdf8a260ef8c4e | 3.3.13 | 20 kB | false | 113 | 18 |
| https://192.168.0.35:2379 | 9ab8fd7903b60d87 | 3.3.13 | 20 kB | true | 113 | 18 |
| https://192.168.0.36:2379 | 7b85be04b10ebeb5 | 3.3.13 | 20 kB | false | 113 | 18 |
+---------------------------+------------------+---------+---------+-----------+-----------+------------+