-
什么是Kubernetes
K8s是Kubernetes的简称,是一个开源的容器编排系统,用于自动部署、扩展和管理容器化应用程序。 Kubernetes源于希腊语,意为“舵手”或“飞行员”,其主要功能包括服务发现与负载均衡、存储编排、Secret和配置管理、批量执行、水平扩缩、自动化上线和回滚、自动装箱以及自我修复等。
核心特性:
-
服务发现与负载均衡:无需修改应用程序即可使用陌生的服务发现机制。
-
存储编排:自动挂载所选存储系统,包括本地存储。
-
Secret和配置管理:部署更新Secrets和应用程序的配置时不必重新构建容器镜像,且不必将软件堆栈配置中的秘密信息暴露出来。
-
批量执行:除了服务之外,Kubernetes还可以管理批处理和CI工作负载。
-
水平扩缩:使用一个简单的命令、一个UI或基于CPU使用情况自动对应用程序进行扩缩。
-
自动化上线和回滚:Kubernetes会分步骤地将针对应用或其配置的更改上线,同时监视应用程序运行状况以确保不会同时终止所有实例。
-
自动装箱:根据资源需求和其他约束自动放置容器,同时避免影响可用性。
-
自我修复:重新启动失败的容器,在节点死亡时替换并重新调度容器,杀死不响应用户定义的健康检查的容器。
Kubernetes的主从设备模型(Master-Slave架构)中,Master节点负责核心的调度、管理和运维,而Slave节点则执行用户的程序。Master节点通常被称为Head Node,而Slave节点则被称为Worker Node。
-
k8s组件
架构
master组件(控制平面)
控制平面:负责管理 Kubernetes 集群中的所有节点、和 Pod。
- api server
它是集群的入口,类似微服务网关这样,所有操作必须通过 API Server。
负责接收来自用户、和其他组件的请求,并通过 REST API 提供集群管理功能。
- scheduler(调度器)
负责根据调度策略(如:资源使用率、亲和性...等),将新创建的 Pod 分配到合适的节点上。
比如:通过 CPU、内存、GPU ...等资源的要求,Scheduler 确保节点有足够的可用资源来满足 Pod 的需求。
并且,通过调度策略,比如:公平调度、优先级...等,确保资源的合理分配和高效利用。
- Controller Manager(控制器)
是集群管理中的重要组件,它负责确保集群的实际状态与期望状态的一致性。
Controller Manager,是由多个控制器组成,每个控制器负责处理集群中的一种或、多种资源对象的状态管理。
- etcd
分布式键值存储系统,用于保存集群的所有配置信息、和状态数据。
etcd,重点保证数据的一致性、和持久性。
以及,提供集群状态的快速读取、和修改能力。
node组件(工作节点)
工作节点是运行实际应用程序的地方,它接收 API Server 的调度指令并运行 Pod。
- Kubelet
每个节点上的代理,负责确保 Pod 正常运行。
一旦 Pod 被调度到节点上,kubelet 在节点上启动并运行 Pod 中的容器。
- kubeProxy
网络代理,管理网络规则,确保容器、和服务之间的网络通信。
比如:使用 iptables 、或 ipvs 维护网络规则,将流量转发到相应的 Pods。
- Pod
Pod是 K8S中最小的可部署单元,通常由一个、或多个紧密耦合的容器组成。
Pod 是 Kubernetes 中的基本构建块,提供了容器的封装、和管理功能。
它们可以包含一个、或多个容器,这些容器共享:网络、存储资源,并在同一个环境中运行。
当创建一个 Pod 时,K8S调度器,会将 Pod 调度到合适的工作节点上。
调度器根据资源需求、节点的负载、和调度策略来选择节点。
- container
负责运行容器,如:Docker、containerd 等。
主要复制:拉取容器镜像,创建、和运行容器。
以及,提供容器的生命周期管理,如:启动、停止和监控容器...等等。
-
Pod
Pod是k8s的最小单位,里面包含一组容器,其中一个为Pause容器,也称为“根容器”。一个Pod下的容器必须运行于同一节点上Pod里面的多个业务容器共享Pause容器的网络和Volume卷。
Pod是短暂的。k8s中其他大多数组件都是围绕着Pod来进行支撑和扩展Pod功能的
每个Pod都有一个唯一的IP地址,称之为Pod IP。在K8S集群中,一个Pod里的容器与另外主机上的Pod容器能够直接通信
-
pause容器
pause容器就是为了管理Pod容器间的共享操作,这个容器需要能够准确地知道如何去创建共享运行环境的容器,还能管理这些容器的生命周期。为了实现这个父容器的构想,kubernetes中,用pause容器来作为一个Pod中所有容器的父容器。
pause容器有两个核心的功能:
-
提供整个Pod的Linux命名空间的基础。
-
启用PID命名空间,它在每个Pod中都作为PID为1进程(init进程),并回收僵尸进程。
Pause容器可以共享两种资源:
- 网络
每个pod都会被分配一个唯一的IP地址。Pod中的所有容器共享网络空间,必须包括IP地址和端口。Pod内部的容器可以使用localhost互相通信。pod中的容器与外界通信的时候,必须分配共享网络资源(例如使用宿主主机中的端口映射)。
- 存储
可以Pod指定多个共享的Volume。Pod中的所有容器都可以访问共享的Volume。Volume也可以用来持久化Pod中的存储资源以防容器重启文件丢失。
Pod与Pause结构的设计初衷
①原因一:
在一组容器作为一个单元的情况下,难以对整体的容器简单地进行判断及有效地进行行动。比如,一个容器死亡了 那么引入与业务无关的Pause容器作为Pod的基础容器,以它的状态代表着整个容器组的状态,这样就可以解决该问题。
②原因二:
Pod里的多个应用容器共享Pause容器的IP,共享Pause容器挂载的Volume,这样简化了应用容器之间的通信问题,也解决了容器之间的文件共享问题。
-
Pod的分类
1、自主式Pod
- 自主式pod:kubernetes直接创建出来的Pod,这种pod删除后就没有了,也不会重建
这种Pod本身是不能自我修复的,当Pod被创建后(不论是由你直接创建还是被其他Controller),都会被Kuberentes调度到集群的Node上。直到Pod的进程终止、被删掉、因为缺少资源而被驱逐、或者Node故障之前这个Pod都会一直保持在那个Node上。Pod不会自愈。如果Pod运行的Node故障,或者是调度器本身故障,这个Pod就会被删除。同样的,如果Pod所在Node缺少资源或者Pod处于维护状态,Pod也会被驱逐。
2、控制器管理的Pod
Kubernetes使用更高级的称为Controller的抽象层,来管理Pod实例。Controller可以创建和管理多个Pod,提供副本管理、滚动升级和集群级别的自愈能力。例如,如果一个Node故障,Controller就能自动将该节点上的Pod调度到其他健康的Node上。虽然可以直接使用Pod,但是在Kubernetes中通常是使用Controller来管理Pod的。
-
Pod里容器的分类
1、基础容器,即Pause
1.1 维护整个Pod网络和存储空间
1.2 node节点中操作
1.3 启动一个容器时,k8s会自动启动一个基础容器
2、初始化容器(initcontainers)
Init容器必须在应用程序容器启动之前运行完成,而应用程序容器是并行运行的,所以Init容器能够提供了一种简单的阻塞或延迟应用容器的启动的方法。Init 容器与普通的容器非常像,除了以下两点:
①init容器总是运行到成功完成为止
②每个init容器都必须在下一个init容器启动之前成功完成启动和退出。
如果 Pod 的 Init 容器失败,k8s 会不断地重启该 Pod,直到 Init 容器成功为止。然而,如果 Pod 对应的重启策略(restartPolicy)为 Never,它不会重新启动。
3、init的容器作用
因为init容器具有与应用容器分离的单独镜像,其启动相关代码具有如下优势:
①Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。例如,没有必要仅为了在安装过程中使用类似 sed、 awk、 python 或 dig 这样的工具而去FROM 一个镜像来生成一个新的镜像。
②Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。
③应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。
④Init 容器能以不同于Pod内应用容器的文件系统视图运行。因此,Init容器可具有访问 Secrets 的权限,而应用容器不能够访问。
⑤由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用容器的启动,
直到满足了一组先决条件。一旦前置条件满足,Pod内的所有的应用容器会并行启动。
4、应用容器(main container)
应用容器会在init容器完成并退出后并行启动。
-
网络
-
网络层级
节点网络:集群宿主机节点间的网络通信,并且负责打通与集群外部的通讯。
pod网络:为集群上的pod提供网络,通过CNI网络插件来完成,如Fannel、Calico、Cilium等。
service网络:部署集群时指定网段,service从这里面分配。service对象的IP地址存在于相关的ipvs、iptables规则中,k8s集群自行管理
-
流量
Kubernetes网络中主要存在四种流量
-
同一pod内的容器间通讯
-
pod间的通讯
-
pod与service的通讯
-
集群外部流量与service间的通讯
-
CNI插件
pod网络插件,需要满足的功能要求:
-
所有pod间直接通信而不需要通过NAT机制
-
所有节点与pod间直接通讯而不需要通过NAT机制
-
所有pod对象都位于同一平面网络内
CNI插件的类型:
-
网络插件:负责将pod连接到网络中
-
IPAM:(IP地址管理),负责分配pod IP地址
CNI插件的网络模型:
overlay:覆盖网络,基于数据包的二次加密进行通讯。
缺点:对性能有轻微影响,封装数据包的过程需要占用少量的CPU,由于数据包中需要额外的字节来对封装进 行编码,(添加VXLAN或者IP-in-IP头),从而减少了可发送的内部数据包的最大大小,意味着相同的数据需要发送更多次。
route:路由网络,基于路由条目进行通信。
-
Calico网络插件
Calico 是一个开源的网络及网络安全解决方案,主要用于容器、虚拟机、基于本地主机的工作负载之间的网络连接。
Calico 以其性能、灵活性而闻名,是一个功能全面且复杂的网络解决方案,适用于需要高性能、高可扩展性和安全性的容器网络应用场景
组件:
-
Felix:运行在每个节点的代理程序,主要负责网络接口监听、路由信息管理、ARP 信息管理、ACL 规则管理、上报节点网络状态、创建 Calico 虚拟网络设备(如 tunl0、vxlan.calico)
-
ETCD:存储集群中节点的所有路由信息,确保网络元数据的一致性、Calico 网络状态的准确性,可以与 Kubernetes 共用
-
BIRD:BGP 客户端,作用是监听并将 Felix 的路由信息读入内核,并通过 BGP 协议在集群节点中广播分发,实现网络互通。BIRD 支持的路由协议包括 BGP、OSPF、RIP 等
BGP 协议:
BGP(Border Gateway Protocol, 边界网关协议)是一种基于策略的域间路由协议,
用于实现网络中不同自治系统(AS)之间的互联互通,
其特点是可以自动发现和学习路由条目,并找出最佳路由。
-
BGP Route Reflector:使所有 BGP 客户端仅与特定的 Route Reflector(路由反射)节点互联,并进行路由同步以减少连接数,可以解决大型网络下的节点规模问题
-
Calicoctl:Calico 的命令行管理工具
Calico 架构及组件示意图:
网络模式:
1、动态路由模式
动态路由模式(Dynamic Routing)采用 BGP 路由协议,自动学习来自其它 AS 自治系统(在 Kubernetes 中即为集群中其他 Node 节点)上的路由条目,也可以称为 BGP 模式。
如果集群 Node 节点均处于同一个二层网络中、或数量规模较大,建议采用该模式。
BGP(Border Gateway Protocol, 边界网关协议)是一种基于策略的域间路由协议,用于实现网络中不同自治系统(AS)之间的互联互通,其特点是可以自动发现和学习路由条目,并找出最佳路由。
BGP 模式可以细分为以下两种模式:
-
全互联(Node-to-Node Mesh)模式
- 每一个 BGP Speaker 都需要和其它 BGP Speaker 建立 BGP 连接,BGP 连接总数为 N^2。如果集群规模过大、Node 节点数量过多会消耗大量连接,因此集群 Node 节点数量超过 100 台后,官方不建议使用该模式
-
路由反射(Router Reflection,RR)模式
- 指定一个或多个 BGP Speaker 为 Router Reflection,与网络中其他 BGP Speaker 建立连接,每个 BGP Speaker 只需与 Router Reflection 建立 BGP 连接即可获取全网的路由信息。在 Calico 中可以通过 Global Peer 实现该模式
2、覆盖网络模式
覆盖网络模式(Overlay Network)采用 IPIP 或 VXLAN 协议对底层网络数据报文进行封装,然后通过上层覆盖网络通信。
如果集群 Node 节点处于不同的二层网络中,可能由于到达目标主机的跳数太多导致性能下降,建议采用该模式。
覆盖网络模式可以细分为以下两种模式:
-
IPIP(IP in IP)模式
-
IPIP 模式下的每个数据报文都有两个 IP 网络层,内层是 Pod 容器之间的 IP 网络报文,外层是 Node 节点之间的网络报文
-
IPIP 模式下的 Calico 会为每个 Node 节点创建一个 tunl0 接口,作为隧道出入口设备,用来封装 IPIP 数据报文,Pod 间的通信经由 IPIP 的三层隧道进行转发
-
IPIP 示意图
-
VXLAN(Virtual eXtensible Local Area Network)模式
-
VXLAN 模式的 Calico 会将数据报文的源 MAC 地址和目的 MAC 地址,分别替换为本机 VXLAN 网卡和目的节点 VXLAN 网卡的 MAC 地址,外层 UDP 网络报文的目的 IP 地址将根据路由及目的节点 VXLAN 的 MAC 查 FDB 表获取
-
VXLAN 模式的 Calico 会为每个 Node 节点创建一个 vxlan.calico 接口,作为隧道出入口设备,用来封装 VXLAN 数据报文,Pod 间的通信经由 VXLAN 的三层隧道进行转发
-
VXLAN 示意图
IPIP 模式与 VXLAN 模式对比:
-
与 VXLAN 模式相比,IPIP 模式开销较小、更轻量化,但其安全性也更差一些
-
IPIP 模式与VXLAN 模式均支持 Always 和 CrossSubnet 两种封装模式
-
Always:始终封装所有流量
-
CrossSubnet:仅在流量跨子网时对其进行封装
-
最后,以 Calico 的 VXLAN 模式为例,Pod 流量在 Node 节点间的转发原理如下图:
VXLAN 模式下 Pod 流量转发示意图
-
资源清单
常用命令:
- 获取当前的资源(比如,get pod / get node):
kubectl get pod:
-A,--all-namespaces 查看当前所有名称空间的资源
-n 指定名称空间,默认值 default,kube-system 空间存放是当前组件资源
--show-labels 查看当前的标签
-l 筛选资源,key、key=value
-o wide 详细信息包括 IP、分配的节点
-w 监视,打印当前的资源对象的变化部分
- 进入 Pod 内部的容器执行命令:
kubectl exec -it podName -c cName(容器名称) -- command
-c 可以省略,默认进入唯一的容器内部
- 查看资源的描述
kubectl explain pod.spec
- 查看 pod 内部容器的 日志
kubectl logs podName -c cName
- 查看资源对象的详细描述
kubectl describe pod podName
- 删除资源对象
kubectl delete kindName objName
--all 删除当前所有的资源对象
- 资源实例化
kubectl create -f demo.pod.yaml
-
什么是资源
k8s中所有的内容都抽象为资源,资源实例化之后称为对象 (比如汽车就是资源,实例化之后的具体的汽车就是对象,比如兰博基尼,小米su7,法拉利等)
-
资源清单的编写
资源清单结构:
-
接口组/版本(apiVersion)
-
类别(kind)
-
元数据(metadata)
-
期望(spec)
kubectl explain pod.spec 命令,可以查询清单编写具体的描述字段key
-
Pod****生命周期
-
第一阶段-init容器
在主容器启动之前运行,用于设置Pod环境,如下载配置文件、准备数据卷等。初始化容器必须按顺序成功执行完毕后,主容器才会启动。
init容器的特点: 1. init容器总是运行到成功完成为止,即不会一直运行
-
每个init都必须在下一个init容器启动前成功完成
-
如果init失败,k8s会不断地重启该pod,直到成功为止,(可以设置策略不重启)
-
init与应用容器具备不同的镜像,可以放一些额外的操作
-
init多个之间是线性启动的,所以可以做一些延迟性操作
- 第二阶段-主容器,即业务应用容器
k8s在这一阶段提供了许多钩子和探针,来保障应用的稳定运行
-
钩子
钩子是由kubelet发起的,主要有:
启动后钩子-容器创建后(即进程启动之前)立即执行,可用于执行一些初始化任务。
关闭前钩子-在容器终止之前执行,可用于执行一些清理任务。
pod中的所有容器都可以配置钩子,钩子类型主要有 exec(执行脚本命令)
和http(发送一个请求)两类,例如:
-
探针
https://www.cnblogs.com/wangjiayu/p/17973214
Kubernetes(k8s)中的探针是一种健康检查机制,用于监测Pod内容器的运行状况。主要包括以下三种类型的探针:
1、存活探针(Liveness Probe)
2、就绪探针(Readiness Probe)
3、启动探针(Startup Probe)(自1.16版本引入)
探针的参数说明(每种探针参数都一样):
1、启动探针(StartupProbe)
Kubernetes (k8s) 的启动探针(StartupProbe)主要用于检测容器内的应用是否已经成功启动并完成初始化任务。它的主要作用有以下几点:
-
延缓其他探针生效: 在容器启动初期,启动探针先于存活探针(LivenessProbe)和就绪探针(ReadinessProbe)生效。当启动探针配置存在时,kubelet不会执行存活和就绪探针,直到启动探针成功为止。这对于某些启动时间较长或者启动过程中有复杂初始化序列的应用程序来说非常重要,可以避免在应用还未完全启动时就被误判为不健康或就绪,进而被错误地重启或流量过早涌入。
-
防止频繁重启: 若应用启动期间,存活探针或就绪探针就开始工作,而此时应用可能还没有完全启动成功,这两个探针可能会因为应用未能及时响应而触发容器重启,造成不必要的服务中断和循环重启。启动探针的存在可以有效地防止此类情况的发生。
-
确保应用稳定: 启动探针使得Kubernetes能够在应用真正启动完毕后才将其视为健康的,并开始接受流量,从而保障了集群中应用服务的稳定性。
2、就绪探针(Readiness Probe)
Kubernetes(k8s)中的就绪探针(Readiness Probe)主要作用是检测容器是否已经准备好对外提供服务。具体来说:
-
状态评估: 就绪探针会定期对容器进行检查,以确定容器内应用程序是否完成了必要的初始化工作,并且能够处理来自外部的请求或流量。
-
流量路由控制: 当就绪探针成功时,表示该容器内部的应用程序已处于可接受请求的状态,此时kubelet会将该容器标记为“就绪”状态,Service将会将其IP地址添加到后端服务列表中,允许Service开始将网络流量转发至这个Pod。
-
避免无效请求: 如果就绪探针失败,则意味着容器可能还在启动过程中、正在重启服务、或者由于某种原因暂时无法正常响应请求。在这种情况下,kubelet会将容器从Service的后端池中移除,确保不会向其发送任何用户请求,从而避免了因应用未准备完毕而引起的错误响应和用户体验下降。
-
平滑过渡: 通过就绪探针,Kubernetes可以实现滚动更新或部署过程中的平滑过渡,新版本的容器在通过就绪探针验证前,不会承担任何实际流量,直到它们完全启动并做好处理请求的准备。
总之,就绪探针是Kubernetes中用于保证服务质量的关键机制之一,它使得集群能够根据容器的实际运行状况动态调整流量分配,确保系统的整体稳定性和可用性。
3、存活探针(Readiness Probe)
Kubernetes(k8s)中的存活探针(Liveness Probe)主要作用是检测容器内主进程或服务是否仍然运行正常且响应健康检查。具体来说:
-
监控状态: 存活探针会定期对容器内的应用进行检查,以判断其是否处于“存活”状态,即应用程序没有崩溃、死锁或其他不可恢复的错误。
-
自动恢复: 当存活探针检测失败时,kubelet将认为该容器内的主进程已经不再健康或者已停止提供预期的服务。此时,kubelet会根据Pod的重启策略来决定是否应该重新启动这个容器。通过这种方式,存活探针可以帮助实现故障自愈,及时恢复服务的可用性。
-
避免僵死进程: 如果一个容器由于内部错误而进入不可用状态但并未退出,存活探针能够识别出这种情况,并触发容器重启,从而避免资源被僵死进程占用。
-
保持服务质量: 通过持续监控和及时重启不健康的容器,存活探针有助于确保整个集群的服务质量,减少因单个容器异常导致的整体服务失效的可能性。
总之,在Kubernetes中,存活探针是一种关键的健康管理机制,用于确保容器内应用程序始终维持在可接受的工作状态,当出现问题时能迅速采取行动修复问题。
探针执行时期:
-
启动探针(Startup Probe):
-
启动探针仅在容器启动阶段执行,探测成功后就不再探测。
-
在容器启动后等待
initialDelaySeconds
开始探测。 -
当容器成功通过启动探针检查,即连续成功达到
successThreshold
次数时,kubelet会停止执行启动探针,并开始执行存活探针和就绪探针。
-
-
存活探针(Liveness Probe):
-
在容器启动并完成启动探针之后开始执行。
-
在容器启动后等待
initialDelaySeconds
开始执行。如果配置了启动探针(Startup Probe),在启动探针成功后等待initialDelaySeconds开始探测。
-
存活探针在整个容器生命周期内持续进行健康检查,除非被暂时禁用或容器重启。
-
-
就绪探针(Readiness Probe):
-
与存活探针类似,也是在容器启动并可能完成启动探针之后开始执行。
-
在容器启动后等待
initialDelaySeconds
开始执行。如果配置了启动探针(Startup Probe),在启动探针成功后等待initialDelaySeconds开始探测。
-
就绪探针在整个容器生命周期内持续进行健康检查,除非被暂时禁用或容器重启。
-
探针实现方式(三种):
- 执行命令: 在容器内部执行一个命令,并根据命令退出时返回的状态码判断容器是否正常运行。通常情况下,如果命令返回0,则表示成功。
livenessProbe:exec:command:- cat- /tmp/health
- TCP Socket 检查: Kubernetes尝试与容器上指定的端口建立TCP连接。如果能够成功建立连接,则说明探测成功。
livenessProbe:tcpSocket:port: 8080
- HTTP GET 请求: Kubernetes通过向容器内指定的端口发送一个HTTP GET请求来检查应用的状态。如果收到的HTTP响应码在200-399范围内,则认为该探测成功。
livenessProbe:httpGet:path: /health-checkport: 8080httpHeaders: # 可选,用于设置自定义HTTP头部- name: Custom-Headervalue: Value
探针示例配置:
livenessProbe:# 类型选择器,可以选择 httpGet、tcpSocket 或 exec 中的一种httpGet: # HTTP GET 请求方式path: /health # 要请求的路径port: 8080 # 要请求的端口httpHeaders: # 可选,HTTP 请求头列表- name: X-Custom-Headervalue: AwesometcpSocket: # TCP Socket 检查方式port: 8080 # 要连接的端口exec: # 执行命令检查方式command:- cat- /tmp/healthy# 基本探测间隔参数:initialDelaySeconds: 30 # 容器启动后延迟多少秒开始执行第一次探测,默认为0秒periodSeconds: 10 # 探测的时间间隔,即每隔多少秒执行一次,默认为10秒(最小值1秒)# 控制何时判断容器健康或不健康的阈值参数:timeoutSeconds: 1 # 探测超时时间,默认为1秒(最小值1秒)successThreshold: 1 # 在连续失败之后需要多少次连续成功才能认为容器是健康的,默认为1failureThreshold: 3 # 连续失败多少次才触发相应动作(如重启容器对于存活探针)readinessProbe: # 就绪探针配置类似
startupProbe: # 启动探针配置也相似,不过主要用于检测应用是否完成启动过程
-
Pod是如何被调度运行的
-
命名空间: namespace
namespace 即 命名空间
命名空间在多数情况下是用于实现多用户的资源隔离的,通过集群内部的资源对象分配到不同的 命名空间中,形成逻辑上的分组,这样可以让不同的组在共享使用整个集群的资源的情况下,还能够被分组管理
在 K8S 初始状态下,K8S 会有 3 个命名空间
- Default 无名字空间对象的默认名字空间
在 K8S 中,集群启动后,会创建一个 default 的命名空间 如果我们创建的 rc ,service,pod,不指定命名空间的话,那么这些资源都将被系统创建为 default 的命名空间中
- kube-system
K8S 系统创建的对象的名字空间
- kube-public
是 K8S 自动创建且被所有用户可读的名字空间
查看命名空间:
kubectl get namesapces
创建命名空间:
apiVersion: v1
kind: NameSpace
metadata:name: myns
--------------------
apiVersion: v1
kind: Pod
metadata:name: busyboxnamespace: myns
spec:containers:- image: busyboxcommand:- ls name: busybox
也可以直接通过命名创建:kubectl create namespace myns
查询按照命名空间过滤,只需要加参数 -n namespace,比如: kubectl get pod -n myns
-
Pod控制器(核心灵魂)
常用命令:
## 根据文件创建资源对象
[root@master ~]# kubectl create -f nginxpod.yml## 查看namespace:
[root@master ~]# kubectl get ns## 查看dev命名空间中的pod:
[root@master ~]# kubectl get pod -n dev## 查看nginxpod.yml文件中配置的资源信息:
[root@master ~]# kubectl get -f nginxpod.yml## 删除资源:
[root@master ~]# kubectl delete -f nginxpod.yml
创建资源的相关命令:apply与replace:
## 执行kubect1 apply -f yaml来创建资源
[root@master ~]# kubectl apply -f nginxpod.yml## 再次执行后会发现资源没有发生改变
kubectl replace -f nginxpod.yml
## 执行kubect1 replace -f yaml来创建资源
[root@master ~]# kubectl replace -f nginxpod.yml
replace会使用新的配置完全替换掉旧的配置,包括那些新配置中没有指定的字段
而apply只会更新不同的字段,没有指定的字段原封不动
kubectl diff -f nginxpod.yml
kubectl diff -f nginxpod.yml
对比目前的配置和yml文件中的配置差异,以及如果运行之后,配置将会如何变化
-dry-run:试运行
- –dry-run: 表示试运行,不真正执行命名(用来测试命令是否正确),即并不会真的创建出pod和deployment实例,去掉该参数后即可真正执行命令。
kubectl create deployment dryrun-test --image=nginx --port=80 replicas=3 --dry-run
#打印相应的API对象而不执行创建
查看生成yaml格式
使用–dry-run试运行可不触发生成命令,然后通过 -o yaml 可实现对其 yaml 资源配置清单的查看
kubectl run dryrun-test --image=nginx --port=80 --dry-run -o yaml
试运行一个pod,并将它的yaml配置格式显示出来(可以用来生成yaml配置文件直接使用)
- ReplicaSet
# 创建rs
[root@k8s-master01 ~]# kubectl create -f pc-replicaset.yaml# 查看rs
# DESIRED:期望副本数量
# CURRENT:当前副本数量
# READY:已经准备好提供服务的副本数量
[root@k8s-master01 ~]# kubectl get rs pc-replicaset -n dev -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
pc-replicaset 3 3 3 22s nginx nginx:1.17.1 app=nginx-pod# 编辑rs的内容,比如副本数量,修改spec:replicas: 6即可
[root@k8s-master01 ~]# kubectl edit rs pc-replicaset -n dev# 使用scale命令实现扩缩容, 后面--replicas=n直接指定目标数量即可
[root@k8s-master01 ~]# kubectl scale rs pc-replicaset --replicas=2 -n dev
replicaset.apps/pc-replicaset scaled# 编辑rs的容器镜像 - image: nginx:1.17.2
[root@k8s-master01 ~]# kubectl edit rs pc-replicaset -n dev
replicaset.apps/pc-replicaset edited# 再次查看,发现镜像版本已经变更了
[root@k8s-master01 ~]# kubectl get rs -n dev -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES ...
pc-replicaset 2 2 2 140m nginx nginx:1.17.2 ...# 同样的道理,也可以使用命令完成这个工作
# kubectl set image rs rs名称 容器=镜像版本 -n namespace
[root@k8s-master01 ~]# kubectl set image rs pc-replicaset nginx=nginx:1.17.1 -n dev
replicaset.apps/pc-replicaset image updated# 查看pod
[root@k8s-master01 ~]# kubectl get pods -n dev
NAME READY STATUS RESTARTS AGE
pc-replicaset-6vmvt 1/1 Running 0 114m
pc-replicaset-cftnp 1/1 Running 0 10s
pc-replicaset-fjlm6 1/1 Running 0 10s
pc-replicaset-fmb8f 1/1 Running 0 114m
pc-replicaset-s2whj 1/1 Running 0 10s
pc-replicaset-snrk2 1/1 Running 0 114m# 使用kubectl delete命令会删除此RS以及它管理的Pod
# 在kubernetes删除RS前,会将RS的replicasclear调整为0,等待所有的Pod被删除后,在执行RS对象的删除
[root@k8s-master01 ~]# kubectl delete rs pc-replicaset -n dev# 如果希望仅仅删除RS对象(保留Pod),可以使用kubectl delete命令时添加--cascade=false选项(不推荐)。
[root@k8s-master01 ~]# kubectl delete rs pc-replicaset -n dev --cascade=false# 如果希望仅仅删除RS对象(保留Pod),可以使用kubectl delete命令时添加--cascade=false选项(不推荐)。
[root@k8s-master01 ~]# kubectl delete rs pc-replicaset -n dev --cascade=false
- deployment
# 创建deployment
[root@k8s-master01 ~]# kubectl create -f pc-deployment.yaml --record=true# 查看deployment
# UP-TO-DATE 最新版本的pod的数量
# AVAILABLE 当前可用的pod的数量
[root@k8s-master01 ~]# kubectl get deploy pc-deployment -n dev
NAME READY UP-TO-DATE AVAILABLE AGE
pc-deployment 3/3 3 3 15s# 扩容
#变更副本数量为5个
[root@k8s-master01 ~]# kubectl scale deploy pc-deployment --replicas=5 -n dev
deployment.apps/pc-deployment scaled# 编辑deployment的副本数量,修改spec:replicas: 4即可
[root@k8s-master01 ~]# kubectl edit deploy pc-deployment -n dev# 变更镜像
[root@k8s-master01 ~]# kubectl set image deployment pc-deployment nginx=nginx:1.17.2 -n dev
deployment.apps/pc-deployment image updated# 查看当前升级版本的状态
[root@k8s-master01 ~]# kubectl rollout status deploy pc-deployment -n dev# 查看升级历史记录
[root@k8s-master01 ~]# kubectl rollout history deploy pc-deployment -n dev# 版本回滚
# 这里直接使用--to-revision=1回滚到了1版本, 如果省略这个选项,就是回退到上个版本,就是2版本
[root@k8s-master01 ~]# kubectl rollout undo deployment pc-deployment --to-revision=1 -n dev# 删除deployment,其下的rs和pod也将被删除
[root@k8s-master01 ~]# kubectl delete -f pc-deployment.yaml
- DaemonSet
# 创建daemonset
[root@k8s-master01 ~]# kubectl create -f pc-daemonset.yaml
daemonset.apps/pc-daemonset created# 查看daemonset
[root@k8s-master01 ~]# kubectl get ds -n dev -o wide
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES
pc-daemonset 2 2 2 2 2 24s nginx nginx:1.17.1
- Job
# 创建job
[root@k8s-master01 ~]# kubectl create -f pc-job.yaml
job.batch/pc-job created# 查看job
[root@k8s-master01 ~]# kubectl get job -n dev -o wide -w
NAME COMPLETIONS DURATION AGE CONTAINERS IMAGES SELECTOR
pc-job 0/1 21s 21s counter busybox:1.30 app=counter-pod
pc-job 1/1 31s 79s counter busybox:1.30 app=counter-pod# 通过观察pod状态可以看到,pod在运行完毕任务后,就会变成Completed状态
[root@k8s-master01 ~]# kubectl get pods -n dev -w
NAME READY STATUS RESTARTS AGE
pc-job-rxg96 1/1 Running 0 29s
pc-job-rxg96 0/1 Completed 0 33s
- CronJob
# 创建cronjob
[root@k8s-master01 ~]# kubectl create -f pc-cronjob.yaml
cronjob.batch/pc-cronjob created# 查看cronjob
[root@k8s-master01 ~]# kubectl get cronjobs -n dev
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
pc-cronjob */1 * * * * False 0 <none> 6s# 删除cronjob
[root@k8s-master01 ~]# kubectl delete -f pc-cronjob.yaml
cronjob.batch "pc-cronjob" deleted
- HPA
# 创建hpa
[root@k8s-master01 1.8+]# kubectl create -f pc-hpa.yaml
horizontalpodautoscaler.autoscaling/pc-hpa created# 查看hpa
[root@k8s-master01 1.8+]# kubectl get hpa -n dev
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
pc-hpa Deployment/nginx 0%/3% 1 10 1 62s
什么是pod控制器
Pod控制器是管理pod的中间层,使用Pod控制器之后,只需要告诉Pod控制器,想要多少个什么样的Pod就可以了,它会创建出满足条件的Pod并确保每一个Pod资源处于用户期望的目标状态。如果Pod资源在运行中出现故障,它会基于指定策略重新编排Pod。
在kubernetes中,有很多类型的pod控制器,每种都有自己的适合的场景,常见的有下面这些:
-
ReplicationController:比较原始的pod控制器,已经被废弃,由ReplicaSet替代
-
ReplicaSet:保证副本数量一直维持在期望值,并支持pod数量扩缩容,镜像版本升级
-
Deployment:通过控制ReplicaSet来控制Pod,并支持滚动升级、回退版本
-
Horizontal Pod Autoscaler:可以根据集群负载自动水平调整Pod的数量,实现削峰填谷
-
DaemonSet:在集群中的指定Node上运行且仅运行一个副本,一般用于守护进程类的任务
-
Job:它创建出来的pod只要完成任务就立即退出,不需要重启或重建,用于执行一次性任务
-
Cronjob:它创建的Pod负责周期性任务控制,不需要持续后台运行
-
StatefulSet:管理有状态应用
-
ReplicaSet(rs)
ReplicaSet的主要作用是保证一定数量的pod正常运行(即当前的pod数量与我们预期的一致),它会持续监听这些Pod的运行状态,一旦Pod发生故障,就会重启或重建。同时它还支持对pod数量的扩缩容和镜像版本的升降级。
比如:
apiVersion: apps/v1 # 版本号
kind: ReplicaSet # 类型
metadata: # 元数据name: # rs名称 namespace: # 所属命名空间 labels: #标签controller: rs
spec: # 详情描述replicas: 3 # 副本数量selector: # 选择器,通过它指定该控制器管理哪些podmatchLabels: # Labels匹配规则app: nginx-podmatchExpressions: # Expressions匹配规则- {key: app, operator: In, values: [nginx-pod]}template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本metadata:labels:app: nginx-podspec:containers:- name: nginximage: nginx:1.17.1ports:- containerPort: 80
-
Deployment(deploy)
为了更好的解决服务编排的问题,kubernetes在V1.2版本开始,引入了Deployment控制器。值得一提的是,这种控制器并不直接管理pod,而是通过管理ReplicaSet来简介管理Pod,即:Deployment管理ReplicaSet,ReplicaSet管理Pod。所以Deployment比ReplicaSet功能更加强大。
Deployment主要功能有下面几个:
-
支持ReplicaSet的所有功能
-
支持发布的停止、继续
-
支持滚动升级和回滚版本
比如:
apiVersion: apps/v1 # 版本号
kind: Deployment # 类型
metadata: # 元数据name: # 控制器名称 ,比如 pc-deploymentnamespace: # 所属命名空间,比如 dev labels: #标签controller: deploy
spec: # 详情描述replicas: 3 # 副本数量revisionHistoryLimit: 3 # 保留的历史版本,用于回滚paused: false # 暂停部署,默认是falseprogressDeadlineSeconds: 600 # 部署超时时间(s),默认是600strategy: # 策略type: RollingUpdate # 滚动更新策略rollingUpdate: # 滚动更新maxSurge: 30% # 最大额外可以存在的副本数,可以为百分比,也可以为整数maxUnavailable: 30% # 最大不可用状态的 Pod 的最大值,可以为百分比,也可以为整数selector: # 选择器,通过它指定该控制器管理哪些podmatchLabels: # Labels匹配规则app: nginx-podmatchExpressions: # Expressions匹配规则- {key: app, operator: In, values: [nginx-pod]}template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本metadata:labels:app: nginx-podspec:containers:- name: nginximage: nginx:1.17.1ports:- containerPort: 80
deployment支持两种更新策略:重建更新
和滚动更新
,可以通过strategy
指定策略类型,支持两个属性:
strategy:指定新的Pod替换旧的Pod的策略, 支持两个属性:type:指定策略类型,支持两种策略Recreate:在创建出新的Pod之前会先杀掉所有已存在的PodRollingUpdate:滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本PodrollingUpdate:当type为RollingUpdate时生效,用于为RollingUpdate设置参数,支持两个属性:maxUnavailable:用来指定在升级过程中不可用Pod的最大数量,默认为25%。maxSurge: 用来指定在升级过程中可以超过期望的Pod的最大数量,默认为25%。
比如重建:
spec:strategy: # 策略type: Recreate # 重建更新
滚动更新:
spec:strategy: # 策略type: RollingUpdate # 滚动更新策略rollingUpdate:maxSurge: 25% maxUnavailable: 25%
版本回滚:
kubectl rollout: 版本升级相关功能,支持下面的选项:
status 显示当前升级状态
history 显示 升级历史记录
pause 暂停版本升级过程
resume 继续已经暂停的版本升级过程
restart 重启版本升级过程
undo 回滚到上一级版本(可以使用--to-revision回滚到指定版本)
pc-deployment: 控制器名称
dev: 命名空间
-
查看当前升级版本的状态 [root@k8s-master01 ~]# kubectl rollout status deploy pc-deployment -n dev deployment "pc-deployment" successfully rolled out
-
- 查看升级历史记录 [root@k8s-master01 ~]# kubectl rollout history deploy pc-deployment -n dev deployment.apps/pc-deployment REVISION CHANGE-CAUSE 1 kubectl create --filename=pc-deployment.yaml --record=true 2 kubectl create --filename=pc-deployment.yaml --record=true 3 kubectl create --filename=pc-deployment.yaml --record=true 可以发现有三次版本记录,说明完成过两次升级
-
版本回滚 这里直接使用--to-revision=1回滚到了1版本, 如果省略这个选项,就是回退到上个版本,就是2版本 [root@k8s-master01 ~]# kubectl rollout undo deployment pc-deployment --to-revision=1 -n dev deployment.apps/pc-deployment rolled back 控制器可保存的历史版本数量由“spec.revisionHistoryLimit”属性进行定义
-
查看deploy信息 [root@k8s-master01 ~]# kubectl get deploy -n dev -o wide NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES pc-deployment 4/4 4 4 74m nginx nginx:1.17.1
-
回滚的原理:查看rs,发现第一个rs中有4个pod运行,后面两个版本的rs中pod为0 其实deployment之所以可是实现版本的回滚,就是通过记录下历史rs来实现的, 一旦想回滚到哪个版本,只需要将当前版本pod数量降为0,然后将回滚版本的pod提升为目标数量就可以了 [root@k8s-master01 ~]# kubectl get rs -n dev NAME DESIRED CURRENT READY AGE pc-deployment-6696798b78 4 4 4 78m pc-deployment-966bf7f44 0 0 0 37m pc-deployment-c848d767 0 0 0 71m
金丝雀发布(即灰度发布)
Deployment控制器支持控制更新过程中的控制,如“暂停(pause)”或“继续(resume)”更新操作。
比如有一批新的Pod资源创建完成后立即暂停更新过程,
此时,仅存在一部分新版本的应用,主体部分还是旧的版本。
然后,再筛选一小部分的用户请求路由到新版本的Pod应用,继续观察能否稳定地按期望的方式运行。
确定没问题之后再继续完成余下的Pod资源滚动更新,否则立即回滚更新操作。这就是所谓的金丝雀发布。
暂停部署:
kubectl rollout pause deployment pc-deployment -n dev
继续部署
kubectl rollout resume deploy pc-deployment -n dev
扩容:
命令式:scale
kubectl scale是一个静态的扩缩容方法,需要手动指定要扩容或缩容的副本数量。使用kubectl scale命令可以更改Deployment、StatefulSet或ReplicaSet的副本数量。
比如:
kubectl scale deployment deployment-nginx --replicas=4 扩容到4个
命令式:patch
Kubectl patch 命令允许用户对运行在 Kubernetes 集群中的资源进行局部更新。相较于我们经常使用的 kubectl apply 命令,kubectl patch 命令在更新时无需提供完整的资源文件,只需要提供要更新的内容即可。
比如: 只更新副本数量字段进行扩容或者缩容
kubectl patch deployments.apps deployment-nginx -p '{"spec": {"replicas": 3}}'
-
DaemonSet(DS)
DaemonSet类型的控制器可以保证在集群中的每一台(或指定)节点上都运行一个副本。一般适用于日志收集、节点监控等场景。也就是说,如果一个Pod提供的功能是节点级别的(每个节点都需要且只需要一个),那么这类Pod就适合使用DaemonSet类型的控制器创建。
DaemonSet控制器的特点:
-
每当向集群中添加一个节点时,指定的 Pod 副本也将添加到该节点上
-
当节点从集群中移除时,Pod 也就被垃圾回收了
apiVersion: apps/v1
kind: DaemonSet
metadata:name: pc-daemonsetnamespace: dev
spec: selector:matchLabels:app: nginx-podtemplate:metadata:labels:app: nginx-podspec:containers:- name: nginximage: nginx:1.17.1
查看daemonset [root@k8s-master01 ~]# kubectl get ds -n dev -o wide 查看pod,发现在每个Node上都运行一个pod [root@k8s-master01 ~]# kubectl get pods -n dev -o wide NAME READY STATUS RESTARTS AGE IP NODE pc-daemonset-9bck8 1/1 Running 0 37s 10.244.1.43 node1 pc-daemonset-k224w 1/1 Running 0 37s 10.244.2.74 node2 删除daemonset [root@k8s-master01 ~]# kubectl delete -f pc-daemonset.yaml daemonset.apps "pc-daemonset" deleted
-
Job
Job,主要用于负责批量处理(一次要处理指定数量任务)短暂的一次性(每个任务仅运行一次就结束)任务。Job特点如下:
-
当Job创建的pod执行成功结束时,Job将记录成功结束的pod数量
-
当成功结束的pod达到指定的数量时,Job将完成执行
apiVersion: batch/v1 # 版本号
kind: Job # 类型
metadata: # 元数据name: # rs名称 namespace: # 所属命名空间 labels: #标签controller: job
spec: # 详情描述completions: 1 # 指定job需要成功运行Pods的次数。默认值: 1parallelism: 1 # 指定job在任一时刻应该并发运行Pods的数量。默认值: 1activeDeadlineSeconds: 30 # 指定job可运行的时间期限,超过时间还未结束,系统将会尝试进行终止。backoffLimit: 6 # 指定job失败后进行重试的次数。默认是6manualSelector: true # 是否可以使用selector选择器选择pod,默认是falseselector: # 选择器,通过它指定该控制器管理哪些podmatchLabels: # Labels匹配规则app: counter-podmatchExpressions: # Expressions匹配规则- {key: app, operator: In, values: [counter-pod]}template: # 模板,当副本数量不足时,会根据下面的模板创建pod副本metadata:labels:app: counter-podspec:restartPolicy: Never # 重启策略只能设置为Never或者OnFailurecontainers:- name: counterimage: busybox:1.30command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 2;done"]
关于重启策略设置的说明:如果指定为OnFailure,则job会在pod出现故障时重启容器,而不是创建pod,failed次数不变如果指定为Never,则job会在pod出现故障时创建新的pod,并且故障pod不会消失,也不会重启,failed次数加1如果指定为Always的话,就意味着一直重启,意味着job任务会重复去执行了,当然不对,所以不能设置为Always
查看job [root@k8s-master01 ~]# kubectl get job -n dev -o wide -w
-
CronJob
CronJob控制器以Job控制器资源为其管控对象,并借助它管理pod资源对象,Job控制器定义的作业任务在其控制器资源创建之后便会立即执行,但CronJob可以以类似于Linux操作系统的周期性任务作业计划的方式控制其运行时间点及重复运行的方式。也就是说,CronJob可以在特定的时间点(反复的)去运行job任务。
apiVersion: batch/v1beta1 # 版本号
kind: CronJob # 类型
metadata: # 元数据name: # rs名称 namespace: # 所属命名空间 labels: #标签controller: cronjob
spec: # 详情描述schedule: # cron格式的作业调度运行时间点,用于控制任务在什么时间执行concurrencyPolicy: # 并发执行策略,用于定义前一次作业运行尚未完成时是否以及如何运行后一次的作业failedJobHistoryLimit: # 为失败的任务执行保留的历史记录数,默认为1successfulJobHistoryLimit: # 为成功的任务执行保留的历史记录数,默认为3startingDeadlineSeconds: # 启动作业错误的超时时长jobTemplate: # job控制器模板,用于为cronjob控制器生成job对象;下面其实就是job的定义metadata:spec:completions: 1parallelism: 1activeDeadlineSeconds: 30backoffLimit: 6manualSelector: trueselector:matchLabels:app: counter-podmatchExpressions: 规则- {key: app, operator: In, values: [counter-pod]}template:metadata:labels:app: counter-podspec:restartPolicy: Never containers:- name: counterimage: busybox:1.30command: ["bin/sh","-c","for i in 9 8 7 6 5 4 3 2 1; do echo $i;sleep 20;done"]
需要重点解释的几个选项:
schedule: cron表达式,用于指定任务的执行时间*/1 * * * *<分钟> <小时> <日> <月份> <星期>分钟 值从 0 到 59.小时 值从 0 到 23.日 值从 1 到 31.月 值从 1 到 12.星期 值从 0 到 6, 0 代表星期日多个时间可以用逗号隔开; 范围可以用连字符给出;*可以作为通配符; /表示每...
concurrencyPolicy:Allow: 允许Jobs并发运行(默认)Forbid: 禁止并发运行,如果上一次运行尚未完成,则跳过下一次运行Replace: 替换,取消当前正在运行的作业并用新作业替换它
查看cronjob [root@k8s-master01 ~]# kubectl get cronjobs -n dev
-
Horizontal Pod Autoscaler(HPA)
HPA可以获取每个Pod利用率,然后和HPA中定义的指标进行对比,同时计算出需要伸缩的具体值,最后实现Pod的数量的调整。其实HPA与之前的Deployment一样,也属于一种Kubernetes资源对象,它通过追踪分析RC控制的所有目标Pod的负载变化情况,来确定是否需要针对性地调整目标Pod的副本数,这是HPA的实现原理。
# 使用kubectl top node 查看资源使用情况
[root@k8s-master01 1.8+]# kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
k8s-master01 289m 14% 1582Mi 54%
k8s-node01 81m 4% 1195Mi 40%
k8s-node02 72m 3% 1211Mi 41%
[root@k8s-master01 1.8+]# kubectl top pod -n kube-system
NAME CPU(cores) MEMORY(bytes)
coredns-6955765f44-7ptsb 3m 9Mi
coredns-6955765f44-vcwr5 3m 8Mi
etcd-master 14m 145Mi
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:name: pc-hpanamespace: dev
spec:minReplicas: 1 #最小pod数量maxReplicas: 10 #最大pod数量targetCPUUtilizationPercentage: 3 # CPU使用率指标scaleTargetRef: # 指定要控制的nginx信息apiVersion: apps/v1kind: Deploymentname: nginx
查看hpa [root@k8s-master01 1.8+]# kubectl get hpa -n dev NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE pc-hpa Deployment/nginx 0%/3% 1 10 1 62s
-
StatefulSet
-
Service
常用命令:
# 创建service
[root@k8s-master01 ~]# kubectl create -f service-clusterip.yaml
service/service-clusterip created# 查看service
[root@k8s-master01 ~]# kubectl get svc -n dev -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service-clusterip ClusterIP 10.97.97.97 <none> 80/TCP 13s app=nginx-pod# 查看service的详细信息# 在这里有一个Endpoints列表,里面就是当前service可以负载到的服务入口
[root@k8s-master01 ~]# kubectl describe svc service-clusterip -n dev
Name: service-clusterip
Namespace: dev
Labels: <none>
Annotations: <none>
Selector: app=nginx-pod
Type: ClusterIP
IP: 10.97.97.97
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.1.39:80,10.244.1.40:80,10.244.2.33:80
Session Affinity: None
Events: <none># 查看ipvs的映射规则
[root@k8s-master01 ~]# ipvsadm -Ln
TCP 10.97.97.97:80 rr-> 10.244.1.39:80 Masq 1 0 0-> 10.244.1.40:80 Masq 1 0 0-> 10.244.2.33:80 Masq 1 0 0# 访问10.97.97.97:80观察效果
[root@k8s-master01 ~]# curl 10.97.97.97:80
10.244.2.33
-
service概念和原理
在kubernetes中,pod是应用程序的载体,我们可以通过pod的ip来访问应用程序,但是pod的ip地址不是固定的,这也就意味着不方便直接采用pod的ip对服务进行访问。
为了解决这个问题,kubernetes提供了Service资源,Service会对提供同一个服务的多个pod进行聚合,并且提供一个统一的入口地址。通过访问Service的入口地址就能访问到后面的pod服务。
Service在很多情况下只是一个概念,真正起作用的其实是kube-proxy服务进程,每个Node节点上都运行着一个kube-proxy服务进程。当创建Service的时候会通过api-server向etcd写入创建的service的信息,而kube-proxy会基于监听的机制发现这种Service的变动,然后它会将最新的Service信息转换成对应的访问规则。
kube-proxy目前支持三种工作模式:
userspace 模式
userspace模式下,kube-proxy会为每一个Service创建一个监听端口,发向Cluster IP的请求被Iptables规则重定向到kube-proxy监听的端口上,kube-proxy根据LB算法选择一个提供服务的Pod并和其建立链接,以将请求转发到Pod上。 该模式下,kube-proxy充当了一个四层负责均衡器的角色。由于kube-proxy运行在userspace中,在进行转发处理时会增加内核和用户空间之间的数据拷贝,虽然比较稳定,但是效率比较低。
iptables模式
iptables模式下,kube-proxy为service后端的每个Pod创建对应的iptables规则,直接将发向Cluster IP的请求重定向到一个Pod IP。 该模式下kube-proxy不承担四层负责均衡器的角色,只负责创建iptables规则。该模式的优点是较userspace模式效率更高,但不能提供灵活的LB策略,当后端Pod不可用时也无法进行重试。
ipvs模式
ipvs模式和iptables类似,kube-proxy监控Pod的变化并创建相应的ipvs规则。ipvs相对iptables转发效率更高。除此以外,ipvs支持更多的LB算法。
ipvs此模式必须安装ipvs内核模块,否则会降级为iptables# 开启ipvs
//使用kubectl api-resources可以查看cm是什么?
修改kube-proxy模式命令:
[root@k8s-master01 ~]# kubectl edit cm kube-proxy -n kube-system
修改mode: "ipvs"
service四种类型:
-
ClusterIP:默认值,它是Kubernetes系统自动分配的虚拟IP,只能在集群内部访问
-
NodePort:将Service通过指定的Node上的端口暴露给外部,通过此方法,就可以在集群外部访问服务
-
LoadBalancer:使用外接负载均衡器完成到服务的负载分发,注意此模式需要外部云环境支持
-
ExternalName: 把集群外部的服务引入集群内部,直接使用
ClusterIP类型:
apiVersion: v1
kind: Service
metadata:name: service-clusteripnamespace: dev
spec:selector:app: nginx-podclusterIP: 10.97.97.97 # service的ip地址,如果不写,默认会生成一个type: ClusterIPports:- port: 80 # Service端口 targetPort: 80 # pod端口
无头service:
修改type=CluserIP
# kubectl edit service service
向集群内部暴露一个IP,外部无法访问,随机ip
type: CluserIP
CluserIP: None
无头service就是CluserIP没有的service,主要作用:因为访问可以直接用ingress域名端口转发,所以可以不使用内网ip,占ip资源。一般给ingress使用
当遇到不需要负载均衡,也不需要单独的 Service IP 的情况,可以通过显式设置集群 IP(spec.clusterIP)的值为 "None" 来创建无头服务(Headless Service)。
无头 Service 不会获得集群 IP,kube-proxy 不会处理这类 Service,而且平台也不会为它们提供负载均衡或路由支持。
无头 Service 允许客户端直接连接到任一 Pod。它不使用虚拟 IP 地址和代理配置路由和数据包转发;而是通过内部 DNS 记录报告各个 Pod 的端点 IP 地址,这些 DNS 记录是由集群的 DNS 服务所提供的。
Service的定义配置:将 .spec.type 设置为 ClusterIP(这也是 type 的默认值),并进一步将 .spec.clusterIP 设置为 None。字符串值 None 是一种特殊情况,与未设置 .spec.clusterIP 字段不同。
两个应用场景:
-
自主选择权。有时候 Client 想自己来决定使用哪个 Real Server,可以通过查询 DNS 来获取 Real Server 的信息。
-
Headless Service 的对应的每一个 Endpoints,即每一个 Pod,都会有对应的 DNS 域名;这样 Pod 之间就能互相访问,集群也能单独访问 Pod。
NodePort类型: (一般测试用,正式环境不实用,因为端口占用严重)
这种方式不足:
1.一个端口只提供一个服务使用
2.只能使用30000-32767之间的端口
3.如果节点/虚拟机的IP地址发送变化,需要人工处理;
所以在生产环境,不推荐这种方式发布服务
如果希望将Service暴露给集群外部使用,那么就要使用到另外一种类型的Service,称为NodePort类型。NodePort的工作原理其实就是将service的端口映射到Node的一个端口上,然后就可以通过NodeIp:NodePort
来访问service了。
apiVersion: v1
kind: Service
metadata:name: service-nodeportnamespace: dev
spec:selector:app: nginx-podtype: NodePort # service类型ports:- port: 80nodePort: 30002 # 指定绑定的node的端口(默认的取值范围是:30000-32767), 如果不指定,会默认分配targetPort: 80
查看service
[root@k8s-master01 ~]# kubectl get svc -n dev -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) SELECTOR
service-nodeport NodePort 10.105.64.191
接下来可以通过电脑主机的浏览器去访问集群中任意一个nodeip的30002端口,即可访问到pod
LoadBalancer类型的Service
LoadBalancer和NodePort很相似,目的都是向外部暴露一个端口,区别在于LoadBalancer会在集群的外部再来做一个负载均衡设备,而这个设备需要外部环境支持的,外部服务发送到这个设备上的请求,会被设备负载之后转发到集群中。
ExternalName类型的Service
ExternalName:将其他链接设置一个集群内部的别名。代码里面使用内部的别名。链接资源有变化,只需要修改链接,别名不用修改。否则需要大量的修改。无缝迁移。类似把其他链接定义一个全局变量,代码内部使用变量,全局变量可以在配置文件修改
ExternalName类型的Service用于引入集群外部的服务,它通过
externalName
属性指定外部一个服务的地址,然后在集群内部访问此service就可以访问到外部的服务了。
apiVersion: v1
kind: Service
metadata:name: service-externalnamenamespace: dev
spec:type: ExternalName # service类型externalName: www.baidu.com #改成ip地址也可以
当集群内部访问这个svc的域名时,即 service-externalname.dev.svc.cluster.local的时候,DNS插件会转化成外部域名www.baidu.com
Endpoints
Endpoint是kubernetes中的一个资源对象,存储在etcd中,用来记录一个service对应的所有pod的访问地址,它是根据service配置文件中selector描述产生的。
创建service的时候如果有selecter,则会默认创建一个同名的endpoints,没有需要管理员手动创建
一个Service由一组Pod组成,这些Pod通过Endpoints暴露出来,Endpoints是实现实际服务的端点集合。换句话说,service和pod之间的联系是通过endpoints实现的。
访问pod需要有两个条件,标签匹配和就绪,如果有需求,pod即使不就绪也要访问,则可以进行如下配置:
-
Ingerss
Service对集群之外暴露服务的主要方式有两种:NotePort和LoadBalancer,但是这两种方式,都有一定的缺点:
-
NodePort方式的缺点是会占用很多集群机器的端口,那么当集群服务变多的时候,这个缺点就愈发明显
-
LB方式的缺点是每个service需要一个LB,浪费、麻烦,并且需要kubernetes之外设备的支持
基于这种现状,kubernetes提供了Ingress资源对象,Ingress只需要一个NodePort或者一个LB就可以满足暴露多个Service的需求。
Ingress相当于一个7层的负载均衡器,是kubernetes对反向代理的一个抽象,它的工作原理类似于Nginx,可以理解成在Ingress里建立诸多映射规则,Ingress Controller通过监听这些配置规则并转化成Nginx的反向代理配置 , 然后对外部提供服务
工作原理:
(1)ingress-controller通过和 kubernetes APIServer 交互,动态的去感知集群中ingress规则变化,
(2)然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段nginx配置。
(3)再写到nginx-ingress-controller的pod里,这个ingress-controller的pod里运行着一个Nginx服务,控制器会把生成的 nginx配置写入 /etc/nginx.conf文件中。
(4)然后reload一下使配置生效。以此达到域名区分配置和动态更新的作用。
创建:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:name: ingress-httpnamespace: dev
spec:rules:- host: nginx.itheima.comhttp:paths:- path: /backend:serviceName: nginx-serviceservicePort: 80- host: tomcat.itheima.comhttp:paths:- path: /backend:serviceName: tomcat-serviceservicePort: 8080
# 查看
[root@k8s-master01 ~]# kubectl get ing ingress-http -n dev
NAME HOSTS ADDRESS PORTS AGE
ingress-http nginx.itheima.com,tomcat.itheima.com 80 22s# 查看详情
[root@k8s-master01 ~]# kubectl describe ing ingress-http -n dev
-
存储
常用命令:
加密base64:
echo -n “houzheng” | base64
解密base64:
echo -n “dafsfjlsjfiojeiofjiosej” | base64 -d
Configmap:
#创建一,基于命令行采纳数
kubectl create configmap nginx-config --from-literal=nginx_port=80 --from-literal=server_name=nginx# 创建二,基于本地文件
kubectl create configmap www-nginx --from-file=www=/opt/config/nginx.conf#查看configmap
kubectl describe configmap nginx-config
kubectl get cm nginx-config -o yaml
secret:
把 mysql 的 root 用户的 password 创建成 secret
kubectl create secret generic mysql-password --from-literal=password=xy123456
查看secret详细信息
kubectl describe secret mysql-password
存储的分类: 元数据:
-
configmap:用于保存配置数据(明文)
-
Secret:用于保存敏感性数据(编码)
-
Downward API:容器在运行时从k8s APIServer获取有关自身的信息
真实数据:
-
Volume:用于存储临时或者持久性数据
-
PersistentVolume: 申请制的持久化存储
configmap
Configmap 是 k8s 中的资源对象,用于保存非机密性的配置的,数据可以用 key/value 键值对的形式保存,也可通过文件的形式保存。使用时, Pods 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。
#创建一,基于命令行采纳数
kubectl create configmap nginx-config --from-literal=nginx_port=80 --from-literal=server_name=nginx# 创建二,基于本地文件
kubectl create configmap www-nginx --from-file=www=/opt/config/nginx.conf#查看configmap
kubectl describe configmap nginx-config
kubectl get cm nginx-config
通过yaml创建:
kubectl apply -f nginx_conf.yaml
apiVersion: v1
kind: ConfigMap
metadata:name: nginx-conflabels:app: nginx-conf
data:nginx.conf: |server {server_name www.nginx.com;listen 80 root /home/nginx/www }
pod中使用configmap:
configmap:
apiVersion: v1
kind: ConfigMap
metadata:name: testlabels:app: test
data:xy: "xiayan"hi: "hello world"
kubectl apply -f test.yaml
pod中以环境变量方式使用:
创建一个pod,引用configmap
apiVersion: v1
kind: Pod
metadata:name: mypod
spec:containers:- name: busyboximage: busyboxcommand: [ "/bin/sh", "-c", "echo $(LEVEL) $(TYPE)" ]env:- name: LEVELvalueFrom:configMapKeyRef:name: testkey: xy- name: TYPEvalueFrom:configMapKeyRef:name: testkey: hirestartPolicy: Never
pod中以卷方式使用:
apiVersion: v1
kind: Pod
metadata:creationTimestamp: nulllabels:run: nginxname: nginx
spec:terminationGracePeriodSeconds: 0#定义configmap类型的卷volumes:- name: configmap1configMap:name: cm3containers:- image: nginximagePullPolicy: IfNotPresentname: nginxresources: {}#把nginx.conf文件挂载到/etc/nginx/nginx.confvolumeMounts:- name: configmap1mountPath: /etc/nginx/nginx.confsubPath: nginx.confdnsPolicy: ClusterFirstrestartPolicy: Always
status: {}
Secret:
Secret 解决了密码、token、秘钥等敏感数据的配置问题,而不需要把这些敏感数据暴露到镜像或者 Pod Spec 中。Secret 可以以 Volume 或者环境变量的方式使用。Secret 类似于 ConfigMap 但专门用于保存机密数据。
类型:
创建 Secret 时,你可以使用 Secret 资源的 type 字段。 Secret 类型有助于对 Secret 数据进行编程处理。
Kubernetes 提供若干种内置的类型,用于一些常见的使用场景。 针对这些类型,Kubernetes 所执行的合法性检查操作以及对其所实施的限制各不相同。默认的 Secret 类型是 Opaque。用 generic 子命令来标明要创建的是一个 Opaque 类型 的Secret
比如:
把 mysql 的 root 用户的 password 创建成 secret
kubectl create secret generic mysql-password --from-literal=password=xy123456
查看secret详细信息
kubectl describe secret mysql-password
通过yaml文件创建:
通过手动加密,基于base64加密
echo -n 'admin' | base64
YWRtaW4=
echo -n 'xy123456' | base64
eHkxMjM0NTY=创建YAML
apiVersion: v1
kind: Secret
metadata: name: mysecret
type: Opaque
data:username: YWRtaW4=password: eHkxMjM0NTY=
kubectl apply -f secret.yaml
kubectl get secret
kubectl describe secret mysecret
使用方式与configmap类似:
变量使用:
apiVersion: v1
kind: Pod
metadata: name: secretpod
spec containers: - name: busybox image: busybox command: [ "/bin/sh","-c","echo $(SECRET_USERNAME) $(SECRET_PASSWORD)" ] env: - name: SECRET_USERNAME valueFrom: secretKeyRef: name: mysecretkey: username- name: SECRET_PASSWORDvalueFrom:secretKeyRef:name: mysecretkey: passwordrestartPolicy: Never
文件使用:
将 Secret 挂载到 Volume 中
vim pod_secret_volume.yaml
apiVersion: v1
kind: Pod
metadata: name: secret-volume-pod
spec: containers: - name: nginx image: nginx volumeMounts: - name: secret-volume mountPath: "/etc/secret" readOnly: true volumes: - name: secret-volume secret: secretName: mysecret
文件使用时,key和创建时的一样,每一个字段都是一个文件,进入pod可以看到/etc/secret下有password和username两个文件,查看内容和我们创建的secret内容吻合。
Downward API
:
为了在容器内获取Pod级别的信息,Kubernetes
提供了Downward API
机制来将Pod
和容器的某些元数据信息注入容器环境内,供容器应用方便地使用。
Downward API可以通过以下两种方式将Pod
和容器的元数据信息注入容器内部:
-
环境变量:将Pod或Container信息设置为容器内的环境变量;
-
Volume挂载:将Pod或Container信息以文件的形式挂载到容器内部。
一、环境变量的方式(使用fieldRef)
apiVersion: v1
kind: Pod
metadata:name: test-env-podnamespace: kube-system
spec:containers:- name: test-env-podimage: daocloud.io/library/nginxenv:- name: POD_NAME #第⼀个环境变量的名字valueFrom: #使⽤valueFrom⽅式设置fieldRef: #关联⼀个字段metadata.namefieldPath: metadata.name #这个字段从当前运⾏的pod详细信息查看- name: POD_NAMESPACEvalueFrom:fieldRef:fieldPath: metadata.namespace- name: POD_IPvalueFrom:fieldRef:fieldPath: status.podIP #因为pod的ip是不固定的,属于状态数据,所以使用status去获取
二、Volume
apiVersion: v1
kind: Pod
metadata:name: test-volume-podnamespace: kube-systemlabels:k8s-app: test-volumenode-env: test
spec:containers:- name: test-volume-pod-containerimage: daocloud.io/library/nginxvolumeMounts:- name: podinfomountPath: /etc/podinfovolumes:- name: podinfodownwardAPI:items:- path: "labels"fieldRef:fieldPath: metadata.labels
三、Downward API支持字段
使⽤ fieldRef 可以声明使⽤:
spec.nodeName - 宿主机名字
status.hostIP - 宿主机 IP
metadata.name - Pod 的名字
metadata.namespace - Pod 的 Namespace
status.podIP - Pod 的 IP
spec.serviceAccountName - Pod 的 Service Account 的名字
metadata.uid - Pod 的 UID
metadata.labels[ '<KEY>' ] - 指定 <KEY> 的 Label 值
metadata.annotations[ '<KEY>' ] - 指定 <KEY> 的 Annotation 值
metadata.labels - Pod 的所有 Label
metadata.annotations - Pod 的所有 Annotation
Volume
volume是kubernetes Pod中多个容器访问的共享目录。volume被定义在pod上,被这个pod的多个容器挂载到相同或不同的路径下。
volume的生命周期与pod的生命周期相同,pod内的容器停止和重启时一般不会影响volume中的数据。所以一般volume被用于持久化pod产生的数据。
Pod 中的每个容器必须独立地指定每个卷的挂载位置。
k8s支持的常见Volume类型如下: 基本存储:EmptyDir、HostPath、NFS 高级存储
emptyDir卷又称临时存储卷
emptyDir类型的volume在pod分配到node上时被创建,kubernetes会在node上自动分配 一个目录,因此无需指定宿主机node上对应的目录文件。这个目录的初始内容为空,当Pod从node上移除时,emptyDir中的数据会被永久删除。emptyDir 的应用场景,暂存空间,例如用于基于磁盘的合并排序
apiVersion: v1
kind: Pod
metadata:name: vol1
spec:containers:- image: busyboxplusname: vm1command: ["sleep", "300"]volumeMounts:- mountPath: /cache #vm1中的卷挂载到容器内的/cachename: cache-volume- image: nginxname: vm2volumeMounts:- mountPath: /usr/share/nginx/html #vm2中的卷挂载到容器内的/usr/share/nginx/htmlname: cache-volumevolumes:- name: cache-volume
volumes:- name: temp-volumeemptyDir: {}
hostPath
HostPath 允许将主机节点(Node)上的文件系统目录直接挂载到 Pod 中。这种 Volume 适合需要直接访问主机文件系统的应用场景,但在生产环境中使用时需注意安全性和可移植性问题。
例如只支持单节点(Node),而且只支持 “ReadWriteOnce”模式
volumes:- name: host-path-volumehostPath:path: /data
PV&PVC
有状态服务:
这是一种特殊的服务,简单的归纳下就是会产生需要持久化的数据,
并且有很强的I/O需求,且重启需要依赖上次存储到磁盘的数据。
如典型的mysql,kafka,zookeeper等等。
PersistentVolume 简称 PV, 是对底层共享存储的一种抽象,将共享存储定义为一种资源,它属于集群级别资源,不属于任何 Namespace,用户使用 PV 需要通过 PVC申请。PV 是由管理员进行创建和配置,它和具体的底层的共享存储技术的实现方式 有关,比如说 Ceph、GlusterFS、NFS等,都是通过插件机制完成与共享存储的对接,且根据不同 的存储 PV 可配置参数也是不相同。
PV概念 persistentVolume:是由管理员设置的存储,它是集群的一部分。就像节点时集群中的资源一样,PV也是集群中的资源。PV是Volumes之类的卷插件,但具有独立于使用PV的pod的生命周期。此API对象包含存储实现的细节,即NFS、iSCSI或者特定于云供应商的存储系统
apiVersion: v1
kind: PersistentVolume
metadata: labels: app: mariadb-pvname: data-mariadb-pv
spec: accessModes: - ReadWriteOncecapacity: storage: 10Gi # 挂载多大的存储空间hostPath: path: /data/mariadb type: DirectoryOrCreatepersistentVolumeReclaimPolicy: Retain # 回收策略storageClassName: standard # 存储类volumeMode: Filesystem # 卷存储模式
存储类 (storageClassName)
PV 可以通过配置 storageClassName 参数指定一个存储类 StorageClass 资源,具有特定 StorageClass 的 PV 只能与指定相同 StorageClass 的 PVC 进行绑定,没有设置 StorageClass的 PV 也是同样只能与没有指定 StorageClass 的 PVC 绑定
PV 可以通过配置 persistentVolumeReclaimPolicy 参数设置回收策略
可选项如下:
Retain(保留): 保留数据,需要由管理员手动清理。
Recycle(回收): 删除数据,即删除目录下的所有文件,比如说执行 rm -rf /thevolume/* 命 令,目前只有 NFS 和 HostPath 支持。
Delete(删除): 删除存储资源,仅仅部分云存储系统支持,比如删除 AWS EBS 卷,目前只有
AWS EBS,GCE PD,Azure 磁盘和 Cinder 卷支持删除。
PV 的生命周期 PV 生命周期总共四个阶段 :
Available(可用)—— 可用状态,尚未被 PVC 绑定。
Bound(已绑定)—— 绑定状态,已经与某个 PVC 绑定。
Released(已释放)—— 与之绑定的 PVC 已经被删除,但资源尚未被集群回收。
Failed(失败)—— 当删除 PVC 清理资源,自动回收卷时失败,所以处于故障状态。
命令行会显示绑定到 PV 的 PVC 的名称 ——kubectl get pv命令
PersistentVolumeClaim 简称 PVC,是用户存储的一种声明,类似于对存储资源的申请,它属于一个 Namespace 中的资源,可用于向 PV 申请 存储资源。PVC 和Pod 比较类似,Pod 消耗的是 Node 节点资源,而 PVC 消耗的是 PV 存储资源,Pod 可以请求 CPU 和 Memory,而PVC 可以请求特定的存储空间和访问模式。
PVC概念 peresistentVolumeClaim是用户存储的请求。它与pod相似,pod消耗节点资源,PVC消耗PV资源。 pod可以请求特定级别的资源(CPU和内存)。盛名可以请求特定的大小和访问模式。例如:可以以读/写一次或者 只读多次模式挂载。
apiVersion: v1
kind: PersistentVolumeClaim
metadata: name: k8sdemo-mariadb-pvclaim labels: app: k8sdemo-mariadb-pvc
spec: accessModes: - ReadWriteOncestorageClassName: standard resources: requests:storage: 1Gi # 申请的存储空间大小volumes: - name: mysqlvolume persistentVolumeClaim:claimName: k8sdemo-mariadb-pvclaim
POD中使用PVC:
StorageClass
StorageClass是一个存储类,通过创建StorageClass可以动态生成一个存储卷,供k8s用户使用。
使用StorageClass可以根据PVC动态的创建PV,减少管理员手工创建PV的工作。
StorageClass的定义主要包括名称、后端存储的提供者(privisioner)和后端存储的相关参数配置。StorageClass一旦被创建,就无法修改,如需修改,只能删除重建。
-
调度器
-
调度器概念
Kubernetes Scheduler(简称k8s Scheduler)是Kubernetes集群中的一个核心组件,它负责将Pod调度到合适的Node上运行,以实现集群资源的优化分配和负载均衡
- 主要功能:
资源分配:根据Pod的资源请求(如CPU、内存)和Node的当前可用资源情况,选择合适的Node来运行Pod。
满足约束条件:考虑Pod的调度约束条件和亲和性/反亲和性规则,如节点标签、区域、拓扑结构等要求,确保Pod被调度到符合其特定需求的Node上。
服务稳定性与优化:通过预选(Filtering)和优选(Scoring)两个阶段的策略执行,确保Pod能够成功调度,并尽可能地优化集群的整体性能和可靠性。
- 调度流程:
监听事件:Scheduler会持续监听API Server的事件,一旦有新的待调度Pod或已有Pod需要重新调度时,它将介入并进行调度决策。
筛选节点:对于每一个Node,检查该节点是否满足Pod的资源需求和其他硬性约束条件,如节点标签匹配、容忍度(Taints and Tolerations)、存储容量等。如果一个Node通过了所有预选策略,则会被加入候选节点集合。
打分排序:Scheduler对候选节点集合应用一系列优选策略,为每个节点计算一个优先级分数。这些优选策略可以包括默认的系统策略(如基于资源利用率的打分)以及用户自定义的策略。Scheduler根据各个节点得到的积分排序,得分最高的节点将被选为Pod的最佳调度位置。
绑定Pod:当确定了最优节点后,Scheduler会在API Server中为Pod创建一个binding对象,将Pod与选定的Node绑定在一起。调度结果写入etcd,并通知kubelet开始在该Node上启动Pod
- 调度策略:
优先级调度:根据Pod的优先级和Node的资源情况,优先调度高优先级的Pod。
公平调度:尽量平衡各个Node的资源使用情况,避免资源过度集中或浪费。
权重调度:根据预设的权重因子,综合考虑多种因素进行调度决策。
节点亲和性:根据节点的标签或特性,将Pod调度到具有相似特性的节点上。
- 调度算法:
预选算法
在Kubernetes(k8s)中,Scheduler的预选算法是Pod调度过程中的一个重要阶段,负责从集群中所有可用的节点中筛选出能够满足Pod资源需求和其他特定条件的候选节点。这一过程主要基于一系列的预选策略(Predicates)进行。以下是关于k8s Scheduler预选算法的详细解析:
预选算法的工作流程
- 获取节点列表:
Scheduler首先会从kube-apiserver获取集群中所有可用的节点列表。
- 遍历节点并筛选:
接着,Scheduler会遍历每一个节点,并根据预定义的预选策略(Predicates)对节点进行筛选。
每个预选策略都会检查节点是否满足特定的条件,例如资源是否充足、是否匹配Pod的标签选择器、是否有端口冲突等。
- 确定候选节点:
只有通过了所有预选策略的节点才会被视为候选节点,进入后续的优选阶段。
- 默认的预选策略
Kubernetes默认加载了多个预选策略,包括但不限于以下几个:
PodFitsPorts:判断Pod所使用的端口在备选节点中是否被占用。
PodFitsResources:判断备选节点的资源(如CPU、内存)是否满足Pod的需求。
PodSelectorMatches(MatchNodeSelector):判断备选节点是否包含Pod的标签选择器指定的标签。
PodFitHost(HostName):判断Pod的spec.nodeName所指定的节点名称和备选节点的名称是否一致。
NoDiskConflict:判断Pod的存储卷(如GCEPersistentDisk或AwsElasticBlockStore)和备选节点中已存在的Pod是否存在冲突。
预选算法的优化
为了提高预选过程的效率,Kubernetes采用了多种优化措施,如:
并行筛选:默认会启动多个goroutine来并行地进行节点的筛选,以提高筛选速度。
局部最优解:通过缩小筛选节点的数量范围,来避免在大型集群中遍历所有节点导致的性能问题。
平均分布:通过分配索引的方式,确保集群中的节点能够均匀地被分配Pod,以维持集群的负载均衡。
自定义预选策略
除了默认的预选策略外,用户还可以根据实际需求自定义预选策略,并将其注册到Scheduler中。自定义预选策略需要实现Kubernetes提供的接口,并在Scheduler的配置文件中进行指定。
- 总结
k8s Scheduler的预选算法是Pod调度过程中的关键一环,通过一系列的预选策略对集群中的节点进行筛选,从而确定能够满足Pod需求的候选节点。这一过程不仅确保了Pod能够被调度到合适的节点上运行,还通过多种优化措施提高了调度的效率和性能。
优选算法
k8s Scheduler的优选算法是在预选算法之后进行的,旨在从通过预选的候选节点中选择出最优的节点来运行Pod。这一过程主要基于一系列的优选函数(Priorities)进行,每个函数都会为候选节点打分,最终选择得分最高的节点作为Pod的运行节点。
优选算法的工作流程
- 获取候选节点:
优选算法首先会接收到预选算法筛选出的候选节点列表。
- 并发打分:
对于每个候选节点,优选算法会并发地根据配置的优选函数进行打分。
每个优选函数都会根据特定的评估标准(如资源利用率、节点标签、亲和性等)为节点计算一个分数。
- 加权求和:
在所有优选函数打分完成后,Scheduler会根据每个优选函数的权重(如果设置了的话)对节点的各个分数进行加权求和,得到节点的最终得分。
- 选择最优节点:
最终,Scheduler会选择得分最高的节点作为Pod的运行节点,并将其绑定到该节点上。
- 常用的优选函数
Kubernetes提供了多种内置的优选函数,包括但不限于以下几个:
LeastRequestedPriority:
计算Pods需要的CPU和内存在当前节点可用资源的百分比,具有最小百分比的节点就是最优的。
得分计算公式:(cpu(capacity-sum(requested))*10/capacity)+(memory(capacity-sum(requested))*10/capacity)/2BalanceResourceAllocation:
选出资源使用率最均匀的节点,即CPU和内存占用率相近的节点。NodePreferAvoidPodsPriority:
如果节点上有注解信息"scheduler.alpha.kubernetes.io/preferAvoidPods",则该节点对该Pod的得分会很低(甚至为0),反之则得分很高。TaintToleration:
将Pod对象的spec.tolerations与节点的taints列表项进行匹配度检查,匹配的条目越多得分越低。ImageLocalityPriority:
根据Node上是否存在Pod的容器运行所需镜像以及镜像的大小对优先级打分。如果Node上存在Pod所需全部镜像,则得分为10分;如果Node上存在Pod容器部分所需镜像,则根据这些镜像的大小来决定分值;如果Node上一个镜像都不存在,则分值为0。InterPodAffinityPriority:
基于Pod亲和性(affinity)和反亲和性(anti-affinity)计算分数。遍历Pod对象亲和性的条目,并将那些能够匹配到节点的权重相加,值越大的得分越高。NodeAffinityPriority:
根据Pod对象中的nodeSelector,对节点进行匹配度检查,能够成功匹配的数量越多,得分就越高。
自定义优选函数
除了内置的优选函数外,用户还可以根据实际需求自定义优选函数,并将其注册到Scheduler中。自定义优选函数需要实现Kubernetes提供的接口,并在Scheduler的配置文件中进行指定。
综上所述,k8s Scheduler的优选算法通过一系列的优选函数为候选节点打分,并选择得分最高的节点作为Pod的运行节点,从而实现了Pod的优化调度。
-
亲和性
在Kubernetes(k8s)中,节点亲和性(Node Affinity)是一种控制Pod调度到特定节点的高级策略。通过定义节点亲和性规则,管理员可以确保Pod被调度到符合特定条件的节点上,从而实现资源优化、性能提升、故障隔离以及满足特定的合规或业务需求。
一、节点亲和性的基本概念
节点亲和性允许Pod根据节点的标签(Labels)和选择器(Selectors)来指定其应该被调度到的节点。这有助于将Pod与具有特定特征(如硬件类 型、地理位置、操作系统等)的节点关联起来。
二、节点亲和性的类型
节点亲和性可以分为两种类型:
- 硬亲和性(requiredDuringSchedulingIgnoredDuringExecution):
Pod必须被调度到满足特定条件的节点上。
如果没有满足条件的节点,Pod将不会被调度,并且将保持Pending状态直到有符合条件的节点出现。
Pod一旦被调度到某个节点上,即使节点的标签或条件发生变化,Pod也不会被重新调度。
- 软亲和性(preferredDuringSchedulingIgnoredDuringExecution):
Pod倾向于被调度到满足特定条件的节点上,但这不是强制性的。
如果没有满足条件的节点,Pod仍然可以被调度到其他节点上。
同样,Pod一旦被调度到某个节点上,即使节点的标签或条件发生变化,Pod也不会被重新调度。
三、节点亲和性的配置
节点亲和性的配置通常通过YAML文件实现,在Pod的spec字段下添加affinity字段,并设置nodeAffinity子字段。以下是一个简单的配置示例:
apiVersion: v1
kind: Pod
metadata: name: my-pod
spec: affinity: # 亲和性配置nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: disktype operator: In values: - ssd containers: - name: my-container image: my-image
在上述示例中,我们定义了一个Pod,它要求被调度到具有disktype=ssd标签的节点上。这是通过硬亲和性规则实现的,因此如果没有满足条件的 节点,Pod将不会被调度。
四、节点亲和性的应用场景
节点亲和性在多种场景下都非常有用,例如:
硬件要求:某些Pod可能对硬件有特殊要求(如需要SSD存储、特定的CPU类型等),这时可以使用节点亲和性将Pod调度到满足这些要求的节点上。
地理位置:在分布式系统中,可能希望将某些Pod调度到特定的地理位置(如靠近用户的数据中心),以提高访问速度和降低延迟。
资源优化:通过节点亲和性,可以将具有相似资源需求的Pod调度到同一节点上,以优化资源使用并减少资源浪费。
五、总结
Kubernetes的节点亲和性提供了一种灵活且强大的方式来控制Pod的调度行为。通过合理配置节点亲和性规则,管理员可以确保Pod被调度到符合特 定条件的节点上,从而实现资源优化、性能提升、故障隔离以及满足特定的合规或业务需求。
pod亲和性:
Pod亲和性/反亲和性:根据Pod之间的依赖关系或排斥关系,将相关的Pod调度到相同或不同的节点上。
在Kubernetes(简称K8S)中,Pod亲和性(Pod Affinity)是集群调度策略的一个重要组成部分,它允许用户指定某种规则,使得Pod更倾向 于被调度到满足特定条件的节点上运行,或者与已经在特定节点上运行的其他Pod部署在一起。以下是对K8S Pod亲和性的详细解释:
一、Pod亲和性的基本概念
Pod亲和性主要用于处理Pod与Pod之间的关系,它允许Pod表达出希望与其相同或不同标签集的Pod共存于同一节点或拓扑域(如机架、可用区等) 的愿望。这种机制有助于优化资源使用、提高服务可靠性,并满足特定的应用程序需求。
-
二、Pod亲和性的类型
-
Pod亲和性可以分为两种类型:
- 硬策略(requiredDuringSchedulingIgnoredDuringExecution):
必须满足条件,比较强硬。
如果没有满足条件的节点,调度器会不断重试,直到找到满足条件的节点为止。
一旦Pod被调度到某个节点,即使后续节点上的Pod标签发生变化,也不会影响已调度Pod的位置。
- 软策略(preferredDuringSchedulingIgnoredDuringExecution):
尽量满足条件,但不强制要求。
如果没有满足条件的节点,Pod仍然可以被调度到其他节点上。
同样,一旦Pod被调度到某个节点,后续节点上的Pod标签变化也不会影响已调度Pod的位置。
三、Pod亲和性的配置
Pod亲和性的配置通常通过YAML文件实现,在Pod的spec字段下添加affinity字段,并设置podAffinity子字段。以下是一个简单的配置示例:
apiVersion: apps/v1
kind: Deployment
metadata: name: my-deployment
spec: replicas: 2 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: containers: - name: my-container image: my-image affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: app operator: In values: - my-app topologyKey: kubernetes.io/hostname
在上述示例中,我们定义了一个Deployment,它包含两个副本的Pod。这些Pod通过Pod亲和性的硬策略被要求调度到与标签app=my-app相同的Pod 所在的节点上。topologyKey设置为kubernetes.io/hostname,表示Pod将被调度到与已存在Pod相同的物理节点上。
四、Pod亲和性的应用场景
Pod亲和性在多种场景下都非常有用,例如:
-
数据本地性:对于需要频繁访问本地存储的Pod,可以将其与存储服务所在的Pod部署在同一节点上,以减少网络延迟和提高性能。
-
服务依赖:当Pod之间存在服务依赖关系时,可以使用Pod亲和性将它们部署在同一节点上,以确保服务的可用性和稳定性。
-
资源优化:通过Pod亲和性,可以将具有相似资源需求的Pod部署在同一节点上,以优化资源使用并减少资源浪费。
五、总结
K8S Pod亲和性是一种强大的调度策略,它允许用户根据Pod之间的依赖关系或资源需求来优化Pod的部署位置。通过合理配置Pod亲和性,可以提高 集群的资源利用率、服务可靠性和应用程序性能。
-
容忍与污点
在Kubernetes(k8s)中,污点(Taints)和容忍(Tolerations)是两种相互配合的机制,用于控制Pod的调度行为,确保Pod不会被调度到不合适的节点上。以下是对污点和容忍的详细解释:
一、污点(Taints)
定义与作用
污点是定义在节点(Node)上的键值对属性,用于让节点拒绝将Pod调度运行于其上,除非Pod有接纳节点污点的容忍度。污点的主要作用是标识节点具有某些不希望的属性,从而阻止Pod被调度到该节点上。
每个污点由一个key、一个可选的value以及一个effect组成,格式为key=value:effect。其中,value可以为空,而effect描述了污点对Pod的作用效果。
- Effect的类型
NoSchedule:表示Kubernetes不会将Pod调度到具有该污点的节点上,但已经调度到该节点的Pod不受影响。
PreferNoSchedule:软策略版本的NoSchedule,表示Kubernetes将尽量避免将Pod调度到具有该污点的节点上,但不是强制的。
NoExecute:表示Kubernetes不仅不会将Pod调度到具有该污点的节点上,还会将已经存在于该节点的Pod驱逐出去。
PreferNoSchedule: 表示k8s将尽量避免将pod调度到具有该污点的Node上
设置与去除
污点可以通过kubectl taint命令进行设置和去除。例如,设置污点使用kubectl taint nodes =:命令,去除污点则使用kubectl taint nodes :-命令。
#设置污点
kubectl taint nodes nodeName key=value1:NoSchedule
# 查找污点
kubectl describe node nodeName
Taints: node-role.kubernetes.io/control-plane:NoSchedule
# 删除污点
kubectl taint nodes nodeName key=value1:NoSchedule-
二、容忍(Tolerations)
定义与作用
容忍是定义在Pod上的键值对属性,用于配置Pod可以容忍哪些污点。只有当Pod具有对节点污点的容忍度时,它才有可能被调度到该节点上。
组成
每个容忍由一个key、一个可选的operator、一个可选的value以及一个effect组成。其中,operator用于指定与污点value的比较方式,默认为Equal;value用于与污点的value进行匹配;effect则指定了容忍的污点效果。
匹配规则
如果operator是Exists,则无需指定value,表示Pod可以容忍所有具有该key的污点。
如果operator是Equal,则Pod的容忍必须与污点的key和value都匹配。
如果不指定operator,则默认为Equal。
示例
apiVersion: v1
kind: Pod
metadata: name: tolerant-pod
spec: containers: - name: nginx-container image: nginx:latest tolerations: - key: "special" operator: "Equal" value: "gpu" effect: "NoSchedule"tolerationSeconds: 3600 # 3600秒后驱除pod
在上面的示例中,Pod tolerant-pod 定义了一个容忍度,表示它可以被调度到具有special=gpu:NoSchedule污点的节点上。
当不指定value时,表示容忍所有污点value
- key: "key2"operator: "Exists"effect: "NoSchedule"
当不指定key值时,表示容忍所有的污点key
tolerations:
- operator: "Exists"
当不指定effect值时,表示容忍所有污点的作用
tolerations:
- key: "key"operator: "Exists"
多个master存在,防止资源浪费,使用一下命令可将pod部署至master
kubectl taint nodes nodeName node-role.kubenetes.io/master=:NoSchedule-
kubectl taint nodes nodeName node-role.kubenetes.io/master=:PreferNoSchedule
污点和容忍是Kubernetes中用于控制Pod调度行为的两种重要机制。通过给节点设置污点,可以阻止不希望的Pod被调度到该节点上;通过在Pod上定义容忍度,可以使得Pod能够容忍节点的污点,从而被调度到该节点上。这两种机制相互配合,实现了对Pod调度行为的灵活控制。
10.4 固定节点调度
设置pod.spec.nodeName 指定pod强制调度到master上
apiVersion: apps/v1
kind: Deployment
metadata:name: nodename-test
spec:replicas: 7selector:matchLabels:app: nodenametemplate:metadata:labels:app: nodenamespec:nodeName: mastercontainers:- name: mywebimage: wangyanglinux/myapp:v1.0ports:- containerPort: 80
设置pod.spec.nodeSelector 通过label-selecotr机制选择节点,由Scheduler策略匹配label,而后调度pod到目标节点,该规则属于强制约束 master如果有noSchedule污点选项 则master有label type=nodeselect也不能在master上创建
apiVersion: apps/v1
kind: Deployment
metadata:name: nodeselect-test
spec:replicas: 2selector: # 选择器matchLabels:app: nodeselecttemplate:metadata:labels:app: nodeselectspec:nodeSelector:type: nodeselect # key:value 节点需要有此标签containers:- name: mywebimage: wangyanglinux/myapp:v1.0ports:- containerPort: 80
-
集群安全机制
-
安全机制说明
由于API-Server 是 Kubernetes 集群数据的唯一访问入口,所以apiserver做统一协调,比如门卫。 访问过程中需要证书、token、或者用户名+密码
访问k8s集群的时候,需要经过三个步骤完成具体操作 第一步:认证 第二步:鉴权(授权) 第三步:准入控制
-
认证
认证是K8S集群安全机制的第一道防线,它负责确认请求者的身份。K8S支持多种认证方式,以适应不同的安全需求和场景。
客户端身份认证常用方式:
- https证书认证,基于ca证书
HTTPS证书认证是基于CA根证书签名的客户端身份认证方式,实现了双向认证。
这种方式安全性高,推荐在生产环境中使用。
通过HTTPS证书认证,客户端和服务器能够相互验证对方的身份,确保通信的安全性。
- http token认证,通过token识别用户
客户端在发起请求时,将Token放入HTTP请求的头部信息中。
虽然这种方式简单易行,但Token存放在文件中且为单向认证,
安全性相对较低,通常不建议在生产环境中使用。
- http基本认证,用户名+密码认证
HTTP Basic认证通过用户名和密码进行认证。
用户名和密码经过Base64编码后放在HTTP请求的Authorization头部中。
然而,Base64编码容易被解码,因此这种方式也不安全,不推荐在生产环境中使用。
-
鉴权
鉴权是在认证通过后,确定请求者有哪些权限的过程。K8S中最常用的鉴权方式是RBAC(基于角色的访问控制)。
RBAC核心组件:
- 角色
role:特定命名空间访问权限
ClusterRole:所有命名空间访问权限
- 角色绑定
rolebinding:角色绑定到主体
ClusterRoleBinding:集群角色绑定到主体
- 主体
user:用户
group:用户组
serviceAccount:服务账号
-
准入控制
准入控制是K8S集群安全机制的最后一道防线,它在资源被创建或修改之前进行最后的检查,确保资源的创建符合集群的策略和规范。
常用准入控制器
-
MutatingWebhook:在资源被持久化之前,可以修改资源对象。
-
ValidatingWebhook:验证资源对象是否符合集群的策略和规范。
-
ResourceQuota:限制资源的使用量,如CPU、内存和存储。
-
NamespaceLifecycle:管理命名空间的生命周期。
-
HLEM
Helm 是一个 Kubernetes 的包管理工具,就像 Linux 下的包管理器,如 yum / apt 等,可以很方便的将之前打包好的 yaml 文件部署到 kubernetes 上。
核心概念:Chart
Chart 是一个包含 Kubernetes 资源定义模板的打包文件。它描述了一个可以被 Helm 管理的应用程序的所有必要资源。
一个 Chart 包括: Chart.yaml:包含 Chart 的元数据。 values.yaml:包含 Chart 的默认配置值。 模板文件夹:包含资源的模板文件(通常是 Kubernetes 的 YAML 文件)。 其他文件:例如 README 文件等。
Release: 每个 Chart 安装到 Kubernetes 集群中就生成一个 Release。 Release 是一个 Chart 的运行实例,可以多次安装相同的 Chart,从而生成多个 Release,每个都有自己独立的配置和状态。
安装helm:
wget https://get.helm.sh/helm-v3.13.2-linux-amd64.tar.gz
tar xf helm-v3.13.2-linux-amd64.tar.gz
mv linux-amd64/helm /usr/bin/
helm version
常用命令:
Helm 常用命令
helm create:在本地创建新的 chart;
helm dependency:管理 chart 依赖;
helm intall:安装 chart;
helm lint:检查 chart 配置是否有误;
helm list:列出所有 release;
helm package:打包本地 chart;
helm repo:列出、增加、更新、删除 chart 仓库;
helm rollback:回滚 release 到历史版本;
helm pull:拉取远程 chart 到本地;
helm search:使用关键词搜索 chart;
helm uninstall:卸载 release;
helm upgrade:升级 release;
使用实例:
添加仓库国内阿里云:helm repo add ali https://apphub.aliyuncs.com
helm repo add bitnami https://charts.bitnami.com/bitnami
添加prometheus源: helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
查看仓库:helm repo list
安装ngix chars:helm install nginx bitnami/nginx 执行后,get pod发现nginx已经开始运行了
查到源中对应的charts:helm search repo redis: