Kubernetes详解
Kubernetes什么是Kubernetes:Kubernetes,从官方网站上可以看到,它是一个工业级的容器编排平台。Kubernetes这个单词是希腊语,它的中文翻译是“舵手”或者“飞行员”。在一些常见的资料中也会看到“ks”这个词,也就是“k8s”,它是通过将8个字母“ubernete”替换为“8”而导致的一个缩写。Kubernetes 为什么要用“舵手”来命名呢?大家可以看一下这张图:这
Kubernetes
什么是Kubernetes:
Kubernetes,从官方网站上可以看到,它是一个工业级的容器编排平台。 Kubernetes
这个单词是希腊语,它的中文翻译是“舵手”或者“飞行员”。在一些常见的资料中也会看到“ks”这个词,也就是“k8s”,它是通过将8个字母“ubernete
”替换为“8”而导致的一个缩写。
Kubernetes 为什么要用“舵手”来命名呢?大家可以看一下这张图:
这是一艘载着一堆集装箱的轮船,轮船在大海上运着集装箱奔波,把集装箱送到它们该去的地方。我们之前其实介绍过一个概念叫做
container,container 这个英文单词也有另外的一个意思就是“集装箱”。Kubernetes
也就借着这个寓意,希望成为运送集装箱的一个轮船,来帮助我们管理这些集装箱,也就是管理这些容器。
这个就是为什么会选用 Kubernetes 这个词来代表这个项目的原因。
更具体一点地来说:Kubernetes 是一个自动化的容器编排平台,它负责应用的部署、应用的弹性以及应用的管理,这些都是基于容器的。
Kubernetes(分布式资源管理框架),用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes提供了应用部署,规划,更新,维护的一种机制。
提供简单的负载均衡、服务部署与弹性伸缩、服务拆分与服务发现。 Pod是Kubernetes管理的最小单位。
Etcd:
Etcd 是一种分布式 kv 存储设施, 他具有一定的一致性,高性能,高可用的方案. 类似的 zookeeper, 但没有 zookeeper 那么重型,功能也没有覆盖那么多. 简单直接的应用就是配置中心。
架构设计总览:
clients 为多个需要 配置的服务, 中间层为 多个 grpc-proxy 做均衡负载, 以免一个 proxy 挂了之后 导致单点问题.
grpc-proxy 可以 同时访问多个 etcd 服务器,进行 kv 的操作. 如果某一个 server 挂了,会自动访问别的
集群中的其他 server 以保证高可用。
Etcd cluster 至少为 3 台, 如果小于 3 台则无法进行选举,造成集群
不可用. (这里需要用 promethus 进行监控预警)
推荐在Kubernetes集群中使用Etch v3,v2版本已在Kubernetes
v1.11中弃用。
K8S的核心组件:
APIserver:所有服务访问的统一入口。
CrontrollerManager:维持副本期望数目。
Scheduler:负责介绍任务,选择合适的节点进行分配任务。
ETCD:键值对数据库,存储K8S集群所有重要信息(持久化)。
Kubelet:直接跟容器引擎交互实现容器的生命周期管理。
Kube-proxy:负责写入规则至IPTables、IPVS(负载均衡)实现服务映射访问的。
Coredns:可以为集群中的SVC创建一个域名IP的的对应关系解析。
DashBoard:给K8S集群提供一个B/S结构访问体系。
Ingress controller:官方只能实现4层代理,Ingress可以实现7层代理。
Federation:提供一个可以跨集群中心多K8S统一管理功能。
Prometheus:提供K8S集群的监控能力。
ELK:提供K8S集群日志统一分析接入平台。
Kubelet:
Kubernetes kubelet
为每个Kubernetes节点(Node)实现Pod和容器操作。
它们作为每个节点上的代理运行,无论该节点是物理服务器还是虚拟机,并在该节点上处理Pod/容器操作。kubelets将名为PodSpec的配置作为输入,并确保PodSpec中指定的容器正在运行且运行正常。
Pod:
自主式Pod:
Pod退出了,此类型的Pod不会被创建。
控制器管理的Pod:
在控制器的生命周期里,始终要维持Pod的副本数目。
网络通讯模式:
Kubernetes的网络模型假定了所有Pod都在一个可以直接连通的扁平网络空间中,这在GCE(Google Compute
Engine)里面是现成的网络模型,Kubernetes假定这个网络已经存在。而在私有云里搭建Kubernetes集群,就不能假定这个网络已经存在了。我们需要自己实现这个网络假设,将不同节点上的Docker容器之间的互相访问先打通,然后运行Kubernetes。
同一个Pod内的多个容器之间:lo
各Pod之间的通讯:Overlay Network
Pod与Service之间的通讯:各节点的Iptables规则。
网络解决方案Kubernetes+Flannel:
Flannel是CoreOS团队针对Kubernetes设计的一个网络规划服务,简单来说,它的功能是让集群中的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址。而且它还能在这些IP地址之间建立一个覆盖网络(Overlay Network),通过这个覆盖网络,将数据包原封不动的传递到目标容器内。
ETCD之Flannel提供说明:
1、存储管理Flannel可分配的IP地址段资源。
2、监控ETCD中每个Pod的实际地址,并在内存中建立维护Pod节点路由器。
不同情况下网络通信方式:
同一个Pod内部通讯:同一个Pod共享同一个网络命名空间,共享同一个Linux协议栈。
Pod1至Pod2:
1、Pod1与Pod2不在同一台主机,Pod的地址是与docker0在同一个网段的,但docker0网段与宿主机网卡是两个完全不同的IP网段,并且不同Node之间的通信只能通过宿主机的物理网卡进行。将Pod的IP和所在Node的IP关联起来,通过这个关联让Pod可以互相访问。
2、Pod1与Pod2在同一台机器,由Docker0网桥直接转发请求至Pod2,不需要经过Flannel
Pod至Service的网络:
目前基于性能考虑,全部为iptables维护和转发。
Pod至外网:
Pod向外网发送请求,查找路由器,转发数据包到宿主机的网卡,宿主网卡完成路由选择后,iptables执行Masquerade,把源IP更改为宿主网卡的IP,然后向外网服务器发送请求。
外网访问Pod:
Servcei
Kubernetes集群:
做集群最少需要三台虚拟机。 一个kubernetes对应一个集群
集群资源分类:
- 名称空间级别
- 集群级别
- 元数据型
什么是资源:
K8S中所有的内容都抽象为资源。资源实例化之后,叫做对象。
名称空间级别:
- 工作负载型资源(workload):Pod、ReplicaSet、Deployment、StatefulSet、DaemonSet、Job、CronJob(RepicationController在v1.11版本被抛弃)。
- 服务发现及负载均衡型资源(ServiceDiscovery LoadBalance):Service、Ingress、…
- 配置与存储型资源:Volume(存储卷)、CSI(容器存储接口,可以扩展各种各样的第三方存储卷)
- 特殊类型的存储卷:ConfigMap(当配置中心来使用的资源类型)、Secret(保存敏感数据)、DownwardAPI(把外部环境中的信息输出给容器)
集群级别资源:Namespace、Node、Role、ClusterRole、RoleBinding、ClusterRoleBingding
元数据类型资源:HPA、PodTemplate、LimitRange
资源清单含义:
在K8S中,一般使用yaml格式的文件来创建符合我们预期的Pod,这样的yaml文件我们一般称为资源清单。
Yaml语法:
简单说明:
是一个可读性高、用来标识数据序列的的格式。YAML的意思其实是:仍是一种标记语言,当为了强调这种语言以数据做为中心,而不是以标记语言为重点。
基本语法:
- 缩进时不允许使用Table键,只允许使用空格。
- 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可。
- #标识注释,从这个字符一直到行尾,都会被解释器忽略。
YAML支持的数据结构:
- 对象:键值对的集合,又称映射(mapping)/哈希(hashes)/字典(dictionary)
- 数组:一组按次序排列的值,又称为序列(sequence)/列表(list)
- 纯量(scalars):单个的,不可再分的值
对象类型:对象的一组键值对,使用冒号结构表示
name:Steve
age:18
Yaml也允许另一种写法,将键值对写成一个行内对象。
hash:{name:Steve,age:18}
数组类型:一组连词线开头的行,构成一个数组
- animal
- Cat
- Dog
数组也可以采用行内表示法:
animal{Cat,Dog}
纯量:纯量是最基本的、不可再分的值。以下类型都属于纯量:
- 字符串、布尔值、整数、浮点数、null
- 时间、日期
复合结构:对象和数组可以结合使用,形成复合结构。
Pod容器的生命周期:
Init容器:
Pod能够具有多个容器,应用运行在容器里面,但是它也可能有一个或多个先于应用容器启动的Init容器。
Init容器与普通的容器非常像,除了如下两点:
- Init容器总是运行到成功完成为止
- 每个Init容器都必须在下一个Init容器启动之前成功完成。
如果Pod的Init容器失败,Kubernetes会不断的重启改Pod,直到Init容器成功为止。如果Pod对应的restartPolicy为Never,它不会重新启动。
Init容器的作用:
因为Init容器具有与应用程序容器分离的单独镜像,所以它们的启动相关代码具有以下优势:
- 它们可以包含并运行实用工具,但是出于安全考虑,是不建议在应用程序容器镜像中包含这些实用工具的。
- 它们可以包含使用工具和定制化代码来安装,但是不能出现在应用程序镜像中。例如,创建镜像没必要FROM另一个镜像,只需要在安装过程中使用类似sed、awk、python或dig这样的工具。
- 应用程序镜像可以分离出创建和部署的角色,而没有必要联合它们构建一个单独的镜像。
- Init容器使用Linux Namespace,所以相对应用程序容器来说具有不同的文件系统视图。因此,它们能够具有访问Secret的权限,而应用程序容器则不能。
- 它们必须在应用程序容器启动之前运行完成,而应用程序容器是并行运行的,所以Init容器能够提供了一种简单的阻塞或延迟应用容器的启动的方法,直到满足了一组先决条件。
特殊说明:
- 在Pod启动过程中,Init容器会按顺序在网络和数据卷初始化之后启动。每个容器必须在下一个容器启动之前成功退出。
- 如果由于运行时或失败退出,将导致容器启动失败,它会根据Pod的restartPolicy指定的策略进行重试、然而,如果Pod的restartPolicy设置为Always,Init容器失败时会使用RestartPolicy策略。
- 在所有的Init容器没有成功之前,Pod将不会变成Ready状态。Init容器的端口将不会在Service中进行聚集。正在初始化中的Pod处于Pending状态,但应该会将Initializing状态设置为true
- 如果Pod重启,所有Init容器必须重新执行
- #对Init容器spec的修改被限制在容器image字段,修改其他字段都不会生效。更改Init容器的image字段,等价于重启改Pod。
- Init容器具有应用容器的所有字段。除了readinessProbe,因为Init容器无法定义不同于完成(completion)的就绪(readiness)之外的其他状态。这会在验证过程中强制执行
- 在Pod中的每个app和Init容器的名称必须唯一;与任何其他容器共享同一个名称,会在验证时抛出错误。
容器探针:
探针是由Kubelet对容器执行的定期诊断。要执行诊断,kubelet调用由容器实现的Handler。
有三种类型的处理程序:
- ExecAction:在容器内执行指定命令。如果命令退出时返回码为0则认为诊断成功。
- TCPSockerAction:对指定端口上的容器的IP地址进行TCP检查。如果端口打开,则诊断被认为是成功的。
- HTTPGetAction:对指定的端口和路径上的容器的IP地址HTTP
Get请求。如果响应的状态码大于等于200且小于400,则诊断被认为是成功的。
每次探测都将会获得以下三种结果之一:
- 成功:容器通过了诊断。
- 失败:容器为通过诊断。
- 未知:诊断失败,因此不会采取任何行动。
探测方式:
- livenessProbe:指示容器是否正在运行。如果存活探测失败,则kubelet会杀死容器,并且容器将受到其重启策略的影响。如果容器不提供存活探针,则默认状态为Success。
- ReadinessProbe:指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与Pod匹配的所有Service的端点中删除该Pod的IP地址。初始延迟之前的就绪状态默认为Failure。如果容器不提供就绪指针,则默认状态为Success。
Pod phase可能存在的值:
挂起(Pending):
Pod已被Kubernetes系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度Pod的时间和通过网络下载镜像的时间,这可能需要花点时间。
运行中(Running):
该Pod已经绑定到了一个节点上,Pod中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态。
成功(Succeeded):
Pod中的所有容器都被成功终止,并且不会再重启。
失败(Failed):
Pod中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说,容器以非0状态退出或者被系统终止。
未知(Unknown):
因为某些原因无法取得Pod的状态,通常是因为与Pod所在主机通信失败。
控制器:
什么是控制器:
Kubernetes中内建了很多controller(控制器),这些相当于一个状态机,用来控制Pod的具体状态和行为。
控制器又被称为工作负载,pod通过控制器实现应用的运维,比如伸缩、升级等。
控制器类型:
- ReplicationController 和 ReplicaSet
- Deployment:适合无状态的服务部署
- DaemonSet:一次部署,所有的node节点都会部署
- StateFulSet:适合有状态的服务部署
- Job/CronJob:一次性的执行任务/周期性的执行任务
- Horizontal Pod Autoscaling
ReplicationController 和replicaset控制器:
- 确保POD资源独享的数值精确反应期望值
- 确保POD健康运行:探测到期POD对象因工作节点故障而不可用时,会自动由调度器调度至其他节点创建缺失的POD副本。
- 弹性伸缩:可通过replicaset控制器动态调整相关POD资源对象数量,必要时还可以通过HPA 控制器实现POD资源规模的自动伸缩。
- replicaset支持集合式的selector;
Deployment控制器:
主要职责是为了保证Pod资源的健康运行,其不同于replicaset(副本集、容器副本)的功能:
- 事件和状态查看:必要时可以查看deployment(调度、部署)对象升级的详细进度和状态
- 回滚:升级操作完成后发现问题,支持使用回滚机制将应用程序返回到前一个由用户指定的历史记录版本中
- 版本记录:对deployment 对象的每一次升级操作都予以保存,以供后续可能的回滚操作。
- 暂停和启动:对于每一次更新,都能够随时暂停和启动
- 多种自动更新方案:一个是recreate,及重建机制,全面停止、删除旧有的POD后用心版本替代,另一种是rollingupdate,及滚动升级机制,逐步替换旧有的POD到新版本。
Deployment为Pod和ResplicaSet提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController来方便的管理应用。典型的应用场景包括:
- 定义Deployment来创建Pod和ReplicaSet
- 滚动升级和回滚应用
- 扩容和缩容
- 暂停和继续Deployment
Deployment更新策略:
Deployment可以保证在升级时只有一定数量的Pod是down的。默认的,它会确保至少有比期望的Pod数量少一个是up状态(最多一个不可用)。
Deployment同时也可以确保只创建出超出期望数量的一定数量的Pod。默认的,它会确保最多比期望的Pod数量多一个的Pod是up的(最多一个surge)
未来的Kubernetes版本中,将从1-1变成25%-25%
Rollover(多个rollout并行):
假如您创建了一个有5个nignx:1.7.9 replica的Deployment,但是当还要3个的nignx:1.7.9
replica创建出来的时候您就会开始更新含有5个nignx:1.9.1replica的Deployment。在这种情况下,Deployment会立即杀掉已创建的3个nignx:1.7.9的Pod,并开始创建nignx:1.9.1的Pod。它不会等到所有的5个nignx:1.7.9的Pod都创建完成后才开始改变航道。
清理Policy(方针、政策):
您可以通过设置.spec.revisonHistoryLimit项来指定deployment最多保留多少revision历史记录。默认的会保留所有的revision;如果将该项设置为0,Deployment就不允许回退了。
Daemonset控制器:
用于在集群中的全部节点(Node)上同时运行一份指定的Pod资源副本,后续新加入集群的节点也会自动创建一个相关的Pod对象,当从集群中移除节点时,此类Pod对象也将被自动回收而无需重建,管理员可使用节点标签进行定义节点相关属性,然后使用节点标签选择器在特定节点上运行Pod对象。删除DaemonSet将会删除它创建的所有Pod。
应用场景:
- 运行集群存储的守护进程,如各节点上运行glusterd或ceph
- 在各节点上运行日志收集守护进程,如fluentd和logstash
- 各个节点上运行监控系统的代理程序。
SatefulSet控制器
StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计),其应用场景包括:
- 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现
- 稳定的网络标识,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP 的 Service)来实现。
- 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须是Running和Ready状态),基于init containers来实现。
- 有序收缩、有序删除(即从N-1到0)
- 解决Pod的独立生命周期,保持Pod启动顺序和唯一性
- 稳定,唯一的网络标识符,持久存储(例如:etcd配置文件,节点地址发生变化,将无法使用)
- 有序,优雅的部署和扩展、删除和终止(例如:mysql主从关系,先启动主,再启动从)
- 有序,滚动更新
- 应用场景:例如数据库
Job 控制器:
负责批量处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束。
用户调配Pod对象执行一次性任务,容器中的进程完成任务后容器不会进行重启,而是将其置于completed(完成)状态,若容器中的进程因错误而终止,则需要依据重启策略判断是否需要重启,未运行完成的Pod若节点故障,则其会被调度至其他节点进行处理。
运行方式:
- 单工作队列的串行式Job,及以多次一次性的作业方式串行执行多次作业,直至满足期望的次数。
- 多工作队列的并行式Job:
这种方式可以设置工作队列数,每个队列仅负责运行一个作业,也可以使用有限队列运行较多作业,即队列数小于总作业数,相当于多个串行队列一起运行
CronJob Spec:
- spec.template格式同Pod
- RestartPolicy仅支持Never或OnFailure
- 单个Pod时,默认Pod成功运行后Job即结束。
- spec.completions标志Job结束需要成功运行的Pod个数,默认为1
- spec.parallelism标志并行运行的Pod的个数,默认为1
- spec.activeDeadlineSeconds标志失败Pod的重试最大时间,超过这个时间不会继续重试。
Cronjob 控制器:
Cron Job:管理基于时间的Job,即:
- 在给定时间点只运行一次。
- 周期性地在给定时间点运行。
用于管理Job控制器资源的运行时间,job控制器定义的作业做任务在执行控制器资源创建之后便会立即执行,但cronjob可以以类似Linux系统的周期性任务计划的方式控制器运行的时间点击重复运行的方式,具体如下:
- 在未来某一时间运行作业一次
- 在指定的时间点重复运行作业
crpnjob控制器在指定的时间点时,"" 和 "*"意义相同,都表示任何可用的有效值。
Horizontal Pod Autoscaling控制器:
应用的资源使用率通常都有高峰和低谷的时候,如何肖峰填谷,提高集群的整体资源利用率,让service中的Pod个数自动调整呢?这就有赖于Horizontal
Pod Autoscaling了,顾名思义,使Pod水平自动缩放。
RS与RC与Deployment关联
RC(ReplicationController)主要的作用就是用来确保容器应用的副本数始终保持在用户定义的副本数。即如果有容器异常退出,会自动创建新的Pod来代替;而如果异常多出来的容器也会自动回收。
Kubernetes官方建议使用RS(ReplicaSet)替代RC(ReplicationController)进行部署,RS跟RC没有本质的不同,只是名字不一样,并且RS支持集合式的selector。
Service的概念
Kubernetes service定义了这样一种抽象:一个Pod的逻辑分组,一种可以访问它们的策略—通常称为微服务。这一组Pod能够被Service访问到,通常是通过Label Selector。
Service能够提供负载均衡的能力,但是在使用上有以下权限:
- 只提供4层负载均衡的能力,而没有7层功能,但有时我们可能需要的匹配规则来转发请求,这点上4层负载均衡是不支持的。
Service的类型:
Service在K8S中有4中类型
- Clusterip:默认类型,自动分配一个仅Cluster内部可以访问的虚拟IP
- NodePort:在ClusterIP基础上为Service在每台机器上绑定一个端口,这样就可以通过NodePort来访问。
- LoadBalancer:在NodePort的基础上,借助cloud provider创建一个外部负载均衡器,并将请求转发到NodePort。
- ExternalName:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有Kubernetes1.7或更高版本的Kube-dns才支持。
VIP和Service代理:
在Kubernetes集群中,每个Node运行一个kube-proxy进程。Kube-proxy负责为Service实现了一种VIP(虚拟IP)的形式,而不是ExternalName的形式。在Kubernetes
v1.0版本,代理完全在userspace。在Kubernetes
v1.1版本,新增了iptables代理,但并不是默认的运行模式。从Kubernetes
v1.2起,默认就是iptables代理。在Kubernetes v1.8.0-beta.0中,添加了ipvs代理。 在Kubernetes
1.14版本开始默认使用ipvs代理, 在Kubernetes v1.0版本,Service是4层(TCP/UDP over IP)概念。在Kubernetes v1.1版本,新增了Ingress API(beta版),用来表示”7层”(HTTP)服务。
ClusterIP:
ClusterIP主要在每个Node节点使用iptables,将发向clusterIP对应端口的数据,转发到kube-proxy中。然后kube-proxy自己内部实现有负载均衡的方法,并可以查询到这个service下对应的Pod的地址和端口,进而把数据转发给对应的Pod的地址和端口。
为了实现图上的功能,主要需要以下几个组件的协同工作:
- apiserver用户通过kubectl命令想apiserver发送创建service的命令,apiservice接收到请求后将数据存储到etcd中。
- kube-proxy kubernetes的每个节点中都有一个叫做kube-proxy的进程,这个进程负责感知service,pod的变化,并将变化的信息写入本地的iptables规则中
- Iptables使用NAT等技术将virtuallP的流量转至endpoint中。
Headless Service:
有时不需要或不想要负载均衡,以及单独的Service IP。遇到这种情况,可以通过指定的Cluster
IP(spec.clusterIP)的值为 “None”来创建Headless
Service。这类Service并不会分配ClusterIP,kube-proxy不会处理它们,而且平台也不会为它们进行负载均衡和路由。
NodePort:
NodePort的原理在于在node上开了一个端口,将向该端口的流量导入到kube-proxy,然后由kube-proxy进一步到给对应的pod。
LoadBalancer:
Loadbalancer和nodePort其实是同一种方式, 区别在于loadbalancer比nodePort多一步,就是可以调用cloud
provider去创建LB来向节点导流。
ExternalName:
这种类型的Service通过返回cname和它的值,可以将服务映射到externalName字段的内容(例如:hub.atguigu.com)。ExternalName
Service是Service的特例,它没有selector,也没有定义任何的端口和Endpoint。相反的,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式提供服务。
Service Ingress
概述
kubernetes 提供了两种内建的负载均衡机制,一种是位于传输层的TCP/IP
service资源,其实现的是TCP负载均衡器,另一种是ingress资源,其实现的是HTTP(S)负载均衡器。
TCP负载均衡器
iptables 和 ipvs均实现的是四层调度,其不能基于URL 的请求调度机制,其也不支持为此类负载均衡配置任何类型的健康检查机制。
ingress 和 ingress controller
ingress 是kubernetes API
的标准资源类型之一,其其实是一组基于DNS名称或URL路径把请求转发至service资源的规则,用于将集群外部的请求流量转发至集群内部完成服务发布,ingress
资源自身并不能进行"流量穿透" ,其仅仅是一组路由规则的集合,这些规则要发挥相应的作用,则需要ingress
controller,其可监听套接字,然后给据这些规则的匹配机制路由请求流量。
注意 :
ingress 不同于deployment,其不是直接运行与kube-controller-manager的一部分,其是kubernetes集群的一个重要附件,需要单独安装才能使用。
ingress
控制器可以由任何具有反向代理(http/https)功能的服务器程序实现,如nginx、envoy、haproxy、vulcand和traefik等,ingress控制器自身也是运行与集群中的POD资源对象,其与北代理的运行的POD资源的应用运行于同一网络中。另外:
ingress控制器可基于ingress资源定义的规则将客户端请求流量直接转发到service对应的后端POD资源上,其会绕过service资源,省去了kube-proxy实现的端口代理开销。
ConfigMap描述信息
ConfigMap功能在Kubernetes1.2版本中引入,许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。ConfigMap
API给我们提供了向容器中注入配置信息的机制,ConfigMap可以用来保存单个属性,也可以用来保存整个配置文件或者JSON二进制大对象。
Secret存在意义:
Secret解决了密码、token、密钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者Pod
Spec中。Secret可以以Volume或者环境变量的方式使用。
Secret有三种类型:
- Service Accout:用来访问Kubernetes API,由Kubernetes自动创建,并且会自动挂载到Pod的/run/secret/kubernetes.io/serviceaccount目录中。
- Opaque:base64编码格式的Secret,用来存储密码、密钥等。
- Kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息。
Service Account:
Service Account用来访问Kubernetes
API,由Kubernetes自动创建,并且会自动挂载到Pod的/run/secret/kubernetes.io/serviceaccount目录中。
Opaque Secret
Opaque类型的数据是一个map类型,要求value是base64编码格式;
Volume
容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器奔溃时,
Kubelet会重启它,但是容器中的文件将丢失—容器以干净的状态(镜像最初的状态)重新启动。其次,在Pod中同时运行多个容器时,这些容器之间通常需要共享文件。Kubernetes中的volume抽象就很好的解决了这些问题。
背景:
Kubernetes中的卷有明确的寿命—与封装它的Pod相同。所以,卷的生命比Pod中的所有容器都长,当这个容器重启时数据仍然得以保存。当然,当Pod不再存在时,卷也将不复存在。也许更重要的是,kubernetes支持多种类型的卷,Pod可以同时使用任意数量的卷。
卷的类型:
emptyDir:
当Pod被分配给节点时,首先创建emptyDir卷,并且只要该Pod在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。Pod中的容器可以读取和写入emptyDir卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上,当出于任何原因从节点中删除Pod时,empty中的数据将被永久删除。
emptyDir的用法有:
- 暂存空间,例如用于基于磁盘的合并排序
- 用作长时间计算崩溃恢复时的检查点
- Web服务器容器提供数据时,保存内容管理器容器提取的文件。
hostPath
hostPath卷将主机节点的文件系统中的文件或目录挂载到集群中。
hostPath的用法如下:
- 运行需要访问Docker内容的容器:使用/var/lib/docker的hostPath
- 在容器中运行cAdvisor;使用/dev/cgroups的hostPath
使用这种卷类型时请注意,因为:
- 由于每个节点上的文件都不同,具有相同配置(例如从podTemplate创建)的pod在不同节点上的行为可能会有所不同
- 当kubernetes按照计划添加资源感知调度时,将无法考虑hostPath使用的资源
- 在底层主机上创建的文件或目录只能由root写入。您需要在特权容器中以root身份运行进程,或修改主机上的文件权限以便写入hostPath卷。
PV-PVC
PersistentVolume(PV):
是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样,PV是Volume之类的卷插件,但具有独立于使用PV的Pod的生命周期。此API对象包含存储实现的细节,即NFS、iSCSI或特定于云供应商的存储系统。
PersistentVolumeClaim(PVC):
是用户存储的请求。它与Pod相似,Pod消耗节点资源,PVC消耗PV资源。Pod可以请求特定级别的资源(CPU和内存)。声明可以请求特定的大小和访问模式(例如,可以以读/写一次或
只读多次模式挂载)
静态pv:
集群管理员创建一些pv。它们带有可供群集用户使用的实际存储的细节。它们存在于Kubernetes API中,可用于消费。
动态:
当管理员创建的静态PV都不匹配的PersistentVolumeClaim时,集群可能会尝试动态地为PVC创建卷。此配置基于storageClasses:PVC必须请求[存储类],并且管理员必修创建并配置该类才能进行动态创建,声明该类为“”可以有效地禁用其动态配置。
要启用基于存储级别的动态存储配置,集群管理员需要启用API
Service上的DefaultStorageClass[准入控制器]。例如,通过确保DefaultStoragClass 位于API
Service组件的–admission-control标志,使用逗号分隔的有序值列表中,可以完成此操作。
绑定:
Master中的控制环路监视新的PVC,寻找匹配的PV(如果可能),并将它们绑定在一起。如果为新的PVC动态调配PV,则该环路将始终该PV绑定到PVC。否则,用户总会得到它们所请求的存储,但是容量可能超出要求的数量。一旦PV和PVC绑定后,PersistentVolumeClaim绑定是排他性的,不管它们是如何绑定的。PVC跟PV绑定是一对一的映射。
持久化卷声明的保护:
PVC保护的目的是确保由pod正在使用的PVC不会从系统中移除,因为如果被移除的话可能会导致数据丢失
当启用PVC保护alpha功能时,如果用户删除了一个pod正在使用的PVC,则该PVC不会被立即删除。PVC的删除将被推迟,直到PVC不再被任何pod使用。
持久化卷类型:
PV访问模式:
PersistentVolume可以以资源提供者支持的任何方式挂载到主机上。如下表所示,供应商具有不同的功能,每个PV的访问模式都将被设置为该卷支持的特定模式。例如,NFS可以支持多个读/写客户端。但特定的NFS PV可能以只读方式导出到服务器上。每个PV都有一套自己的用来描述特定功能的访问模式。
- ReadWriteOnce—该卷可以被单个节点以读/写模式挂载
- ReadOnlyMany—该卷可以被多个节点以只读模式挂载
- ReadWriteMany—该卷可以被多个节点以读/写模式挂载
在命令行中,访问模式缩写为:
- RWO–ReadWriteOnce
- ROX–ReadOnlyMany
- RWX–ReadWriteMany
回收策略:
- Retain(保留)—手动回收
- Recycle(回收)—基本擦除
- Delete(删除)—关联的存储资产(例如AWS E8S、GCE PD、Azure Disk和OpenStack Cinder卷)将被删除 当前,只有NFS和HostPath支持回收策略。AWS E8S、GCE PD、Azure Disk和Cinder卷支持删除策略。
状态:
卷可以处于以下的某种状态:
- Available(可用)—一块空闲资源还没有被任何声明绑定。
- Bound(已绑定)—卷已经被声明绑定。
- Released(已释放)—声明被删除,但是资源还未被集群重新声明
- Failed(失败)—该卷自动回收失败
命令行会显示绑定到PV到PVC的名称
关于StatefulSet
StatefulSet的启动顺序:
- 有序部署:部署StatesfulSet时,如果有多个Pod副本,它们会被顺序地创建(从0到N-1)并且,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态。
- 有序删除:当Pod被删除时,它们被终止的顺序是从N-1到0。
- 有序扩展:当对Pod执行扩展操作时,与部署一样,它前面的Pod必须都处于Running和Ready状态。
StatefulSet使用场景:
- 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现。
- 稳定的网络标识符,即Pod重新调度后其PodName和HostName不变。
- 有序部署,有序扩展,基于init containers来实现。
- 有序收缩
Scheduler(调度):
Scheduler是Kubernetes的调度器,主要任务是把定义的pod分配到集群的节点上。听起来非常简单,但有很多要考虑的问题:
- 公平:如何保证每个节点都能被分配资源
- 资源高效利用:集群所有资源最大化被使用
- 效率:调度的性能更好,能够尽快的对大批量的pod完成调度工作
- 灵活:允许用户根据自己的需求控制调度的逻辑
Scheduler是作为单独的程序运行的,启动之后会一监听API
Service,获取PodSpec.NodeName(节点名称)为空的Pod,对每个pod都会创建一个binding,表明该pod应该放到哪个节点上。
调度过程:
调度分为几个部分:首先是过滤掉不满足条件的节点,这个过程称为predicate;然后对通过的节点按照顺序优先级排序,这个是priority;最后从中选择优先级最高的节点。如果中间任何一步有错误,就直接返回错误。
如果predicate过程中没有合适的节点,pod会一直在pending状态,不断重试调度,直到节点满足条件。经过这个步骤,如果有多个节点满足条件,就继续priorities(优先事项)过程,按照优先级大小对节点排序。
优先级由一系列键值对组成,键是该优先级项的名称,值是它的权重(该项的重要性)。
这些优先选项包括:
- LeastRequestedPriority:通过计算CPU和Memory的使用率来决定权重,使用率越低权重越高。换句话说,这个优先级指标倾向于资源使用比例更低的节点。
- BalancedResourceAllocation:节点上CPU和Memory使用率越近,权重越高。这个应该和上面的一起使用,不应该单独使用。
·ImageLocalityPriority:倾向于已经有要使用镜像的节点,镜像总大小值越大,权重越高。通过算法对所有的优先级项目和权重进行计算,得出最终的结果。
自定义调度器:
除了Kubernetes自带的调度器,你也可以编写自己的调度器。通过spec:schedulername参数指定调度器的名字,可以为pod选择某个调度器进行调度。比如下面的pod选择my-scheduler进行调度,而不是默认的default-scheduler:
节点亲和性:
pod.spec.nodeAffinity
- preferredDuringSchedulinglgnoredDuringExecution:软策略
- requiredDuringSchedulinglgnoredDuringExecution:硬策略
键值运算关系:
- In:label的值在某个列表中
- Notln:label的值不在某个列表中
- Gt:label的值大于某个值
- Lt:label的值小于某个值
- Exists:某个label存在
- DoesNotExist:某个label不存在
Taint和Toleration(污点和容忍)
几点亲和性,是pod的一种属性(偏好或硬性要求),它使pod被吸引到类特定的节点。Taint则相反,它使节点能够排斥一类特定的pod。
Taint额Toleration相互配合,可以用来避免pod被分配到不合适的节点上,每个节点都可以应用一个或多个taint,这表示对于那些不能容忍这些taint的pod,是不会被该节点接受的。如果亮toleration应用于pod上,则表示这些pod可以(但不要求)被调度到具有匹配的taint的节点上。
污点(Taint):
污点的组成:
使用Kubectl
taint命令可以给某个Node节点设置污点,Node被设置上污点之后就和Pod之间存在了一种相斥的关系,可以让Node拒绝Pod的调度执行,甚至将Node已经存在的Pod驱逐出去。
每个污点的组成如下:
Key-value:effect
每个污点有一个key和value作为污点的标签,其中value可以为空,effect(影响)描述污点的作用。当前taint
effect支持如下三个选项: ·NoSchedule:表示K8S将不会将Pod调度到具有该污点的Node上
·PreferNoSchedule:表示K8S将尽量避免将Pod调度到具有该污点的Node上。
·NoExecute:表示K8S将不会将Pod调度到具有该污点的Node上,同时会将Node上已经存在的Pod驱逐出去。
污点的设置、查看、和去除:
容忍(Toleration):
设置了污点的Node将根据taint的effect:NoSchedule、PreferNoSchedule、NoExecute和Pod之间产生互斥的关系,Pod将在一定程度上不会被调度到Node上。但我们可以在Pod上设置容忍(Toleration),意思是设置了容忍的Pod将可以容忍污点的存在,可以被调度到存在污点的Node上。
- 其中Key、value、effect要与Node上设置的taint保持一致
- operator的值为Exists将会忽略value值
- tolerationSeconds用于描述当Pod需要被驱逐时可以在Pod上继续保留运行的时间。
当不指定key值时,表示可以容忍所有的污点key:
- tolerations:
- operator: “Exists”
当不指定effect值时,表示容忍所有的污点作用:
- tolerations:
- key:”key”
- Operator:”Exists”
有多个Master存在时,防止资源浪费,可以如下设置:
Kubectl taint nodes Node-Name node-role.kubernetes.io/master=:PerferNoSchedule
指定调度节点:
-
Pod.spec.nodeName将Pod直接调度到指定的Node节点上,会跳过Scheduler的调度策略,该匹配规则是强制匹配。
-
Pod.spec.nodeSelector:通过kubernetes的label-selector机制选择节点,由调度器调度策略匹配label,而后调度Pod到目标节点,该匹配规则属于强制约束。
安全
机制和说明
Kubernetes作为一个分布式集群的管理工具,保证集群的安全性是其一个重要的任务。API Service是集群内部各个组件通信的中介,也是外部控制的入口。所以Kubernetes的安全机制基本就是围绕保护API Service来设计的。Kubernetes使用了认证(Authentication)、鉴权(Authorization)、准入机制(AdmissionControl)三步来保证API Service的安全。
Authentication(认证)
- HTTP Token认证:通过一个Token来识别合法用户
HTTP
Token的认证是用一个很长的特殊编码方式的并且难以被模拟的字符串。Token来表达客户的一种方式。Token是一个很长的很复杂的字符串,每一个Token对应一个用户名存储在API
Service能访问的文件中,当客户端发起API调用请求时,需要在HTTP Header里放入Token
- HTTP Base认证:通过用户名+密码 的方式认证
用户名+:+密码 用BASE64算法进行编码后的字符串放在HTTP Request中的Heather
Authorization域里发送给服务端,服务端收到后进行编码,获取用户名及密码。
- 最严格的HTTPS证书认证:基于CA跟证书签名的客户端身份认证方式
HTTPS证书认证
需要认证的节点:
两种类型:
- Kubernetes组件对API Server的访问:kubectl、Controller Manager、Scheduler、kubelet、kube-proxy
- kubernetes管理的Pod对容器的访问:Pod(dashborad也是以Pod形式运行)
安全性说明:
- Controller Manager、Scheduler与API Server在同一台机器上,所以直接使用API Server的非安全端口访问,–insecure-bind-address-127.0.0.1
- kubectl、kublelet、kube-proxy访问API就都需要证书进行HTTPS双向认证。
证书颁发:
- 手动签发:通过K8S集群的跟ca进行签发HTTPS证书
- 自动签发:kubelet首次访问API Server时,使用token做认证,通过后,Controller Manager会为kubelet生成一个证书,以后的访问都是用证书做认证了。
Kubeconfig
kubeconfig文件包含集群参数(CA证书、API
Server),客户端参数(上面生成的证书和私钥),集群context信息(集群名称、用户名)。Kubernetes组件通过启动时指定不同的kubeconfig文件可以切换到不用的集群。
ServerAccount(服务器帐户)
Pod中的容器访问API
Server。因为Pod的创建,销毁是动态的,所以要为它手动生成证书就不可行了。kubernetes使用了Server
Account解决Pod访问API Server的认证问题。
Secret与SA的关系
Kubernetes设计了一种资源对象叫做Secret,分为两类,一种是用于ServerAccount的service-account-token,另一种是用于保存用户自定义保密信息的Opoque。ServerAccount中用到包含三个部分:Token、ca.crt、namespace
- token是使用API Server私钥签名的JWT。用于访问API Server时,Server端认证。
- ca.crt根证书。用于client端验证API Server发送的证书
- namespace,标识这个server-account-token的作用域名空间
默认情况下,每个namespace都会有一个ServiceAccount,如果Pod在创建期间没有指定的ServiceAccount,就会使用Pod所属的namespace的ServiceAccount
Authorization(授权)
上面认证过程,只是确认通信的双方都确认了对方是可信的,可以相互通信。而鉴权是确定请求方有哪些资源的权限。API Server目前支持以下几种授权策略(通过API Server的启动参数”–authorization-mode”设置)
- AlwaysDeny:表示拒绝所有的请求,一般用于测试
- AlwaysAllow:允许接收所有请求,如果集群不需要授权流程,则可以采用该策略
- ABAC(Attribute-Based Access Control):基于属性的访问控制,表示使用用户配置的授权规则对用户请求进行匹配和控制
- Webbook:通过调用外部REST服务对用户进行授权
- RBAC(Role-Based-Access-Control):基于角色的访问控制,现行默认规则。
RBAC授权模式:
RBAC(Role-Based-Access-Control)基于角色的访问控制,在Kubernetes1.5中引入,现行版本成为默认标准。相对其他访问控制,拥有以下优势:
- 对集群中的资源和非资源均拥有完整的覆盖
- 整个RBAC完全由几个API对象完成,同其他API对象一样,可以用kubectl或API进行操作
- 可以在运行时进行调整,无需重启API Server
需要注意的是Kubernetes并不会提供用户管理,那么User、Group、ServerAccount指定的用户又是从哪里来的呢?Kubernetes组件(kubectl、kube-proxy)或是其他自定义的用户在想CA申请证书时,需要提供一个证书请求文件。
API Server会把客户端证书的CN字段作为User,把names.0字段作为Group。 Kubelet使用TLS
Bootstaping认证时,API Server可以使用Bootstrap Token或者Token。 authentication
file验证=token,无论哪一种,kubernetes都会为token绑定一个默认的User和Group。
Pod使用ServiceAccount认证时,service-account-token中的JWT会保存User信息。
有了用户信息,再创建一对角色/角色绑定(集群角色/集群角色绑定)资源对象,就可以完成权限绑定了。
Role and ClusterRole
在RBAC
API中,Role表示一组规则权限,权限只会增加(累加权限),不存在一个资源一开始就有很多权限而通过RBAC对其进行减少的操作;Role可以定义在一个namespace中,如果想要跨namespace则可以创建ClusterRole
ClusterRole具有与Role相同的权限角色控制能力,不同的是ClusterRole是集群级别的,ClusterRole可以用于:
- 集群级别的资源控制(例如node访问权限)
- 非资源型endpoints(例如/healthz访问)
- 所有命名空间资源控制(例如pods)
RoleBinding and ClusterRoleBinding
RoleBinding可以将角色中定义的权限授权用户或用户组,RoleBinding包含一组权限列表(subjects),权限列表中包含有不同形式的待授予权限资源类型(users,groups,or
service
accounts);RoleBinding同样包含对被Bind的Role引用;RoleBinding适用于某个命名空间内授权,而ClusterRoleBinding适用于某个命名空间内授权,而ClusterRoleBinding适用于集群范围内的授权。
将default命名空间的pod-reader
Role授予jane用户,此后jane用户在default命名空间中将具有pod-reader的权限。
RoleBinding同样可以引用ClusterRole来对当前namespace内用户、用户组或ServiceAccount进行授权,这种操作允许集群管理员在整个集群内定义一些通用的ClusterRole,然后在不同的namespace中使用RoleBinding。
例如,以下RoleBinding引用了一个ClusterRole。这个ClusterRole具有整个集群内对secrets的访问权限;但是其授权用户dave只能访问development空间中的secrets(因为RoleBinding定义在development命名空间)
使用ClusterRoleBinding可以对整个集群中的所有命名空间资源权限进行授权;以下ClusterRoleBinding样例展示了授权manager组内所有用户在全部命名空间中对secrets进行访问。
Resources
Kubernetes集群内一些资源一般以其名称字符串来表示,这些字符串一般会在API的URL地址中出现;同时某些资源也会包含子资源。例如logs资源就属于pods的子资源,API中样例如下:
如果要在RBAC授权模型中控制这些子资源的访问权限,可以通过/分隔符来实现。以下是一个定义pods资源logs访问权限的Role定义样例:
To subjects
RoleBinding和ClusterRoleBinding可以将Role绑定到Subjects可以是groups、users或者service
accounts。
Subject中Users使用字符串表示,它可以是一个普通的名字字符串,如”alice”;也可以是email格式的邮箱地址,如”wangynaglinux@163.com”;甚至是一组字符串形式的数字ID。但是Users的前缀system:是系统保留的,集群管理员应该确保普通用户不会使用这个前缀格式。
Groups书写格式与Users相同,都为一个字符串,并且没有特定的格式要求:同样ststem前缀为系统保留。
实践:创建一个用户只能管理dev空间
准入控制
准入控制是API Service的插件集合,通过添加 不同的插件,实现额外的准入控制规则。甚至API Server的一些主要功能都需要通过Admission Controller实现,比如ServiceAccount
官方文档上有一份针对不同版本的准入控制器推荐列表,其中最新的1.14的推荐列表是:
列举几个插件的功能:
- NamespaceLifecycle(命名空间生命周期):防止在不存在的namespace上创建对象,防止删除系统预置namespace,删除 namespace时,连带删 除它的所有的资源对象。
- LimitRanger(限制器):确保请求的资源不会超过资源所在namespace的LimitRange的限制。
- ServiceAccount(服务账户):实现了自动化添加ServiceAccount。
- ResourceQuota(资源配额):确保请求的资源不会超过资源的ResourceQuota限制。
Helm(舵)
在没使用helm之前,向kubernetes部署应用,我们要依次部署deployment、svc等,步骤较繁琐。况且随着很多项目微服务化,复杂的应用在容器中部署以及管理显得较为复杂,helm通过打包的方式,支持发布的版本管理和控制,很大程度上简化了kubernetes应用的部署和管理。
Helm本质就是让K8S的应用管理(Deployment、Service等)可配置,能动态生成。通过动态生成k8s资源清单文件(deployment.yaml、service.yaml)。然后调用kubectl自动执行k8s资源部署。
Helm是官方提供的类似于YUM的包管理器,是部署环境的流程封装。Helm有两个重要的概念:chart和release
·chart是创建一个应用的信息集合,包括各种Kubernetes对象的配置模板、参数定义、依赖关系、文档说明等。Chart是应用 部署的自包含逻辑单元。可以将chart想象成apt、yum中的软件包。
·release是chart的运行实例,代表了一个正在运行的应用。当chart被安装到kubernetes集群,就生成一个release。Chart 能够多次安装到同一个集群,每次安装都是一个release。
Helm包含两个组件:Helm客户端和Tiller服务器,如下图所示:
Helm客户端负责chart和release的创建和管理以及和Tiller的交互。Tiller服务器运行在kubernetes集群中,它会处理Helm客户端的请求,与kuberestes API Server交互。
Helm部署:
越来越多的公司和团队开始使用Helm这个Kubernetes的包管理器,我们也将使用Helm安装Kubernetes的常用组件。Helm由客户端helm令行工具和服务端tiller组成,Helm的安装十分简单。下载helm命令行工具到moster节点node1 的/usr/locai/bin下,这里下载的2.13.1版本:
为了安装服务端tiller,还需要在这台机器上配置好kubectl工具和kubeconfig文件,确保kubectl工具可以在这台机器上访问apiserver且正常使用。这里的node1节点以及配置好了kubectl
因为kubernetes API Server开启了RBAC访问控制,所以需要创建tiller使用的service account:tiller并分配合适的角色给它。这里简单直接分配cluster-admin这个集群内置的ClusterRole给它,创建rbac-config.yaml文件:
Tiller默认被部署在K8S集群中的kue-system这个namespace下:
Helm自定义模板:
Debug
使用Helm部署dashboard
Kubernetes-dashboard.yaml:
资源限制-Pod
Kubernetes对资源的限制实际上是通过cgroup来控制的,cgroup是容器的一组用来控制内核如何运行进程的相关属性集合,针对内核、CPU和各种设备都有对应的cgroup
默认情况下,Pod运行没有CPU和内存的限额。这意味着系统中的任何Pod将能够像执行该Pod所在的节点一样,消耗足够多的CPU和内存。一般会针对某些应用的pod资源进行资源限制,这个资源限值是通过resources的requests和limits来实现。
Requests要分配的资源,limits为最高请求的资源值。可以简单理解为初始值和最大值。
资源限制-名称空间
计算资源配额
配置对象数量配额限制
配置CPU和内存LimitRange
- default即limit的值
- defaultRequest即request的值
添加Google incubator仓库
部署Elasticsearch
部署Fluentd
部署kibana
证书可用时限
Go环境部署
下载源码
修改kubeadm源码包更新证书策略
更新kubeadm
更新各节点证书至Master节点
更多推荐
所有评论(0)