k8s的pod

kubernetes中的资源

1.资源管理介绍

在kubernetes中,所有的内容都抽象为资源,用户需要通过操作资源来管理kubernetes。 kubernetes的本质上就是一个集群系统,用户可以在集群中部署各种服务 所谓的部署服务,其实就是在kubernetes集群中运行一个个的容器,并将指定的程序跑在容器中。

kubernetes的最小管理单元是pod而不是容器,只能将容器放在 Pod 中, kubernetes一般也不会直接管理Pod,而是通过 Pod控制器来管理Pod的。

Pod中服务的访问是由kubernetes提供的 Service 资源来实现。 Pod中程序的数据需要持久化是由kubernetes提供的各种存储系统来实现

2.什么是pod

Pod就是Kubernetes世界里装容器的"豆荚"(Pod直译就是豆荚)。 一个豆荚里可以装一颗豆子(一个容器),也可以装好几颗紧紧挨着的豆子(多个容器)。

(1)它是K8s里最小的"干活单位"

在Kubernetes里,没有"单个容器"这个概念。你没法直接让K8s去跑一个Docker容器,你必须把容器装进Pod这个"盒子"里,K8s只认这个"盒子"。所以,Pod是K8s调度和分配资源(比如CPU、内存)的最小单元。

(2)里面的容器"同生共死"

一个Pod里的所有容器,是打包在一起部署的,它们一定运行在同一台物理机或虚拟机上。

  • 共享IP地址 :Pod里的所有容器共用同一个IP地址。它们之间互相访问,直接用localhost:端口就行,就像住在一个房子里互相串门。

  • 共享存储:Pod可以挂载一个"共享文件夹",里面的容器都能往里读写文件。比如一个容器负责写日志,另一个容器负责读取这个日志上传到云端。

  • 同生共死:只要这个Pod在,里面的容器就都在。一旦Pod被销毁(比如崩溃了被重启),里面的所有容器都会被一起销毁重建,IP地址也会变。

(3)为什么要多放几个容器在一个pod里

有一个经典场景叫**"主容器 + 边车容器"**:

  • 主容器:跑你核心的业务程序(比如一个Java Web服务)。

  • 边车容器(Sidecar):作为辅助,专门负责给主程序做"杂活"。比如自动拉取最新的配置文件、给主程序做代理网关、或者把主程序的日志格式转换一下再上报。

因为这两个容器必须配合得天衣无缝(共享网络和文件),而且必须同时启动、同时消亡,所以把它们塞进同一个Pod里,让K8s统一管理,最省心。

3.pod管理的核心目标

Pod管理的终极目标,是将应用的部署、扩缩容、自愈、更新等运维工作自动化,让应用按照用户期望的状态运行

4.pod管理的手段

在实践中,我们极少直接创建和管理Pod,而是通过Kubernetes提供的各种"控制器"(Controller)来间接管理。

控制器就像一个自动化的管家,你只需告诉它"我需要什么类型的应用、需要几个副本",它就会自动创建、监控并维护Pod的数量和状态

常见的管理方式如下:

(1)命令空间管理

就好比你直接踹一脚售货机,喊一嗓子:"给我来罐可乐!"对应的命令就是kubectl create deployment nginx --image=nginx。这种搞法简单粗暴,适合你自己在家练手。但毛病也很明显------你踹完这脚,售货机是给你可乐了,可明天这机器重启了,它不记得你踹过它,那罐可乐就没了。也就是说,你用命令创建的东西,Kubernetes不会帮你长期维护

#查看命名空间

#创建命名空间

删除命名空间

#查看pod运行情况和在哪里运行

#创建pod

#当pod创建出现问题

#查看pod运行的详细信息

#删除pod

(2)声明式

你提前写一张纸条(YAML文件),上面画清楚:"我要一罐可乐,而且只要我这纸条在,你就得保证我这罐可乐永远在。"然后你把纸条交给售货员,喊一声**kubectl apply -f 那张纸条.yaml** 。售货员就会一直盯着,可乐没了就补,凉了给你换热的。这才是生产环境该有的玩法,因为你的需求变成了文件,能存进Git,能追溯历史,别人也能看懂你当初到底想要什么。

5.kubectl命令

kubectl是你跟Kubernetes集群对话的唯一工具。你想让集群干点啥,都得通过它。这11个命令基本覆盖了你日常运维80%以上的操作。

(1)create------创建资源

两种用法:

直接敲命令:kubectl create deployment nginx --image=nginx

用YAML文件:kubectl create -f nginx.yaml

两者的区别:直接敲命令适合快速测试,用YAML文件适合正式环境,因为文件能存进Git,可追溯、可复用。

注意,create是强制创建,如果你创建的资源已经存在了,它会报错告诉你"已经有了"。所以日常更常用的是apply(声明式),而不是createapply的特点是"有则更新,无则创建",更符合声明式管理的思路。

(2)edit------直接编辑资源

这个命令会打开一个文本编辑器(默认是vim),让你直接修改集群里某个资源的YAML配置。

比如你想改一下Nginx的镜像版本,敲kubectl edit deployment nginx,它会自动打开配置文件,你改完保存退出,集群立刻生效。

这玩意儿的好处是快,不用手动写文件再apply。坏处是:你的修改不会保留在任何本地文件里,如果集群重启了,改的东西可能就丢了。所以临时调试可以用edit,正式变更还是建议改本地的YAML文件再apply

(3)patch------打补丁

patch比edit更"轻量"。edit是把整个配置文件打开让你改,patch是你只告诉系统"我要把某个字段改成某个值",其他不动。

比如你想给Deployment打个标签,可以敲:

kubectl patch deployment nginx -p '{"spec":{"template":{"metadata":{"labels":{"version":"v2"}}}}}'

这玩意儿长得吓人,但它确实有用。适合自动化脚本里做小范围修改,或者紧急情况下快速改动一个字段。日常手工操作,edit比patch用得更多,因为edit更直观。

(4)expose------暴露服务

这个命令的作用是:把你跑在Pod里的服务,变成集群内部或外部可以访问的Service。

举个例子,你跑了个Nginx在Pod里,端口是80,但集群外面的人根本访问不到,因为Pod的IP是虚拟的、不稳定的。这时候你用kubectl expose deployment nginx --port=80 --target-port=80,就创建了一个Service,别人就能通过Service的IP或者域名访问到你的Nginx了。

简单说,create是"造东西",expose是"把东西亮出来让别人看见"

(5)logs------查看日志

排错最常用的命令之一,没有它你基本没法干活。

用法很简单:kubectl logs pod-name,就能看到Pod里容器的标准输出日志。

如果Pod里有多个容器,得指定容器名:kubectl logs pod-name -c container-name

常用的几个参数:

-f:持续跟踪日志输出,跟tail -f一样。

--tail=100:只看最后100行日志。

--since=1h:只看过去一小时的日志。

这个命令的本质就是:你去翻容器的stdout和stderr打印的东西。所以写程序的时候一定记得把关键信息打印到标准输出,不然Kubernetes没法帮你收集。

(6)attach------连接到运行中的容器

这个命令是让你"钻进"一个正在运行的容器里,连接到它的主进程上。

比如你跑了个程序,它有个交互式命令行(像Python的REPL),用kubectl attach能直接连上去跟它交互。

但说实话,这命令日常用得很少。因为大多数业务程序不是交互式的,你需要的是"进容器里看看"或者"在容器里执行命令",而不是"连到主进程"。所以下面这个命令才是你真正需要的。

(7)exec------在容器里执行命令

它让你在Pod的容器里执行任意命令。

最常用的就是:kubectl exec -it pod-name -- /bin/bash,意思是"给我一个交互式的bash shell,让我进这个容器里操作"。

一旦进去了,你就可以用linux那套东西:ls看看文件、ps看看进程、cat看看配置文件、curl调调本地服务。这比看日志来得更直接。

如果Pod里有多个容器,同样得加-c container-name指定容器。

记住:logs是"从外面看程序打印了什么",exec是"进到里面亲自看看",两者配合使用,什么问题都能查出来。

(8)cp------复制文件

这个命令用来在容器和宿主机之间拷文件。

两个方向:

从宿主机拷到容器:kubectl cp /本地文件路径 pod-name:/容器里的路径

从容器拷到宿主机:kubectl cp pod-name:/容器里的文件路径 /本地路径

这玩意儿在出问题的时候特别管用。比如你的程序出core了,产生了coredump文件在容器里,容器一重启文件就没了。这时候赶紧kubectl cp把文件拷出来,然后慢慢分析。

或者你的Pod里缺了个配置文件,暂时不想重新打镜像,也可以临时拷一个进去。

(9)rollout------版本变更管理

这个命令专门管Deployment、StatefulSet这些控制器的版本发布过程。

具体命令有这几个:

kubectl rollout status deployment/nginx:查看发布状态,看新版本是正在滚动更新还是已经完成了。

kubectl rollout history deployment/nginx:查看发布历史,看看你之前发布过哪些版本。

kubectl rollout undo deployment/nginx:回退到上一个版本,这就是传说中的"后悔药"。

kubectl rollout undo deployment/nginx --to-revision=2:回退到指定的某个历史版本。

这个命令是做版本发布和回退的核心工具,跟Deployment控制器配合使用,能轻松实现无停机更新。

(10)scale------扩缩容

这个命令用来调整Pod的副本数量。

用法:kubectl scale deployment/nginx --replicas=5,意思是把这个应用的Pod数量从现在的数调整到5个。

比如双11流量来了,你敲个命令把副本数从3扩到10;流量过去了再缩回来。这个操作配合HPA(Horizontal Pod Autoscaler)自动扩缩容之前,手动操作全靠它。

注意,scale只改数量,不改版本。也就是说,扩容只是加机器跑老代码,不会动程序本身

(11)label------打标签

标签是Kubernetes里最核心的组织方式。Pod、节点、各种资源都可以打标签,然后通过标签来筛选和操作。

kubectl label pod my-pod app=frontend:给这个Pod打个标签,标明它是前端应用。

更常用的场景是:

给节点打标签:kubectl label node node-1 disktype=ssd,然后你的Pod就可以用nodeSelector指定只跑在有ssd标签的节点上。

筛选资源:kubectl get pods -l app=frontend,只查看带有app=frontend标签的Pod。

label本身只是打了个标记,真正起作用的是Kubernetes的各种控制器和调度器会"读"这些标记来决定行为。所以可以把label理解成"给资源贴便签",方便后续的管理和筛选。

6.deployment控制器

在Kubernetes里,你绝对不要直接创建一个"裸Pod"。什么叫裸Pod?就是没有老板管的打工仔,今天在这台机器上,明天挂了没人理。你得给他配个包工头,这个包工头就叫Deployment

怎么雇这个包工头呢?两种方式:

命令式:kubectl create deployment web --image=nginx:1.18。这一下子,包工头就到位了,他立马给你拉起来一个Pod。

声明式:写个YAML,里面kind: Deployment,然后kubectl apply -f。这是正规军的玩法。

(1)建立控制器

(2)更新业务版本

包工头干的最牛的一件事叫滚动更新 。假设你现在的应用版本是1.18,想升级到1.19。你只要告诉包工头:"给我把镜像换成1.19。"包工头不会傻乎乎地把所有旧Pod全停了再起新的------那服务就断了。他的骚操作是:先偷偷起一个新Pod(1.19),等这个新Pod确定能跑了,再干掉一个旧Pod(1.18)。如此循环,始终保持在线数量不变。整个过程用户几乎无感知。对应的命令就是kubectl set image deployment/web nginx=nginx:1.19

(3)版本回退

万一新版本有坑,出了Bug,你也别慌。包工头手里有个"后悔药",叫版本回退 。你只需要敲kubectl rollout undo deployment/web,他立马按照之前的步骤反过来操作,把新Pod一个个换成旧Pod。这就跟游戏存档读档一样,任何时候都能回到上一个稳定版本。

7.怎么写pod的YAML文件

(1)多容器模式

什么时候你会往一个Pod里放多个容器?最典型的场景是主容器+边车容器。主容器跑你的业务代码,边车容器在旁边干杂活,比如收集日志、拉取配置文件、做本地代理。

为什么非要塞一起?因为这哥俩得共享IP地址和硬盘空间。塞一起了,他俩用localhost就能互相访问,就像在同一个屋里喊一嗓子就能听见。你如果分开成两个Pod,那就得通过网络通信,复杂得多。

YAML里怎么写?在spec.containers下面写两个- name就行。第一个是主容器,第二个是辅助的。Kubernetes会把他俩同时启动,同时销毁。

(2)把pod端口暴露到主机(hostport)

这个字段的意思是:把Pod里容器的端口,映射到Pod所在那台物理机(或者虚拟机)的端口上。

比如你的容器里跑的是Nginx,监听80端口。你设置了hostPort: 8080,那么外部的人就能通过"这台机器的IP+8080端口"访问到你的Nginx。

但这里得说一句实在话:生产环境很少这么干。因为Pod是飘忽不定的,今天在这台机器,明天挂了重启就到那台机器了。你把端口绑死在一台机器上,灵活性就没了。生产环境暴露服务用的是Service,那是另一套东西。所以你只需要知道有这回事就行,调试的时候偶尔用用。

(3)给Pod传环境变量(env)

这个好理解。你的程序可能需要连接数据库,数据库的地址是mysql.company.com。你不想把这个地址硬编码在镜像里,因为测试环境和生产环境地址不一样。

那就在YAML里写env,传个键值对进去。比如- name: DB_HOSTvalue: "mysql.company.com"。程序启动的时候读环境变量DB_HOST就能拿到这个值。

这东西说白了就是给容器塞进去几个全局变量。

#在浏览器中访问 node下面看到的主机ip

(4)挑一台机器来运行(nodeSelector)

Kubernetes集群里有很多台物理机,每台机器的配置可能不一样。有的机器装了SSD硬盘,有的没装;有的机器是GPU机器,专门跑AI。

你可以在Pod的YAML里写nodeSelector: disktype: ssd,意思是:调度器你给我听好了,必须把这个Pod安排到有SSD硬盘的机器上去,别的地儿我不去。

这是最基础的节点选择方式,简单粗暴。

(5)让Pod直接用主机的网络(hostNetwork)

这个比较特殊。正常情况下,Pod有自己的IP地址,是Kubernetes内部的一个虚拟IP。但你设置了hostNetwork: true之后,Pod就不再拥有自己的IP了,而是直接使用宿主机的IP和网络端口。

这就意味着,如果你跑个Nginx监听80端口,它就真的占用了这台宿主机的80端口。这台机器上再也跑不了第二个监听80端口的服务了。

这玩意儿一般什么时候用?通常是那些需要跟宿主机网络紧密耦合的组件,比如某些网络插件或者监控组件。普通业务应用千万别随便开这个开关,开了就绑死了,调度不灵活,端口还容易冲突。

6. 资源优先级(QoS Class)------系统怎么给你"排座位"

这是Kubernetes里一个很重要的机制,但很多人不太在意。你得理解,你跑的Pod在系统眼里是有三六九等的。

系统怎么给你划分等级?就看两个参数:requests(我要多少资源)和limits(我最多用多少资源)。

Guaranteed(保障型) :期望值和最大使用限制相同,优先级最高 这是最高等级,VIP。条件是你Pod里每个容器requestslimits都必须设置,而且数值必须相等。比如CPU都是1核,内存都是1G。这种Pod,系统把它当亲儿子,任何情况下都不驱逐它,除非它自己挂了。

Burstable(弹性型) :中等等级。设定了资源限制,但是期望值和限制值不同,资源使用优先级次之 条件是你设置了requests,但limitsrequests大,或者limits没设。比如你要了0.5核,但最多能用2核。平时资源充足的时候随便你用,万一系统资源紧张了,系统会优先干掉BestEffort,再不行才会考虑干掉你。

BestEffort(尽力型) :没有做任何资源限制,资源使用优先级最低 最低等级,没人管的孩子。条件是你压根没设置requestslimits。系统就当你是乞丐,有什么剩饭给你吃一口,没得吃随时把你踢出去。

7. 容器挂了要不要重启(restartPolicy)

这个策略管的是:容器进程退出之后,系统该怎么处理。

Always:这是默认值。只要容器退出,不管是因为报错退出还是正常退出,统统给我重启。适合Web服务这种需要7x24小时在线的。

OnFailure:只有容器以非0状态码退出(也就是报错退出)时才重启。如果容器正常执行完毕,状态码是0,就不重启。这适合Job任务,比如跑个批处理脚本,跑完就拉倒。

Never:死活不重启。无论因为什么原因退出,都不重启。这也适合一次性任务,你执行一次就完事,不想留后患。

8.pod生命周期

(1)Init容器(初始化容器)

这是在主容器启动之前,必须先跑完的特殊容器。

打个比方,你的主程序是个餐厅,但开始营业之前,你得先让服务员把桌子擦干净、把食材备好。这些准备工作就由Init容器来完成。

Init容器有几个特点:

它是串行执行的,如果一个Pod里有多个Init容器,必须一个一个来,前一个成功了,后一个才开始。

必须成功,如果某个Init容器执行失败了,Kubernetes会一直重试,直到成功为止,否则主容器永远不会启动。

常见的用法是:在Init容器里检查数据库是不是已经准备好了,或者从Git仓库拉取一些配置数据到共享目录里,供主容器使用。

(2)探针(Probe)------系统的"医生"

Pod启动之后,Kubernetes怎么知道你的程序是死是活?靠的就是探针。这相当于系统给你安排了一个私人医生,定期给你做体检。

体检有两种:

livenessProbe(存活探针) :检查你是不是还"活着"。如果这个检查失败了,系统会认为你的程序已经死锁或者崩溃了,然后直接把容器杀掉,再重新启动一个。这叫自动恢复。

没有存活探针时

有存活探针时

readinessProbe(就绪探针):检查你是不是"准备好了"接待请求。如果这个检查失败了,系统不会杀你,但会把你的Pod从服务的负载均衡列表里踢出去,不再给你分发流量。直到你检查通过了,才重新给你流量。

没有就绪探针时

有就绪探针时

为什么要有两个?因为一个程序启动可能要加载大量数据,比如加载缓存需要30秒。如果这时候用存活探针检查,发现你没响应,可能会把你杀掉重启------那就永远起不来了。所以正确的做法是:存活探针的检查要宽松一点,就绪探针的检查要精确一点

探针怎么检查呢?有三种方式:

httpGet :向容器里的某个HTTP接口发GET请求,返回200-399就认为健康。比如你的应用有个/health接口。

tcpSocket:尝试连接容器里的某个TCP端口,能连上就认为健康。

exec:在容器里执行一条命令,返回0就认为健康。

配置里还有几个关键参数:initialDelaySeconds(启动后等几秒再开始检查,避免程序还没起来就误报)、periodSeconds(每隔几秒检查一次)、failureThreshold(连续失败几次才算真正失败)。

相关推荐
Dear~yxy2 小时前
k8s中的控制器管理
云原生·容器·kubernetes
众人皆醒我独醉2 小时前
自动扩缩容:KPA/HPA/KEDA 三条路径
面试·kubernetes·llm
qizhideyu3 小时前
kubernetes中的pod管理
云原生·容器·kubernetes
lxw20230271163 小时前
k8s的pod管理
linux·容器·kubernetes
Yiiz.4 小时前
Kubernetes Pod 与控制器知识点
云原生·容器·kubernetes
高磊20054 小时前
Kubernetes Pod 管理实战详解
linux·容器·kubernetes
流星白龙4 小时前
【Docker】9.Docker 镜像仓库实战
运维·docker·容器
想要成为老金高手5 小时前
Kubernetes 实战笔记(一):Pod 管理与 kubectl 核心命令全解
笔记·容器·kubernetes
张洛闻Eren5 小时前
云原生k8s【第六课】:K8s 访问控制
运维·docker·云原生·容器·kubernetes·k8s