kubernetes网络详解

1.kube-proxy实现的service原理剖析

kubernetes 的每个服务都有一个固定的虚拟 ip(这个 ip 也被称为 cluster IP),自动并且动态地绑定后面的 pod,所有的网络请求直接访问服务 ip,服务会自动向后端做转发。Service 除了提供稳定的对外访问方式之外,还能起到负载均衡(Load Balance)的功能,自动把请求流量分布到后端所有的服务上,服务可以做到对客户透明地进行水平扩展(scale)。
这里写图片描述

而实现 service 这一功能的关键,就是 kube-proxy。kube-proxy 运行在每个节点上,监听 API Server 中服务对象的变化,通过管理 iptables 来实现网络的转发。

注意:
kube-proxy 要求 NODE 节点操作系统中要具备 /sys/module/br_netfilter 文件,而且还要设置 bridge-nf-call-iptables=1,如果不满足要求,那么 kube-proxy 只是将检查信息记录到日志中,kube-proxy 仍然会正常运行,但是这样通过 Kube-proxy 设置的某些 iptables 规则就不会工作。http://blog.csdn.net/zcc_heu/article/details/78822551

1.1 相关概念

1.1.1 Port相关概念

  • port
    这里的port表示:service暴露在cluster ip上的端口,clusterIP:port 是提供给集群内部客户访问service的入口。

  • nodePort
    nodeIP:nodePort 是提供给集群外部客户访问service的入口。

  • targetPort
    targetPort很好理解,targetPort是pod上的端口,从port和nodePort上到来的数据最终经过kube-proxy流入到后端pod的targetPort上进入容器。

总的来说,port和nodePort都是service的端口,前者暴露给集群内客户访问服务,后者暴露给集群外客户访问服务。从这两个端口到来的数据都需要经过反向代理kube-proxy流入后端pod的targetPod,从而到达pod上的容器内。

1.1.2 ip相关概念

  • Pod IP
    pod的ip,每个Pod启动时,会自动创建一个镜像为gcr.io/google_containers/pause:0.8.0的容器,容器内部与外部的通信经由此容器代理,该容器的IP也可以称为Pod IP。

  • Cluster IP
    Pod IP 地址是实际存在于某个网卡(可以是虚拟设备)上的,但Service Cluster IP就不一样了,没有网络设备为这个地址负责。它是由kube-proxy使用Iptables规则重新定向到其本地端口,再均衡到后端Pod的。当proxy发现一个新的service后,它会在本地节点打开一个任意端口,建相应的iptables规则,重定向服务的IP和port到这个新建的端口,开始接受到达这个服务的连接。

  • 外部IP
    nodeIP,Service对象在Cluster IP range池中分配到的IP只能在内部访问,如果服务作为一个应用程序内部的层次,还是很合适的。如果这个Service作为前端服务,准备为集群外的客户提供业务,我们就需要给这个服务提供公共IP了。指定service的spec.type=NodePort,这个类型的service,系统会给它在集群的各个代理节点上分配一个节点级别的端口,能访问到代理节点的客户端都能访问这个端口,从而访问到服务。

1.2 kube-proxy介绍

kube-proxy 目前主要有两种实现 service 的方案:userspace 和 iptables。Kubernetes 1.8引入lvs作为实验性的kube-proxy

  • userspace 是在用户空间监听一个端口,所有的 service 都转发到这个端口,然后 kube-proxy 在内部应用层对其进行转发。因为是在用户空间进行转发,所以效率也不高。
  • iptables 完全实现 iptables 来实现 service,是目前默认的方式,也是推荐的方式,效率很高(只有内核中 netfilter 一些损耗)。这篇文章通过 iptables 模式运行 kube-proxy,后面的分析也是针对这个模式的,userspace 只是旧版本支持的模式,以后可能会放弃维护和支持。
  • lvs方案可以解决目前iptables存在的一些问题:
    • 解决iptables性能问题(iptables在内核中通过chain的方式来使用net_filter,有很多service的时候iptables就会很大,reload的过程会很长)
    • 解决iptables无法保留源Ip地址头的问题。
    • 可提供多种不同负载均衡算法,如最少连接和加权路由等

1.2.1 kube-proxy启动参数介绍

kube-proxy 的功能相对简单一些,也比较独立,需要的配置并不是很多,比较常用的启动参数包括:

参数                         含义                               默认值
--alsologtostderr           打印日志到标准输出                    false
--bind-address              HTTP 监听地址                       0.0.0.0
--cleanup-iptables          如果设置为 true,会清理 proxy 设置     false
                            的 iptables 选项并退出    
--healthz-bind-address      健康检查 HTTP API 监听端口            127.0.0.1
--healthz-port              健康检查端口                         10249
--iptables-masquerade-bit   使用 iptables 进行 SNAT 的掩码长度    14
--iptables-sync-period      iptables 更新频率                   30s
--kubeconfig                kubeconfig 配置文件地址    
--log-dir                   日志文件目录/路径    
--masquerade-all            如果使用 iptables 模式,对所有流量     false
                            进行 SNAT 处理  
--master                    kubernetes master API Server地址    iptables
--proxy-mode                代理模式,userspace 或者 iptables,
                            目前默认是 iptables,如果系统或者
                            iptables 版本不够新,会 fallback 到
                            userspace 模式    
--proxy-port-range          代理使用的端口范围, 格式为             0-0
                            beginPort-endPort,如果没有指定,
                            会随机选择   
--udp-timeout               UDP 空连接 timeout 时间,只对         250ms
                            userspace 模式有用  
--v                         日志级别                             0

1.2.2 docker启动参数设置

  • set --iptables=false so docker will not manipulate iptables for host-ports (too coarse on older docker versions, may be fixed in newer versions) so that kube-proxy can manage iptables instead of docker.
  • --ip-masq=false
    • if you have setup PodIPs to be routable, then you want this false, otherwise, docker will rewrite the PodIP source-address to a NodeIP.
    • some environments (for example GCE) still need you to masquerade out-bound traffic when it leaves the cloud environment. This is very environment specific.
    • if you are using an overlay network, consult those instructions.

参考:
https://github.com/kubernetes/kubernetes/issues/40182
https://kubernetes.io/docs/getting-started-guides/scratch/#docker

2.CNI介绍

一直以来,kubernetes 并没有专门的网络模块负责网络配置,它需要用户在主机上已经配置好网络。kubernetes 对网络的要求是:容器之间(包括同一台主机上的容器,和不同主机的容器)可以互相通信,容器和集群中所有的节点也能直接通信。

kubernetes 网络的发展方向是希望通过插件的方式来集成不同的网络方案, CNI 就是这一努力的结果。CNI只专注解决容器网络连接和容器销毁时的资源释放,提供一套框架,所以CNI可以支持大量不同的网络模式,并且容易实现。

2.1 网络创建步骤

在Kubernetes创建Pod后CNI提供网络的过程主要分三个步骤:

  • Kubelet runtime创建network namespace
  • Kubelete触发CNI插件,指定网络类型(网络类型决定哪一个CNI plugin将会被使用)
  • CNI插件将创建veth pair, 检查IPAM类型和数据,触发IPAM插件,获取空闲的IP地址并将地址分配给容器的网络接口

2.2 各步骤详解

2.2.1 Kubelet runtime创建network namespace

kubelet先创建pause容器,并为这个pause容器生成一个network namespace,然后把这个network namespace关联到pause容器上。
这里写图片描述

2.2.2 Kubelet触发CNI插件

在触发cni插件的时候会将cni的配置load给cni插件
执行CNI需要传入以下变量:

# 添加或者删除网卡
CNI_COMMAND=ADD/DEL

# 容器的ID
CNI_CONTAINERID=xxxxxxxxxxxxxxxxxxx

#  容器网络空间主机映射路径
CNI_NETNS=/proc/4390/ns/net

# CNI参数,使用分号分开,只要是POD的一些相关信息
CNI_ARGS=IgnoreUnknown=1;K8S_POD_NAMESPACE=default;K8S_POD_NAME=22-my-nginx-2523304718-7stgs;K8S_POD_INFRA_CONTAINER_ID=xxxxxxxxxxxxxxxx

# 容器内网卡的名称
CNI_IFNAME=eth0

# CNI二进制文件路径
CNI_PATH=/opt/cni/bin.

例:
这里写图片描述

2.2.3 Kubelet调用相应CNI插件

  • CNI插件内部创建veth pair
    这里写图片描述
  • 通过IPAM插件获取空闲的ip地址
    这里写图片描述
  • 将ip配置到容器net namespace的网络设备
    这里写图片描述

2.3 代码分析

2.3.1 非k8s场景

calico-cni-plugin中将k8s场景下的使用和非k8s场景下的使用分离开了。

if orchestrator == "k8s" {
    if result, err = k8s.CmdAddK8s(args, conf, nodename, calicoClient, endpoint); err != nil {
        return err
    }
} else {
    // Default CNI behavior - use the CNI network name as the Calico profile.
    profileID := conf.Name
......

在非k8s的场景中,github.com/projectcalico/cni-plugin/calico.go:

// There's no existing endpoint, so we need to do the following:
// 1) Call the configured IPAM plugin to get IP address(es)
// 2) Configure the Calico endpoint
// 3) Create the veth, configuring it on both the host and container namespace.

首先查看calico是中是否已经存在了同名的endpoint,如果不存在则创建。

然后在host上创建veth设备,host端命令默认以”caliXX”,容器端命名指定的ifname.

最后更新endpoint的信息,并提交到calico中。

cni-plugin/k8s/k8s.go:

...
if _, err := calicoClient.WorkloadEndpoints().Apply(endpoint); err != nil {
    // Cleanup IP allocation and return the error.
    utils.ReleaseIPAllocation(logger, conf.IPAM.Type, args.StdinData)
    return nil, err
...

2.3.2 k8s使用场景

如果是在k8s下使用,主要是添加对k8s注解的解读,实现指定IP等功能。

github.com/projectcalico/cni-plugin/k8s/k8s.go:

func CmdAddK8s(args *skel.CmdArgs, conf utils.NetConf, nodename string, calicoClient *calicoclient.Client, endpoint *api.WorkloadEndpoint) (*current.Result, error) {
    var err error
    var result *current.Result

    k8sArgs := utils.K8sArgs{}
    err = types.LoadArgs(args.Args, &k8sArgs)
    ......
    ipAddrsNoIpam := annot["cni.projectcalico.org/ipAddrsNoIpam"]
    ipAddrs := annot["cni.projectcalico.org/ipAddrs"]
    ......

设置endpoint,创建veth的过程与非k8s场景下的使用相同。

3.网络插件flannel介绍

这里写图片描述

4.网络插件calico介绍

它在CNM和CNI两大阵营都扮演着比较重要的角色。既有着不俗的性能表现,提供了很好的隔离性,还有不错的ACL控制能力。

Calico 是一个三层的数据中心网络方案,基于三层路由,不需要二层网桥。而且方便集成 OpenStack 这种 IaaS 云架构,能够提供高效可控的 VM、容器、裸机之间的通信。

通过将整个互联网的可扩展IP网络原则压缩到数据中心级别,Calico在每一个计算节点利用Linux Kernel实现了一个高效的vRouter来负责数据转发,而每个vRouter通过BGP协议负责把自己上运行的workload的路由信息向整个Calico网络内传播——小规模部署可以直接互联,大规模下可通过指定的BGP route reflector来完成。所有的workload之间的数据流量都是通过IP路由的方式完成互联的。

Calico 节点组网可以直接利用数据中心的网络结构(支持 L2 或者 L3),不需要额外的 NAT、端口映射、隧道或者 VXLAN overlay network,扩展性和性能都很好。与其他容器网络方案相比,Calico 还有一大优势:丰富而灵活的network policy。用户可以通过动态定义各个节点上的 ACL 规则,控制进出容器的数据包,来提供Workload的多租户隔离、安全组以及其他可达性限制等功能,实现业务需求。

这里写图片描述

如上图所示,这样保证这个方案的简单可控,而且没有封包解包,节约CPU计算资源的同时,提高了整个网络的性能。

4.1 calico BGP模式

4.1.1 简介

这里写图片描述
这里写图片描述

结合上面这张图,我们来过一遍Calico的核心组件:

  • Felix(Calico Agent):跑在每台需要运行Workload的节点上的守护进程,主要负责配置路由及ACLs等信息来确保Endpoint的连通状态;根据对接的编排框架的不同,felix主要包含以下功能:
    • 网络接口管理:把接口的一些信息告诉内核,让内核正确的处理这个接口的链路,特殊情况下,会去响应ARP请求,允许ip forwarding等。
    • 路由管理:在节点上把endpoints的路由配置到Linux kernel FIB(forwarding information base), 保障包正确的到达节点的endpoint上,我的理解endpoints是节点上的虚拟网卡
    • ACL管理:准入控制列表,设置内核的ACL,保证只有合法的包才可以在链路上发送,保障安全。
    • 状态报告:把节点的网络状态信息写入etcd。
  • The Orchestrator plugin:通过该插件更好地与编排系统(k8s/mesos/openstack等)进行集成。(The purpose of these plugins is to bind Calico more tightly into the orchestrator, allowing users to manage the Calico network just as they’d manage network tools that were built into the orchestrator.)工作包括:
    • API转化:编排系统 kubernetes openstack等有自己的API,编排插件翻译成calico的数据模型存到calico的数据库中。
    • 信息反馈:把网络状态的一些信息反馈给上层的编排调度系统
  • etcd:分布式键值存储,主要负责网络元数据一致性,确保Calico网络状态的准确性;用途有:

    • 数据存储
    • 各组件之间通信
  • BGP Client(BIRD):主要负责把Felix写入Kernel的路由信息分发到当前Calico网络,确保Workload间的通信的有效性;BIRD Bird是一个BGP client,它会主动读取felix在host上设置的路由信息,然后通过BGP协议广播出去。

  • BGP Route Reflector(BIRD):大规模部署时使用,摒弃所有节点互联的 mesh 模式(每个BGP客户端之间都会相互连接,会以 N^2次方增长),reflector负责client之间的连接,防止它们需要两两相连。通过一个或者多个BGP Route Reflector来完成集中式的路由分发;为了冗余,可以部署多个reflectors, 它仅仅包含控制面,endpoint之间的数据不经过它们。

  • birdc是bird的client,可以用来查看bird的状态,例如
    • 查看配置的协议: birdctl -s /var/run/calico/bird.ctl show protocols
    • 查看所有的路由: birdctl -s /var/run/calico/bird.ctl show route
      可以到birdc中查看更多的命令。

架构详情请见官网:https://docs.projectcalico.org/v2.6/reference/architecture/

4.1.2 bgp模式流量分析

1.流量从容器中到达主机的过程
cni-plugin会在指定的network ns中创建veth pair。位于容器中的veth,将被设置ip,在容器中可以看到内部ip地址是启动kube-proxy时指定的--cluster-cidr=192.168.0.0/16中的一个:
这里写图片描述
并将169.254.1.1设置为默认路由,在容器内可以看到:
这里写图片描述
因为169.254.1.1是无效IP,因此,cni-plugin还要在容器内设置一条静态arp:
这里写图片描述
在主机上查看网络接口,可以找到和上述mac地址一致的一个calixxx接口:
这里写图片描述
由以上可见:169.254.1.1的mac地址被设置为了veth设备在host中的一端veth的mac地址,容器中所有的报文就会发送到主机的veth端。

2.流量从主机到达其他pod的过程
查看主机路由表:
这里写图片描述
可以看到到10.233.64.0/18这个pod网段的流量主要走两种iface:calixxxxx和eno16777984(主机网卡),走calixxxx的是访问在同一主机的pod的流量;走eno16777984的是访问其他主机的pod的流量,然后Gateway直接就是所要访问的pod所在主机的ip。

3.docker bridge模式对比
单纯使用docker bridge模式起容器的话可以看到内部ip地址是docker0网桥那个网段的内部地址:
这里写图片描述

同样会创建veth pair。位于容器中的veth,将被设置ip,并设置bridge0网桥172.17.0.1为默认路由,在容器内可以看到:
这里写图片描述
因为172.17.0.1是docker0网桥的有效IP,因此,这里就没有再像calico模式一样设设置一条静态arp了。
在主机上查看网络接口,可以找到对应在主机上的vethxxx接口:
这里写图片描述

4.2 Calico的IP-in-IP模式

Calico的BGP模式在主机间跨子网的情况下要求网关的路由器也支持BGP协议才可以,当数据中心环境不满足这个要求时,可以考虑使用ipip模式。IPIP是一种将各Node的路由之间做一个tunnel,再把两个网络连接起来的模式,启用IPIP模式时,Calico将在各Node上创建一个名为”tunl0”的虚拟网络接口。

4.2.1 ipip模式下连通性验证

在ipip模式创建的ip pool(10.20.0.0/24)里创建子网络,如:

docker network create --driver calico --ipam-driver calico-ipam  --subnet 10.20.0.0/24 net1
docker network create --driver calico --ipam-driver calico-ipam  --subnet 10.20.0.0/24 net2
docker network create --driver calico --ipam-driver calico-ipam  --subnet 10.20.0.0/24 net3

上面创建了net1,net2和net3三个不同的网络。上面的命令在任意一个节点上执行即可。由于所有节点使用的是同一套etcd,在每个节点上都可以通过docker network ls命令查看到生成的网络信息
参考官网上的一个例子,在node1和node2上分别创建几个容器来测试下容器网络的连通性。

#node1
docker run --net net1 --name workload-A -tid busybox
docker run --net net2 --name workload-B -tid busybox
docker run --net net1 --name workload-C -tid busybox
#node2
docker run --net net3 --name workload-D -tid busybox
docker run --net net1 --name workload-E -tid busybox

可以在node1上使用如下命令来试验连通性:

#同一网络内的容器(即使不在同一节点主机上)可以使用容器名来访问
docker exec workload-A ping -c 4 workload-C.net1
docker exec workload-A ping -c 4 workload-E.net1
#不同网络内的容器需要使用容器ip来访问(使用容器名会报:bad address)
docker exec workload-A ping -c 2  `docker inspect --format "{{ .NetworkSettings.Networks.net2.IPAddress }}" workload-B`

同一网络内的容器是能相互通信的;不同网络内的容器相互是不通的。不同节点上属于同一网络的容器也是能相互通信的,这样就实现了容器的跨主机互连。

4.2.2 ipip模式流量分析

1.流量从容器中到达主机的过程
同4.1.2的bgp模式

2.流量从主机到达其他pod的过程
启用IPIP模式时,Calico将在node上创建一个tunl0的虚拟网卡做隧道使用,如以下2图所示:
这里写图片描述
这里写图片描述
查看主机路由表:
这里写图片描述
可以看到到192.168.x.x这个pod网段的流量主要走两种iface:calixxxxx和tunl0,走calixxxx的是访问在同一主机的pod的流量;走tunl0的是访问其他主机的pod的流量,然后Gateway直接就是所要访问的pod所在主机的ip。

5.calico部署

5.1 前提

根据官方文档(https://docs.projectcalico.org/v2.6/getting-started/kubernetes/installation/),calico部署前,已有的k8s集群需做好以下配置:

  • kubelet需要添加如下启动参数
--network-plugin=cni                     //指定网络插件类型
--cni-conf-dir=/etc/cni/net.d            //指定cni配置文件目录
--cni-bin-dir=/opt/cni/bin               //指定cni可执行文件目录

备注:
1.后两个参数在启动calico-node pod的install-cni容器的时候也会指定挂载进容器,需要和这里设置的一样。
2.net.d下有如下内容:

[root@k8smaster01 net.d]# ll
总用量 12
-rw-rw-r--. 1 root root 1490 125 21:47 10-calico.conf
-rw-r--r--. 1 root root  273 125 21:47 calico-kubeconfig
drwxr-xr-x. 2 root root 4096 12月  5 21:47 calico-tls

其中,10-calico.conf是一些calico的基本配置项,内容如下:

{
    "name": "k8s-pod-network",
    "cniVersion": "0.1.0",
    "type": "calico",
    "etcd_endpoints": "https://10.142.21.21:2379",
    "etcd_key_file": "/etc/cni/net.d/calico-tls/etcd-key",
    "etcd_cert_file": "/etc/cni/net.d/calico-tls/etcd-cert",
    "etcd_ca_cert_file": "/etc/cni/net.d/calico-tls/etcd-ca",
    "log_level": "info",
    "mtu": 1500,
    "ipam": {
        "type": "calico-ipam"
    },
    "policy": {
        "type": "k8s",
        "k8s_api_root": "https://10.233.0.1:443",
        "k8s_auth_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJjYWxpY28tbm9kZS10b2tlbi1qNHg0bSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJjYWxpY28tbm9kZSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6ImE4N2ZiZjY1LWQzNTctMTFlNy1hZTVkLTAwNTA1Njk0ZWI2YSIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlLXN5c3RlbTpjYWxpY28tbm9kZSJ9.om9TzY_4uYSx2b0kVooTmlA_xrHlL0vpGd4m6Pxq4s--CwQHQb5yvOy3qtMqpRlQrSliDRSLUi1O5QQXfjWNrbyk206B4F0k9NsZi0s-1ZzNVhwI6hsatXl8NZ0qb4LQ2rulm5uM9ykKwXnGpQyCghtwlcBGqQmY63VrBdZHxD3NeyCJ9HqM8BfhclpfzepN-ADADhNn59m96cSaXPJbogVOoMdntXn9x9kn_VaQn5A-XIBNQDMGrUhz1dWCOFfG3nVlxAbo24UcxurvtX4gWyxlUTrkc195i_cnuTbYlIMfBCgKsnuf9QMryn5EWULC5IMB8hPW9Bm1e8fUIHeMvQ"
    },
    "kubernetes": {
        "kubeconfig": "/etc/cni/net.d/calico-kubeconfig"
    }
}

3.我部署的是calico2.6.2版本,该版本涉及的各组件版本信息请见:https://docs.projectcalico.org/v2.6/releases/#v2.6.2
Calico 依赖 etcd 在不同主机间共享和交换信息,存储 Calico 网络状态。Calico 网络中的每个主机都需要运行 Calico 组件,提供容器 interface 管理、动态路由、动态 ACL、报告状态等功能。

  • kube-proxy必须采用iptables proxy mode(1.2 以后是默认模式):
--proxy-mode=iptables
  • kubec-proxy 组件启动方式不能采用 --masquerade-all 启动,因为会与 Calico policy 冲突

5.2 calicoctl部署

5.2.1 calicoctl安装

到这获取calicoctl并安装:https://github.com/projectcalico/calicoctl/releases/

wget -O /usr/local/bin/calicoctl https://github.com/projectcalico/calicoctl/releases/download/v1.6.1/calicoctl

chmod +x calicoctl

5.2.2 calicoctl配置

calicoctl默认是会读取/etc/calico/calicoctl.cfg的配置文件(也可以通过–config选项来指定要读取的配置文件),配置里指定etcd集群的地址,文件的格式类似如下:
vim /etc/calico/calico.cfg

ETCD_ENDPOINTS="https://10.142.21.21:2379,https://10.142.21.22:2379,https://10.142.21.23:2379"
ETCD_CA_CERT_FILE="/etc/calico/certs/ca_cert.crt"
ETCD_CERT_FILE="/etc/calico/certs/cert.crt"
ETCD_KEY_FILE="/etc/calico/certs/key.pem"
CALICO_IP="10.142.21.21"
CALICO_IP6=""
CALICO_NO_DEFAULT_POOLS="true"
CALICO_LIBNETWORK_ENABLED="true"
CALICO_HOSTNAME="k8smaster01"

5.2.3 常用calicoctl命令

查看ip pool

calicoctl get ipPool

查看节点状态信息

calicoctl node status

创建ipPool

calicoctl apply -f - << EOF
apiVersion: v1
kind: ipPool
metadata:
  cidr: 192.168.0.0/16
spec:
  ipip:
    enabled: true
  nat-outgoing: true
EOF

修改calico网络模式,由BGP改为ipip:

calicoctl apply -f - << EOF
apiVersion: v1
kind: ipPool
metadata:
  cidr: 192.168.0.0/16
spec:
  ipip:
    enabled: true
    mode: always
  nat-outgoing: true
EOF

5.3 calico核心组件部署

主要涉及3个组件:calico/node:v2.6.2、calico/cni:v1.11.0、calico/kube-controllers:v1.0.0,使用kubernetes部署,使用的yaml文件请见:https://github.com/projectcalico/calico/blob/v2.6.2/master/getting-started/kubernetes/installation/hosted/calico.yaml
下面以我的实际文件为例进行讲解:

5.3.1 calico-config(configmap)

kind: ConfigMap
apiVersion: v1
metadata:
  name: calico-config
  namespace: kube-system
data:
  # Configure this with the location of your etcd cluster.
  etcd_endpoints: "https://10.142.21.21:2379"

  # Configure the Calico backend to use.
  calico_backend: "bird"

  # The CNI network configuration to install on each node.
  cni_network_config: |-
    {
        "name": "k8s-pod-network",
        "cniVersion": "0.1.0",
        "type": "calico",
        "etcd_endpoints": "__ETCD_ENDPOINTS__",
        "etcd_key_file": "__ETCD_KEY_FILE__",
        "etcd_cert_file": "__ETCD_CERT_FILE__",
        "etcd_ca_cert_file": "__ETCD_CA_CERT_FILE__",
        "log_level": "info",
        "mtu": 1500,
        "ipam": {
            "type": "calico-ipam"
        },
        "policy": {
            "type": "k8s",
            "k8s_api_root": "https://__KUBERNETES_SERVICE_HOST__:__KUBERNETES_SERVICE_PORT__",
            "k8s_auth_token": "__SERVICEACCOUNT_TOKEN__"
        },
        "kubernetes": {
            "kubeconfig": "__KUBECONFIG_FILEPATH__"
        }
    }

  # If you're using TLS enabled etcd uncomment the following.
  # You must also populate the Secret below with these files.
  etcd_ca: "/calico-secrets/etcd-ca"
  etcd_cert: "/calico-secrets/etcd-cert"
  etcd_key: "/calico-secrets/etcd-key"

说明:
1.这个configmap给calico-node配置env使用
2.calico-config的data.etcd_endpoints(endpoints为etcd的真实环境地址)

5.3.2 calico-etcd-secrets(secret)

# The following contains k8s Secrets for use with a TLS enabled etcd cluster.
# For information on populating Secrets, see http://kubernetes.io/docs/user-guide/secrets/
apiVersion: v1
kind: Secret
type: Opaque
metadata:
  name: calico-etcd-secrets
  namespace: kube-system
data:
  # Populate the following files with etcd TLS configuration if desired, but leave blank if
  # not using TLS for etcd.
  # This self-hosted install expects three files with the following names.  The values
  # should be base64 encoded strings of the entire contents of each file.
  etcd-key: 太长了,省略...
  etcd-cert: 太长了,省略...
  etcd-ca: 太长了,省略...

说明:
1. 这个secret用来给calico-node和kube-controller连接etcd使用
2. calico-etcd-secrets的etcd-key、etcd-cert、etcd-ca,分别使用/etc/ssl/etcd/ssl/目录下的node-k8smaster01-key.pem、node-k8smaster01.pem、ca.pem(根据实际环境的证书数据填写。)的base64编码(生成base64编码:base64 /etc/ssl/etcd/ssl/node-k8smaster01-key.pem)

5.3.3 calico-node(daemonset)

# This manifest installs the calico/node container, as well
# as the Calico CNI plugins and network config on
# each master and worker node in a Kubernetes cluster.
kind: DaemonSet
apiVersion: extensions/v1beta1
metadata:
  name: calico-node
  namespace: kube-system
  labels:
    k8s-app: calico-node
spec:
  selector:
    matchLabels:
      k8s-app: calico-node
  template:
    metadata:
      labels:
        k8s-app: calico-node
      annotations:
        scheduler.alpha.kubernetes.io/critical-pod: ''
        /cheduler.alpha.kubernetes.io/tolerations: |
          [{"key": "dedicated", "value": "master", "effect": "NoSchedule" },
           {"key":"CriticalAddonsOnly", "operator":"Exists"}]
    spec:
      hostNetwork: true
      serviceAccountName: calico-node
      # Minimize downtime during a rolling upgrade or deletion; tell Kubernetes to do a "force
      # deletion": https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods.
      terminationGracePeriodSeconds: 0
      containers:
        # Runs calico/node container on each Kubernetes node.  This
        # container programs network policy and routes on each
        # host.
        - name: calico-node
          image: quay.io/calico/node:v2.6.2
          env:
            # The location of the Calico etcd cluster.
            - name: ETCD_ENDPOINTS
              valueFrom:
                configMapKeyRef:
                  name: calico-config
                  key: etcd_endpoints
            # Choose the backend to use.
            - name: CALICO_NETWORKING_BACKEND
              valueFrom:
                configMapKeyRef:
                  name: calico-config
                  key: calico_backend
            # Cluster type to identify the deployment type
            - name: CLUSTER_TYPE
              value: "k8s,bgp"
            # Disable file logging so `kubectl logs` works.
            - name: CALICO_DISABLE_FILE_LOGGING
              value: "true"
            # Set Felix endpoint to host default action to ACCEPT.
            - name: FELIX_DEFAULTENDPOINTTOHOSTACTION
              value: "ACCEPT"
            # Disable IPv6 on Kubernetes.
            - name: FELIX_IPV6SUPPORT
              value: "false"
            # Set Felix logging to "info"
            - name: FELIX_LOGSEVERITYSCREEN
              value: "info"
            # Set MTU for tunnel device used if ipip is enabled
            - name: FELIX_IPINIPMTU
              value: "1440"
            # Location of the CA certificate for etcd.
            - name: ETCD_CA_CERT_FILE
              valueFrom:
                configMapKeyRef:
                  name: calico-config
                  key: etcd_ca
            # Location of the client key for etcd.
            - name: ETCD_KEY_FILE
              valueFrom:
                configMapKeyRef:
                  name: calico-config
                  key: etcd_key
            # Location of the client certificate for etcd.
            - name: ETCD_CERT_FILE
              valueFrom:
                configMapKeyRef:
                  name: calico-config
                  key: etcd_cert
            # Auto-detect the BGP IP address.
            - name: IP
              value: ""
            - name: FELIX_HEALTHENABLED
              value: "true"
          securityContext:
            privileged: true
          resources:
            requests:
              cpu: 250m
          livenessProbe:
            httpGet:
              path: /liveness
              port: 9099
            periodSeconds: 10
            initialDelaySeconds: 10
            failureThreshold: 6
          readinessProbe:
            httpGet:
              path: /readiness
              port: 9099
            periodSeconds: 10
          volumeMounts:
            - mountPath: /lib/modules
              name: lib-modules
              readOnly: true
            - mountPath: /var/run/calico
              name: var-run-calico
              readOnly: false
            - mountPath: /calico-secrets
              name: etcd-certs
        # This container installs the Calico CNI binaries
        # and CNI network config file on each node.
        - name: install-cni
          image: quay.io/calico/cni:v1.11.0
          command: ["/install-cni.sh"]
          env:
            # The location of the Calico etcd cluster.
            - name: ETCD_ENDPOINTS
              valueFrom:
                configMapKeyRef:
                  name: calico-config
                  key: etcd_endpoints
            # The CNI network config to install on each node.
            - name: CNI_NETWORK_CONFIG
              valueFrom:
                configMapKeyRef:
                  name: calico-config
                  key: cni_network_config
          volumeMounts:
            - mountPath: /host/opt/cni/bin
              name: cni-bin-dir
            - mountPath: /host/etc/cni/net.d
              name: cni-net-dir
            - mountPath: /calico-secrets
              name: etcd-certs
      volumes:
        # Used by calico/node.
        - name: lib-modules
          hostPath:
            path: /lib/modules
        - name: var-run-calico
          hostPath:
            path: /var/run/calico
        # Used to install CNI.
        - name: cni-bin-dir
          hostPath:
            path: /opt/cni/bin
        - name: cni-net-dir
          hostPath:
            path: /etc/cni/net.d
        # Mount in the etcd TLS secrets.
        - name: etcd-certs
          secret:
            secretName: calico-etcd-secrets

备注:
1.calico-node的CALICO_IPV4POOL_CIDR参数(注:需要根据实际环境更改)
2.每个pod里除pause外有两个容器:calico-node和install-cni,其中calico-node这个容器里起了多个进程,有:calico-felix、bird、bird6、confd(confd根据etcd上状态信息,与本地模板,生成并更新BIRD配置)
3.根据环境里的所有节点的taints,为daemon/calico-node添加tolerations参数,使其能在每个节点上都能部署。例如如下参数:

spec:
   tolerations:
- key: "nginx-ingress-controller"
  operator: "Equal"
      value: "true"
    effect: "NoSchedule"
   hostNetwork: true

这是为了taints的节点能够部署calico-node。其中的key和value为标记的taints。

5.3.4 calico-kube-controllers(deployment)

# This manifest deploys the Calico Kubernetes controllers.
# See https://github.com/projectcalico/kube-controllers
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: calico-kube-controllers
  namespace: kube-system
  labels:
    k8s-app: calico-kube-controllers
  annotations:
    scheduler.alpha.kubernetes.io/critical-pod: ''
    scheduler.alpha.kubernetes.io/tolerations: |
      [{"key": "dedicated", "value": "master", "effect": "NoSchedule" },
       {"key":"CriticalAddonsOnly", "operator":"Exists"}]
spec:
  # The controllers can only have a single active instance.
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      name: calico-kube-controllers
      namespace: kube-system
      labels:
        k8s-app: calico-kube-controllers
    spec:
      # The controllers must run in the host network namespace so that
      # it isn't governed by policy that would prevent it from working.
      hostNetwork: true
      serviceAccountName: calico-kube-controllers
      containers:
        - name: calico-kube-controllers
          image: quay.io/calico/kube-controllers:v1.0.0
          env:
            # The location of the Calico etcd cluster.
            - name: ETCD_ENDPOINTS
              valueFrom:
                configMapKeyRef:
                  name: calico-config
                  key: etcd_endpoints
            # Location of the CA certificate for etcd.
            - name: ETCD_CA_CERT_FILE
              valueFrom:
                configMapKeyRef:
                  name: calico-config
                  key: etcd_ca
            # Location of the client key for etcd.
            - name: ETCD_KEY_FILE
              valueFrom:
                configMapKeyRef:
                  name: calico-config
                  key: etcd_key
            # Location of the client certificate for etcd.
            - name: ETCD_CERT_FILE
              valueFrom:
                configMapKeyRef:
                  name: calico-config
                  key: etcd_cert
          volumeMounts:
            # Mount in the etcd TLS secrets.
            - mountPath: /calico-secrets
              name: etcd-certs
      volumes:
        # Mount in the etcd TLS secrets.
        - name: etcd-certs
          secret:
            secretName: calico-etcd-secrets

5.3.5 calico-policy-controller(deployment)

# This deployment turns off the old "policy-controller". It should remain at 0 replicas, and then
# be removed entirely once the new kube-controllers deployment has been deployed above.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: calico-policy-controller
  namespace: kube-system
  labels:
    k8s-app: calico-policy
spec:
  # Turn this deployment off in favor of the kube-controllers deployment above.
  replicas: 0
  strategy:
    type: Recreate
  template:
    metadata:
      name: calico-policy-controller
      namespace: kube-system
      labels:
        k8s-app: calico-policy
    spec:
      hostNetwork: true
      serviceAccountName: calico-kube-controllers
      containers:
        - name: calico-policy-controller
          image: quay.io/calico/kube-controllers:v1.0.0
          env:
            # The location of the Calico etcd cluster.
            - name: ETCD_ENDPOINTS
              valueFrom:
                configMapKeyRef:
                  name: calico-config
                  key: etcd_endpoints

5.3.6 calico-kube-controllers(serviceaccount)

apiVersion: v1
kind: ServiceAccount
metadata:
  name: calico-kube-controllers
  namespace: kube-system

5.3.7 calico-node(serviceaccount)

apiVersion: v1
kind: ServiceAccount
metadata:
  name: calico-node
  namespace: kube-system

整体流量具体怎么走的,请参考(有时间再整理):
http://blog.csdn.net/liukuan73/article/details/78635711
http://blog.csdn.net/liukuan73/article/details/78837424
http://cizixs.com/2017/03/30/kubernetes-introduction-service-and-kube-proxy?utm_source=tuicool&utm_medium=referral
http://www.lijiaocn.com/%E9%A1%B9%E7%9B%AE/2017/03/27/Kubernetes-kube-proxy.html

路由广播

calico-node容器剖析
Felix TODO
BIRD TODO
confd 通过监听etcd修改BGP配置 AS number, logging levels, IPAM信息等
数据流
主要靠三个东西: 让内核响应ARP请求 用route让endpoint(workload)互通 用iptables进行安全隔离

calico/kube-controllers 容器
此容器里包含以下控制器:

policy controller: 监控网络策略 配置calico策略
profile controller: 监控namespaces和配置calico profiles
workloadendpoint controller: 监控pod标签的变化和更新calico workload endpoints
node controller: 监听k8s移除节点,和移除calico相关联的数据
配置calico CNI插件
calico CNI最小化配置:

{
“name”: “any_name”,
“cniVersion”: “0.1.0”,
“type”: “calico”,
“ipam”: {
“type”: “calico-ipam”
}
}
如果calico-node容器自定义了一个NODENAME而不是 node的hostname CNI插件必须配置相同的node name

{
“name”: “any_name”,
“nodename”: “”,
“type”: “calico”,
“ipam”: {
“type”: “calico-ipam”
}
}
其它相关配置: datastore type, Etcd location

logging:

{
“name”: “any_name”,
“cniVersion”: “0.1.0”,
“type”: “calico”,
“log_level”: “DEBUG”,
“ipam”: {
“type”: “calico-ipam”
}
}
IPAM

使用calico IPAM分配ip地址池

{
“name”: “any_name”,
“cniVersion”: “0.1.0”,
“type”: “calico”,
“ipam”: {
“type”: “calico-ipam”,
“assign_ipv4”: “true”,
“assign_ipv6”: “true”,
“ipv4_pools”: [“10.0.0.0/24”, “20.0.0.0/16”],
“ipv6_pools”: [“2001:db8::1/120”]
}
}
kubernetes 配置

calico需要访问kubernets api server,找到pod的标签,所以需要配置apiserver相关信息

{
“name”: “any_name”,
“cniVersion”: “0.1.0”,
“type”: “calico”,
“kubernetes”: {
“kubeconfig”: “/path/to/kubeconfig”
},
“ipam”: {
“type”: “calico-ipam”
}
}
允许kubernetes networkpolicy

设置了这个就必须运行calico/kube-controllers 把 policy,profile,workloadendpoint都设置成允许

{
“name”: “any_name”,
“cniVersion”: “0.1.0”,
“type”: “calico”,
“policy”: {
“type”: “k8s”
},
“kubernetes”: {
“kubeconfig”: “/path/to/kubeconfig”
},
“ipam”: {
“type”: “calico-ipam”
}
}

参考

1.http://lameleg.com/tech/calico-architecture.html
2.http://www.lijiaocn.com/%E9%A1%B9%E7%9B%AE/2017/08/04/calico-arch.html
3.http://blog.csdn.net/felix_yujing/article/details/55213239
4.https://mritd.me/2017/07/31/calico-yml-bug/
5.http://v.youku.com/v_show/id_XMzE2MzM5MzMwNA==.html

猜你喜欢

转载自blog.csdn.net/liukuan73/article/details/78883847