[容器化技术之十五] K8S集群架构搭建之二 —— etcd 集群搭建和 flannel 网络部署

二、集群环境搭建

2.5 部署 etcd 集群

  etcd 是基于 Raft 的分布式 key-value 存储系统,由 CoreOS 开发,常用于服务发现,共享配置以及并发控制(如 leader 选举、分布式锁等)。kubernetes 使用 etcd 存储所有运行数据。

  下面介绍部署一个三节点高可用 etcd 集群的步骤:

  • 下载和分发 etcd 二进制文件;
  • 创建 etcd 集群各节点的 x509 证书,用于加密客户端(如 etcdctl)与 etcd 集群、etcd 集群之间的数据流;
  • 创建 etcd 的 systemd unit 文件,配置服务参数;
  • 检查集群工作状态;


    etcd 集群各节点的名称和 IP 如下:
  • master:192.168.27.135
  • node1:192.168.27.133
  • node2:192.168.27.134

注意:如果没有特殊说明,下面的操作默认在 master 节点上执行,然后远程分发文件和执行命令。

2.5.1 下载和分发 etcd 二进制文件

  到 https://github.com/coreos/etcd/releases 页面下载最新版本的发布包:

cd /opt/k8s/work
wget https://github.com/coreos/etcd/releases/download/v3.3.10/etcd-v3.3.10-linux-amd64.tar.gz
tar -xvf etcd-v3.3.10-linux-amd64.tar.gz

  如果下载过慢,直接从百度网盘下载对应的压缩包

链接:https://pan.baidu.com/s/1Zt9SGin72ahERM7ykJ8o7w
提取码:27m2

  解压后分发二进制文件到集群所有节点:

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    scp etcd-v3.3.10-linux-amd64/etcd* root@${node_ip}:/opt/k8s/bin
    ssh root@${node_ip} "chmod +x /opt/k8s/bin/*"
  done



2.5.2 创建 etcd 证书和私钥

  创建证书签名请求:

cd /opt/k8s/work/cert
cat > etcd-csr.json <
  • hosts 字段指定授权使用该证书的 etcd 节点 IP 或域名列表,这里将 etcd 集群的三个节点 IP 都列在其中

  生成证书和私钥:

cd /opt/k8s/work/cert
cfssl gencert -ca=/opt/k8s/work/cert/ca.pem \
    -ca-key=/opt/k8s/work/cert/ca-key.pem \
    -config=/opt/k8s/work/cert/ca-config.json \
    -profile=kubernetes etcd-csr.json | cfssljson -bare etcd
ls etcd*pem

  分发生成的证书和私钥到各 etcd 节点:

cd /opt/k8s/work/cert
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



2.5.3 创建 etcd 的 systemd unit 模板文件

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
cat > etcd.service.template <

  其中 ${} 的是环境变量,生成模板文件的时候变量占位会被替换为环境变量值,##变量##是等下循环批量文本替换时会被替换的变量,生成模板文件后打开,检查环境变量是否有被正常替换。

[容器化技术之十五] K8S集群架构搭建之二 —— etcd 集群搭建和 flannel 网络部署_第1张图片

  • 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 证书;


    2.5.4 为各节点创建和分发 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_NAMESNODE_IPS 为相同长度的 bash 数组,分别为节点名称和对应的 IP;

  打开任意一个文件查看 ##变量## 是否已经被替换

[容器化技术之十五] K8S集群架构搭建之二 —— etcd 集群搭建和 flannel 网络部署_第2张图片

  分发生成的 systemd unit 文件,并将分发的文件重命名为 etcd.service

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}:/usr/lib/systemd/system/etcd.service
  done

  分发到 node1 和 node2 报错了,说是找不到目录 /usr/lib/systemd/system/,排查结果是因为 ubuntu 的 systemd unit 文件放置的目录跟 centos 不一样,应该放到 /lib/systemd/system/ 目录中,重新单独执行分发的命令:

[容器化技术之十五] K8S集群架构搭建之二 —— etcd 集群搭建和 flannel 网络部署_第3张图片



2.5.5 启动 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 会卡住一段时间,为正常现象。


    2.5.6 检查启动结果
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
[容器化技术之十五] K8S集群架构搭建之二 —— etcd 集群搭建和 flannel 网络部署_第4张图片

  确保状态为 active (running),否则查看日志,确认原因:

journalctl -u etcd

[容器化技术之十五] K8S集群架构搭建之二 —— etcd 集群搭建和 flannel 网络部署_第5张图片



2.5.7 验证服务状态

  部署完 etcd 集群后,在任一 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=/opt/k8s/work/cert/ca.pem \
    --cert=/etc/etcd/cert/etcd.pem \
    --key=/etc/etcd/cert/etcd-key.pem endpoint health
  done

  正常情况下输出如下:

>>> 192.168.27.135
https://192.168.27.135:2379 is healthy: successfully committed proposal: took = 25.485544ms
>>> 192.168.27.133
https://192.168.27.133:2379 is healthy: successfully committed proposal: took = 27.127103ms
>>> 192.168.27.134
https://192.168.27.134:2379 is healthy: successfully committed proposal: took = 20.815013ms



2.5.8 查看当前的 leader

source /opt/k8s/bin/environment.sh
ETCDCTL_API=3 /opt/k8s/bin/etcdctl \
  -w table --cacert=/opt/k8s/work/cert/ca.pem \
  --cert=/etc/etcd/cert/etcd.pem \
  --key=/etc/etcd/cert/etcd-key.pem \
  --endpoints=${ETCD_ENDPOINTS} endpoint status

  输入如下,可见当前的 leader 为 192.168.27.135

[容器化技术之十五] K8S集群架构搭建之二 —— etcd 集群搭建和 flannel 网络部署_第6张图片


2.6 部署 flannel 网络

  kubernetes 要求集群内各节点(包括 master 节点)能通过 Pod 网段互联互通。flannel 使用 vxlan 技术为各节点创建一个可以互通的 Pod 网络,使用的端口为 UDP 8472,需要开放该端口(如公有云 AWS等)。

  flanneld 第一次启动时,从 etcd 获取配置的 Pod 网段信息,为本节点分配一个未使用的地址段,然后创建 flannedl.1 网络接口(也可能是其他名称,如 flannel1 等)。

  flannel 将分配给自己的 Pod 网段信息写入 /run/flannel/docker 文件,docker 后续使用这个文件中的环境变量设置 docker0 网桥,从而从这个地址为本节点的所有 Pod 容器分配 IP。

  注意:如果没有特殊指明,下面的所有操作均在 master 节点上执行,然后远程分发文件和执行命令。

2.6.1 下载和分发 flanneld 二进制文件

  到 https://github.com/coreos/flannel/releases 页面下载最新版本的发布包:

cd /opt/k8s/work
mkdir flannel
wget https://github.com/coreos/flannel/releases/download/v0.10.0/flannel-v0.10.0-linux-amd64.tar.gz
tar -xzvf flannel-v0.10.0-linux-amd64.tar.gz -C flannel

  如果下载过慢,直接从百度网盘下载对应的压缩包

链接:https://pan.baidu.com/s/1Zt9SGin72ahERM7ykJ8o7w
提取码:27m2

[容器化技术之十五] K8S集群架构搭建之二 —— etcd 集群搭建和 flannel 网络部署_第7张图片

  分发 flanneld 二进制文件到集群所有节点:

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    scp flannel/{flanneld,mk-docker-opts.sh} root@${node_ip}:/opt/k8s/bin/
    ssh root@${node_ip} "chmod +x /opt/k8s/bin/*"
  done



2.6.2 创建 flannel 证书和私钥

  flannel 从 etcd 集群存取网段分配信息,而 etcd 集群启用了双向 x509 证书认证,所以需要为 flanneld 生成证书和私钥。

  创建证书签名请求:

cd /opt/k8s/work/cert
cat > flanneld-csr.json <
  • 该证书只会被 kubectl 当做 client 证书使用,所以 hosts 字段为空;

  生成证书和私钥:

cfssl gencert -ca=/opt/k8s/work/cert/ca.pem \
  -ca-key=/opt/k8s/work/cert/ca-key.pem \
  -config=/opt/k8s/work/cert/ca-config.json \
  -profile=kubernetes flanneld-csr.json | cfssljson -bare flanneld
ls flannel*pem

  将生成的证书和私钥分发到所有节点(master 和 worker):

cd /opt/k8s/work/cert
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "mkdir -p /etc/flanneld/cert"
    scp flanneld*.pem root@${node_ip}:/etc/flanneld/cert
  done



2.6.3 向 etcd 写入集群 Pod 网段信息

cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
etcdctl \
  --endpoints=${ETCD_ENDPOINTS} \
  --ca-file=/opt/k8s/work/cert/ca.pem \
  --cert-file=/opt/k8s/work/cert/flanneld.pem \
  --key-file=/opt/k8s/work/cert/flanneld-key.pem \
  set ${FLANNEL_ETCD_PREFIX}/config '{"Network":"'${CLUSTER_CIDR}'", "SubnetLen": 21, "Backend": {"Type": "vxlan"}}'
  • flanneld 当前版本 (v0.10.0) 不支持 etcd v3,故使用 etcd v2 API 写入配置 key 和网段数据;
  • 写入的 Pod 网段 ${CLUSTER_CIDR} 地址段如 /16 必须小于 SubnetLen,必须与 kube-controller-manager 的 --cluster-cidr 参数值一致;


    2.6.4 创建 flanneld 的 systemd unit 文件
cd /opt/k8s/work
source /opt/k8s/bin/environment.sh
cat > flanneld.service << EOF
[Unit]
Description=Flanneld overlay address etcd agent
After=network.target
After=network-online.target
Wants=network-online.target
After=etcd.service
Before=docker.service

[Service]
Type=notify
ExecStart=/opt/k8s/bin/flanneld \\
  -etcd-cafile=/etc/kubernetes/cert/ca.pem \\
  -etcd-certfile=/etc/flanneld/cert/flanneld.pem \\
  -etcd-keyfile=/etc/flanneld/cert/flanneld-key.pem \\
  -etcd-endpoints=${ETCD_ENDPOINTS} \\
  -etcd-prefix=${FLANNEL_ETCD_PREFIX} \\
  -iface=${IFACE} \\
  -ip-masq
ExecStartPost=/opt/k8s/bin/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker
Restart=always
RestartSec=5
StartLimitInterval=0

[Install]
WantedBy=multi-user.target
RequiredBy=docker.service
EOF
  • mk-docker-opts.sh 脚本将分配给 flanneld 的 Pod 子网网段信息写入 /run/flannel/docker 文件,后续 docker 启动时使用这个文件中的环境变量配置 docker0 网桥;
  • flanneld 使用系统缺省路由所在的接口与其它节点通信,对于有多个网络接口(如内网和公网)的节点,可以用 -iface 参数指定通信接口;
  • flanneld 运行时需要 root 权限;
  • -ip-masq: flanneld 为访问 Pod 网络外的流量设置 SNAT 规则,同时将传递给 Docker 的变量 --ip-masq(/run/flannel/docker 文件中)设置为 false,这样 Docker 将不再创建 SNAT 规则; Docker 的 --ip-masq 为 true 时,创建的 SNAT 规则比较“暴力”:将所有本节点 Pod 发起的、访问非 docker0 接口的请求做 SNAT,这样访问其他节点 Pod 的请求来源 IP 会被设置为 flannel.1 接口的 IP,导致目的 Pod 看不到真实的来源 Pod IP。 flanneld 创建的 SNAT 规则比较温和,只对访问非 Pod 网段的请求做 SNAT。


    2.6.5 分发 flanneld systemd unit 文件到所有节点
source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    # 如果分发的服务器是 ubuntu这里路径改成 /lib/systemd/system/ 
    scp flanneld.service root@${node_ip}:/usr/lib/systemd/system/    
  done



2.6.6 启动 flanneld 服务

source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "systemctl daemon-reload && systemctl enable flanneld && systemctl restart flanneld"
  done



2.6.7 检查启动结果

source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh root@${node_ip} "systemctl status flanneld|grep Active"
  done
[容器化技术之十五] K8S集群架构搭建之二 —— etcd 集群搭建和 flannel 网络部署_第8张图片

  确保状态为 active (running),否则查看日志,确认原因:

journalctl -u flanneld



2.6.8 检查分配给各 flanneld 的 Pod 网段信息
  查看集群 Pod 网段(/16):

source /opt/k8s/bin/environment.sh
etcdctl \
  --endpoints=${ETCD_ENDPOINTS} \
  --ca-file=/etc/kubernetes/cert/ca.pem \
  --cert-file=/etc/flanneld/cert/flanneld.pem \
  --key-file=/etc/flanneld/cert/flanneld-key.pem \
  get ${FLANNEL_ETCD_PREFIX}/config

  输出:

{"Network":"172.30.0.0/16", "SubnetLen": 21, "Backend": {"Type": "vxlan"}}

  查看已分配的 Pod 子网段列表(/24):

source /opt/k8s/bin/environment.sh
etcdctl \
  --endpoints=${ETCD_ENDPOINTS} \
  --ca-file=/etc/kubernetes/cert/ca.pem \
  --cert-file=/etc/flanneld/cert/flanneld.pem \
  --key-file=/etc/flanneld/cert/flanneld-key.pem \
  ls ${FLANNEL_ETCD_PREFIX}/subnets

  输出:


[容器化技术之十五] K8S集群架构搭建之二 —— etcd 集群搭建和 flannel 网络部署_第9张图片

  查看某一 Pod 网段对应的节点 IP 和 flannel 接口地址:

source /opt/k8s/bin/environment.sh
etcdctl \
  --endpoints=${ETCD_ENDPOINTS} \
  --ca-file=/etc/kubernetes/cert/ca.pem \
  --cert-file=/etc/flanneld/cert/flanneld.pem \
  --key-file=/etc/flanneld/cert/flanneld-key.pem \
  get ${FLANNEL_ETCD_PREFIX}/subnets/172.30.40.0-21

  输出:


[容器化技术之十五] K8S集群架构搭建之二 —— etcd 集群搭建和 flannel 网络部署_第10张图片
  • 172.30.40.0/21 被分配给节点 master(192.168.27.135);
  • VtepMAC 为 master 节点的 flannel.1 网卡 MAC 地址;


    2.6.9 检查节点 flannel 网络信息
ip addr show
[容器化技术之十五] K8S集群架构搭建之二 —— etcd 集群搭建和 flannel 网络部署_第11张图片
  • flannel.1 网卡的地址为分配的 Pod 子网段的第一个 IP(.0),且是 /32 的地址;
ip route show |grep flannel.1
  • 到其它节点 Pod 网段请求都被转发到 flannel.1 网卡;
  • flanneld 根据 etcd 中子网段的信息,如 ${FLANNEL_ETCD_PREFIX}/subnets/172.30.80.0-21 ,来决定进请求发送给哪个节点的互联 IP;


    2.6.10 验证各节点能通过 Pod 网段互通

  在各节点上部署 flannel 后,检查是否创建了 flannel 接口(名称可能为 flannel0、flannel.0、flannel.1 等):

source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    ssh ${node_ip} "/usr/sbin/ip addr show flannel.1|grep -w inet"
  done

  输出(由于133、134都是ubuntu,可执行目录不一样):


[容器化技术之十五] K8S集群架构搭建之二 —— etcd 集群搭建和 flannel 网络部署_第12张图片

  在各节点上 ping 所有 flannel 接口 IP,确保能通:

source /opt/k8s/bin/environment.sh
for node_ip in ${NODE_IPS[@]}
  do
    echo ">>> ${node_ip}"
    # 这里 ping 的网段都是上面步骤中分配给每个节点的网段
    ssh ${node_ip} "ping -c 1 172.30.40.0"
    ssh ${node_ip} "ping -c 1 172.30.48.0"
    ssh ${node_ip} "ping -c 1 172.30.176.0"
  done

你可能感兴趣的:([容器化技术之十五] K8S集群架构搭建之二 —— etcd 集群搭建和 flannel 网络部署)