跳至主要內容

部署CNI网络

Zenghr大约 11 分钟kubernetes

部署CNI网络

1.简介

kubernetes 要求集群内各节点(包括 master 节点)能通过 Pod 网段互联互通

通过给 Kubelet 传递 --network-plugin=cni 命令行选项来选择 CNI 插件。 Kubelet 从 --cni-conf-dir (默认是 /etc/cni/net.d) 读取文件并使用该文件中的 CNI 配置来设置每个 pod 的网络。 CNI 配置文件必须与 CNI 规约open in new window匹配,并且配置引用的任何所需的 CNI 插件都必须存在于 --cni-bin-dir(默认是 /opt/cni/bin

2. 下载 CNI

准备二进制文件

下载地址:https://github.com/containernetworking/plugins/releasesopen in new window

解压二进制包并移动到默认工作目录:

mkdir -p /opt/cni/bin
tar zxvf cni-plugins-linux-amd64-v0.8.6.tgz -C /opt/cni/bin

3. flannel 插件

3.1 Flannel介绍

以下内容转载自:https://www.cnblogs.com/itzgr/p/12558767.html#_label0open in new window

Kubernetes的网络模型假定了所有Pod都在一个可以直接连通的扁平网络空间中。若需要实现这个网络假设,需要实现不同节点上的Docker容器之间的互相访问,然后运行Kubernetes。目前已经有多个开源组件支持容器网络模型。如Flannel、Open vSwitch、直接路由和Calico。

Flannel之所以可以搭建Kubernetes依赖的底层网络,是因为它能实现以下两点。

  1. 它能协助Kubernetes,给每一个Node上的Docker容器都分配互相不冲突的IP地址。
  2. 它能在这些IP地址之间建立一个覆盖网络(Overlay Network),通过这个覆盖网络,将数据包原封不动地传递到目标容器内。

Flannel 架构图:

Flannel架构图

如上图所示,Flannel首先创建了一个名为 flannel0 的网桥,而且这个网桥的一端连接 docker0 网桥,另一端连接一个叫作flanneld的服务进程。

flanneld进程上连etcd,利用etcd来管理可分配的IP地址段资源,同时监控etcd中每个Pod的实际地址,并在内存中建立了一个Pod节点路由表;

​ flanneld进程下连docker0和物理网络,使用内存中的Pod节点路由表,将docker0发给它的数据包包装起来,利用物理网络的连接将数据包投递到目标flanneld上,从而完成Pod到Pod之间的直接地址通信。

​ Flannel之间的底层通信协议的可选技术包括UDP、VxLan、AWS VPC等多种方式。通过源flanneld封包、目标flanneld解包,最终docker0收到的就是原始的数据,对容器应用来说是透明的,感觉不到中间Flannel的存在。

​ Flannel每次分配的地址段都在同一个公共区域获取,从而实现不同Node上的Pod分配的IP不产生冲突。而且在Flannel分配好地址段后,其余操作由Docker完成的,Flannel通过修改Docker的启动参数将分配给它的地址段传递进去:

--bip=172.17.18.1/24

通过如上方式,Flannel就控制了每个Node上的docker0地址段的地址,从而保障了所有Pod的IP地址在同一个水平网络中且不产生冲突。

​ Flannel完美地实现了对Kubernetes网络的支持,但是它引入了多个网络组件,在网络通信时需要转到flannel0网络接口,再转到用户态的flanneld程序,到对端后还需要走这个过程的反过程,所以也会引入一些网络的时延损耗。

另外,Flannel模型默认采用了UDP作为底层传输协议,UDP本身是非可靠协议,虽然两端的TCP实现了可靠传输,但在大流量、高并发的应用场景下还建议多次测试。

3.2 部署flannel

# github 上的文件,可能会下载失败,可以本地下载上传至虚拟机
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
# 替换 docker 源
sed -i -r "s#quay.io/coreos/flannel:.*-amd64#registry.cn-shanghai.aliyuncs.com/gcr-k8s/flannel:v0.12.0-amd64#g" kube-flannel.yml
# 修改ip配置要与 kube-controller 配置中的 cluster-cidr=172.20.0.0/16 一样
net-conf.json: |
{
	"Network": "172.20.0.0/16",
	"Backend": {
		"Type": "vxlan"
	}
}

# 启动
kubectl apply -f kube-flannel.yml
# 查看
kubectl get pods --namespace kube-system
kubectl get svc --namespace kube-system

提示

注:如果Node有多个网卡的话,参考 flannel issues39701open in new window, 目前需要在kube-flannel.yml中使用--iface参数指定集群主机内网网卡的名称, 否则可能会出现dns无法解析。容器无法通信的情况,需要将kube-flannel.yml下载到本地, flanneld启动参数加上--iface=iface-name

4. Calico 插件

4.1 Calco组件简介

​ Calico是一个基于BGP的纯三层的网络方案,与OpenStack、Kubernetes、AWS、GCE等云平台都能够良好地集成。Calico在每个计算节点都利用Linux Kernel实现了一个高效的vRouter来负责数据转发。每个vRouter都通过BGP1协议把在本节点上运行的容器的路由信息向整个Calico网络广播,并自动设置到达其他节点的路由转发规则。

​ Calico保证所有容器之间的数据流量都是通过IP路由的方式完成互联互通的。Calico节点组网时可以直接利用数据中心的网络结构(L2或者L3),不需要额外的NAT、隧道或者Overlay Network,没有额外的封包解包,能够节约CPU运算,提高网络效率。

qUxtPP
qUxtPP

4.2 Calico 架构

0IZcpm
0IZcpm

Calico的主要组件:

  • Felix:Calico Agent,运行在每个Node上,负责为容器设置网络资源(IP地址、路由规则、iptables规则等),保证跨主机容器网络互通。
  • etcd:Calico使用的后端存储。
  • BGP Client:负责把Felix在各Node上设置的路由信息通过BGP协议广播到Calico网络。
  • Route Reflector:通过一个或者多个BGP Route Reflector来完成大规模集群的分级路由分发。
  • CalicoCtl:Calico命令行管理工具。

4.3 Calico 部署步骤过程

在Kubernetes中部署Calico的主要步骤如下:

  1. 修改Kubernetes服务的启动参数,并重启服务。
    1. 设置Master上kube-apiserver服务的启动参数:--allow-privileged=true(因为calico-node需要以特权模式运行在各Node上)。
    2. 设置各Node上kubelet服务的启动参数:--networkplugin=cni(使用CNI网络插件)。
  1. 创建Calico服务,主要包括calico-node和calico policy controller。需要创建的资源对象如下:
    1. 创建ConfigMap calico-config,包含Calico所需的配置参数。
    2. 创建Secret calico-etcd-secrets,用于使用TLS方式连接etcd。
    3. 在每个Node上都运行calico/node容器,部署为DaemonSet。
    4. 在每个Node上都安装Calico CNI二进制文件和网络配置参数(由install-cni容器完成)。
    5. 部署一个名为calico/kube-policy-controller的Deployment,以对接Kubernetes集群中为Pod设置的Network Policy。

4.4 部署 calico

# 下载 yaml 文件
wget https://docs.projectcalico.org/v3.14/getting-started/kubernetes/installation/hosted/calico.yaml
# 修改 - name: CALICO_IPV4POOL_CIDR value: 172.20.0.0/16
sed -i -e "s?192.168.0.0/16?172.20.0.0/16?g" canal.yaml

4.4.1 需要修改如下几处配置:

ConfigMap 配置修改

kind: ConfigMap
apiVersion: v1
metadata:
  name: calico-config
  namespace: kube-system
data:
  etcd_endpoints: "http://192.168.10.102:2379"
  etcd_ca: "/calico-secrets/etcd-ca"   # "/calico-secrets/etcd-ca"
  etcd_cert: "calico-secrets/etcd-cert" # "/calico-secrets/etcd-cert"
  etcd_key: "/calico-secrets/etcd-key"  # "/calico-secrets/etcd-key"
  typha_service_name: "none"
  calico_backend: "bird"

对主要参数说明如下:

  • etcd_endpoints:Calico使用etcd来保存网络拓扑和状态,该参数指定etcd服务的地址,可手动设置。
  • calico_backend:Calico的后端,默认为bird。
  • cni_network_config:符合CNI规范的网络配置。其中 type=calico 表示kubelet将从 /opt/cni/bin 目录下搜索名为calico的可执行文件,并调用它来完成容器网络的设置。ipam中的 type=calico-ipam 表示kubelet将在 /opt/cni/bin 目录下搜索名为calico-ipam的可执行文件,用于完成容器IP地址的分配。

修改 Pods 使用的 IP 网段 , 配置文件默认使用 192.168.0.0/16 网段

Secret 配置修改

apiVersion: v1
kind: Secret
type: Opaque
metadata:
  name: calico-etcd-secrets
  namespace: kube-system
data:
  # Example command for encoding a file contents: cat <file> | base64 -w 0
  # 如果配置了TLS ,则需要设置相应的证书和密钥文件路径
  etcd-key: (cat /etc/kubernetes/ca/server/server-key.pem | base64 -w 0) # 将输出结果填写在这
  etcd-cert: (cat /etc/kubernetes/ca/server/server.pem | base64 -w 0) # 将输出结果填写在这
  etcd-ca: (cat /etc/kubernetes/ca/ca.pem | base64 -w 0) # 将输出结果填写在这

DaemonSet 配置修改
添加网卡发现规则

containers:
  - name: calico-node
    image: calico/node:v3.14.2
    env:
      # .../
      # Auto-detect the BGP IP address.
      - name: IP
        value: "autodetect"
      # Calico 模式设置
      - name: CALICO_IPV4POOL_IPIP
        value: "Always"
      # 定义ipv4自动发现网卡规则 
      - name: IP_AUTODETECTION_METHOD
        value: "interface=enp.*"
      # no effect. This should fall within `--cluster-cidr`.
      # 需要修改此处,打开注释替换 pod ip
      - name: CALICO_IPV4POOL_CIDR
        value: "172.20.0.0/16"

在该Pod中包括如下两个容器:

  • install-cni:在Node上安装CNI二进制文件到 /opt/cni/bin 目录下,并安装相应的网络配置文件到 /etc/cni/net.d 目录下,设置为initContainers并在运行完成后退出。
  • calico-node:Calico服务程序,用于设置Pod的网络资源,保证Pod的网络与各Node互联互通。它还需要以hostNetwork模式运行,直接使用宿主机网络。

calico-node服务的主要参数如下。

  • CALICO_IPV4POOL_CIDR:Calico IPAM的IP地址池,Pod的IP地址将从该池中进行分配。
  • CALICO_IPV4POOL_IPIP:是否启用IPIP模式。启用IPIP模式时,Calico将在Node上创建一个名为tunl0的虚拟隧道。
  • IP_AUTODETECTION_METHOD:获取Node IP地址的方式,默认使用第1个网络接口的IP地址,对于安装了多块网卡的Node,可以使用正则表达式选择正确的网卡,例如"interface=eth.*"表示选择名称以eth开头的网卡的IP地址。
  • FELIX_IPV6SUPPORT:是否启用IPv6。
  • FELIX_LOGSEVERITYSCREEN:日志级别。
  • securityContext.privileged=true:以特权模式运行。

另外,如果启用RBAC权限控制,则可以设置ServiceAccount。

IP Pool可以使用两种模式:BGP或IPIP。使用IPIP模式时,设置 CALICO_IPV4POOL_IPIP="always" ,不使用IPIP模式时,设置CALICO_IPV4POOL_IPIP="off" ,此时将使用BGP模式。

calico-kube-controllers解析配置

calico-kube-controllers容器,用于对接Kubernetes集群中为Pod设置的Network Policy

如果启用RBAC权限控制,则可以设置ServiceAccount。用户在Kubernetes集群中设置了Pod的Network Policy之后,calicokube-controllers就会自动通知各Node上的calico-node服务,在宿主机上设置相应的iptables规则,完成Pod间网络访问策略的设置。

4.4.2 修改完 yaml 文件,执行部署

# 部署
kubectl apply -f calico.yaml
# 查看 calico pods
kubectl  get pods -n kube-system
# 查看 node 是否正常,现在 node 服务正常了
kubectl get node

NAME       			 STATUS   ROLES    AGE    VERSION
192.168.10.101   Ready    <none>   4d4h   v1.18.6
192.168.10.102   Ready    <none>   4d4h   v1.18.6

5. 通过系统服务+Docker方式部署

5.1 配置 service 文件

vim /lib/systemd/system/kube-calico.service

注意修改 IP 以及证书位置

[Unit]
Description=calico node
After=docker.service
Requires=docker.service
[Service]
User=root
PermissionsStartOnly=true
ExecStart=/usr/bin/docker run --net=host --privileged --name=calico-node \
  -e ETCD_ENDPOINTS=https://192.168.10.102:2379 \
  -e ETCD_CA_CERT_FILE=/etc/kubernetes/ca/ca.pem \
  -e ETCD_CERT_FILE=/etc/kubernetes/ca/calico/calico.pem \
  -e ETCD_KEY_FILE=/etc/kubernetes/ca/calico/calico-key.pem \
  -e CALICO_LIBNETWORK_ENABLED=true \
  -e CALICO_NETWORKING_BACKEND=bird \
  -e CALICO_DISABLE_FILE_LOGGING=true \
  -e CALICO_IPV4POOL_CIDR=172.20.0.0/16 \
  -e CALICO_IPV4POOL_IPIP=off \
  -e FELIX_DEFAULTENDPOINTTOHOSTACTION=ACCEPT \
  -e FELIX_IPV6SUPPORT=false \
  -e FELIX_LOGSEVERITYSCREEN=info \
  -e FELIX_IPINIPMTU=1440 \
  -e FELIX_HEALTHENABLED=true \
  -e IP=192.168.10.101 \
  -v /etc/kubernetes/ca:/etc/kubernetes/ca \
  -v /var/run/calico:/var/run/calico \
  -v /lib/modules:/lib/modules \
  -v /run/docker/plugins:/run/docker/plugins \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /var/log/calico:/var/log/calico \
  calico/node:v3.14.2
ExecStop=/usr/bin/docker rm -f calico-node
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target

5.2 启动 kube-calico 服务

systemctl daemon-reload # 修改配置重启的时候用
systemctl enable kube-calico.service
service kube-calico start
# 查看日志
journalctl -f -u kube-calico

5.3 calico 客户端工具 calicoctl

下载 calicoctl 二进制文件, 下载地址:https://github.com/projectcalico/calicoctl/releasesopen in new window

chmod 755 calicoctl
mv calicoctl /usr/local/bin/

5.4 查看节点运行情况

calicoctl node status
Calico process is running.
IPv4 BGP status
+---------------+-------------------+-------+----------+-------------+
| PEER ADDRESS  |     PEER TYPE     | STATE |  SINCE   |    INFO     |
+---------------+-------------------+-------+----------+-------------+
| 192.168.10.101 | node-to-node mesh | up    | 13:13:13 | Established |
+---------------+-------------------+-------+----------+-------------+
IPv6 BGP status
No IPv6 peers found.

查看端口BGP 协议是通过TCP 连接来建立邻居的,因此可以用netstat 命令验证 BGP Peer

netstat -natp|grep ESTABLISHED|grep 179
tcp        0      0 192.168.10.102:60959     192.168.10.103:179       ESTABLISHED 29680/bird

5.5 配置 IP Pool

默认情况下,calicoctl将在上查找配置文件/etc/calico/calicoctl.cfg。您可以将该--config选项与需要数据存储访问的命令一起使用,以覆盖此选项。该文件可以是YAML或JSON格式。它必须有效并且可由读取calicoctl。以下是一个YAML示例:

vim /etc/calico/calicoctl.cfg

apiVersion: projectcalico.org/v3
kind: CalicoAPIConfig
metadata:
spec:
  etcdEndpoints: https://192.168.10.102:2379
  etcdKeyFile: /etc/kubernetes/ca/calico/calico-key.pem
  etcdCertFile: /etc/kubernetes/ca/calico/calico.pem
  etcdCACertFile: /etc/kubernetes/ca/ca.pem

查看集群ippool情况

calicoctl get ipPool -o yaml

# 输出内容如下
- apiVersion: projectcalico.org/v3
  kind: IPPool
  metadata:
    creationTimestamp: "2020-08-14T10:38:44Z"
    name: default-ipv4-ippool
    resourceVersion: "13109"
    uid: 3e3b1506-e9a8-4d02-96f7-2ceb63ade2ea
  spec:
    blockSize: 26
    cidr: 172.20.0.0/16
    ipipMode: Never
    natOutgoing: true
    nodeSelector: all()
    vxlanMode: Never
kind: IPPoolList
metadata:
  resourceVersion: "57796"

6. 授权Apiserver访问kubelet

cat > /etc/kubernetes/server/cfg/apiserver-to-kubelet-rbac.yaml << EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    rbac.authorization.kubernetes.io/autoupdate: "true"
  labels:
    kubernetes.io/bootstrapping: rbac-defaults
  name: system:kube-apiserver-to-kubelet
rules:
  - apiGroups:
      - ""
    resources:
      - nodes/proxy
      - nodes/stats
      - nodes/log
      - nodes/spec
      - nodes/metrics
      - pods/log
    verbs:
      - "*"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: system:kube-apiserver
  namespace: ""
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: system:kube-apiserver-to-kubelet
subjects:
  - apiGroup: rbac.authorization.k8s.io
    kind: User
    name: kubernetes
EOF

#  启动
kubectl apply -f apiserver-to-kubelet-rbac.yaml