《Kubernetes权威指南》的阅读笔记,由于Kubernetes项目还在快速发展中,书里有些内容已有更新的变化,不过核心内容变化不大,书还是值得认真看的。
基本概念
Master
Master是整个Kubernetes系统的调度中心,其主要由以下3个重要组件组成(原本为4个组件,但etcd存在单点此处就使用了自建的外部etcd集群):- kube-apiserver
以RESTful方式提供API给外部调用,将核心对象存储在etcd中并提供增删改查功能。 - kube-scheduler
负责集群资源调度。监听etcd集群pod目录变化,将新增的pod按照分配算法分配到node节点中,调用kube-apiserver接口将node和pod进行关联。 - kube-controller-manager
Master的主要功能集中在kube-controller-manager组件上。主要负责执行不同的控制器,主要的控制器有以下几种:- Endpoint Controller:维护Service和Pod的关联关系。
- Replication Controller:维护Pod实例的运行个数,确保Pod的运行个数和设置的一致,Pod副本数过多则销毁,过少则增加。
- Namespace Controller:通过调用kube-apiserver提供的接口获取Namespace信息,删除被标记为
Terminating
的Namespace并删除该Namespace下ServiceAccount、RC、Pod、Secret、ResourceQuota等资源。 - ServiceAccount Controller & Token Controller:主要负责新的Namespace中默认帐号、密钥、证书和Token的管理。
- Node Controller:负责发现、管理和监控Node节点。Node Controller通过定期调用kube-apiserver提供的接口获取Node节点信息(
kubelet启动时调用kube-apiserver接口注册Node信息并定时更新Node信息
) - ResourceQuota Controller:负责资源配额控制,确保指定对象使用的系统资源在规定范围内。
- Service Controller:负责监控Service变化,确保外部 LoadBalancer 被更新。
- kube-apiserver
Node
Node是Kubernetes相对于Master的节点,Node上主要运行着众多Pod(默认Master不运行Pods等)。Node上由2个组件组成:- kubelet
kubelet主要负责监控和管理Pod(启动/停止)、Volume等,定期调用kube-apiserver接口从etcd获取分配到该Node的Pod信息并启动/停止容器,定期通过kub-apiserver汇报Pod状态。 - kube-proxy
kube-proxy主要用于Kubernetes的Service。kube-proxy从etcd中获取Service和Endpoints(Pod’s IP+Port)信息,Kubernetes为每个Service分配一个ClusterIP,kube-proxy根据从etcd获取到的信息为每个Service随机监听一个端口,所有到该Service的请求(ClusterIP:Port
)会被转发到该kube-proxy的随机端口上(通过iptables的nat实现转发),再由kube-proxy根据从etcd中获取到的信息转发给Pod(Pod在别的Node就转发到kube-proxy)。
- kubelet
Pod
Pod是Kubernetes中最小的操作单元,一个Pod中可以有一个或多个容器(Container)(一个Pod中的多个容器应该是紧耦合的)。Pod的生命周期是通过Replication Controller来管理的,Pod被分配到具体的Node上并被创建、启动和销毁(默认Master不运行Pod )。
Kubernetes之所以要在容器(Container)之上再封装一层Pod,是因为Docker容器之间通信麻烦和效率不高,所以通过Pod将多个紧耦合的容器(Container)组合起来,每个Pod内都会启动一个google_containers/pause
的容器(Container),然后再启动所需的业务容器,业务容器通过google_containers/pause
容器共享网络。
同一个Pod内的容器共享以下资源:- PID Namespace:同一个Pod内的应用程序能看到其他应用程序的PID(原本不同容器的PID是相互隔离的)
- Network Namespace:Pod内多个容器能访问同一个IP和端口(原本不同容器网络访问需要通过容器IP+Port方式,共享后同一个Pod内的所有容器都可直接通过localhost相互访问)
- IPC Namespace:Pod内多个容器可使用SystemV IPC或POSIX消息队列通信
- UTS Namespace:Pod内的多个容器共享一个主机名
- Volume(共享存储卷):Pod内的多个容器可访问Pod级别的Volumes,即多个容器可共享存储空间。
Label
Label以key/value
的形式附加到Pod、Service、RC(ReplicationController)、Node等对象上,定义对象的可识别属性,然后通过Label Selector(选择器)对对象进行选择和管理。Replication Controller就是通过Label Selector来选择需要管理的Pod的。
Label Selector的定义由多个逗号分隔,如下例子所示:1
2
3
4"label": {
"key1": "value1",
"key2": "value2"
}Label Selector有基于等式(Equality-based)和基于集合(Set-based)两种形式。
- 基于等式:name = nginx,选择所有Label中
key=name
且value=nginx
的对象。 - 基于集合:name in (nginx, tengine),选择所有Label中
key=name
且value=nginx
或value=tengine
的对象。
- 基于等式:name = nginx,选择所有Label中
RC(Replication Controller)
Replication Controller用于定义Pod副本的数量。Kubernetes通过Replication Controller实现动态伸缩以达到应用集群高可用的目的。
Kubernetes可通过kubectl scale
实现动态伸缩Pod1
kubectl scale rc <ReplicationControllerName> --replicas=3
删除RC,通过RC创建的Pods并不会随之跟着删除。
Service
Service是一组相同服务Pod集群的对外访问入口,Kubernetes会为Service分配一个ClusterIP作为该Service的入口。引入Service是为了外部对后端Pod的变化无感知。
Kubernetes会根据Service定义中的Label Selector,将Service和Endpoint对象(Pod的IP:Port)关联起来。查看Endpoint对象:1
kubectl get endpoints
Kubernetes分配给Service的ClusterIP只能在内部访问,若想Service被外部访问则需要分配一个”公网IP”。暴露Service的方式有三种:
- NodePort:这种是最常用的方式,直接在Node机器上监听端口。在定义Service时指定
spec.type=NodePort
并指定spec.ports.nodePort
的值。Kubernetes会在Node上监听spec.ports.nodePort
端口提供外部访问。并非一定要要指定spec.ports.nodePort
的值,spec.ports.nodePort
端口的范围必须在30000
~32767
内,不指定spec.ports.nodePort
则会随机在范围内分配一个IP。 - LoadBalancer:这种是在云服务(GCE/AWS)提供LoadBalancer时可使用,在定义Service时指定
spec.type=LoadBalancer
并指定Service的nodePort
和ClusterIP
- Ingress:Ingress是Kubernetes1.2版本后引入的,通过Ingress来利用Nginx/HAProxy等常见开源反向代理软件实现对外暴露服务功能。
- NodePort:这种是最常用的方式,直接在Node机器上监听端口。在定义Service时指定
Volume
Volume是Pod中能被多个容器访问的共享目录。Kubernetes的Volume和Docker的Volume差不多,但Kubernetes的Volume是随Pod销毁而销毁的,Pod中的容器停止或重启不影响Kubernetes的Volume。
Kubernetes提供多种类型的Volume,如下所示:- EmptyDir:EmptyDir Volume在Pod被分配到Node时创建,Pod内的所有容器都可以读写EmptyDir中的文件。Pod被删除时EmptyDir也会被删除。
hostPath:hostPath Volume是在Pod中挂载宿主机上的文件或目录。常用于需要持久保留的文件。由于Pod可能分配到多个Node上,挂载多个Node的hostPath Volume可能会导致数据的不一致。可在创建RC的时候指定Pod挂载宿主机的目录,比如将宿主机中
/data
目录挂载到Pod容器内的/data
上:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28apiVersion: v1
kind: ReplicationController
metadata:
name: nginx
labels:
name: nginx
spec:
replicas: 2
selector:
name: nginx
template:
metadata:
labels:
name: nginx
spec:
volumes:
- name: "nginx-log"
hostPath:
path: "/data"
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
volumeMounts:
- name: "nginx-log"
mountPath: "/data"gcePersistentDisk:使用GCE的永久磁盘(Persistent Disk),当Pod被删除时,这类磁盘只被卸载不会被删除。
- awsElasticBlockStore:使用AWS的EBS。
- nfs:使用NFS提供的目录挂载到Pod中。
- glusterfs:使用GlusterFS提供的目录挂载到Pod中。
- rdb:使用Linux块设备共享存储挂载到Pod中。
- gitRepo:通过挂载一个空目录,并从GIT库clone一个git repository以供pod使用。
- secret:为Pod提供加密存储,Secret Volume是通过tmpfs实现的,不能持久化。
- persistentVolumeClaim:从PV(persistentVolume)中申请所需的空间,PV通常是种网络存储,如GCEPersistentDisk、AWSElasticBlockStore、NFS、iSCSI等。
Namespace
Kubernetes的Namespace和Linux系统中的Namespace并非同一个东西,但功能相似都是用于隔离。Kubernetes通过将对象分配到不同的Namespace中以达到分组管理的目的。
Kubernetes启动后会创建一个default
的Namespace,使用kubeadm
部署集群的话会创建kube-system
的Namespace。若不知道资源对象的Namespace,则Pod、RC、Service等都会被创建到default
的默认Namespace中。可通过以下命令查看Namespace:1
kubectl get namespace
可通过yaml文件创建Namespace:
1
2
3
4
5#namespace-test.yaml
apiVersion: v1
kind: Namespace
metadata:
name: test1
kubectl create -f namespace-test.yaml
Annotation
Annotation也是使用key/value
形式进行定义,个人理解为相当于备注的作用。
Kubernetes创建Pod流程
- 通过
kubectl
提交一个创建RC请求给kube-apiserver
,kube-apiserver
将请求存到etcd
kube-controller-manager
通过调用kube-apiserver
接口得知创建RC事件,分析后发现集群中没有该RC对应的Pod,根据RC定义中的Pod模板生成Pod对象并调用kube-apiserver
接口存入etcd
。kube-scheduler
监听etcd发现有创建Pod事件,kube-scheduler
根据算法得出Pod被分配到哪个Node,调用kube-apiserver
将结果存入etcd
。- 目标Node上的
kubectl
通过调用kube-apiserver
得知需要创建Pod并按照相关定义创建Pod及容器。该Node的kubectl
对Pod进行监控和管理并定期调用kube-apiserver
接口上报Pod的状态。
Kubernetes创建Service流程
- 通过
kubectl
提交创建Service请求给kube-apiserver
,kube-apiserver
将请求存到etcd
kube-controller-manager
调用kube-apiserver
接口得知创建Service事件,通过Label
查询到与Service相关的Pod,生成Service的Endpoint信息并调用kube-apiserver
接口存入etcd
。- Node上的
kube-proxy
调用kube-apiserver
接口查询到Service和对应Endpoint信息,在Node上监听随机端口,配置iptables将所有到Service的ClusterIP:Port的请求都转发到kube-proxy
监听的随机端口上,kube-proxy
将请求转发到Pod上。
Kubernetes核心原理
kube-apiserver
kube-apiserver默认会监听两个端口,一个是非安全用于接受HTTP请求的8080
端口,另一个是安全的HTTPS端口6443
用于认证等安全机制请求,kube-apiserver主要功能:
- 提供集群管理API接口
- 集群各功能模块间数据交互和通信的中枢
- 提供安全机制
Kubernetes提供kubectl
命令行工具将API功能封装成简单的命令集。更多具体功能使用kubectl -h
获取。
kube-apiserver提供API接口访问Pod、Node和Service等,详细的API接口没去研究。
Kubernetes中基本上都是通过调用kube-apiserver提供的接口完成集群中模块间信息的交换的。比如Node上的kubectl
会定期调用API报告节点状态并存入etcd中,Node Controller通过调用API获取到节点相关信息并作出相应操作。为了缓解kube-apiserver的压力各功能模块会定时调用API获取信息并保持到本地缓存,使得某些情况下模块不需要直接调用API而通过访问缓存数据间接调用API。
kube-controller-manager原理
kube-controller-manager
作为Kubernetes集群的管理控制中心,对集群内的Node、Pod副本、Endpoint、Namespace、ServiceAccount和ResourceQuota等资源进行管理及执行自动修复流程。如上所说,kube-controller-manager
是由多个Controller组成,对各个Controller进行较深入了解。
Replication Controller
Replication Controller的主要功能是确保Pod的副本数目和RC定义中的一致。正常来说,都是通过RC来创建Pod的,所以Replication Controller的管理对象是Pod。Pod的状态值如下:
- pending:API Server已创建Pod,但Pod内有一个或多个容器没创建
- running:Pod内所有容器已创建,且至少有一个容器正常运行
- successded:Pod内所有容器均停止成功且不会再重启
- failed:Pod内所有容器已退出,且至少一个发生错误退出
Pod的重启策略有三种Always
、OnFailure
和Never
,只有是Always
时,Replication Controller才会管理该Pod。当Pod副本状态为failed
或被删除且RestartPolicy=Always
时,Replication Controller会重新创建该Pod的副本。
通过具体的RC实例来说明Replication Controller是如何创建Pod的。创建一个Nginx的RC实例,启动2个Pod:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21apiVersion: v1
kind: ReplicationController
metadata:
name: nginx
labels:
name: nginx
spec:
replicas: 2
selector:
name: nginx
template:
metadata:
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
kind: ReplicationController
:指明这是个ReplicationControllerspec.replicas
:指明该RC的Pod副本数目spec.selector
:指明该RC关联的Podspec.template
:RC创建的Pod实例都是根据RC定义中的创建。spec.template.spec.containers
:指明Pod中容器的属性(该使用什么镜像、端口等)
需要注意到是,删除RC并不会影响其所已经创建的Pod。Pod可以通过修改其Label实现脱离RC的管控(RC是通过spec.selector
中的name
来关联Pod的)。
Replication Controller主要就是根据RC定义中的spec.replicas
值来调整Pod的副本数目,以确保集群中有且仅有spec.replicas
个Pod实例。
Replication Controller的常用模式如下:
- Rescheduling:重新调度,即在Pod副本实例发生异常时重新创建Pod副本实例。
Scaling:手动或自动扩容/缩容。可通过
kubectl scale
命令实现1
kubectl scale rc <ReplicationControllerName> --replicas=<NUM>
Rolling Updates:滚动更新,ReplicationController通过逐个对Pod进行更新来实现滚动升级。一般是重新创建一个RC,然后新RC中的Pod数目不断增加,旧RC中Pod数目不断减少直至
0
。1
kubectl rolling-update <OLD_RC_NAME> --update-period=10s -f <NEW_RC>.yaml
Kubernetes1.2版本后推荐使用Deployment来进行Rolling Updates。新的Deployment会创建ReplicaSet,关于这个内容改天专门来写。
Node Controller
Node Controller主要负责发现、管理和监控Node。kubectl
启动时调用API注册Node并定时调用API上报Node信息,kube-apiserver
将Node信息存入etcd。Node信息包括:Node健康状态、节点资源、节点名称、节点地址信息、OS版本、Docker版本和kubelet版本。
Node健康状态分为:True
(就绪)、False
(未就绪)和Unknown
(未知)
Node Controller会定期调用API接口获取Node信息。如果kube-controller-manager
启动时没有指定CIDR
则为每个Node生产CIDR
并设置Node的spec.PodCIDR
属性;逐个读取Node信息并和Node Controller中nodeStatusMap
中保存的信息做对比,若无变化则更新探测时间,有变化则更新nodeStatusMap
中的信息。若规定时间内没收到Node信息则将状态设置为Unknown
并调用API存入etcd。再逐个读取Node信息,将非True
状态Node加入待删队列,若发现该Node故障则删除etcd中Node信息及相关资源信息。
ResourceQuota Controller
ResourceQuota Controller是对Kubernetes集群进行资源配额管理的,支持三个层次的资源配额管理:
- 容器级别:对容器CPU和Memory进行限制
- Pod级别:对Pod内所有容器进行资源限制
- Namespace级别:Namespace级别的限制包括以下方面:
- Pod数量
- RC数量
- Service数量
- ResourceQuota数量
- Secret数量
- PV(persistentVolume)数量
Kubernetes中配额管理是通过准入机制(admission control)实现的,配额的准入控制器有LimitRanger和ResourceQuota,LimitRanger作用于Pod和Container,ResourceQuota作用于Namespace。
ResourceQuota Controller以Namespace作为分组统计单元,调用API定时从etcd中获取每个Namespace中的ResourceQuota信息,计算Pod、RC、Service等资源对象和Container实例使用的资源(CPU/Memory)并调用API存入etcd。用户请求创建资源时,kube-apiserver调用admission controller的ResourceQuota插件从etcd中配额信息,若某项资源超过配额则该请求被拒绝。
Namespace Controller
Namespace Controller主要就是用来管理Namespace的。当Namespace被标记为优雅删除(即设置了DeletionTimestamp
删除期限),则该Namespace状态被设置为Terminating
。Namespace Controller会删除该Namespace下的所有资源,然后执行finalize
操作(删除spec.finalizers
信息)。当Namespace Controller发现一个Namespace设置了DeletionTimestamp
且spec.finalizers
值为空则调用API删除Namespace。
Service Controller & Endpoint Controller
当调用API创建Service时,Kubernetes会为该Service指派一个集群内网IPClusterIP
,Service中的spec.selector
指明该Service和name: nginx
的Pod关联,每个Pod的80
端口都被映射到本地节点的80
端口(targetPort
)。创建Service时指定了spec.selector
的话,Kubernetes会创建一个和Service同名的Endpoint对象。该Endpoint对象其实就是和Service关联的Pod的IP+Port。
也可创建没spec.selector
的Service,Kubernetes便不会自动创建与之相关的Endpoint,可手动创建和Service同名的Endpoint指定后端Pod。
创建Nginx的Service实例:1
2
3
4
5
6
7
8
9
10
11
12
13apiVersion: v1
kind: Service
metadata:
name: nginx-service
labels:
name: nginx-service
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
name: nginx
Service是Kubernetes中的对象,请求从Service到Pod的工作是由kube-proxy
来完成的。kube-proxy
为每个Service在本机上随机监听一个端口,通过添加iptables规则将访问Service的请求转发到kube-proxy
的随机端口,然后kube-proxy
根据Round Robin
算法及Session保持(SessionAffinity
)决定将请求转发到后端的哪个Pod。
Kubernetes支持两种模式找到Service:
- Container的Service环境变量
在创建Pod时,在所有Pod中的Container中加入一系列的Service环境变量,如{SVCNAME}_SERVICE_HOST
/{SVCNAME}_SERVICE_PORT
等,{SVCNAME}
是大写的Service Name,若有-
则自动转换为_
。 - DNS
DNS服务器通过调用API监控Service相关活动,新增Service时创建一系列DNS记录。
更为常用的是DNS SVC被命名端口的记录,若service_name.namespace_name
的Service有名为”http”的端口,则可用_http._tcp.service_name.namespace_name
通过DNS服务器找到对于的Pod暴露端口。
对于Service的暴露,如前面所说常用三种方式:LoadBalancer、NodePort和Ingress。详细参照前面。
Service Controller和Endpoint Controller分别监控Service和Endpoint对象,调用API更新变更再存入etcd中。
kube-scheduler
kube-scheduler
主要负责Pod的调度,将待调度的Pod按照特定的调度算法和调度策略绑定到合适的Node上并将信息存入etcd。Node上的kubelet
监听到kube-scheduler
产生的Pod绑定事件后,获取对应的Pod清单、下载image镜像并启动Container容器。
kube-scheduler
默认调度流程分两步,Kubernetes提供一系列的预选策略和优选策略,此处不一一具体分析:
- 预选策略:遍历所有Node,筛选符合条件的Node。
- 优选策略:基于预选策略,采用优选策略计算积分,最终选出最佳Node。
kubelet
Kubernetes会在每个Node节点中运行kubelet
,kubelet
主要负责以下功能:
- Node管理
kubelet
在启动时会调用API以注册Node信息(可手动设置不进行自动注册),并定期调用API将信息存入etcd。 - Pod管理
kubelet
通常通过以下3种获取Node上的Pod清单:- 文件:在启动
kubelet
时指定,--pod-manifest-path=/etc/kubernetes/manifests
。 - HTTP URL:指定
--manifest-url
。 - API Server:调用API监听etcd目录同步Pod清单。
前两种非API Server方式创建的Pod称之为Static Pod,kubelet
会将Static Pod汇报给API Server,API Server会为Static Pod创建Mirror Pod与其匹配。kubelet
通过API Server方式创建或修改Pod大致流程如下:
- 创建Pod的数据目录
- 调用API获取Pod清单
- 挂载外部卷(Extenal Volume)到Pod
- 下载Pod所需的Secret
- 检查Node运行中的Pod,若Pod中无容器或
Pause
容器没启动,则先停止Pod内所有容器,若有要删除的容器则删除 - 为每个Pod创建
Pause
容器,Pod中的其他容器通过Pause
容器共享网络 - 为Pod中的每个容器做如下处理:为容器计算hash值,用容器名去Docker查询对应容器的hash值,若hash值不同则停止容器。若设置了
restartPolicy
则按照策略处理,无则调用Docker client下载镜像并运行容器。
- 文件:在启动
健康检查
Pod通过两种探针检查容器健康状态:LivenessProbe:用于判断容器是否健康。若不健康,
kubelet
则删除容器并按照restartPolicy
策略处理。LivenessProbe检查可分成三种实现方式,LivenessProbe
的定义在Pod的spec.containers
中:ExecAction:容器内执行一条命令,退出码为
0
则健康1
2
3
4
5
6
7
8
9
10
11
12
13
14spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 3TCPSocketAction:对容器内端口做TCP检测,端口能被访问则健康
- HTTPGetAction:对容器特点的端口+路径调用
GET
方法,HTTP响应状态码在200
~400
之间为健康1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
livenessProbe:
httpGet:
path: /heath_pah
port: 80
httpHeaders:
- name: X-Custom-Header
value: Awesome
initialDelaySeconds: 5
periodSeconds: 3
ReadinessProbe:用于判断容器是否启动完成且准备接受请求。若ReadinessProbe检查失败,Endpoint Controller会删除Service中该Pod的Endpoint信息。
网络原理
Kubernetes网络模型
Kubernetes使用的网络模型称为IP-per-Pod模型,每个Pod拥有单独的IP地址,IP是以Pod为单位分配的。一个Pod内的所有容器共享网络(使用同一个Network Namespace通过Pause容器实现),IP和端口在Pod内部和外部都是一致的(不需要NAT)。
Kubernetes设计之初是运行在谷歌的GCE环境上的,GCE默认就支持Kubernetes的网络。但要在非GCE环境运行Kubernetes则需要先搭建出符合Kubernetes网络要求的环境,目前开源的方案有很多诸如Flannel、Weave等用于实现Kubernetes中容器与容器之间网络的环境。
Kubernetes主要针对一下几种网络场景制定不同的解决方案:- 容器间通信
这里的容器间通信特指在同一个Pod内的容器间通信,正如前面所说,同一个Pod内的容器是通过Pause容器共享同一个Network Namespace的,同一个Pod内的容器甚至可以通过localhost
直接访问彼此的端口,这就使得同一个Pod内容器间的通信变得简单高效。 Pod间通信
- 同一Node中Pod间通信
由于同一个Node中的不同Pod都是通过veth
连接到同一个docker0
网桥上,Pod的IP地址和docker0
的IP地址在同一个网段内,所有同一个Node上的不同Pod都由docker0
网桥进行中转,可直接通信。 不同Node中Pod间通信
由于Pod的IP是隐藏在docker0
网桥后的,出了docker0
后不同Node之间的Pod是无法感知到对方,所以需要有完善的网络方案使得Pod之间能使用私有IP进行通信、集群内Pod的IP分配不会冲突、Pod的IP和Node的IP关联(Pod通信时需要先找到Node)。为此有了多个不同的开源网络组件:Flannel
Flannel会创建flannel0
网桥,一端连接docker0
,另一端连接flanneld
服务进程。flanneld
服务进程利用etcd
来管理分配IP并监听etcd
中每个Pod的IP,创建Pod节点路由表。flanneld
服务进程根据Pod节点路由表将从docker0
发来的数据包进行封装通过物理网络传输到目的flanneld
上,以此完成不同Node上的Pod通信。1
containerA-->docker0-->flannel0-->flanneld-->NodeA-->[Network]-->NodeB-->flanneld-->flannel0-->docker0-->containerB
Open vSwitch
Open vSwitch是一个开源虚拟交换机软件,该项目较成熟但比较复杂,一般最求高性能网络的话网上都比较推荐此方案,由于比较复杂我也没怎么研究。- 直接路由
简单来说,直接路由就是让集群能够通过docker0
直接通信,让每个Node的路由表有到所有docker0
的路由,将docker0
和Node的eth0
关联起来。简单的可手动在所有Node上添加到集群内所有docker0
地址的路由,但更实际的方案是结合动态路由协议来做。
- 同一Node中Pod间通信
- Pod和Service间通信
正如前面所说,Pod和Service间的通信是通过kube-proxy
实现的,kube-proxy
为Service随机监听一个端口并添加iptables规则将到Service的请求转发到kube-proxy
,再由kube-proxy
根据Endpoint信息转发到后端的Pod。
值得一提的是如果Service定义中指定了Session保持,则kube-proxy
会查看是否存在改IP的affinityState
对象,存在则转到改对象对应的Pod。 - 外部到内部访问
同样如前面所说,外部访问内部目前主要有3种方式:NodePort、LoadBalancer和Ingress。接下来重点讲一下Ingress。
Ingress是利用Nginx/HAProxy等反向代理软件来暴露服务,从而实现外部到内部的访问,Ingress可根据URL(/serviceA
)、域名来进行暴露Service。
Ingress在Kubernetes中也是一个对象资源,Kubernetes使用Ingress Controller来对控制管理Ingress资源,Ingress Controller主要与Kubernetes API交互,负责感知规则变化,然后生成配置文件,最后reload Pod中的Nginx。Ingress Controller不像其他Controller一样包含在kube-controller-manager
里,需要选择适合的Ingress Controller并运行。
- 容器间通信