Pod是K8s里最小的部署和调度单元,不是容器,更像是一个“容器小组”,里面可以装一个或多个容器。这些容器共享Pod的网络、存储资源,相当于在同一个“小空间”里工作,能直接通过localhost通信。和容器的区别很明显:容器是独立的运行实例,而Pod是容器的“载体”,K8s不会直接调度容器,只会调度Pod。比如一个应用需要主容器+日志收集容器,这两个容器就会放在同一个Pod里,统一管理、统一调度,生命周期也保持一致,容器挂了Pod可能会重启,而Pod被删除,里面的容器也会跟着消失。
K8s的Service主要有4种类型,用途各不相同,都是为了解决Pod漂移(IP变化)导致的访问问题。第一种ClusterIP,默认类型,只在集群内部可用,给Pod分配一个集群内唯一的虚拟IP,供集群内其他服务访问,外部访问不到。第二种NodePort,在每个节点上开放一个固定端口,外部通过“节点IP+端口”就能访问Pod,适合测试环境。第三种LoadBalancer,对接云厂商的负载均衡器,自动分配公网IP,外部直接通过公网IP访问,适合生产环境对外服务。第四种ExternalName,把Service映射到外部域名,比如把数据库Service映射到云数据库的域名,不用在Pod里写死外部地址,灵活方便。
K8s自动扩缩容主要靠两种控制器:HPA(水平扩缩容)和VPA(垂直扩缩容),日常用得最多的是HPA。HPA是通过监控Pod的CPU、内存使用率,或者自定义指标(比如QPS、并发数),当指标达到设定阈值(比如CPU使用率超过80%),就自动增加Pod副本数;指标低于阈值,就自动减少副本数,实现“按需扩容、闲时缩容”。VPA则是调整单个Pod的资源配置,比如把Pod的CPU从1核调到2核,不用增加副本数,适合单Pod性能瓶颈的场景。另外,还可以结合Cluster Autoscaler,当集群节点资源不够时,自动增加节点;节点空闲时,自动删除节点,实现集群层面的自动扩缩容。
Ingress相当于K8s集群的“入口网关”,用来管理外部访问集群内服务的规则,解决NodePort端口多、LoadBalancer成本高的问题。它本身不是服务,需要配合Ingress Controller(比如Nginx-Ingress)才能工作。工作原理很简单:外部请求先访问Ingress Controller(绑定公网IP),Ingress里配置了域名、路径和Service的映射规则(比如xxx.com/api映射到api-service),Ingress Controller根据这些规则,把请求转发到对应的Service,再由Service转发到Pod。它还支持HTTPS、路径重写、负载均衡、域名转发,相当于一个“智能路由器”,统一管理集群的外部访问入口。
两者都是用来存储Pod的配置信息,核心区别是存储的内容和安全性不同。ConfigMap用来存非敏感的配置,比如应用的配置文件、环境变量、命令行参数,比如数据库地址、端口号、日志级别,数据是明文存储的,任何人能查看。Secret用来存敏感数据,比如密码、密钥、Token,数据会经过Base64编码(不是加密,只是编码,能解密),默认权限更严格,防止敏感信息泄露。另外,ConfigMap可以直接挂载为文件或环境变量,Secret除了这两种方式,还能挂载为密钥文件,或者通过环境变量注入,适合需要保密的配置场景,两者都能实现配置与Pod解耦,不用把配置写死在镜像里。
Namespace就是K8s里的“资源隔离文件夹”,用来把集群内的资源(Pod、Service、ConfigMap等)分成不同的逻辑组,互不干扰。默认有3个命名空间:default(默认存放未指定命名空间的资源)、kube-system(K8s系统组件所在的命名空间)、kube-public(公共资源,所有人可见)。它的核心用途有两个:一是隔离资源,比如开发、测试、生产环境用不同的Namespace,避免资源命名冲突、误操作(比如删错Pod);二是管理资源权限,给不同的Namespace分配不同的用户权限,比如开发人员只能操作dev命名空间,不能碰prod命名空间,提升集群安全性和可管理性,适合多团队、多环境共用一个K8s集群的场景。
DaemonSet是K8s的一种控制器,作用是让集群中的每一个(或指定)节点,都运行一个相同的Pod副本,而且节点新增时,会自动在新节点上部署这个Pod;节点删除时,对应的Pod也会被删除,保证“节点有则Pod有,节点无则Pod无”。常见应用场景很明确:一是节点级别的日志收集,比如在每个节点上部署Fluentd、Filebeat,收集节点和容器的日志;二是节点监控,比如部署Prometheus Node Exporter,采集每个节点的CPU、内存、磁盘等指标;三是网络插件,比如Calico、Flannel,需要在每个节点上运行,保证节点间的网络通信,这些都是需要在所有节点上统一部署的服务,适合用DaemonSet管理。
StatefulSet是用来部署有状态应用的控制器,比如数据库(MySQL、PostgreSQL)、分布式集群(ZooKeeper、Elasticsearch),这类应用需要固定的名称、网络标识、持久化存储,不能随意漂移。它和Deployment的核心区别的是:Deployment部署无状态应用,Pod名称是随机的,IP会变,删除重建后身份丢失;StatefulSet的Pod有固定的名称(比如xxx-0、xxx-1)、固定的网络标识,持久化存储和Pod一一对应,删除重建后,还是原来的身份,数据不会丢失。另外,StatefulSet的更新、扩缩容是有序的(比如先更xxx-0,再更xxx-1),Deployment是无序更新,适合无状态应用(比如Web服务、API服务)。
Service Mesh(服务网格)就是K8s集群中“管理服务间通信的专用网络层”,核心是“解耦服务通信和业务逻辑”,不用在应用代码里写任何通信相关的代码(比如重试、限流、监控)。它的结构分数据面和控制面:数据面是Sidecar容器(比如Envoy),和每个Pod绑定,所有服务间的请求都经过Sidecar转发;控制面(比如Istio)统一管理所有Sidecar,配置通信规则。主要作用有:流量管理(路由、负载均衡、灰度发布)、可观测性(监控服务调用、日志、链路追踪)、安全性(服务间TLS加密、访问控制),简单说,就是“专门管服务之间怎么通信”,让开发人员专注业务,运维人员专注通信管理。
PV和PVC是K8s中用来实现Pod数据持久化的两个核心资源,两者是“供需关系”,类比成“仓库和仓库申请单”。PV是集群管理员提前创建的“持久化存储资源”,比如一块云磁盘、NFS存储,定义了存储的大小、类型、访问模式,是“供”。PVC是Pod对存储的“申请单”,由开发人员创建,指定需要的存储大小、类型,是“需”。当PVC的需求和PV的配置匹配时,K8s会自动将PV和PVC绑定,Pod通过PVC就能使用PV的存储资源。这样做的好处是,开发人员不用关心底层存储的具体实现(是云盘还是NFS),管理员统一管理存储资源,实现存储和Pod解耦,数据不会因为Pod删除而丢失。
Affinity(亲和性)和Anti-Affinity(反亲和性),是用来控制Pod调度位置的规则,简单说就是“让Pod跑到指定的节点上,或者不跑到指定的节点上”。Affinity分节点亲和性(Node Affinity)和Pod亲和性(Pod Affinity):节点亲和性是让Pod调度到符合条件的节点(比如带“ssd=true”标签的节点);Pod亲和性是让两个相关的Pod调度到同一个节点或同一个节点组(比如Web服务和缓存服务,放一起访问更快)。Anti-Affinity则相反,让Pod不调度到符合条件的节点,或不与某个Pod在同一节点(比如数据库Pod,避免所有副本都在一个节点,防止节点挂了服务中断)。应用场景主要是优化性能、提高可用性、避免资源争抢。
两者都是K8s的自动扩缩容工具,核心区别是“扩缩容的方式不同”。HPA是水平扩缩容,也就是增加或减少Pod的副本数,比如CPU使用率超标,就多启动几个Pod分担压力;使用率低,就关掉几个Pod节省资源,不改变单个Pod的资源配置(CPU、内存),适合无状态应用(比如Web服务),能应对突发流量,也是日常最常用的扩缩容方式。VPA是纵向扩缩容,也就是调整单个Pod的资源配置,比如把Pod的CPU从1核调到2核、内存从1G调到2G,不增加副本数,适合有状态应用(比如数据库),或者单Pod性能瓶颈、无法横向扩容的场景。两者可以配合使用,实现更灵活的资源管理。
Taints(污点)和Tolerations(容忍度),是用来控制Pod能否调度到某个节点的“黑名单机制”。Taints是给节点打上的“污点标签”,比如给节点打上“node-role=master”的污点,默认禁止Pod调度到这个节点(防止普通Pod占用主节点资源);Tolerations是给Pod配置的“容忍规则”,如果Pod有对应污点的容忍度,就能调度到带有该污点的节点上。工作原理很简单:节点有污点,就会“排斥”所有没有对应容忍度的Pod;只有Pod配置了匹配的容忍度,才能“绕过”污点,被调度到该节点。主要用途是隔离节点,比如主节点、GPU节点,只让特定的Pod(比如系统组件、需要GPU的Pod)调度上去。
Jobs和CronJobs都是用来运行“一次性或周期性任务”的控制器,区别是任务的执行方式不同。Jobs用来运行一次性任务,比如数据备份、数据迁移、批量处理,任务执行完成后,Pod就会变成Completed状态,不会再重启,就算Pod挂了,Jobs也会自动重启Pod,直到任务完成。CronJobs是在Jobs的基础上,增加了“周期性调度”功能,按照Cron表达式(比如每天凌晨3点、每小时一次)定期执行任务,比如每天凌晨备份数据库、每小时清理日志。两者都适合运行非长期运行的任务,不用手动启动,自动执行、自动管理,避免人工操作失误,适合自动化运维场景。
K8s的网络策略(Network Policy),就是用来控制Pod之间、Pod与外部之间通信的“防火墙规则”,默认情况下,集群内所有Pod都能互相通信,网络策略可以限制这种通信,提升安全性。它通过标签选择器,指定哪些Pod可以被访问、哪些Pod可以访问别人,还能限制通信的端口和协议。工作原理:网络策略会被网络插件(比如Calico、Weave)执行,当Pod之间有通信请求时,网络插件会检查是否符合网络策略的规则,如果符合就允许通信,不符合就拒绝。比如可以配置“只有Web服务Pod能访问数据库Pod,其他Pod不能访问”,或者“禁止Pod访问外部网络”,主要用于微服务间的访问控制,防止非法访问和横向渗透。
Resource Quotas(资源配额),是用来给命名空间设置“资源使用上限”的机制,防止某个命名空间的资源被耗尽,影响其他命名空间的服务。管理员可以给每个命名空间配置Resource Quotas,限制该命名空间内所有Pod的总CPU、总内存、总Pod数量、总PV数量等。比如给dev命名空间设置CPU上限为10核、内存上限为20G,那么该命名空间内所有Pod的CPU总和不能超过10核,内存总和不能超过20G,超过后就无法创建新的Pod。它的核心作用是合理分配集群资源,避免资源滥用,适合多团队、多环境共用一个K8s集群的场景,保证每个命名空间都能获得足够的资源,同时不影响全局。
Labels(标签)和Annotations(注解)都是用来给K8s资源(Pod、Service、Node等)添加元数据的,但用途和特性完全不同。Labels是“用于选择和筛选资源”的键值对,比如给Pod打“app=web、env=dev”的标签,然后通过标签选择器,筛选出所有env=dev的Pod,用于Service关联Pod、Deployment管理Pod、网络策略控制通信,是K8s中资源关联和筛选的核心。Annotations是“用于存储资源的附加信息”的键值对,比如资源的创建时间、维护人员、版本信息、文档链接,这些信息不会被K8s用于资源选择和调度,只是给用户或运维人员查看、使用,不会影响资源的运行,相当于资源的“备注信息”。
Init Containers(初始化容器),是在Pod的主容器启动之前执行的容器,执行完成后就会退出,不会长期运行,主容器只有在所有Init Containers都执行成功后,才会启动。它的核心用途是给主容器做初始化准备工作,比如:等待其他服务(比如数据库)启动完成,避免主容器启动后连接不上数据库;拉取主容器需要的配置文件、依赖包;初始化数据库、创建目录、修改权限等。比如一个Web服务Pod,需要先等待数据库Pod启动,再拉取配置文件,这些操作就可以放在Init Containers里执行,不用在主容器里写复杂的初始化逻辑,实现初始化和业务逻辑解耦,保证主容器启动时,所有依赖都已准备就绪。
Headless Service(无头服务),是一种特殊的Service,和普通Service的核心区别是“没有ClusterIP(虚拟IP)”,也不会做负载均衡。普通Service会分配一个ClusterIP,请求访问Service时,会自动转发到后端的Pod,实现负载均衡;而Headless Service不会分配ClusterIP,访问它的域名时,会直接返回后端所有Pod的IP地址,不会做转发和负载均衡,客户端需要自己决定访问哪个Pod。它的主要用途是部署有状态应用(比如ZooKeeper、MySQL集群),这些应用需要知道集群中其他Pod的IP地址,通过Headless Service的DNS解析,就能获取所有Pod的IP,实现集群内的节点发现和通信。
livenessProbe(存活探针)和readinessProbe(就绪探针),都是用来监控Pod状态的工具,核心区别是“监控的目的不同”。livenessProbe用来判断Pod是否“活着”(正常运行),比如检查主容器的进程是否存在、接口是否能访问,如果探测失败,K8s会认为Pod异常,会自动重启该Pod,避免Pod“假死”(容器在运行,但应用已经崩溃)。readinessProbe用来判断Pod是否“准备好”(可以接收请求),比如检查应用是否初始化完成、数据库连接是否正常,如果探测失败,K8s会把该Pod从Service的后端列表中移除,不再转发请求给它,直到探测成功,避免把请求发给未准备好的Pod,导致请求失败。
两者都是Affinity(亲和性)规则,核心区别是“调度的依据不同”,一个是针对节点,一个是针对Pod。Node Affinity(节点亲和性),是根据节点的标签来调度Pod,比如让Pod调度到带有“disk=ssd”“region=beijing”标签的节点上,只关注节点本身的属性,和其他Pod无关。Pod Affinity/Anti-Affinity(Pod亲和性/反亲和性),是根据其他Pod的标签来调度当前Pod,比如让Web服务Pod和缓存Pod调度到同一个节点(亲和性),让数据库的不同副本Pod调度到不同节点(反亲和性),关注的是Pod之间的关系。简单说,Node Affinity管“Pod去哪个节点”,Pod Affinity管“Pod和哪个Pod在一块”。
Deployment的滚动更新,是一种“不中断服务”的更新方式,核心是“逐步替换旧Pod、启动新Pod”,避免更新过程中服务不可用。它的工作原理:先启动1个(或多个,可配置)新Pod,等待新Pod就绪后,再终止1个旧Pod,重复这个过程,直到所有旧Pod都被替换成新Pod。滚动更新可以配置两个关键参数:maxSurge(最多可以超出期望副本数的Pod数量,比如期望3个,maxSurge=1,最多可以有4个Pod运行)、maxUnavailable(最多不可用的Pod数量,比如maxUnavailable=1,最多有1个Pod不可用)。这种方式不会中断服务,更新失败还能快速回滚到旧版本,适合无状态应用的日常更新,是生产环境最常用的更新策略。
两者的使用方式有相似之处(都能挂载为文件或注入环境变量),但核心区别在于“安全配置和使用限制”。ConfigMap的使用方式比较简单:可以直接挂载为Pod内的配置文件(比如把ConfigMap里的app.conf挂载到Pod的/etc/app目录),也可以通过环境变量注入到Pod中,供应用读取,没有太多安全限制,明文展示,任何人都能查看。Secret的使用方式更注重安全:除了挂载为文件、注入环境变量,还能挂载为密钥文件(权限为600,只有root能读写),避免敏感信息泄露;另外,Secret可以通过Secrets Store CSI Driver对接外部密钥管理系统(比如Vault),实现敏感数据的安全存储和自动同步,而ConfigMap不支持这种方式,主要用于非敏感配置。
两者都是K8s中的存储资源,核心区别是“生命周期和管理方式不同”。Volume(普通卷)是和Pod绑定的,生命周期和Pod一致,Pod创建时Volume创建,Pod删除时Volume也会被删除,数据会丢失(除非是宿主目录挂载),是“临时存储”,由开发人员在Pod定义中直接配置,比如emptyDir、hostPath。PersistentVolume(PV)是集群级别的持久化存储,生命周期和Pod无关,由管理员提前创建,独立于Pod存在,Pod删除后,PV依然存在,数据不会丢失,是“永久存储”。另外,PV需要通过PVC申请才能使用,而普通Volume直接在Pod中配置即可,适合不同的存储场景:临时数据用Volume,持久化数据用PV+PVC。
K8s的服务发现,核心是“让Pod能通过服务名,自动找到对应的Service和后端Pod,不用记IP地址”,主要靠两个机制实现:DNS和环境变量。第一种是DNS(最常用),K8s集群内置了DNS服务(比如CoreDNS),当创建Service时,DNS会自动给Service创建一条域名记录(格式:service-name.namespace.svc.cluster.local),Pod通过这个域名就能访问Service,DNS会自动解析Service的ClusterIP,再由Service转发到后端Pod。第二种是环境变量,当Pod启动时,K8s会自动把集群内已存在的Service的IP、端口,以环境变量的形式注入到Pod中,Pod通过读取环境变量就能访问Service。另外,Headless Service通过DNS返回所有Pod的IP,实现Pod级别的服务发现。
Resource Limits(资源限制)和Requests(资源请求),是用来给Pod配置CPU、内存资源的两个参数,核心作用是“保证Pod能获得足够资源,同时不滥用资源”。Requests是Pod启动时,向K8s请求的最小资源量,比如requests.cpu=1核、requests.memory=1G,K8s会调度Pod到资源充足(至少有1核CPU、1G内存)的节点上,保证Pod能正常启动。Limits是Pod运行时,能使用的最大资源量,比如limits.cpu=2核、limits.memory=2G,Pod的CPU使用率不能超过2核,内存不能超过2G,超过后CPU会被限流,内存会被OOM杀死。简单说,Requests是“最低保障”,Limits是“最高上限”,两者配合使用,合理分配集群资源,避免资源争抢和浪费。
两者的更新策略核心区别是“更新顺序和数据安全性”,因为StatefulSet部署有状态应用,Deployment部署无状态应用。Deployment的更新是“无序更新”,可以同时启动多个新Pod、终止多个旧Pod,只要满足maxSurge和maxUnavailable的限制,更新速度快,适合无状态应用,不用考虑Pod的顺序。StatefulSet的更新是“有序更新”,默认从序号最大的Pod开始(比如xxx-2→xxx-1→xxx-0),只有当前Pod更新完成且就绪后,才会更新下一个Pod,更新过程中,旧Pod不会被立即删除,直到新Pod就绪,保证数据不丢失。另外,StatefulSet支持分区更新(只更新部分Pod),Deployment不支持,更适合有状态应用的平稳更新。
K8s跨集群通信,核心是“让不同K8s集群的Pod、Service能互相访问”,常用的有3种方式,各有适用场景。第一种是联邦集群(Kubernetes Federation),把多个集群组成一个联邦,统一管理Service、ConfigMap等资源,联邦Service会在每个集群创建对应的Service,实现跨集群访问,适合多集群统一管理的场景。第二种是VPN/专线,给两个集群的节点之间建立VPN或专线,打通集群网络,让两个集群的Pod处于同一个虚拟网络,直接通过IP访问,适合中小规模集群。第三种是Service Mesh(比如Istio),通过Istio的多集群模式,统一管理跨集群的服务通信,支持流量路由、负载均衡、TLS加密,适合大规模微服务跨集群部署的场景。另外,还可以通过Ingress暴露服务,让其他集群通过公网访问,适合简单的跨集群访问需求。
K8s管理敏感数据,核心是“避免明文存储,做好权限控制”,主要有4种方式,优先用更安全的方案。第一种是Secret,最基础的方式,把敏感数据Base64编码后存储,挂载为文件或注入环境变量,注意Base64不是加密,需要配合权限控制(比如限制Secret的访问权限)。第二种是Secrets Store CSI Driver,对接外部密钥管理系统(比如Vault、阿里云KMS),敏感数据存储在外部系统,Pod通过CSI驱动动态挂载,不用把敏感数据存到K8s中,最安全。第三种是ServiceAccount Token,用于Pod访问K8s API,通过Service Mesh或RBAC控制权限,避免手动管理密钥。第四种是加密静态数据,开启K8s的静态加密功能,把etcd中存储的敏感数据(比如Secret)加密,防止etcd被攻破后数据泄露。
ServiceAccount(服务账户),是K8s中给Pod提供“身份标识”的资源,用来控制Pod访问K8s API的权限,和我们平时用的用户账户(比如kubectl用的账户)不一样,是给Pod用的。每个命名空间默认有一个default ServiceAccount,Pod如果不指定ServiceAccount,就会使用这个默认账户。它的核心用途:一是身份认证,Pod通过ServiceAccount的Token,向K8s API服务器证明自己的身份;二是权限控制,通过RBAC(角色权限控制),给ServiceAccount分配不同的权限(比如只能查看Pod,不能删除Pod),Pod就拥有了对应的权限,比如让Pod能调用K8s API,获取集群内的资源信息、创建/删除资源。简单说,ServiceAccount就是Pod的“身份证”,用来控制Pod能做什么、不能做什么。
CRD(自定义资源定义),就是允许用户在K8s中“自定义新的资源类型”,扩展K8s的功能,因为K8s默认的资源(Pod、Service、Deployment)不能满足所有业务需求。比如你有一个自定义的应用(比如分布式任务调度系统),需要一种新的资源来管理,就可以通过CRD创建一个新的资源类型(比如Task),之后就能像操作Pod一样,用kubectl create、kubectl get等命令操作Task资源。CRD本身只是定义资源类型,还需要配合Custom Controller(自定义控制器),才能实现对自定义资源的管理(比如调度、更新、自愈)。CRD的核心作用是扩展K8s的能力,让K8s能适配各种自定义业务场景,比如Service Mesh、AI训练任务等。
PodPreset(Pod预设),是用来“自动给Pod注入配置”的资源,不用在每个Pod的定义中重复写相同的配置,减少重复工作。它的工作原理:管理员创建PodPreset,定义好需要注入的配置(比如环境变量、Volume、VolumeMount),并通过标签选择器,指定哪些Pod会被注入这些配置。当创建Pod时,如果Pod的标签和PodPreset的标签选择器匹配,K8s会自动把PodPreset中的配置注入到Pod中,不用手动在Pod中配置。比如多个Pod都需要相同的环境变量(比如数据库地址),就可以创建一个PodPreset,统一注入,后续创建Pod时,只要打对应标签,就能自动获得配置,适合多个Pod共用相同配置的场景,简化Pod配置。
Pod的优先级,是用来决定“当集群资源不足时,哪个Pod会被优先保留,哪个Pod会被驱逐”的规则,核心是通过PriorityClass(优先级类)来配置。首先,管理员创建PriorityClass,给每个PriorityClass设置一个优先级数值(数值越大,优先级越高),比如创建“high-priority”(数值1000)、“low-priority”(数值100)。然后,在Pod的定义中,通过priorityClassName字段,指定该Pod使用的PriorityClass,比如把核心服务的Pod设置为high-priority,普通服务的Pod设置为low-priority。当集群资源不足时,K8s会优先驱逐优先级低的Pod,释放资源给优先级高的Pod,保证核心服务不中断,适合有核心服务和非核心服务的场景。
PDB(Pod干扰预算),是用来“保护Pod不被过多中断”的资源,避免因为主动干扰(比如节点维护、Pod更新),导致某个服务的可用Pod数量过少,影响服务可用性。它的核心作用是设置“最小可用Pod数量”或“最大不可用Pod数量”,比如给一个有3个副本的Web服务配置PDB,设置minAvailable=2,意味着无论发生什么主动干扰,该服务的可用Pod数量都不能少于2个,K8s会保证在中断Pod时,至少保留2个可用Pod。PDB只针对主动干扰(手动删除Pod、节点排水),不针对被动故障(Pod崩溃、节点宕机),主要用于保护核心服务,确保服务在维护、更新时依然可用。
HPA(水平Pod自动扩缩容)的扩缩容依据,就是各种度量指标,主要分为3类,日常最常用前两类。第一类是资源指标(默认支持),包括CPU使用率和内存使用率,比如设置CPU使用率超过80%扩容、低于20%缩容,这是最基础、最易配置的指标,不需要额外部署组件。第二类是自定义指标,比如QPS(每秒请求数)、并发数、请求延迟,这些指标需要通过Metrics Server + 自定义指标适配器(比如Prometheus Adapter)获取,适合业务层面的扩缩容(比如根据请求量扩容)。第三类是外部指标,比如云厂商的负载均衡器请求数、消息队列的队列长度,需要对接外部系统获取指标,适合和外部服务联动的场景。HPA会定期采集这些指标,对比设定阈值,自动调整Pod副本数。
K8s日志管理的核心思路是“容器日志集中收集、统一存储、按需查询”,常用的方案是“日志驱动+日志收集器+存储+查询”的组合。第一步,容器日志输出到stdout和stderr(K8s推荐方式),容器引擎(Docker、containerd)通过日志驱动,把日志写到节点的本地文件。第二步,在每个节点上部署日志收集器(比如Fluentd、Filebeat),采集节点上的容器日志,过滤、格式化后,发送到日志存储系统。第三步,日志存储系统(比如Elasticsearch、Loki)存储日志,支持长期存储和检索。第四步,通过查询工具(比如Kibana、Grafana),查询、分析日志,设置告警。另外,还可以通过日志聚合工具(比如EFK、ELK),实现日志的全流程管理,适合大规模集群的日志监控和问题排查。
两者都是用来控制集群资源使用的机制,核心区别是“控制的范围和粒度不同”。Quota(资源配额)是针对“整个命名空间”的,控制的是命名空间内所有Pod的总资源上限,比如限制dev命名空间的总CPU为10核、总内存为20G,防止整个命名空间滥用资源,适合多命名空间的资源管理。LimitRange(限制范围)是针对“命名空间内的单个Pod或容器”的,控制的是单个Pod/容器的资源范围,比如设置单个Pod的CPU请求量最小0.5核、最大2核,单个容器的内存最小512M、最大1G,防止单个Pod占用过多资源,或者请求资源过少导致无法正常运行。简单说,Quota管“整体”,LimitRange管“个体”,两者配合使用,实现更精细的资源控制。
两者都是用来“保证Pod副本数稳定”的控制器,核心作用是维持指定数量的Pod副本运行,Pod挂了就自动重启,ReplicaSet是ReplicationController的“升级版”,现在基本不用ReplicationController了。它们的主要区别是“标签选择器的支持不同”:ReplicationController只支持等式标签选择器(比如app=web),只能匹配标签完全等于指定值的Pod;ReplicaSet支持集合式标签选择器(比如app in (web, api)),能匹配标签满足集合条件的Pod,更灵活。另外,ReplicaSet是Deployment的底层实现,Deployment会自动创建和管理ReplicaSet,不用手动创建ReplicaSet,而ReplicationController需要手动创建,功能更单一,现在生产环境都用Deployment+ReplicaSet,替代了ReplicationController。
使用Init Containers初始化Pod,步骤很简单,在Pod的定义中,通过initContainers字段配置即可,和配置主容器(containers字段)类似,但有几个关键注意点。首先,Init Containers是一个数组,可以配置多个初始化容器,它们会按顺序执行,前一个执行完成后,后一个才会启动,所有Init Containers执行成功后,主容器才会启动。其次,配置Init Containers的命令(command)或镜像(image),实现初始化逻辑,比如等待数据库启动(用wget、curl命令检查数据库端口)、拉取配置文件(用wget下载配置)、初始化数据库(执行sql脚本)。最后,注意Init Containers的资源配置(CPU、内存),可以单独配置,和主容器的资源配置不冲突。比如配置一个Init Container,等待MySQL启动,再启动主容器(Web服务),确保Web服务启动时能正常连接数据库。
两者都是用来运行“非长期运行任务”的控制器,核心区别是“任务的执行方式和周期不同”。Job是“一次性任务”,创建后就会启动Pod执行任务,任务执行完成(Pod变成Completed状态)后,就不会再运行,就算Pod挂了,Job也会自动重启Pod,直到任务完成,比如数据备份、批量处理。CronJob是“周期性任务”,基于Cron表达式(比如* * * * * 代表每分钟一次),定期启动Job执行任务,任务完成后,Job会被保留(可配置保留数量),到下一个周期再重新启动新的Job,比如每天凌晨3点备份数据库、每小时清理日志。简单说,Job是“做一次就停”,CronJob是“按时间重复做”,根据任务的周期需求选择即可。
Pod的自动伸缩主要靠两种方式,结合使用能实现更灵活的伸缩,满足不同场景需求。第一种是HPA(水平Pod自动扩缩容),这是最常用的方式,通过监控Pod的CPU、内存使用率,或者自定义指标(QPS、并发数),自动增加或减少Pod的副本数,不改变单个Pod的资源配置,适合无状态应用(比如Web服务),应对突发流量。第二种是VPA(纵向Pod自动扩缩容),通过监控Pod的资源使用情况,自动调整单个Pod的CPU、内存配置(比如从1核1G调到2核2G),不增加副本数,适合有状态应用(比如数据库),或者单Pod性能瓶颈的场景。另外,结合Cluster Autoscaler,当集群节点资源不足时,自动增加节点;节点空闲时,自动删除节点,实现集群层面的自动伸缩,保证Pod能正常调度。
Service Mesh(服务网格)的核心功能是“管理服务间的通信”,不用修改应用代码,就能实现各种通信相关的能力,主要有4大核心功能。第一,流量管理,比如路由控制(根据请求路径、版本转发流量)、负载均衡(轮询、加权轮询)、灰度发布/蓝绿部署(逐步切换流量到新版本)、熔断降级(服务不可用时,避免雪崩)。第二,可观测性,比如监控服务调用的QPS、延迟、错误率,收集服务调用日志,实现链路追踪(跟踪一个请求的完整路径),方便排查问题。第三,安全性,比如服务间通信TLS加密(防止数据窃听、篡改),访问控制(限制哪些服务能访问当前服务),身份认证(验证服务身份)。第四,可配置性,所有功能都通过控制面统一配置,不用重启应用,实时生效,简化运维管理。
Pod的优先级和抢占机制,是用来“保证核心Pod优先获得资源”的机制,分为两个步骤:优先级配置和抢占执行。首先,管理员创建PriorityClass(优先级类),设置优先级数值(数值越大,优先级越高),然后在Pod中指定priorityClassName,给Pod分配优先级。当集群资源充足时,所有Pod都能正常调度,优先级不影响;当集群资源不足,无法调度新的高优先级Pod时,抢占机制就会触发:K8s会寻找集群中优先级更低的Pod,驱逐这些低优先级Pod,释放资源,然后将高优先级Pod调度到对应的节点上。注意,抢占机制只会驱逐“可抢占”的低优先级Pod,不会驱逐有PDB保护的Pod,避免影响服务可用性,核心是优先保障核心服务的运行。
两者都是用来“控制Pod调度到指定节点”的方式,核心区别是“灵活性和功能丰富度不同”。Node Selector(节点选择器)是最简单的调度方式,通过键值对匹配节点标签,比如Pod配置nodeSelector: {disk: ssd},就只能调度到带有“disk=ssd”标签的节点上,只能做“等于”匹配,没有容错性,比如没有符合条件的节点,Pod就会一直处于Pending状态。Node Affinity(节点亲和性)更灵活,支持“等于、不等于、包含、不包含”等多种匹配规则,还能设置“软亲和性”(preferredDuringSchedulingIgnoredDuringExecution)和“硬亲和性”(requiredDuringSchedulingIgnoredDuringExecution):硬亲和性必须满足,否则Pod无法调度;软亲和性尽量满足,不满足也能调度到其他节点,容错性更强,功能更丰富,现在基本替代了Node Selector。
配置Pod使用特定的网络策略,核心是“通过标签关联Pod和网络策略”,步骤很简单,分为两步。第一步,创建NetworkPolicy(网络策略),在策略中通过podSelector(Pod选择器),指定该策略作用于哪些Pod(比如给策略配置podSelector: {app: web},就作用于所有带“app=web”标签的Pod),然后配置通信规则(比如允许哪些Pod访问、禁止哪些Pod访问、允许的端口和协议)。第二步,给需要应用该策略的Pod,打上和网络策略podSelector匹配的标签(比如给Web服务Pod打“app=web”标签),这样网络策略就会自动作用于这些Pod。注意,网络策略需要网络插件(比如Calico、Weave)支持才能生效,没有网络插件,网络策略不会起作用,另外,一个Pod可以被多个网络策略作用,规则会叠加。
Rolling Update(滚动更新),是K8s中Deployment和StatefulSet的一种“不中断服务”的更新方式,核心是“逐步替换旧Pod、启动新Pod”,避免更新过程中服务不可用。它的执行过程(以Deployment为例):1. 管理员触发更新(比如修改镜像版本);2. Deployment根据maxSurge参数(最多超出期望副本数的Pod数量),启动1个(或多个)新Pod;3. 等待新Pod启动完成并就绪后,根据maxUnavailable参数(最多不可用的Pod数量),终止1个(或多个)旧Pod;4. 重复步骤2和3,直到所有旧Pod都被替换成新Pod,更新完成。如果更新过程中出现问题,可以随时回滚到旧版本,保证服务稳定性,是生产环境最常用的更新方式,适合无状态应用和有状态应用。
使用PV和PVC实现Pod数据持久化,分为3个步骤,流程清晰,管理员和开发人员分工协作。第一步,管理员创建PV(持久化存储资源),定义存储的大小、类型(比如NFS、云盘)、访问模式(比如ReadWriteOnce,只能被一个Pod挂载读写),PV是集群级别的资源,独立于Pod存在。第二步,开发人员创建PVC(存储申请单),指定需要的存储大小、类型,和PV的配置匹配,比如PVC申请10G、ReadWriteOnce的存储。第三步,K8s自动将PVC和匹配的PV绑定,然后在Pod的定义中,通过volumeMounts和volumes字段,将PVC挂载到Pod中,Pod就能使用PV的存储资源,数据会持久化存储,Pod删除后,PV和PVC依然存在,数据不会丢失。如果需要删除存储,先删除Pod,再删除PVC,最后删除PV即可。
Probes(探针)是K8s用来“监控Pod和容器状态”的工具,通过定期执行检查,判断容器是否正常运行、是否准备好接收请求,主要有3种类型,各自用途不同。第一种是livenessProbe(存活探针),用来检查容器是否“活着”,比如检查容器内的进程是否存在、接口是否能正常访问,如果探测失败,K8s会自动重启该容器,避免容器“假死”(容器在运行,但应用已崩溃)。第二种是readinessProbe(就绪探针),用来检查容器是否“准备好”接收请求,比如检查应用是否初始化完成、数据库连接是否正常,如果探测失败,K8s会把该Pod从Service的后端列表中移除,不再转发请求,直到探测成功。第三种是startupProbe(启动探针),用来检查容器是否启动完成,适合启动时间长的应用(比如Java应用),启动探针成功后,才会执行存活探针和就绪探针,避免启动过程中被误判为异常。