kubernetes基础知识分享
1. kubernetes简介
Kubernetes 是一个跨主机集群的 开源的容器调度平台,它可以自动化应用容器的部署、扩展和操作 , 提供以容器为中心的基础架构。
1.1 起源
Kubernetes最初源于谷歌内部的Borg。Borg是谷歌内部的大规模集群管理系统,负责对谷歌内部很多核心服务的调度和管理。Borg的目的是让用户能够不必操心资源管理的问题,让他们专注于自己的核心业务,并且做到跨多个数据中心的资源利用率最大化。
1.2 作用
Kubernetes 是用于自动部署,扩展和管理容器化应用程序的开源系统。旨在消除编排物理/虚拟计算,网络和存储基础设施的负担,使运营商和开发人员将重点放在以容器为中心的系统运行上。
Kubernetes 具备完善的集群管理能力,包括多层次的安全防护和准入机制、多租户应用支撑能力、透明的服务注册和服务发现机制、内建负载均衡器、故障发现和自我修复能力、服务滚动升级和在线扩容、可扩展的资源自动调度机制、多粒度的资源配额管理能力。
Kubernetes 还提供完善的管理工具,涵盖开发、部署测试、运维监控等各个环节。
1.3 发展现状
2018年3月,CNCF(云原生计算基金会)技术监督委员会(简称TOC)通过投票表决,最终认定Kubernetes成为该基金会的首个结业项目。
目前,三家规模最大的云服务供应商亚马逊、谷歌、微软都提供自己的托管Kubernetes服务。
根据CNCF统计数据,2018年,云原生技术增长了200%,全球有近三分之一的企业运行50个容器,运营50至249个容器的企业占比也超过25%,有超过80%的受访者把Kubernetes作为容器管理的首选方案。
京东2016年就开始将自己的JDOS2.0切换到了Kubernetes技术栈,相比JDOS1.0物理机使用率提高了3倍,整体资源利用率提高了30%;2017年中超过60%的业务运行在kubernetes平台上;截止至2018年,京东维护着全球最大的kubernetes集群(数据来源:kubernetes中文社区、Container Day 2018容器技术大会)。
2. 架构与服务组件
2.1 架构
2.2 组件
2.2.1 Master节点
Master是整个集群的大脑,所有的编排、调度、API访问等都由Master来负责。
- kube-apiserver
提供了资源操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制。并且无论是集群内部还是外部的组件,都必须通过APIServer来访问数据,实现解耦合,同时各种REST对象(Pod、Service、Node、Namespace等)的数据通过该API接口被提交到后端的持久化存储(etcd)中。 kube-scheduler
负责对资源进行调度,分配某个pod到某个合适的节点上,并将绑定信息写入etcd。默认调度流程主要分为以下两步:- 预选调度过程:即遍历所有目标Node,筛选出符合要求的候选节点。为此Kubernetes内置了多种预选策略(xxx Predicates)供用户选择。
- 确定最优节点:在第一步的基础上,采用优选策略(xxx Priority)计算每个候选节点的积分,积分最高者胜出。
- 预选调度过程:即遍历所有目标Node,筛选出符合要求的候选节点。为此Kubernetes内置了多种预选策略(xxx Predicates)供用户选择。
- kube-controller-manager
集群内部的管理控制中心,负责维护集群状态,包括集群内的Node、Pod副本、服务端点(Endpoint)、命名空间(NameSpace)、服务账号(ServiceAccount)、资源定额(ResourceQuota)等的管理并执行自动修复流程,确保集群处于预期的工作状态。 Etcd
保存了整个集群的状态,是一个分布式键值对存储系统;2.2.2 Node节点
kubelet
Kubernetes集群中,每个Node节点上都会启动一个Kubelet服务进程。该进程用于处理Master节点下发到本节点的任务,管理Pod及Pod中的容器。每个Kubelet进程会在API Server上注册节点自身信息,定期向Master节点汇报节点资源的使用情况,并通过cAdvise监控容器和节点资源。
Kubelet功能如下:
- 节点管理:Kubelet在启动时通过API Server注册节点信息,并定时向API Server发送节点新消息,API Server在接收到这些信息后,将这些信息写入etcd。
- Pod管理:Kubelet可以获取自身Node上所要运行的Pod清单;所有针对Pod的操作都会被Kubelet监听到。接收apiserver的HTTP请求,汇报pod的运行状态。
- 容器健康检查:
LivenessProbe探针:用于判断容器是否健康,告诉Kubelet一个容器什么时候处于不健康的状态。
ReadinessProbe探针:用于判断容器是否启动完成,且准备接受请求。- cAdvisor资源监控:开源的分析容器资源使用率和性能特性的代理工具,即监控agent。
kube-proxy
KUbernetes集群中的每个Node上都运行一个Kube-Proxy进程。是一个Service的透明代理兼负载均衡器。核心功能是是将某个Service的访问转发到后端的多个Pod实例上。基本原理:
对于每一个TCP类型的Kubernetes Service,kube-proxy都会在本地Node上建立一个Socket Server负责可接受请求,然后默认采用Round Robin负载均衡算法均匀发送到后端某个Pod上。
为pod上的服务提供访问的代理;给service对象提供cluster内部的服务发现和负载均衡;2.3 通信流程
1. 准备好一个包含应用程序的Deployment对象yml文件,然后通过kubectl客户端工具发送给ApiServer。
2. ApiServer接收到客户端的请求并将资源内容存储到数据库(etcd)中。
3. Controller组件(包括scheduler、replication、endpoint)监控资源变化并作出反应。
4. ReplicaSet检查数据库变化,创建期望数量的pod实例。
5. Scheduler再次检查数据库变化,发现尚未被分配到具体执行节点(node)的Pod,然后根据一组相关规则将pod分配到可以运行它们的节点上,并更新数据库,记录pod分配情况。
6. Kubelet监控数据库变化,管理后续pod的生命周期,发现被分配到它所在的节点上运行的那些pod。如果找到新pod,则会在该节点上运行这个新pod。
7. kuberproxy运行在集群各个主机上,管理网络通信,如服务发现、负载均衡。当有数据发送到主机时,将其路由到正确的pod或容器。对于从主机上发出的数据,它可以基于请求地址发现远程服务器,并将数据正确路由,在某些情况下会使用轮询调度算法(Round-robin)将请求发送到集群中的多个实例。
3. 相关资源对象
类别 | 名称 | |
---|---|---|
资源对象 | Pod、ReplicaSet、ReplicationController、Deployment、StatefulSet、DaemonSet、Job、CronJob、HorizontalPodAutoscaling、Node、Namespace、Service、Ingress、Label、CustomResourceDefinition | |
存储对象 | Volume、PersistentVolume、Secret、ConfigMap | |
策略对象 | SecurityContext、ResourceQuota、LimitRange | |
身份对象 | ServiceAccount、Role、ClusterRole |
3.1 Pod
Pod是kubernetes中可以创建和部署的最小单位。一个pod代表一个应用实例。
Pod中封装着应用的容器,这些容器共享一组资源:
- PID Namespace:Pod中的不同应用程序可以看到其他应用程序的进程PID。
- Network Namespace:Pod中的多个容器能够访问同一个IP和端口范围,IP per Pod。
- UTS Namespace:Pod中的多个容器共享一个主机名。
- Volumes(共享存储卷):Pod中的各个容器可以访问在Pod级别定义的Volumes。
Pod定义
Pod定义通过Yaml或json格式的配置文件完成,其中kind为Pod,spec中包含了对Containers的定义,可以定义多个容器。简单的pod定义文件如下所示:
//redis-slave-pod.yaml
apiVersion: v1 #当前格式的版本
kind: Pod #当前创建资源的类型, 当前类型是Pod
metadata: #当前资源的元数据
name: redis-slave #当前资源的名字 是元数据必须的项
labels: #至少一个labels标签,可任意创建一个 key:value
name: redis-slave
spec: #是当前Deployment的规格说明
restartPolicy: Never #pod重启策略
containers: #容器
- name: slave #容器名
image: kubeguide/guestbook-redis-slave:latest #镜像名和版本号
ports: #端口信息
- containerPort: 6379 #容器开启的端口
env: #pod环境变量
- name: GET_HOSTS_FROM
value: env
Pod的生命周期
通过ymal/json模板定义-->分配到Node上运行-->Pod所含容器运行结束后Pod也结束。
整个过程Pod处于以下四种状态之一:
- Pending:Pod定义正确,提交至Master,但是容器还未完全创建(Pod调度、镜像下载/运行等耗时)。
- Running:Pod已被分配到某个Node上,且其包含的所有Container镜像均已创建完成并正确运行。
- Succeeded:Pod中所有容器都成功结束,且不会被重启,这是Pod的一种最终状态。
- Failed:Pod中所有容器都结束可,但至少有一个容器是以失败结束的。这也是Pod的一种最终状态。
一般不独立创建Pod,而使用controller对象管理Pod实例,提供副本管理、滚动升级和集群级别的自动恢复。
3.2 Label
Label以key/value形式附加到Pos、Service、RC、Node等上面,每个对象可以定义多个label,以提供给Label Selector选择对象,Label Selector有两种形式:
- 等式方式:= 、 == 、 !=
- 集合方式:in 、 notin 、 !
下面是一个label的使用场景
通过Label标记后台Pod(tier=backend,app=myapp),前端Pod(tier=frontend,app=myapp),然后使用Selector选择带有特定Label的Pod,并将Service或者controller应用到上面。
通过label可以给对象创建多组标签,Service、Controller等通过Label Selector来选择对象范围。Label和Label Selector共同构成了Kubernetes系统中最核心的应用模型,使得被管理对象能够被精确地分组管理。
3.3 控制器对象
Kubernetes内置了许多controller,控制Pod的具体状态和行为。
Controller能够自动创建并维护Pod副本数量,并实现了更新、回滚、伸缩等功能。
Deployment
为Pod和ReplicaSet提供了一个声明式定义的方法,替代以前的ReplicationController来方便的管理应用。应用场景:
- 定义Deployment来创建Pod和ReplicaSet
- 滚动升级和回滚应用
- 扩容和缩容
- 暂停和继续Deployment
一个简单的Deployment定义如下
apiVersion: extensions/v1beta1 #当前格式的版本
kind: Deployment #当前创建资源的类型, 当前类型是Deployment
metadata: #当前资源的元数据
name: nginx-test #当前资源的名字 是元数据必须的项
spec: #是当前Deployment的规格说明
replicas: #指当前创建的副本数量 默认不填 默认值就为‘1’
template: #定义pod的模板
metadata: #当前pod的元数据
labels: #至少一个labels标签,可任意创建一个 key:value
app: web_server
spec: #当前pod的规格说明
containers: #容器
- name: nginx #是容器的名字容器名字是必须填写的
image: nginx:latest #镜像 镜像的名字和版本
StatefulSet
为pod提供唯一性标识,可以保证部署和扩容得顺序。
;解决有状态服务问题,应用场景包括:- 稳定的持久化存储
- 稳定的网络标志,重新调度后PodName和HostName不变
- 有序部署,有序扩展、收缩、删除
DaemonSet
保证每个Node上都运行一个Pod的副本,当有Node加入集群时,也会为他们新增一个Pod。当Node移除时,会回收Pod。删除DaemonSet将删除它创建的所有Pod。
典型用法- 集群存储daemon
- 日志收集daemon
- 监控daemon
ReplicationController和ReplicaSet
ReplicationController用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的Pod来替代;如果出现异常多出来的容器也会自动回收。
在新版本的Kubernetes中建议使用ReplicaSet来取代ReplicationController。ReplicaSet支持集合式的selector。
虽然ReplicaSet可以独立使用,但一般还是建议使用 Deployment 来自动管理ReplicaSet,这样就无需担心跟其他机制的不兼容问题(比如ReplicaSet不支持rolling-update但Deployment支持)。
Job
Job负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束。
CronJob
Cron Job 管理基于时间的 Job,即:
- 在给定时间点只运行一次
- 周期性地在给定时间点运行
Horizontal Pod Autoscaling
Pod水平自动缩放,削峰填谷,提高整体资源利用率。
可以直接create hpa也可以通过deployment使用autoscale创建。
1.6版本之后必须通过API server、Heapseter或者kube-aggregator来获取监控指标。3.4 服务发现对象
Service
pod是动态创建的因此IP地址可能发生变化,因此定义一种抽象Service,能够通过Lable Selector实现一组backend pod的访问。
Ingress
Ingress 是从Kubernetes集群外部访问集群内部服务的入口。是一种HTTP方式的路由转发机制,会为kubernetes服务配置HTTP负载均衡器。
3.5 存储对象
Secret
解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod Spec中。
ConfigMap
用来保存键值对配置数据,提供给pod或者controller
Volume
卷与封装它的Pod生命周期相同,当Pod消失时,卷也不存在了。使用时需要为pod指定卷,以及将它挂载到容器的位置。
Persistent Volume
管理员创建的集群存储资源,其生命周期独立于使用其的pod。其包含存储细节,即NFS、ISCSI或特定于云供应商的存储系统。
要使用PV需要创建PersistentVolumeClaim(pvc),pvc是对pv资源的请求。StorageClass
提供了描述存储“类”的方法。不同的class可能映射到不同的服务质量等级或者备份策略。通过StorageClass可以动态创建pv,避免了管理员手动创建新的存储卷。
- 集群管理员预先创建存储类(StorageClass);
- 用户创建使用存储类的持久化存储声明(PVC:PersistentVolumeClaim);
- 存储持久化声明通知系统,它需要一个持久化存储(PV: PersistentVolume);
- 系统读取存储类的信息;
- 系统基于存储类的信息,在后台自动创建PVC需要的PV;
- 用户创建一个使用PVC的Pod;
- Pod中的应用通过PVC进行数据的持久化;
- 而PVC使用PV进行数据的最终持久化处理。
定义存储类
每一个存储类都包含provisioner、parameters和reclaimPolicy这三个参数域,当一个属于某个类的PersistentVolume需要被动态提供时,将会使用上述的参数域。存储类定义之后不能更新,管理员能够为pvc指定默认的存储类。
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: standard # 指定存储类的供应者
provisioner: kubernetes.io/aws-ebs
parameters: # 指定存储类型
type: gp2
reclaimPolicy: Retain # 指定回收策略
mountOptions:
- debug
常见provision
其中有一些存储没有内部分配器,需要使用外部分配器或者第三方存储供应商自己的外部分配器。外部分配器地址:https://github.com/kubernetes-incubator/external-storage
存储卷 | 内置供应者 | 配置例子 |
---|---|---|
AWSElasticBlockStore | ✓ | AWS |
AzureFile | ✓ | Azure File |
AzureDisk | ✓ | Azure Disk |
CephFS | – | – |
Cinder | ✓ | OpenStack Cinder |
FC | – | – |
FlexVolume | – | – |
Flocker | ✓ | – |
GCEPersistentDisk | ✓ | GCE |
Glusterfs | ✓ | Glusterfs |
iSCSI | – | – |
PhotonPersistentDisk | ✓ | – |
Quobyte | ✓ | Quobyte |
NFS | – | – |
RBD | ✓ | Ceph RBD |
VsphereVolume | ✓ | vSphere |
PortworxVolume | ✓ | Portworx Volume |
ScaleIO | ✓ | ScaleIO |
StorageOS | ✓ | StorageOS |
Local | – | Local |
本地持久化存储
通过pv、pvc创建
3.6 身份策略对象
Service Account
Service Account为Pod中的进程提供身份信息,主要用于集群内部服务访问kubernets的apiserver。
RBAC
基于角色的访问控制,
Network Policy
网络策略说明一组Pod之间如何被允许相互通信,以及如何与其他网络Endpoint进行通信。NetworkPolicy使用标签来选择Pod,并定义了一些规则,这些规则指明允许什么流量进入到选中的Pod上。
3.7 扩展
自定义资源扩展API
自定义资源是对Kubernetes API的扩展,kubernetes中的每个资源都是一个API对象的集合。
4. kubernetes网络
4.1 网络模型
IP-per-pod模型
Docker0以Pod为单位分配IP,一个Pod内部的所有容器共享一个网络命名空间(ip、网络设备、配置)。Pod内外IP一致。
实现方式:
kubernetes每创建一个Pod就会创建一个pause容器作为Pod的网络接入点(gc.io/google_containers/pause:0.8.0),Pod中的其他容器会使用--net=container:***(即docker四种网络模式中的container模式)接入到pause容器。同一个Pod中的容器共享网络的namespace,即共享IP和端口范围。
- container-to-container通信
同一个Pod内通过localhost,不同Pod通过Pod间通信- Pod-to-Pod通信
- 同一个Node之间的Pod通信
直接访问Pod全局ip,因为同一个Docker0网桥分配ip、进行路由。
- 不同Node之间的Pod通信
kubernets会记录所有正在运行的Pod的IP分配信息到etcd中,作为service的Endpoint。通信需要的条件:1.k8s集群上的IP不冲突。2.Pod的IP与Node的IP关联使Pod可以相互访问。条件1可以通过开源的网络组件管理资源池分配。条件2需要有机制在Pod数据发出时知道对方PodIP挂在哪个Node上,然后将数据发送到对方Node网卡上,然后对方将相应数据转移到Docker0上,之后Docker0就知道如何将数据发送到Pod上了。
在谷歌的GCE环境下这些条件是满足的,k8s假设底层已经具备这些条件。而在实际的私有云环境中,还需要额外的网络配置才能达到要求,因此出现不少开源网络组件。如flannel、calico。
4.2 flannel
简介
Flannel是CoreOS团队针对Kubernetes设计的一个覆盖网络(Overlay Network)工具,为Kubernets提供网络规划服务,他能实现以下两点功能:
- 协助kubernets,给每一个Node上的Docker容器分配不冲突的IP地址。
- 它能在这些IP地址之间建立一个覆盖网络(Overlay Network),通过这个覆盖网络,将数据包原封不动的传递到目标容器内。
flannel网络实现
flannel支持多种网络模式,常用的是vxlan、UDP、hostgw。
vxlan和UDP的区别是vxlan是内核封包,而UDP是flanneld用户态程序封包,所以UDP的方式性能会稍差;hostgw模式是一种主机网关模式,容器到另外一个主机上容器的网关设置成所在主机的网卡地址,这个和calico非常相似,calico是通过BGP声明,而hostgw是通过中心的etcd分发,所以hostgw是直连模式,不需要通过overlay封包和拆包,性能比较高,但hostgw模式最大的缺点是必须是在一个二层网络中,毕竟下一跳的路由需要在邻居表中,否则无法通行。
在实际的生产环境中,最常用的还是vxlan模式。
Flannel在kubernetes上的应用如图所示,其中cni0为代替docker0实现的网桥。
flanneld进程
- 在每个宿主机上创建和配置flannel.1设备,这个设备就是VXLAN所需要的VTEP设备,它既有IP地址也有MAC地址。
- 连接etcd,管理可分配IP地址段资源,获取subnet lease(租约),同时监控etcd中每个pod的实际地址,flanneld一旦获取subnet租约、配置完backend,它会将一些信息写入/run/flannel/subnet.env文件。 每个节点都会在FLANNEL_NETWORK网段下划分一个不冲突的子网。
- 配置主机路由、配置ARP和FDB表。flanneld启动后在节点创建flannel.1路由信息。每启动一个节点,flaneld会到其他节点添加新节点flannel.1的ARP信息。
- 实现flannel方案对应的CNI插件。在这个过程中,flannel启动后在每台宿主机上生成他对应的CNI配置文件(就是configmap),通知集群要使用Flannel作为容器网络方案。
# cat /run/flannel/subnet.env
FLANNEL_NETWORK=192.168.64.0/20
FLANNEL_SUBNET=192.168.64.1/24
FLANNEL_MTU=1450
FLANNEL_IPMASQ=true
流程如图所示:
container1 访问 container2,相对UDP比较来看,当container1发出请求后,这个目的的地址是10.244.1.3的IP包,会先出现在docker0网桥,然后被路由到本机flanner1设备上处理,也就是说,来到了“隧道”的出口。既目的宿主机的VTEP设备。而这个设备信息正是每台宿主机上的flanneld进程负责维护的。
vxlan数据包通信流程:
1. 容器直接使用目标容器的ip访问,默认通过容器内部的eth0发送出去。
2. 报文通过veth pair被发送到vethXXX。
3. vethXXX是直接连接到网桥cni0的,报文通过虚拟bridge cni0发送出去。
4. 查找路由表,外部容器ip的报文都会转发到flannel.1上,这是一个vtep设备。
5. flannel1.1在原始IP包上添加目的vtep设备的MAC地址。通过flanneld在etcd维护的各个节点之间的路由表查询目的设备IP地址,然后以此查询flanneld在本地维护的ARP表获得目的MAC地址。 此次封装的数据帧实际上不能在宿主机二层网络传输,称为内部数据帧。
6. Linux内核在内部数据帧上添加VXLAN头,表示这是VXLAN使用的数据帧。
7. Linux将数据帧添加UDP头,但是flanne.1不知道目的主机的地址,因此flannel.1作为网桥,在二层网络进行UDP转发,依据flannel进程维护的FDB信息。
8. 接下来进行宿主机网络封包。
9. 报文通过宿主机之间的网络找到目标主机。
10. 报文继续往上,到传输层,交给监听在8285端口的flanneld程序处理。 11. 数据被解包,然后发送给flannel.1。
12. 查找路由表,发现对应容器的报文要交给cni0。
13. cni0找到连到自己的pod,把报文发送过去。
4.3 Calico
Calico是基于BGP的三层网络。能够实现没有IP封装或者网络地址转换的情况下进行通信,性能更高。
Calico主要由下面几个组件组成:
- Etcd:负责存储网络信息
- BGP Client:负责将Felix配置的路由信息分到其他节点
- Felix:Calico Agent:每个节点都需要运行,主要负责配置路由、配置ACLs、报告状态
- BGP Route Reflector: 大规模部署时需要用到,作为BGP client的中心连接点,可以避免每个节点互联
工作原理
Calico把每个操作系统的协议栈当做一个路由器,然后把所有的容器作为连在这个路由器上的网络终端,在路由器之间运行标准的路由协议——BGP的协议,然后让它们自己去学习这个网络拓扑该如何转发。所以Calico方案其实是一个纯三层的方案,也就是说让每台机器的协议栈的三层去确保两个跨主机容器之间的三层连通性。
对于控制平面,它每个节点上会运行两个主要的程序,一个是Felix,它会监听ECTD中心的存储,从它获取事件,如果用户在这台机器上加了一个IP,或者是分配了一个容器等。接着会在这台机器上创建出一个容器,并将其网卡、IP、MAC都设置好,然后在内核的路由表里面写一条,注明这个IP应该到这张网卡。绿色部分是一个标准的路由程序,它会从内核里面获取哪一些IP的路由发生了变化,然后通过标准BGP的路由协议扩散到整个其他的宿主机上,让外界都知道这个IP在这里,你们路由的时候得到这里来。
由于Calico是一种纯三层的实现,因此可以避免与二层方案相关的数据包封装的操作,中间没有任何的NAT,没有任何的overlay,所以它的转发效率可能是所有方案中最高的,因为它的包直接走原生TCP/IP的协议栈,它的隔离也因为这个栈而变得好做。因为TCP/IP的协议栈提供了一整套的防火墙的规则,所以它可以通过IPTABLES的规则达到比较复杂的隔离逻辑。
总结
Flannel最大的缺陷就是不支持ACL,即Kubernetes中的Network Policy,而Calico启动了一个Canal项目,结合了Calico和Flannel。Network Policy功能由Calico提供,network功能由Flannel提供。
canal项目已经于2018年10月停止更新。
5. 服务发现与负载均衡
kuberntes实现了服务实例间的负载均衡和不同服务间的服务发现,创造了Service对象,同时又为从集群外部访问集群创建了Ingress对象。
service
由于Pod存在生命周期,由相应controller控制,所以IP是动态的,如果其他Pod想要发现并连接这组Pod,需要通过service。其通过LabelSelector实现Pod对接。
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
上述配置将创建一个名称为“my-service”的 Service对象,它会将请求代理到使用TCP端口9376,并且具有标签 "app=MyApp" 的Pod上。
service有三种代理模式userspace、iptables、ipvs,目前默认是iptables。这种模式kube-proxy会监视kuberntes master对Service对象和Endpoints对象的添加和移除。对每个service,会配置iptables规则,从而捕获到达service的请求并重定向到相应Pod,默认请求策略是随机选择。
kubernetes的service的访问类型有三种:
- cluster: 内部访问
- ExternalName:内部访问,提供外部服务的别名
- nodeport: 外部访问
loadbanlance: 外部访问,通常需要第三方云服务商提供支持
Ingress Controller
K8S的Ingress对象提供了另一种服务暴露的方法,通过虚拟主机或者虚拟目录的方式为K8S上的所有HTTP服务提供暴露服务,还能实现 HTTPS、负载均衡、状态统计等。Ingress本质上是一组规则的集合,用于外部访问集群内服务。其需要通过Ingress Controller创建
internet--> [ Ingress ] -->[ Services ]
Ingress Controller通常和Loadbalancer一起用于执行Ingress的定义规则。Service Load Balance
Ingress出现以前,Service Load Balancer是推荐的解决Service局限性的方式。Service Load Balancer将haproxy跑在容器中,并监控service和endpoint的变化,通过容器IP对外提供4层和7层负载均衡服务。
社区提供的Service Load Balancer支持四种负载均衡协议:TCP、HTTP、HTTPS和SSL TERMINATION,并支持ACL访问控制。Custom Load Balance
虽然Kubernetes提供了丰富的负载均衡机制,但在实际使用的时候,还是会碰到一些复杂的场景是它不能支持的,比如:
- 接入已有的负载均衡设备
- 多租户网络情况下,容器网络和主机网络是隔离的,这样 kube-proxy 就不能正常工作这个时候就可以自定义组件,并代替kube-proxy来做负载均衡。
基本的思路是监控kubernetes中service和endpoints的变化,并根据这些变化来配置负载均衡器。比如weave flux、nginx plus、kube2haproxy等。