一、Kubernetes特性
1、自动装箱
建构于容器之上,基于资源依赖及其他约束自动完成容器部署且不影响其可用性,并通过调度机制混合关键型应用和非关键型应用的工作负载于一点以提高资源利用率。
2、自我修复(自愈)
支持容器故障后自动重启、节点故障后重新调度容器,以及其他可用节点、健康状态检查失败后关闭容器并重新创建等自我修复机制。
3、水平扩展
支持通过简单命令或UI手动水平扩展,以及基于CPU等资源负载率的自动水平扩展机制。
4、服务发现和负载均衡
Kubernetes通过其附加组件之一的KubeDNS(或CoreDNS)为系统内置了服务发现功能,它会为每个Service配置DNS名称,并允许集群内的客户端直接使用此名称发出访问请求,而Service则通过iptables或ipvs内建了负载均衡机制。
5、自动发布和回滚
Kubernetes支持“灰度”更新应用程序或其配置信息,它会监控更新过程中应用程序的健康状态,以确保它不会在同一时刻杀掉所有实例,而此过程中一旦有故障发生,就会立即自动执行回滚操作。
6、密钥和配置管理
Kubernetes的ConfigMap实现了配置数据与Docker镜像解耦,需要时,仅对配置做出变更而无须重新构建Docker镜像,这为应用开发部署带来了很大的灵活性。此外,对于应用所依赖的一些敏感数据,如用户名和密码、令牌、密钥等信息,Kubernetes专门提供了Secret对象为其解耦,既便利了应用的快速开发和交付,又提供了一定程度上的安全保障。
7、存储编排
Kubernetes支持Pod对象按需自动挂载不同类型的存储系统,这包括节点本地存储、公有云服务商的云存储(如AWS和GCP等),以及网络存储系统(例如,NFS、iSCSI、GlusterFS、Ceph、Cinder和Flocker等)。
8、批量处理执行
除了服务型应用,Kubernetes还支持批处理作业及CI(持续集成),如果需要,一样可以实现容器故障后恢复。
二、Kubernetes工作原理
Kubernetes使用共享网络将多个物理机或虚拟机汇集到一个集群中,在各服务器之间进行通信,该集群是配置Kubernetes的所有组件、功能和工作负载的物理平台。集群中一台服务器(或高可用部署中的一组服务器)用作Master,负责管理整个集群,余下的其他机器用作Worker Node(早期版本中也称为Minion),它们是使用本地和外部资源接收和运行工作负载的服务器。集群中的这些主机可以是物理服务器,也可以是虚拟机(包括IaaS云端的VPS)。
从抽象的视角来讲,Kubernetes还有着众多的组件来支撑其内部的业务逻辑,包括运行应用、应用编排、服务暴露、应用恢复等,它们在Kubernetes中被抽象为Pod、Service、Controller等资源类型,下面列出了几个较为常用的资源抽象。
1、Pod
Kubernetes并不直接运行容器,而是使用一个抽象的资源对象来封装一个或者多个容器,这个抽象即为Pod,它也是Kubernetes的最小调度单元。同一Pod中的容器共享网络名称空间和存储资源,这些容器可经由本地回环节口lo直接通信,但彼此之间又在Mount、User及PID等名称空间上保持了隔离。尽管Pod中可以包含多个容器,但是作为最小调度单元,它应该尽可能地保持“小”,即通常只应该包含一个主容器,以及必要的辅助型容器(sidecar)。
2、资源标签
标签(Label)是将资源进行分类的标识符,资源标签其实就是一个键值型(key/values)数据。标签旨在指定对象(如Pod等)辨识性的属性,这些属性仅对用户存在特定的意义,对Kubernetes集群来说并不直接表达核心系统语义。标签可以在对象创建时附加其上,并能够在创建后的任意时间进行添加和修改。一个对象可以拥有多个标签,一个标签也可以附加于多个对象(通常是同一类对象)之上。
3、标签选择器
标签选择器(Selector)全称为“Label Selector”,它是一种根据Label来过滤符合条件的资源对象的机制。例如,将附有标签“role:backend”的所有Pod对象挑选出来归为一组就是标签选择器的一种应用,用户通常使用标签对资源对象进行分类,而后使用标签选择器挑选出它们,例如将其创建为某Service的端点。
4、Pod控制器
尽管Pod是Kubernetes的最小调度单元,但用户通常并不会直接部署及管理Pod对象,而是要借助于另一类抽象—控制器(Controller)对其进行管理。用于工作负载的控制器是一种管理Pod生命周期的资源抽象,它们是Kubernetes上的一类对象,而非单个资源对象,包括ReplicationController、ReplicaSet、Deployment、StatefulSet、Job等。
5、服务资源(Service)
Service是建立在一组Pod对象之上的资源抽象,它通过标签选择器选定一组Pod对象,并为这组Pod对象定义一个统一的固定访问入口(通常是一个IP地址),若Kubernetes集群存在DNS附件,它就会在Service创建时为其自动配置一个DNS名称以便客户端进行服务发现。到达Service IP的请求将被负载均衡至其后的端点—各个Pod对象之上,因此Service从本质上来讲是一个四层代理服务。另外,Service还可以将集群外部流量引入到集群中来。
6、存储卷
存储卷(Volume)是独立于容器文件系统之外的存储空间,常用于扩展容器的存储空间并为它提供持久存储能力。Kubernetes集群上的存储卷大体可分为临时卷、本地卷和网络卷。临时卷和本地卷都位于Node本地,一旦Pod被调度至其他Node,此种类型的存储卷将无法访问到,因此临时卷和本地卷通常用于数据缓存,持久化的数据则需要放置于持久卷(persistent volume)之上。
7、Name和Namespace
名称(Name)是Kubernetes集群中资源对象的标识符,它们的作用域通常是名称空间(Namespace),因此名称空间是名称的额外的限定机制。在同一个名称空间中,同一类型资源对象的名称必须具有唯一性。名称空间通常用于实现租户或项目的资源隔离,从而形成逻辑分组。创建的Pod和Service等资源对象都属于名称空间级别,未指定时,它们都属于默认的名称空间“default”。
8、Annotation
Annotation(注解)是另一种附加在对象之上的键值类型的数据,但它拥有更大的数据容量。Annotation常用于将各种非标识型元数据(metadata)附加到对象上,但它不能用于标识和选择对象,通常也不会被Kubernetes直接使用,其主要目的是方便工具或用户的阅读及查找等。
9、Ingress
Kubernetes将Pod对象和外部网络环境进行了隔离,Pod和Service等对象间的通信都使用其内部专用地址进行,如若需要开放某些Pod对象提供给外部用户访问,则需要为其请求流量打开一个通往Kubernetes集群内部的通道,除了Service之外,Ingress也是这类通道的实现方式之一。
三、Kubernetes集群组件
一个典型的Kubernetes集群由多个工作节点(worker node)和一个集群控制平面(control plane,即Master),以及一个集群状态存储系统(etcd)组成。其中Master节点负责整个集群的管理工作,为集群提供管理接口,并监控和编排集群中的各个工作节点。各节点负责以Pod的形式运行容器,因此,各节点需要事先配置好容器运行依赖到的所有服务和资源,如容器运行时环境等。
Master节点主要由apiserver、controller-manager和scheduler三个组件,以及一个用于集群状态存储的etcd存储服务组成,而每个Node节点则主要包含kubelet、kube-proxy及容器引擎(Docker是最为常用的实现)等组件。此外,完整的集群服务还依赖于一些附加组件,如KubeDNS等。
1、Master组件
Kubernetes的集群控制平面由多个组件组成,这些组件可统一运行于单一Master节点,也可以以多副本的方式同时运行于多个节点,以为Master提供高可用功能,甚至还可以运行于Kubernetes集群自身之上。Master主要包含以下几个组件。
(1)API Server
API Server负责输出RESTful风格的Kubernetes API,它是发往集群的所有REST操作命令的接入点,并负责接收、校验并响应所有的REST请求,结果状态被持久存储于etcd中。因此,API Server是整个集群的网关。
(2)集群状态存储(Cluster State Store)
Kubernetes集群的所有状态信息都需要持久存储于存储系统etcd中,不过,etcd是由CoreOS基于Raft协议开发的分布式键值存储,可用于服务发现、共享配置以及一致性保障(如数据库主节点选择、分布式锁等)。因此,etcd是独立的服务组件,并不隶属于Kubernetes集群自身。生产环境中应该以etcd集群的方式运行以确保其服务可用性。
etcd不仅能够提供键值数据存储,而且还为其提供了监听(watch)机制,用于监听和推送变更。Kubernetes集群系统中,etcd中的键值发生变化时会通知到API Server,并由其通过watch API向客户端输出。基于watch机制,Kubernetes集群的各组件实现了高效协同。
(3)控制器管理器(Controller Manager)
Kubernetes中,集群级别的大多数功能都是由几个被称为控制器的进程执行实现的,这几个进程被集成于kube-controller-manager守护进程中。由控制器完成的功能主要包括生命周期功能和API业务逻辑,具体如下。
·生命周期功能:包括Namespace创建和生命周期、Event垃圾回收、Pod终止相关的垃圾回收、级联垃圾回收及Node垃圾回收等。
·API业务逻辑:例如,由ReplicaSet执行的Pod扩展等。
(4)调度器(Scheduler)
Kubernetes是用于部署和管理大规模容器应用的平台,根据集群规模的不同,其托管运行的容器很可能会数以千计甚至更多。API Server确认Pod对象的创建请求之后,便需要由Scheduler根据集群内各节点的可用资源状态,以及要运行的容器的资源需求做出调度决策,其工作逻辑如图1-12所示。另外,Kubernetes还支持用户自定义调度器。
2、Node负责提供运行容器的各种依赖环境,并接受Master的管理。每个Node主要由以下几个组件构成。
(1)Node的核心代理程序kubelet
kubelet是运行于工作节点之上的守护进程,它从API Server接收关于Pod对象的配置信息并确保它们处于期望的状态(desired state,后文不加区别地称之为“目标状态”)。kubelet会在API Server上注册当前工作节点,定期向Master汇报节点资源使用情况,并通过cAdvisor监控容器和节点的资源占用状况。
(2)容器运行时环境
每个Node都要提供一个容器运行时(Container Runtime)环境,它负责下载镜像并运行容器。kubelet并未固定链接至某容器运行时环境,而是以插件的方式载入配置的容器环境。这种方式清晰地定义了各组件的边界。目前,Kubernetes支持的容器运行环境至少包括Docker、RKT、cri-o和Fraki等。
(3)kube-proxy
每个工作节点都需要运行一个kube-proxy守护进程,它能够按需为Service资源对象生成iptables或ipvs规则,从而捕获访问当前Service的ClusterIP的流量并将其转发至正确的后端Pod对象
3、核心附件
Kubernetes集群还依赖于一组称为“附件”(add-ons)的组件以提供完整的功能,它们通常是由第三方提供的特定应用程序,且托管运行于Kubernetes集群之上。下面列出的几个附件各自为集群从不同角度引用了所需的核心功能。
·KubeDNS:在Kubernetes集群中调度运行提供DNS服务的Pod,同一集群中的其他Pod可使用此DNS服务解决主机名。Kubernetes自1.11版本开始默认使用CoreDNS项目为集群提供服务注册和服务发现的动态名称解析服务,之前的版本中用到的是kube-dns项目,而SkyDNS则是更早一代的项目。
·Kubernetes Dashboard:Kubernetes集群的全部功能都要基于Web的UI,来管理集群中的应用甚至是集群自身。
·Heapster:容器和节点的性能监控与分析系统,它收集并解析多种指标数据,如资源利用率、生命周期事件等。新版本的Kubernetes中,其功能会逐渐由Prometheus结合其他组件所取代。
·Ingress Controller:Service是一种工作于传统层的负载均衡器,而Ingress是在应用层实现的HTTP(s)负载均衡机制。不过,Ingress资源自身并不能进行“流量穿透”,它仅是一组路由规则的集合,这些规则需要通过Ingress控制器(Ingress Controller)发挥作用。目前,此类的可用项目有Nginx、Traefik、Envoy及HAProxy等。
四、Kubernetes网络模型基础
1、网络模型概述
Kubernetes的网络中主要存在四种类型的通信:同一Pod内的容器间通信、各Pod彼此之间的通信、Pod与Service间的通信,以及集群外部的流量同Service之间的通信。Kubernetes为Pod和Service资源对象分别使用了各自的专用网络,Pod网络由Kubernetes的网络插件配置实现,而Service的网络则由Kubernetes集群予以指定。为了提供更灵活的解决方式,Kubernetes的网络模型需要借助于外部插件实现,它要求任何实现机制都必须满足以下需求。
·所有Pod间均可不经NAT机制而直接通信。
·所有节点均可不经NAT机制而直接与所有容器通信。
·容器自己使用的IP也是其他容器或节点直接看到的地址。换句话讲,所有Pod对象都位于同一平面网络中,而且可以使用Pod自身的地址直接通信。
Kubernetes使用的网络插件必须能为Pod提供满足以上要求的网络,它需要为每个Pod配置至少一个特定的地址,即Pod IP。Pod IP地址实际存在于某个网卡(可以是虚拟设备)上,而Service的地址却是一个虚拟IP地址,没有任何网络接口配置此地址,它由kube-proxy借助iptables规则或ipvs规则重新定向到本地端口,再将其调度至后端Pod对象。Service的IP地址是集群提供服务的接口,也称为Cluster IP。
Pod网络及其IP由Kubernetes的网络插件负责配置和管理,具体使用的网络地址可在管理配置网络插件时指定,如10.244.0.0/16网络。而Cluster网络和IP则是由Kubernetes集群负责配置和管理,如10.96.0.0/12网络。
总结起来,Kubernetes集群至少应该包含三个网络。一个是各主机(Master、Node和etcd等)自身所属的网络,其地址配置于主机的网络接口,用于各主机之间的通信,例如,Master与各Node之间的通信。此地址配置于Kubernetes集群构建之前,它并不能由Kubernetes管理,管理员需要于集群构建之前自行确定其地址配置及管理方式。第二个是Kubernetes集群上专用于Pod资源对象的网络,它是一个虚拟网络,用于为各Pod对象设定IP地址等网络参数,其地址配置于Pod中容器的网络接口之上。Pod网络需要借助kubenet插件或CNI插件实现,该插件可独立部署于Kubernetes集群之外,亦可托管于Kubernetes之上,它需要在构建Kubernetes集群时由管理员进行定义,而后在创建Pod对象时由其自动完成各网络参数的动态配置。第三个是专用于Service资源对象的网络,它也是一个虚拟网络,用于为Kubernetes集群之中的Service配置IP地址,但此地址并不配置于任何主机或容器的网络接口之上,而是通过Node之上的kube-proxy配置为iptables或ipvs规则,从而将发往此地址的所有流量调度至其后端的各Pod对象之上。Service网络在Kubernetes集群创建时予以指定,而各Service的地址则在用户创建Service时予以动态配置。
2、集群上的通信
Kubernetes集群的客户端大体可以分为两类:API Server客户端和应用程序(运行为Pod中的容器)客户端。第一类客户端通常包含人类用户和Pod对象两种,它们通过API Server访问Kubernetes集群完成管理任务,例如,管理集群上的各种资源对象。第二类客户端一般也包含人类用户和Pod对象两种,它们的访问目标是Pod上运行于容器中的应用程序提供的各种具体的服务,如redis或nginx等,不过,这些访问请求通常要经由Service或Ingress资源对象进行。另外,第二类客户端的访问目标对象的操作要经由第一类客户端创建和配置完成后才能进行。
访问API Server时,人类用户一般借助于命令行工具kubectl或图形UI(例如Kubernetes Dashboard)进行,也可通过编程接口进行访问,包括REST API。访问Pod中的应用时,其访问方式要取决于Pod中的应用程序,例如,对于运行Nginx容器的Pod来说,其最常用工具自然是浏览器。
管理员(开发人员或运维人员)使用Kubernetes集群的常见操作包括通过控制器创建Pod,在Pod的基础上创建Service供第二类客户端访问,更新Pod中的应用版本(更新和回滚)以及对应用规模进行扩容或缩容等,另外还有集群附件管理、存储卷管理、网络及网络策略管理、资源管理和安全管理等,这些内容将在后面的章节中展开。不过,这一切的前提是要先构建出一个可用的Kubernetes集群。