第27章 Kubernetes—生产级容器集群平台
27.1 简介
27.2 核心概念
k8s为了更好的管理应用的生命周期,将不同资源对象进行了进一步的操作抽象。学习k8s实际上就是要掌握这些不同的抽象对象。
k8s中每种对象都拥有一个对应的声明式API。对象包括三大属性:元数据(metadata)、规范(spec)和状态(status)。通过这3个属性,
用户可以定义让某个对象处于给定的状态(如多少Pod运行在哪些节点上)以及表现策略(如如何升级、容错),而无需关心具体的实现细节。
当使用k8s管理这些对象时,每个对象可以使用一个外部json或者yaml模板文件来定义,通过参数传递给命令或API。每个模板文件中定义
apiVersion(如v1)、kind(如Deployment、Service)、metadata(包括名称、标签信息等)、spec(具体的定义)等信息。
基础的操作对象主要是指资源抽象对象,包括:
1.容器组(Pod)
k8s中最小的资源单位。由位于同一节点上若干容器组成,彼此共享网络命名空间和存储卷(Volume)。Pod是k8s中进行管理的
最小资源单位,是最为基础的概念。跟容器类似,pod是短暂的,随时可变的,通常不带状态。一般每个pod中除了应用容器外,还包括
一个初始的pause容器,完成网络和存储空间的初始化。
2.服务(Service)
对外提供某个特定功能的一组pod(可通过标签来选择)和所关联的访问配置。由于pod的地址是不同的,而且随时可变,直接访问pod
将无法获得稳定的业务。k8s通过服务提供唯一固定的访问地址(如ip地址或者域名),不随后面pod改变而变化。用户无需关心具体的pod
信息。
3.存储卷(Volume)
存储卷类似于docker中的概念,提供数据的持久化存储(如pod重启后),并支持更高级的生命周期管理和参数指定功能,支持多种
本地和云存储类型。
4.命名空间(Namespace)
k8s通过命名空间来实现虚拟化,将同一组物理资源虚拟化为不同的抽象集群,避免不同租户的资源发生命名冲突,另外可以进行
资源限额。
另外,为了方便操作这些基础对象,k8s还引入了控制器(Controller)的高级概念。这些控制器面向特定场景提供了自动管理pod功能,
用户使用控制器无需关心具体的pod相关细节。
控制器抽象对象主要包括:
1.副本集(ReplicaSet)
旧版本中叫做复制控制器(Replication Controller)。副本集是一个基于pod的抽象。使用它可以让集群中始终维持某个pod
的指定副本数的健康实例。副本集中的pod互相并无差异,可以彼此替换。由于操作相对底层,一般不推进直接使用。
2.部署(Deployment)
从1.2.0版本开始引入。比副本集更高级的抽象,可以管理pod或副本集,并且支持升级操作。部署控制器可以提供比副本集更方便
的操作,推进使用。
3.状态集(StatefulSet)
管理带有状态的应用。相比部署控制器,状态集可以为pod分配独一无二的身份,确保在重新调配等操作时也不会互相替换。自1.9
版本开始正式支持。
4.Daemon集(DaemonSet)
确保节点上肯定运行某个pod,一般用来采集日志(如logstash)、监控节点(如collectd)或提供存储(如glusterd)使用、
5.任务(Job)
适用于短期处理场景。任务将创建若干pod,并确保给定数目的pod最终正常退出(完成指定处理)。
6.横向Pod扩展器(Horizontal Pod Autoscaler,HPA)
类似于云里面的自动扩展组,根据pod的使用率(如cpu)自动调整一个部署里面pod的个数,保障服务可用性。
7.入口控制器(Ingress Controller)
定义外部访问集群中资源的一组规则,用来提供七层代理和负载均衡服务。
此外,还有一些管理资源相关的辅助概念,主要包括:
1.标签(Label)
键值对,可以标记到资源对象上,用来对资源进行分类和筛选。
2.选择器(Selector)
基于标签概念的一个正则表达式,可通过标签筛选出一组资源。
3.注解(Annotation)
键值对,可以存放大量任意数据,一般用来添加对资源对象的详细说明,可供其他工具处理。
4.密码数据(Secret)
存放敏感数据,例如用户认证的口令等。
5.名字(Name)
用户提供给资源的别名,同类资源不能重名。
6.持久化存储(PersistentVolume)
确保数据不丢失。
7.资源限额(Resource Quotas)
用来限制某个命名空间下对资源的使用。
8.安全上下文(Security Context)
应用到容器上的系统安全配置,包括uid、gid、capabilities、SELinux角色等。
9.服务账号(Service Accounts)
操作资源的用户账号。
27.3 资源抽象对象
k8s对集群中的资源进行了不同级别的抽象,每个资源都是一个REST对象,通过API进行操作,通过json或yaml格式模板文件进行定义。
27.3.1 容器组
在k8s中,并不直接操作容器,最小的管理单位是容器组(Pod)。容器组由一个或者多个容器组成,k8s围绕容器进行创建、调度、停止等
生命周期管理。
同一个容器组中,各个容器共享命名空间(包括网络、IPC、文件系统等容器支持的命名空间)、cgroups限制和存储卷。这意味着同一个
容器组中,各个应用可以很方便的互相进行访问,比如通过localhost地址进行网络访问,通过信号量和共享内存进行进程间通信等,类似经典
场景中运行在同一个操作系统中的一组进程。可以简单的将一个Pod当作是一个抽象的虚拟机,里面运行若干个不同的进程(每个进程实际上就是
一个容器)。
实现上,是先创建一个 gcr.io/google_containers/pause 容器,创建相关命名空间,然后创建pod中的其他应用容器,并共享pause
容器的命名空间。
组成容器组的若干容器往往是存在共同的应用目的,彼此关联十分紧密。
和其他资源类似,容器组是一个REST对象,用户可以通过yaml或者json模板文件来定义。
可以说,容器组既保持了容器轻量解耦的特性,又提供了操作的便利性,在实践中提供了比单个容器更为灵活和更有意义的抽象。
容器组生命周期包括5种状态值:
1.待定(Pending)
2.运行(Running)
3.成功(Succeeded)
4.失败(Failed)
5.未知(Unknow)
27.3.2 服务
服务的提出,主要是解决pod地址可变的问题。由于pod随时可能发生故障,并可能在其他节点上被重启,它的地址是不能保持固定的。因此,
用一个服务来代表提供某一类功能(可以通过标签来筛选)的一些pod,并分配不随pod位置变化而改变的虚拟访问地址(Cluster IP)。这也服务
微服务的理念。
服务可以分为下面几种类型:
1.ClusterIP
提供一个集群内部的地址,该地址只能在集群内解析和访问。ClusterIP是默认的服务类型;
2.NodePort
在每个集群节点上映射服务到一个静态的本地端口。从集群外部可以直接访问,并自动路由到内部自动创建的ClusterIP;
3.LoadBalancer
使用外部的路由服务,自动路由访问到自动创建的NodePort和ClusterIP;
4.ExternalName
将服务映射到externalName域指定的地址,需要1.7版本以上kube-dns的支持。
27.3.3 存储卷
存储卷(Volume)即容器挂载的数据卷,跟Pod有一致的生命周期,pod生存过程(包括重启)中,数据卷跟着存在;pod退出,则数据卷跟着
退出。
27.4 控制器抽象对象
控制器抽象对象是基于对所操作对象的进一步抽象,附加了各种资源的管理功能,目前主要包括副本集、部署、状态集、Daemon集、任务等。
1.副本集和部署
2.状态集
3.Daemon集
4.任务
5.横向Pod扩展器
27.5 其他抽象对象
1.标签
2.注解
3.选择器
4.秘密数据
5.UID和名字
6.命名空间
7.污点和容忍
27.6 快速体验
27.7 重要组件
Node上至少包括:
1.容器引擎
本地的容器依赖,目前支持docker和rkt;
2.kubelet
节点上最主要的工作代理,汇报节点状态并实现容器组的生命周期管理;
3.kube-proxy
代理对抽象的应用地址的访问,负责配置正确的服务发现和负载均衡转发规则(通常利用iptables规则);
4.辅助组件
可选,supervisord用来保持kubelet和docker进程运行,fluentd用来转发日志等。
Node节点有几个重要的信息:地址信息(Address)、状态(Condition)、容量信息(Capacity)、节点信息(Info)。
1.地址信息包括:
a)主机名(HostName)
节点所在的系统的主机别名,基本不会用到;
b)外部地址(ExternalIP)
集群外部客户端可以通过该地址访问到节点;
c)内部地址(InternalIP)
集群内可访问的地址,外部往往无法通过该地址访问节点。
状态信息包括磁盘不足(OutOfDisk)、就绪(Ready)、空余内存过低(MemoryPressure)、空余磁盘过低(DiskPressure)等。
容量信息包括常见的操作系统资源,如cpu、内存、最多存放的pod个数等。节点信息包括操作系统内核信息、k8s版本信息、docker引擎
版本信息等,会被kubelet定期汇报。
27.7.1 Etcd
27.7.2 kube-apiserver
27.7.3 kube-scheduler
27.7.4 kube-controller-manager
27.7.5 kubelet
27.7.6 kube-proxy
27.8 使用kubectl
27.8.1 获取kubectl
27.8.2 命令格式
27.8.3 全局参数
27.8.4 通用子命令
27.9 网络设计
1.场景分析,对k8s来说,典型的要考虑如下4种通信场景:
1.Pod内(容器之间)
因为容器共享了网络命名空间,可以通过lo直接通信,无需额外支持;
2.Pod之间
又区分同一个节点上和不同节点上,前者通过本地网桥通信即可,后者需要在各种绑定的网桥之间打通;
3.Pod和服务之间
因为服务是虚拟的ClusterIP,因此,需要在节点上配置代理机制(例如iptables)来映射到后端的pod;
4.外部访问服务
要从外面访问服务,必须经过负载均衡器,通过外部可用的地址映射到内部服务上。
2.直接路由
所有pod直接暴露在物理网络上,大家彼此的地址可见,不能有地址冲突,不同子网之间通过路由机制进行三层转发。此时,各个Node上会
创建chr0网桥,并且需要开启本地转发支持。
另外,配置docker服务的默认网桥,并且取消docker对iptables的自动修改。
为了让Pod可以通过Node地址来访问外网,可以配置SNAT。
3.Overlay网络