calico 一、介绍与安装

大番茄 2020年03月09日 2,234次浏览

Calico v3.11.2
Kubernetes v1.16.7

官方文档:
https://docs.projectcalico.org/introduction/
https://github.com/projectcalico/calico
https://docs.projectcalico.org/v3.11/introduction/

各版本:
https://docs.projectcalico.org/releases

日期:20200310
我看的时候v3.13还不能在生产使用,发行说明里面明确说明了还没有准备好生产使用,v3.12也是只有v3.12.0版本.
https://docs.projectcalico.org/v3.13/release-notes/
https://docs.projectcalico.org/v3.12/release-notes/

所以这里来安装v3.11.2版本。生产环境版本应该会更低。


一、calico介绍

calico支持kubernetes的网络策略kind: NetworkPolicy。flannel不支持,而且,flannel一般是用在集群节点数少的情况下,比如十几个节点。

Calico支持广泛的平台,包括Kubernetes,OpenShift,Docker EE,OpenStack和裸机服务。

Calico有丰富的网络策略,可以在主机网络层和服务层(如果使用Istio&Envoy)上实施相同的策略。

Calico在每一个节点使用linux内核实现一个高效的虚拟路由器(vRouter)来负责数据转发,而每个 vRouter 通过 BGP 协议负责把自己上运行的路由信息向整个 Calico 网络内传播。

可以与路由器建立BGP对等关系,实现跨子网通信,而非封装的方式。

每个节点都当做是一个自治系统。通过BGP连接起来。,

calico有两种网络互连模式, 一种就是BGP, 一种是封装。
BGP模式跟flannel的host-gw差不多,都是更新节点路由信息的方式,只是flannel是由进程自己获取节点信息来维护路由信息,而calico是由BGP协议传播节点路由信息。

封装也有两种方式,一种是默认的IPIP, 一种是VXLAN。

经常问到的问题:
https://docs.projectcalico.org/v3.11/reference/faq#are-the-calico-manifests-compatible-with-coreos

二、安装准备

网络中需要能够运行BGP协议。纯VXLAN模式不需要BGP,可以用于在不支持BGP的公有云环境中运行calico。

1、系统要求

https://docs.projectcalico.org/v3.11/getting-started/kubernetes/requirements

  • Linux kernel >= 3.10
  • 以下linux发行版有所需内核和一些依赖项:
    • RedHat Linux 7
    • CentOS 7
    • CoreOS Container Linux stable
    • Ubuntu 16.04
    • Debian 8
  • 关闭 NetworkManager, NetworkManager会操作路由表,可能会干扰calico正确处理路由的功能。
  • 关闭防火墙与selinux。

2、存储方面

calico可以使用etcd或k8s集群存储数据,如果使用etcd,需要calico所有组件都可以访问etcd v3集群。

3、特权

calico需要运行在特权容器。
用两种方式:

  • apiserver运行参数添加--allow-privileged
    pod添加containers.securityContext.privileged: true参数。calico的yaml文件里已经添加了。
  • 添加pod安全策略kind: PodSecurityPolicy

kubernetes要求

k8s版本

官方对以下版本测试了calico v3.11

  • 1.14
  • 1.15
  • 1.16

cni插件

Calico 作为cni插件安装,kubelet必须通过传递参数--network-plugin=cni来使用cni网络。

k8s集群中必须只有calico网络方案

目前calico不支持将其他网络方案迁移到Calico网络
不过好像可以从flannel迁移到calico。

支持的kube-proxy模式

Calico支持以下kube-proxy模式:

  • iptables (默认)
  • ipvs需要Kubernetes> = v1.9.3。有关更多详细信息,请参阅 在

IP池配置

为Pod IP地址选择的IP范围不能与网络中的任何其他IP范围重叠,包括:

  • Kubernetes Service 地址范围
  • 分配主机IP的范围

应用层策略要求

kube-apiserver需要启用MutatingAdmissionWebhook准入控制器。k8s 1.9版本以上都默认启用。

Istio v1.0,v1.1,v1.2或v1.3
请注意,Kubernetes 1.16+版需要Istio 1.2版或更高版本。

内核模块

如果是上面的linux发行版,已经支持了。

  • nf_conntrack_netlink 子系统
  • ip_tables (对于IPv4)
  • ip6_tables (对于IPv6)
  • ip_set
  • xt_set
  • ipt_set
  • ipt_rpfilter
  • ipt_REJECT
  • ipip (如果使用Calico联网)

三、安装

https://docs.projectcalico.org/v3.11/getting-started/kubernetes/installation/calico

组件介绍

https://docs.projectcalico.org/v3.11/reference/architecture/

FelixConfd

Felix在所有calico节点上运行, 是主要的组件。
负责本节点接口路由,确保各pod之间或是pod与主机之间可以通信。
还有acl规则,以及其他任何可以帮助网络连接的,比如iptables规则,arp代理。

Confd在所有节点,负责使用存储中存在的配置为Felix和Bird生成配置文件。
这两个组件都由calico-node这个程序提供,而且是在同一个容器里启动的。

calico-node -felix
calico-node -confd
BirdBird6

在所有calico节点运行,是BGP客户端,负责BGP的操作,在主机之间分配IPv4和IPv6路由。
具体是这个样子:
将felix生成的路由通过BGP协议发送到网络中,并且接受其他节点通过BGP发送过来的路由,以生成全局的路由信息。还可以作为BGP路由反射器。

Typha

Typha是一个可选的组件,位于数据存储与Felix之间,通过减少每个节点对数据存储的影响来增加规模。Felix与Confd连接Typha,Typha再连接存储。
当超过50个Calico节点时,使用Typha来避免数据存储中的瓶颈和性能问题。但是etcdv3已经优化过很多客户端的情况,所以在使用etcdv3的情况下不建议使用Typha
https://docs.projectcalico.org/v3.11/reference/typha/

kube-controllers

https://docs.projectcalico.org/v3.11/reference/kube-controllers/configuration

属于Orchestrator插件的范畴,每个主要的云编排平台都有独立的Orchestrator插件,kubernetes就是kube-controllers。通过监听kubernetes api来执行一些操作。

准备calico的yaml文件

官方提供了3个安装用的yaml文件。
分别是使用k8s存储少于或等于50个节点:
https://docs.projectcalico.org/v3.11/manifests/calico.yaml
使用k8s存储大于50个节点:
https://docs.projectcalico.org/v3.11/manifests/calico-typha.yaml
使用etcd存储:
https://docs.projectcalico.org/v3.11/manifests/calico-etcd.yaml

这里不搞这么复杂,使用etcd存储,etcdv3环境下不需要使用Typha。


下载calico-etcd.yaml文件以后,有3个地方需要修改一下:

修改calico-etcd.yaml里的配置

1、连接etcd需要的证书。

image.png

把连接etcd的证书,放到secret对应的位置,因为secret里面都是base64编码的,所以使用提示的cat <file> | base64 -w 0生成,然后放到对应位置就可以了。比如我这里:

[root@k8s-master ~]# cat calico-etcd/cacert.pem | base64 -w 0
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZ5ekNDQTdPZ0F3SUJBZ0lKQVBCL0x0d3VkRitJTUEwR0NTcUdTSWIzRFFFQkN3VUFNSHd4Q3pBSkJnTlYKQkFZVEFrTk9NUXN3Q1FZRFZRUUlEQUpDU2pFTE1Ba0dBMVVFQnd3Q1Frb3hFakFRQmdOVkJBb01DV0YwWlhOMApMbkIxWWpFTE1Ba0dBMVVFQ3d3Q2IzQXhGVEFUQmdOVkJBTU1ER05oTG1GMFpYTjBMbkIxWWpFYk1Ca0dDU3FHClNJYjNEUUVKQVJZTWIzQkFZWFJsYzNRdWNIVmlNQjRYRFRJd01ETXdOekF3TURZMU1Gb1hEVE13TURNd05UQXcKTURZMU1Gb3dmREVMTUFrR0ExVUVCaE1DUTA0eEN6QUpCZ05WQkFnTUFrSktNUXN3Q1FZRFZRUUhEQUpDU2pFUwpNQkFHQTFVRUNnd0pZWFJsYzNRdWNIVmlNUXN3Q1FZRFZRUUxEQUp2Y0RFVk1CTUdBMVVFQXd3TVkyRXVZWFJsCmMzUXVjSFZpTVJzd0dRWUpLb1pJaHZjTkFRa0JGZ3h2Y0VCaGRHVnpkQzV3ZFdJd2dnSWlNQTBHQ1NxR1NJYjMKRFFFQkFRVUFBNElDRHdBd2dnSUtBb0lDQVFEUVlPbWsyQXJhaDVOemJ3ZXBEcW5TRThmYUZoT0Z5K1Y3d2JzVgppMVBOL1BSTkdMU25hZGJldlQyUnZwMnRVMU1mVk1zVU05SEQzVnhydWk4bVNaNzh2NjAvMlZqSGorV2hxWDhlCng4U2ZJaU1SMmRLWEhDL1g1L2QvNE12SlYvTWlHV1VpZkxvdTc2a08vZmdzdTNjVjFwbzR2SzRvMmhyWDMzeHIKTEZZMnJwV2N5TTRmNTdwNlcwbGY3TjM5ZWpPdFNNYnNsMHdBdEJOUlQ2QmJwM2hhbW1BaTAwMHNQVHJBSlBmOQpHRGt5WU9EZ2FnNC8rL1VHTFlaMXRHSHlVRnRYSGdsVzNaWXlzd1MxeDlIcVB0ckNoODNzSjRLRjJ5Qy9QcStyClplcWMzQkhDRkZpNk0zMmcwMFlENzJFVU56elk2Rk1ZSmxiVFg2V0MydThwN1FoMlZmbjFtOXFPb3pyQVFSQWUKNG1MbXI2MlFmRU9IYWNRZTVaTnVSVUdwaEd4N1NsRHE2K1BvMmZjVXFqZEVCajlqY0xJSE1MU09kc3hWWFl1dQpIbmdCdkVDaE9aUGNURW4wRlZTbk9ndzhqdVlvSDh5d0s0WlZYeExlZWlheHcwUStkdnpmVjBvaVF3Z3ZjcDhvCmx1WW1mUksrY1hvT01iRFltRDhwWWNGMHhnL21QWHg2TVR2Y3M5WURwcnkrbWszWEMxTXczZHlQMnk3WnlSVU0KN1ZxZ0VnY00wbzZWMUU0YlhSV0cyYWttR0pHSnhzVWVvVXJBUWZhQ2c5WW9STkV3MWYxdVdHaTRvVmROMC9mQQpzUXBiMGkvODRXSFE1L0hDcFM2cnBhdWlWdlVpZ1gvY2NEa0lMSlNyQVJiTm5ISVl5VHhSRG9oQk1Qc1Y1VkxkCjZLd29Id0lEQVFBQm8xQXdUakFkQmdOVkhRNEVGZ1FVaEtMS0RLODVOVlNtWEJ5S0ttWndOM3Zuc1FZd0h3WUQKVlIwakJCZ3dGb0FVaEtMS0RLODVOVlNtWEJ5S0ttWndOM3Zuc1FZd0RBWURWUjBUQkFVd0F3RUIvekFOQmdrcQpoa2lHOXcwQkFRc0ZBQU9DQWdFQWV1cDhQK0lybjlZY3grRWNEY0NnQnlKT2kvNXZxWk1IUm96THk4VEp0c3BICjBwWFRvc2d4dWl1aTlBbnZweEcwMFYxK3RBVWp6NEtEQ3p5RWF4L3JuSHdUSlc4YmZ3bm9rRkNBMXJ2TW9oYWoKa3hYaUZ1cWlIU2xPcklidDFMcFpGRE9aVnBVb0tJNWtybGRicnIyMjJod3VXSjRGQWZBaWM3SEl3YlRwOEduSgpWaVBVSDBrZ3llak9VU2ZVdGkwUDBVa2o1S0U0L0F1M0RQRGVYWldUekdKTUJMMHRiZ0JKK1V4NHVpblhyUis5CldFN2kvaWFtVGJrTHhSRXNmQkJRMTNFZkliUHBxQ2JJS2VTZUtsUllkR3lHeVFlU0ExNHZtYlhoOVJFS3BhN0MKbWxUQm1TZnFLQU1Gd1RtYVlwclhRUkZ4Sm9Wb1RoZFRUOFdoRC9kV1BkQ1pCdzg0bEg3QkRQN0prY2k3V1J5RApkWXdhVExWZzRhRFBBZTFpdnp4d2x3QmFQdWR5SzhramxLcUdsOHdZQnhVZWRuMjNQM1dEOSs5YUNnTmtrUEVYCmdsUmtWc0NOcUxOcnhHL2w1RDB0eXdDc2pPYWV0RnFjdmRRWGlSNTc4U083cUNFQVVleGZxQjl5VTN0Z0JIUUcKa0lpME92eFRla0UxK1BxUWR0NlQ5R2xjS0RkUjhkc2Z4cnQ3T1hxTnJuMlIwOTUveUgwczRhK20xdzZDWld5RQpHaFlKNUV6d1k3ZXF0S0ZsTWR5eTNGdFllZFZyVCtwOTVlcGRmRnpKVDl1dTNGUGlwVk1Wa3loTmtyUjM1L1luCkY4ZWhZWUVORGE3b0phRXBXNGx3clR5RkdGZy9xZVBzL0JmZU5iaDdWOTlFTzVieS9PdDZucWFkUjZnRTFodz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=

上面是ca证书文件,放到ca.crt位置:
image.png
以此类推。

2、连接etcd的地址。

image.png
填上etcd的地址,以及把注释的那个etcd证书路径放到对应的位置。
完了之后是这个样子:
image.png

3、修改pods地址范围

CALICO_IPV4POOL_CIDR这个位置

            - name: CALICO_IPV4POOL_CIDR
              value: "192.168.0.0/16"

改成你对应的地址范围, 我这里:

            - name: CALICO_IPV4POOL_CIDR
              value: "10.6.0.0/16"

4、修改calico工作模式

calico工作模式有2模式,一种是BGP对等技术CALICO_IPV4POOL_IPIP`

            - name: CALICO_IPV4POOL_IPIP
              value: "Always"

这里的Always表示使用IPIPVXLAN,如果使用VXLAN还需要CALICO_IPV4POOL_VXLANAlways,但是没有测试过。

可以设置为: Always, CrossSubnet, Never
CrossSubnet是IPIP与BGP混合模式。

这里修改CALICO_IPV4POOL_IPIPNeverorOff来使用BGP。


上面的一些要修改的地方以及其他地方的意思:
https://docs.projectcalico.org/v3.11/getting-started/kubernetes/installation/config-options
https://docs.projectcalico.org/v3.11/reference/node/configuration


这样就可以应用了,只是里面的镜像地址是国外的,可能不好下载,如果需要的话可以使用我传到阿里云的地址,这里有介绍:
https://www.yxingxing.net/archives/kubernetes-20200117-inside-image


修改kubelet参数

如果之前使用过flannel或者其他的cni插件,最好把/etc/cni目录删了,里面包含kubelet使用flannel插件的配置。不然的话就会成这样:

[root@k8s-node2 bin]# ls /etc/cni/net.d
10-calico.conflist  10-flannel.conflist  calico-kubeconfig  calico-tls

存放插件的那个目录倒是无所谓。


有三个参数:

--network-plugin   # 调用的网络插件。写cni。
--cni-bin-dir      # cni插件目录
--cni-conf-dir     # cni配置目录

--cni-bin-dir 默认位置是/opt/cni/bin/
--cni-conf-dir 默认位置是 /etc/cni/net.d
这两个参数默认就行, calico安装以后会自动在目录里生成对应的文件。
所以,添加下面这一条就行了,然后重启kubelet。

--network-plugin=cni

重启以后kubelet日志里会报错:

==> kubelet.WARNING <==
E0310 20:35:14.300902   23198 kubelet.go:2187] Container runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized
W0310 20:35:17.502225   23198 cni.go:237] Unable to update cni config: no networks found in /etc/cni/net.d

节点状态会变成NotReady:

[root@k8s-master ~]# kubectl get nodes
NAME        STATUS     ROLES    AGE     VERSION
k8s-node1   NotReady   <none>   2d21h   v1.16.7
k8s-node2   NotReady   <none>   3d7h    v1.16.7
k8s-node3   NotReady   <none>   5h41m   v1.16.7

这个没事, 只是因为kubelet的网络部分报错,下面把calico-etcd.yaml应用一下就好了。

应用yaml文件

[root@k8s-master ~]# kubectl apply -f calico-etcd.yaml
secret/calico-etcd-secrets created
configmap/calico-config created
clusterrole.rbac.authorization.k8s.io/calico-kube-controllers created
clusterrolebinding.rbac.authorization.k8s.io/calico-kube-controllers created
clusterrole.rbac.authorization.k8s.io/calico-node created
clusterrolebinding.rbac.authorization.k8s.io/calico-node created
daemonset.apps/calico-node created
serviceaccount/calico-node created
deployment.apps/calico-kube-controllers created
serviceaccount/calico-kube-controllers created
[root@k8s-master ~]#
[root@k8s-master ~]# kubectl get pods -n kube-system
NAME                                      READY   STATUS              RESTARTS   AGE
calico-kube-controllers-d669f4bdd-7gt25   0/1     ContainerCreating   0          7s
calico-node-65dgj                         0/1     Init:0/2            0          8s
calico-node-gbsqt                         0/1     Init:0/2            0          8s
calico-node-kxplx                         0/1     Init:0/2            0          8s

等待。。。。。

[root@k8s-master ~]# kubectl get pods -n kube-system
NAME                                      READY   STATUS    RESTARTS   AGE
calico-kube-controllers-d669f4bdd-2qjnd   1/1     Running   0          5m25s
calico-node-f4qj4                         1/1     Running   0          5m25s
calico-node-jg6zf                         1/1     Running   0          5m25s
calico-node-jgwjg                         1/1     Running   0          5m25s
[root@k8s-master ~]# kubectl get nodes
NAME        STATUS   ROLES    AGE     VERSION
k8s-node1   Ready    <none>   2d21h   v1.16.7
k8s-node2   Ready    <none>   3d7h    v1.16.7
k8s-node3   Ready    <none>   5h50m   v1.16.7

三、后续

calico把所有节点都当做了路由器,所以网络实现有点特殊。

安装完以后,在节点上会发现多了一个类型是dummydummy0网卡, 但是没有ip。

4: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 12:58:3d:08:0d:21 brd ff:ff:ff:ff:ff:ff

启动pod以后,容器的网卡没有关联到dummy0上面。
容器的网络命名空间与主机是靠veth peer连接的。一般情况下这一端连在网桥上,比如docker0,cni0等, 另一端连接容器网络命名空间。
但是calico有点不一样了,这一端不连接在网桥上,他就是主机上一个独立的网卡。


再查看容器的网络信息,这里使用ip来查看容器的网络信息。
发现容器地址的掩码是32位的,这就表示它自己就是一个网络。所以也不可能会有网关之类的。

[root@k8s-node1 bin]# ip netns exec test1 ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
3: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1440 qdisc noqueue state UP group default
    link/ether da:c3:29:e5:55:72 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.6.36.65/32 scope global eth0
       valid_lft forever preferred_lft forever
[root@k8s-node1 bin]# ip netns exec test1 ip route list
default via 169.254.1.1 dev eth0
169.254.1.1 dev eth0 scope link

默认路由就是直接从网卡设备发出,另一端也就到主机了。


通信方式:
pod中有默认路由,但是因为连接的veth网卡没有地址,所以就伪造了一个网关169.254.1.1,然后通过主机的arp代理响应veth网卡的mac。从而可以让pod中的arp请求成功,从而把数据发送到主机上。然后转发走。
有兴趣可以看看这个:
https://www.yxingxing.net/archives/calico-20200311-repeate#%E5%90%8E%E7%BB%AD


节点路由信息中包含所有pod的路由,而不是单单某个网段的路由。 从而知道直接发给哪个容器的网卡。

[root@k8s-node1 bin]# ip route list
default via 172.100.102.1 dev ens192 proto static metric 100
10.6.36.64 dev cali873cacc82fb scope link
blackhole 10.6.36.64/26 proto bird
10.6.36.65 dev cali89c77a2a7a4 scope link
10.6.107.192/26 via 172.100.102.73 dev ens192 proto bird
10.6.169.128/26 via 172.100.102.72 dev ens192 proto bird
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
172.100.102.0/24 dev ens192 proto kernel scope link src 172.100.102.71 metric 100

如果只是为了实现通信,把pod的网卡挂到没有地址的网桥上也是一样的,路由就可以写一个网段, 但是calico可能是为了实现网络策略,还有arp proxy,所以特意把pod的网卡单独出来管理。


同节点容器之间交换数据,有网桥那种方式是直接通过网桥交换数据。而calico这种都需要通过主机路由来实现。


容器veph peer网卡mtu是1440,是因为yaml文件里的configmap里的veth_mtu配置的1440,默认是IPIP的设置。
BGP环境下,其实也无所谓,毕竟容器出来就是主机的3层路由了。主要还是用于隧道环境,这个大小作用于隧道网卡的MTU,因为多了一层IPIP或VXLAN的封装,不能超过物理传输MTU的大小。
一般环境纯BGP的,可以改成1500, IPIP 1480, VXLAN 1450。configmap改完以后需要重启calico-node节点。这个网址有介绍:
https://docs.projectcalico.org/v3.11/networking/mtu

重启calico-node。

kubectl rollout restart daemonset/calico-node -n kube-system

已经存在的容器网卡mtu不会变。

如何监控

https://docs.projectcalico.org/v3.11/maintenance/monitor-component-metrics

故障排除:

https://docs.projectcalico.org/maintenance/troubleshooting#configure-networkmanager