Kubernetes组件和网络架构介绍
Kubernetes组件
Kubernetes Master:kube-apiserver、kube-controller-manager、kube-scheduler
Kubernetes Node:kube-proxy、kubelet
kube-apiserver: API-server 负载输出RESTful风格的Kubernetes API, 它是集群的所有REST操作命令的
接入点,并负责接收、校验并响应所有REST请求,结果状态被持久存储于etcd中。
因此API server 是整个集群网关
kube-scheduler: 负责调度
kube-controller-manager: 负责容器编排,集群内部的管理控制中心,负责集群内的Node、Pod副本、服务端点
(Endpoint)、命名空间(Namespace)、服务账号(ServiceAccount)、资源定额(ResourceQuota)的管理。
kubelet:kubelet 是运行在node 上的守护进程,它从API server接收关于pod对象的配置信息并确保它们的
处于期望状态(desired state目标状态)。kubelet会在API server上注册当前节点,定期向Master汇报节点
资源使用情况,并通过cAdvisor监控容器和节点资源占用情况
kube-proxy:一个网络代理,每个node上都运行一个kube-proxy守护进程,它能够按需为server资源对象生成
iptables或ipvs规则,从而捕获访问当前server和GlusterIP 的流量并将其转发至后端正真pod对象
CNI (Container Network Interface):eg:flannel、calico
CRI (Container Runtime Interface):eg:docker
CSI (Container Storage Interface):eg:PV
OCI(Open Container Initiative, 开放容器标准):eg:runC
pod:解析
1.Pod是K8s进行创建、调度和管理的最小单位
2.Pod运行于Node节点上, 若干相关容器的组合
3.Pod内包含的容器运行在同一宿主机上,使用相同的网络命名空间、IP地址和端口,能够通过localhost进行通信
4.Pod可以指定一组共享存储。Volumes Pod中的所有容器都可以访问共享卷,从而使这些容器可以共享数据
5.Pod 就是 k8s 世界里的"应用",而一个应用可以由多个容器组成。
ps:Pod本身无法自我修复,K8s中使用kube-controller-manager管理Pod
pause容器:
1)每个Pod中都有一个pause容器,pause容器做为Pod的网络接入点
2)属于同一个Pod的所有容器共享网络的namespace
3)一个Pod里的容器与另外主机上的Pod容器能够直接通信(lo)
4)属于同一个Pod的所有容器共享Volume挂载卷
一、K8s网络设计
1.每个Pod都拥有一个独立IP地址,Pod内所有容器共享一个网络命名空间
2.集群内所有Pod都在一个直接连通的扁平网络中,可通过IP直接访问
(1) 所有容器之间无需NAT就可以直接互相访问
(2) 所有Node和所有容器之间无需NAT就可以直接互相访问
(3) 容器自己看到的IP跟其他容器看到的一样
二、K8s网络要求
K8s对网络的要求总的来讲主要有两个最基本的要求,分别是:
1)要能够为每一个Node上的Pod分配互相不冲突的IP地址
2)要所有Pod之间能够互相访问
三、K8s网络规范
CNI是由CoreOS提出的一个容器网络规范。已采纳规范的包括Apache Mesos, Cloud Foundry, Kubernetes, Kurma 和 rkt。
另外 Contiv Networking, Project Calico 和 Weave这些项目也为CNI提供插件。
四、K8s网络实现
隧道方案
隧道方案在IaaS层的网络中应用也比较多,将pod分布在一个大二层的网络规模下。网络拓扑简单,但随着节点规模的增长复杂度会提升。
Weave:UDP广播,本机建立新的BR,通过PCAP互通
Open vSwitch(OVS):基于VxLan和GRE协议,但是性能方面损失比较严重
Flannel:UDP广播,VxLan
Racher:IPsec
路由方案
路由方案一般是从3层或者2层实现隔离和跨主机容器互通的,出了问题也很容易排查。
Calico:基于BGP协议的路由方案,支持很细致的ACL控制,对混合云亲和度比较高。
Macvlan:从逻辑和Kernel层来看隔离性和性能最优的方案,基于二层隔离,所以需要二层路由器支持,大多数云服务商不支持,所以混合云上比较难以实现。
五、K8s Pod的网络创建流程
1.每个Pod除了创建时指定的容器外,都有一个kubelet启动时指定的基础容器
2.kubelet创建基础容器,生成network namespace
3.kubelet调用网络CNI driver,由它根据配置调用具体的CNI 插件(eg:calico,flannel)
4.CNI 插件给基础容器配置网络
5.Pod 中其他的容器共享使用基础容器的网络
k8s网络
三种 IP 定义
1.Node IP:Node 节点的 IP 地址,即物理机(虚拟机)的 IP 地址。
2.Pod IP:Pod 的 IP 地址,即 docker 容器的 IP 地址,此为虚拟 IP 地址。
3.Cluster IP:Service 的 IP 地址,此为虚拟 IP 地址。
三种 IP 的理解
Node IP:是物理机的IP(或虚拟机IP)。每个Service都会在Node节点上开通一个端口,外部可以通过http://NodeIP:NodePort
即可访问 Service 里的 Pod 提供的服务。
Pod IP:是每个Pod的IP地址,Docker Engine根据 docker 网桥的 IP 地址段进行分配的,通常是一个虚拟的二层网络。
同Service下的pod可以直接根据PodIP相互通信
不同Service下的pod在集群间pod通信要借助于 cluster ip
pod和集群外通信,要借助于node ip
Cluster IP: 是Service的IP地址,此为虚拟 IP 地址,外部网络无法 ping 通,只有k8s集群内部访问使用。
Cluster IP仅仅作用于K8s Service这个对象,并由K8es管理和分配P地址 Cluster
IP无法被ping,他没有一个“实体网络对象”来响应 Cluster IP只能结合Service
Port组成一个具体的通信端口,单独的Cluster IP不具备通信的基础,并且他们属于K8s集群这样一个封闭的空间。
在不同Service下的pod节点在集群间相互访问可以通过Cluster IP
K8s的网络中pod的通信:
1. 同一Pod内的容器间通信:
因为pause容器提供pod内网络共享,所以容器直接可以使用localhost(lo)访问其他容器
2. 各Pod彼此之间的通信(两个pod在一台主机上面, 两个pod分布在不同主机之上)
1)两个pod在一台主机上面: 通过docker默认的docker网桥互连容器(docker0), ifconfig 查了docker0
2)两个pod分布在不同主机之上: 通过CNI插件实现,eg: flannel、calico
3. Pod与Service间的通信
Service分配的ip叫cluster ip是一个虚拟ip(相对固定,除非删除service),这个ip只能在k8s集群内部使用,
如果service需要对外提供,只能使用Nodeport方式映射到主机上,使用主机的ip和端口对外提供服务。
节点上面有个kube-proxy进程,这个进程从master apiserver获取信息,感知service和endpoint的创建,然后做两个事:
1.为每个service 在集群中每个节点上面创建一个随机端口,任何该端口上面的连接会代理到相应的pod
2.集群中每个节点安装iptables/ipvs规则,用于clusterip + port路由到上一步定义的随机端口上面,所以集群中每个node上面都有service的转发规则:iptables -L -n -t filter
Pod Network
K8s的一个Pod中包含有多个容器,这些容器共享一个Network Namespace,即是共享一个Network Namespace中的一个IP。创建Pod时,首先会生成一个pause容器,然后其他容器会共享pause容器的网络。
docker ps -a 可查看到/pause容器,和kubectl get pod -o wied 查到的容器名字是一样的
pause的ip又是从哪里分配到的?如果还是用一个以docker0为网关的内网ip就会出现问题了。
docker默认的网络是为同一台宿主机的docker容器通信设计的,K8s的Pod需要跨主机与其他Pod通信,
所以需要设计一套让不同Node的Pod实现透明通信(without NAT)的机制。
docker0的默认ip是172.17.0.1,docker启动的容器也默认被分配在172.17.0.1/16的网段里。跨主机的Pod
通信要保证Pod的ip不能相同,所以还需要设计一套为Pod统一分配IP的机制。
以上两点,就是K8s在Pod network这一层需要解决的问题,可以利用插件解决如:flannel或者calico