05.部署 flannel 网络

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

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

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

    从 flannel 的 下载最新版本的安装包:

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

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

    创建 flannel 证书和私钥

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

    1. cd /opt/k8s/work
    2. cat > flanneld-csr.json <<EOF
    3. {
    4. "CN": "flanneld",
    5. "hosts": [],
    6. "key": {
    7. "algo": "rsa",
    8. "size": 2048
    9. },
    10. "names": [
    11. {
    12. "C": "CN",
    13. "ST": "BeiJing",
    14. "L": "BeiJing",
    15. "O": "k8s",
    16. "OU": "4Paradigm"
    17. }
    18. ]
    19. }
    20. EOF
    • 该证书只会被 kubectl 当做 client 证书使用,所以 hosts 字段为空;

    生成证书和私钥:

    1. cfssl gencert -ca=/opt/k8s/work/ca.pem \
    2. -ca-key=/opt/k8s/work/ca-key.pem \
    3. -config=/opt/k8s/work/ca-config.json \
    4. -profile=kubernetes flanneld-csr.json | cfssljson -bare flanneld
    5. ls flanneld*pem

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

    1. cd /opt/k8s/work
    2. for node_ip in ${NODE_IPS[@]}
    3. do
    4. echo ">>> ${node_ip}"
    5. ssh root@${node_ip} "mkdir -p /etc/flanneld/cert"
    6. scp flanneld*.pem root@${node_ip}:/etc/flanneld/cert
    7. done

    向 etcd 写入集群 Pod 网段信息

    注意:本步骤只需执行一次

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

    分发 flanneld systemd unit 文件到所有节点

    1. cd /opt/k8s/work
    2. source /opt/k8s/bin/environment.sh
    3. for node_ip in ${NODE_IPS[@]}
    4. do
    5. echo ">>> ${node_ip}"
    6. scp flanneld.service root@${node_ip}:/etc/systemd/system/
    7. done

    启动 flanneld 服务

    1. source /opt/k8s/bin/environment.sh
    2. for node_ip in ${NODE_IPS[@]}
    3. do
    4. echo ">>> ${node_ip}"
    5. ssh root@${node_ip} "systemctl daemon-reload && systemctl enable flanneld && systemctl restart flanneld"
    6. done
    1. source /opt/k8s/bin/environment.sh
    2. for node_ip in ${NODE_IPS[@]}
    3. do
    4. echo ">>> ${node_ip}"
    5. ssh root@${node_ip} "systemctl status flanneld|grep Active"
    6. done

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

    1. journalctl -u flanneld

    检查分配给各 flanneld 的 Pod 网段信息

    查看集群 Pod 网段(/16):

    1. source /opt/k8s/bin/environment.sh
    2. etcdctl \
    3. --endpoints=${ETCD_ENDPOINTS} \
    4. --ca-file=/etc/kubernetes/cert/ca.pem \
    5. get ${FLANNEL_ETCD_PREFIX}/config

    输出:

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

    输出(结果视部署情况而定):

    1. /kubernetes/network/subnets/172.30.80.0-21
    2. /kubernetes/network/subnets/172.30.32.0-21
    3. /kubernetes/network/subnets/172.30.184.0-21

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

    1. source /opt/k8s/bin/environment.sh
    2. etcdctl \
    3. --endpoints=${ETCD_ENDPOINTS} \
    4. --ca-file=/etc/kubernetes/cert/ca.pem \
    5. --cert-file=/etc/flanneld/cert/flanneld.pem \
    6. --key-file=/etc/flanneld/cert/flanneld-key.pem \
    7. get ${FLANNEL_ETCD_PREFIX}/subnets/172.30.80.0-21

    输出(结果视部署情况而定):

    {"PublicIP":"172.27.137.240","BackendType":"vxlan","BackendData":{"VtepMAC":"ce:9c:a9:08:50:03"}}

    • 172.30.80.0/21 被分配给节点 zhangjun-k8s01(172.27.137.240);
    • VtepMAC 为 zhangjun-k8s01 节点的 flannel.1 网卡 MAC 地址;

    检查节点 flannel 网络信息

    1. [root@zhangjun-k8s01 work]# ip addr show
    2. 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    3. link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    4. inet 127.0.0.1/8 scope host lo
    5. valid_lft forever preferred_lft forever
    6. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    7. link/ether 00:22:0d:33:89:75 brd ff:ff:ff:ff:ff:ff
    8. inet 172.27.137.240/20 brd 172.27.143.255 scope global dynamic eth0
    9. valid_lft 100647283sec preferred_lft 100647283sec
    10. 3: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default
    11. link/ether ce:9c:a9:08:50:03 brd ff:ff:ff:ff:ff:ff
    12. inet 172.30.80.0/32 scope global flannel.1
    13. valid_lft forever preferred_lft forever
    • flannel.1 网卡的地址为分配的 Pod 子网段的第一个 IP(.0),且是 /32 的地址;
    1. [root@zhangjun-k8s01 work]# ip route show |grep flannel.1
    2. 172.30.32.0/21 via 172.30.32.0 dev flannel.1 onlink
    3. 172.30.184.0/21 via 172.30.184.0 dev flannel.1 onlink
    • 到其它节点 Pod 网段请求都被转发到 flannel.1 网卡;
    • flanneld 根据 etcd 中子网段的信息,如 ${FLANNEL_ETCD_PREFIX}/subnets/172.30.80.0-21 ,来决定进请求发送给哪个节点的互联 IP;

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

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

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

    1. source /opt/k8s/bin/environment.sh
    2. for node_ip in ${NODE_IPS[@]}
    3. do
    4. echo ">>> ${node_ip}"
    5. ssh ${node_ip} "ping -c 1 172.30.80.0"
    6. ssh ${node_ip} "ping -c 1 172.30.32.0"