Kubernetes 学习总结(45)—— 懂 Pod 就懂了 Kubernetes 的一半

前言

Kubernetes 可以理解成一个对计算、网络、存储等云计算资源的抽象后的标准 API 服务。几乎所有对 Kubernetes 的操作,不管是用 kubectl 命令行工具,还是在UI或者CD Pipeline 中,都相当于在调用其 REST API。很多人说 Kubernetes 复杂,除了其本身实现架构复杂以外,还有一个原因就是里面有二十多种原生资源的 API 学起来曲线比较陡。但不用担心,我们只要抓住本质 – 提供容器计算能力的平台,就能纲举目张,很容易快速理解。在 K8S 中,最重要也最基础的资源是 Pod,翻译一下就是“豆荚”,我们用下面这个最最基础的 Nginx 容器为例,搞清楚豆荚的一生,K8S 就懂了一半。大家也不需要研究 Kubernetes 怎么搭建,推荐用 OrbStack 在本地一键安装一套 Docker & K8S 环境出来,快速开始实验。首先,写一段这样的 Yaml 文件出来。

# nginx.yaml
apiVersion: v1
kind: Pod
metadata:name: nginxlabels:app: nginx
spec:containers:- name: webimage: nginxports:- name: webcontainerPort: 80protocol: TCP

然后用 kubectl 将 nginx 的 Pod 进行创建,命令后面加 -v8 是详细日志模式,可以看出来 kubectl 到底做了什么事情。

kubectl create pod -f nginx.yaml -v8kubectl get pod -v8

在 OpenLens 或 K9S 等可视化工具中,我们可以看到一个叫 Nginx 的 Pod 就被”生“出来了,从 kubectl 的详细日志中也可以看到 POST/GET 等请求的信息。​​​​​​

I1127 14:55:06.886901   83798 round_trippers.go:463] GET http://127.0.0.1:60649/77046cfbc5f80b52d9a1501954ee0672/api/v1/namespaces/default/pods?limit=500
I1127 14:55:06.886916   83798 round_trippers.go:469] Request Headers:
I1127 14:55:06.886921   83798 round_trippers.go:473]     User-Agent: kubectl...
I1127 14:55:07.166333   83798 round_trippers.go:580]     Cache-Control: no-cache, private

可以看到,在创建完成 Pod 之后,实际的 Pod 比我们在 Yaml 中声明的字段更多,这些多出来的字段就是 Pod 从出生后的经历证明:由调度器调度到集群可用节点、交给 kubelet 管理 Pod 生命周期、分配网络IP、挂载临时存储、容器运行时拉取镜像启动容器、控制器协调校正运行状态等等。

apiVersion: v1
kind: Pod
metadata:name: nginxnamespace: default
status:phase: RunninghostIP: 10.....podIP: 10.....conditions:- type: Initializedstatus: 'True'lastProbeTime: nulllastTransitionTime: '2023-11-27T06:59:13Z'- type: Readystatus: 'True'lastProbeTime: null.....
spec:volumes:- name: kube-api-access-72rkq......containers:- name: webimage: nginxports:- name: webcontainerPort: 80protocol: TCPresources: {}volumeMounts:- name: kube-api-access-72rkqreadOnly: truemountPath: /var/run/secrets/kubernetes.io/serviceaccountterminationMessagePath: /dev/termination-logterminationMessagePolicy: FileimagePullPolicy: AlwaysrestartPolicy: AlwaysterminationGracePeriodSeconds: 30dnsPolicy: ClusterFirstserviceAccountName: defaultserviceAccount: defaultsecurityContext: {}schedulerName: default-schedulertolerations:- key: node.kubernetes.io/not-readyoperator: Existseffect: NoExecutetolerationSeconds: 300- key: node.kubernetes.io/unreachableoperator: Existseffect: NoExecutetolerationSeconds: 300priority: 0enableServiceLinks: truepreemptionPolicy: PreemptLowerPriority

展开来看,运行一个容器,必要的就是3大件:计算、网络、存储。

  1. 计算资源,就是 CPU/Mem/GPU,是在 spec 的 container 部分声明,这个案例中没有设置到底需要多少 resources,requests 和 resources.limits 为空,也就是说可能占满整个宿主机,这种情况一般叫 Best-Effort QoS 级别,调度优先级是比较低的。

  2. 实际情况下一般会设置合理的 requests/limits,达到 Burstable QoS 级别或者设置 requests、limits 一模一样达到 Guarantee 级别。这个 Pod 经过调度器调度到某个节点之后,就会交给一个叫 CRI(Container Runtime Interface)的接口,让 CRI 的实现来把容器真正建出来,通常是 containerd,cri-o,podman, docker 等等。

  3. 网络方面,可以看到在 status 里面,多出了 PodIP 字段,这个是调用底层一个叫 CNI(Container Network Interface)的接口,让 CNI 的实现层给出的IP,这个过程比较复杂,涉及到一个叫 pause 容器的东西,入门的时候可以忽略这些细节。

  4. 存储方面,可以看到自动挂载了一个 volume/volumeMounts,这是对 Pod 挂载的额外存储,可能是配置文件或密钥,也可能是挂载一些云厂商提供的持久化存储,比如 EBS、EFS 盘,则会涉及到 K8S 第三类底层接口,CSI(Container Storage Interface,我们用的云厂商的 Kubernetes 发行版本一般都已经内置了CSI的实现。

有了计算网络存储,Pod 就运行起来了,如果我们要更新 Pod,可以用 Update, Patch 接口,但是,Pod是一个 Kubernetes 的原子资源,只能更新极少数字段,比如 image 和 readinessGate。如果想结束掉这个 Pod,可以用 Delete 接口,来让 Pod 进入 Terminating 状态,最终被控制器删除,回收掉计算资源,容器镜像文件最终也会被 GC 掉。

这里只是讲了最浅显的流程,详细的 Pod 生命周期可以参考这里:https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/,尤其是一些和业务强相关的生命周期活动,比如 postStart 并行的启动 hook,preStop 串行的停止 hook,发送 SIGTERM 尝试结束进程,过了 Graceful Period 后发送 SIGKILL 信号等等,对业务很有用。

Kubernetes 集群视角的计算、网络、存储

至此,我们明白了计算网络存储资源,如何赋予到 Pod 这个载体上。那么,计算、网络、存储的资源池本身,在 Kubernetes 里叫什么?Kubernetes 集群的计算节点叫 Node,和传统云平台对硬件机器的定义不同,Node 也是抽象的资源,可以长出来,也可以死掉,不和运行哪个容器直接绑定,而是通过 label/selector,affinity 等调度相关的机制关联到 Pod。Kubernetes 集群的块存储资源叫 PersistentVolume,实际使用场景下,一般是用分布式文件系统来实现,根据业务的磁盘请求,自动创建 PersistentVolume 的东西叫 StorageClass。

  • Kubernetes 的网络是分好几层的:让整个集群变成一个大内网的 Pod 网络;让集群内服务互相访问自带 L4 负载均衡的 Service 网络,以及做精细流量治理的 L7 Ingress/GatewayAPI/ServiceMesh 网络。还有控制网络访问策略的 NetworkPolicy 资源。
  • 首先我们看 Pod 网络,虽然不同 CNI 实现的网络原理差别巨大,但目的都是一样的,给每个 Pod 分配IP,并打通和其他 Pod 之间的路由。比如 AWS 就用了一个很讨巧的方式实现,直接给 Pod 分配当前 VPC-Subnet 的二级IP,DHCP和路由表都是复用的,Pod 之间和现有 EC2 节点之间的通信方式完全一样。
  • 再来看作为内部L4负载均衡器的 Service 网络,给每个 K8S services 资源分配一个虚拟 IP(ClusterIP)。ClusterIP 分配后,kube-proxy 组件负责来实现这个虚拟IP的路由的创建和 Pod Endpoint 变化的实时校正。

还是以 AWS EKS 为例,EKS 默认使用的 iptables 模式,kube-proxy 会在每个节点上把每个 ClusterIP Service 的 IP 写入 iptables,用 iptables 命令可以看到实现细节。

  • 由于每次变更导致的 iptables 修改,大规模集群用 K8S 内置的 Service 负载均衡是存在性能问题的,切换到 ipvs 模式可以解决;

  • 还有一种没有 ClusterIP 的 Headless Service,借助 DNS 实现了端点自动发现,不是常规的 L4 负载均衡;

  • 如果需要直接把某个 Service 暴露到公网去,还有 NodePort/LoadBalancer 类型的 Service,kube-proxy 会在集群每个节点 listen NodePort 端口,iptables写入 NodePort 对应的 DNAT 规则;

  • LoadBalancer / NodePort类型的Service还有一个关键字段“externalTrafficPolicy”,简单理解是跨节点负载均衡模式还是本地节点直连模式,跨节点负载均衡还会引起外部 LB 的健康检查失效问题以及内部服务无法获取 Client IP 问题,这些都是平台方需要处理好的,不需要业务方关心,业务团队记住一个原则,永远不要用 NodePort Service 就行。

# https://zhuanlan.zhihu.com/p/196393839
iptables -L -n
# Chain OUTPUT (policy ACCEPT)
# target     prot opt source               destination         
# KUBE-PROXY-FIREWALL  all  --  anywhere             anywhere             ctstate NEW /* kubernetes load balancer firewall */
# KUBE-SERVICES  all  --  anywhere             anywhere             ctstate NEW /* kubernetes service portals */
# KUBE-FIREWALL  all  --  anywhere             anywhere  iptables -L -t nat
#Chain KUBE-SVC-TCOU7JCQXEZGVUNU (1 references)
#target     prot opt source               destination         
#KUBE-SEP-HI2KQBDGYW5OVKWN  all  --  anywhere             anywhere             /* kube-system/kube-dns:dns -> 10.52.xx.xx:53 */ statistic mode random probability 0.50000000000#KUBE-SEP-XQT5TF2PMBOMEGDC  all  --  anywhere             anywhere             /* kube-system/kube-dns:dns -> 10.52.xx.xx:53 */

最后了解一下L7服务网络,一般由类似 Nginx Ingress/Envoy 之类的应用流量负载均衡器提供,对于业务来说,就当把 nginx conf 拆成一个一个 yaml 片段就好。Ingress 直管南北向流量,而 Service Mesh 把东西南边向流量全托管了,也能实现一些比 Nginx conf 里面更复杂的行为,比如流量加密、鉴权、故障注入、熔断降级、重试等等。

其他原生资源要么是对 Pod 套娃、要么是打辅助的

Kubernetes 的 API 设计非常符合单一职责原则(SRP),Pod 就是一个包容器的单纯的豆荚,delete 了就没了。但是,你要跑服务怎么办?没关系,单一职责原则下,实现新功能就是一个套娃,Kubernetes 抽象了一个叫 Deployment 套住一个叫 ReplicaSet的东西,ReplicaSet 再来套住 Pod。这样,Deployment 只管变更处理轮换 RS,RS 只管保证有 n 个 pod 在跑,Pod 没了再生,死了重启,这里也体现了 Erlang 典型的 let it crash 思维。哪天你说要训练一个AI模型干掉 OpenAI,Kubernetes 给你提供了一个叫 CronJob和 Job 的抽象,CronJob 套住了 Job,Job 又套住了 Pod。Job 只管一次性 run 的东西,要重试几次,跑完多久删 Pod 这些事,Cronjob则是一个天然的分布式cron,只管定时把 job 这个东西生出来。CronJob 和 Job 广泛用在大数据处理管线、CICD管线,AI训练这些领域。OpenAI 也是一个包含 8000 多个节点的巨大Kubernetes 集群训练出来的。哪天你又想用 Kubernetes 运行一个数据库,恭喜头铁的你,学到了最复杂的一种原生资源,StatefulSet,deployment是把豆荚当牲畜,想杀就杀,StatefulSet 是把Pod 当宠物,宠物不好养的,每个 Pod 都不能随便动,更新的时候只能按序一个一个更新。除了这些对 Pod 套娃的资源,剩下的可以理解成打辅助的,比如把流量引入集群的Ingress,内部流量负载均衡的 Service,给每个Pod提供的分布式配置ConfigMap、分布式密钥存储 Secret。还有一些策略控制和资源限额的辅助类,这里不一一展开了。

重新思考 Kubernetes 是什么

到这里,我们大概搞清楚了 Kubernetes 对于使用者来说意味着什么。从Kubernetes 自身的组件视图来看包括这些东西:

  • 每个机器装一个叫 kubelet 的 Agent,控制这台机器运行什么

  • 每个机器装一个 kube proxy 的东西用来托管网络防火墙规则,并装一个 CNI 的实现,控制集群内部的 Pod IP 分配和网络路由

  • 可选的,装一个CSI的实现,接管持久化存储盘的创建和挂载

  • 这些东西都听 API Server + Controller Manager + Scheduler 组成的控制中心,这套控制中心暴露一套标准的可扩展的 REST API,数据全部存到了 ETCD 元数据集群里。让我们操作分布式集群,再也不用撸 shell 命令,一切命令都 API 化,一切资源都变成了 ETCD 的数据记录。

了解了这些,也就明白了 Kubernetes 本质上是对现有技术的封装,形成了一套云资源操作系统,真正干活的还是服务器上的进程而已,真正对资源做隔离的还是 cgroup 和 namespace 这些 linux 内核原有的东西。了解了这些,也就明白了,为什么 Kubernetes 挂了不影响正在跑的服务?为什么在Kubernetes 集群做应用性能调优,还是去看 EC2 用什么 instance type,PV存储是哪一代的 EBS、EFS,还是去看 Subnet 内核 VPC 之间怎么优化 RTT 延迟和提升带宽?Kubernetes 包含了分布式集群的一切,Kubernetes 又一无所有。

Kubernetes 的 A/B 面

  • Kubernetes 带来的最大的几个好处,分别是标准化、弹性、可扩展。REST API 带来的管理界面完全标准化,存个 ETCD 记录就创建或校正资源状态带来了极致弹性,扩缩容就在弹指之间。开发一个自定义资源就实现任意功能带来了丰富的可扩展性,演化出庞大的 CloudNative 生态系统。既要又要还要,标准,弹性,可扩展,都有了,看起来很完美,但任何事物都有两面,Kubernetes 的这些好处,也是坏处的根源。标准化的暗面是复杂化。标准要考虑到所有情况,所以这个标准不可能简单,仅仅是一个Pod的spec,就有几十个字段,可能一小半字段大部分人都没有见过。
  • Kubernetes 学透的难度和自建运维难度,从培训考证机构可见一斑。即使是大公司,也最好不要有自建 Kubernetes 的念头,Kubernetes 自己的几个组件每个都有上百个启动参数,要么是不懂坑有多大的年轻人,要么是假装整明白的人,要么是身在云厂商里面真正懂的人。弹性的暗面是易失性,连集群的 Node 能随时长出、随时消逝,带来了对应用架构的侵入,在 Kubernetes 中运行的有状态服务必须具备动态发现的能力,想在代码中配置静态IP的时代结束了。我还发现一个 Kubernetes 带来的效应,”日志丢失焦虑“,在VM上大概没有人会担心日志没采集到,Kubernetes上Pod飘来飘去,总有人问,服务挂掉前的最后一行日志怎么采的,采不到怎么办?
  • 可扩展的暗面是良莠不齐,在CNCF Landscape和开源社区的并不是都是优秀的产品,甚至有些问题很大的东西也流行起来。比如之前团队有位同事仔细读过 Clickhouse operator 代码,这个1.5K star的项目,代码质量可能在及格线以下。4年前和另一位同事尝试用 ES Operator 和 Kafka Helm Chart 来运维 ES/Kafka,当时成熟度还远没有达到生产可用的水平。另外,Helm 这个 Kubernetes 最流行的包管理工具,也是”worse is better“的典型代表,Helm 作者哲学家 Matt Butcher 提出 OAM 思想后,自己去搞”下一代云计算”WASM生态去了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/603632.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker nginx滚动日志配置

将所有日志打印到控制台 nginx.conf user nginx; worker_processes auto; # 日志打印控制台 error_log /dev/stdout; #error_log /var/log/nginx/error.log notice; pid /var/run/nginx.pid;events {worker_connections 1024; }http {include /etc/nginx/m…

循环链表和双向链表

下面是 C 语言中循环链表和双链表的链式表示和实现示例&#xff1a; **循环链接表&#xff1a;** c #include <stdio.h> #include <stdlib.h> struct Node { int data; struct Node* next; }; // Function to create a new node struct Node* createNode(int da…

Mysql与Redis如何保证数据一致性问题

目录 一、Mysql与Redis同步数据是否存在延迟呢&#xff1f; 二、如何保证一致性&#xff1f; 2.1、第一种方式&#xff1a;手动编码 2.2、第二种方式&#xff1a;MQ异步更新 2.3、第三种方式&#xff1a;binlog同步数据 2.4、第四种方式&#xff1a;双写一致性 2.5、第五…

ASP.NET可视化流程设计器源码

源码介绍: ASP.NET可视化流程设计器源码已应用于众多大型企事业单位。拥有全浏览器兼容的可视化流程设计器、表单设计器、基于角色的权限管理等系统开发必须功能&#xff0c;大大为您节省开发时间&#xff0c;是您开发OA.CRM、HR等企事业各种应用管理系统和工作流系统的最佳基…

Python爬虫获取百度的图片

一. 爬虫的方式&#xff1a; 主要有2种方式: ①ScrapyXpath (API 静态 爬取-直接post get) ②seleniumXpath (点击 动态 爬取-模拟) ScrapyXpath XPath 是 Scrapy 中常用的一种解析器&#xff0c;可以帮助爬虫定位和提取 HTML 或 XML 文档中的数据。 Scrapy 中使用 …

Intel x86架构之I/O APIC

全文来自Intel手册&#xff08;见参考1&#xff09;&#xff1a;Intel? 82093AA I/O Advanced Programmable Interrupt Controller (I/O APIC) Datasheet 注意&#xff1a;下文中已经指出手册中的对应页面和章节&#xff0c;请对照手册原文看&#xff0c;任何个人理解错误&…

期货日数据维护与使用_日数据维护_模块整体代码

目录 写在前面 setting.py sqlite_tool.py future_widget.py 写在前面 本文默认已经创建了项目&#xff0c;如果不知道如何创建一个空项目的&#xff0c;请参看以下两篇博文 PyQt5将项目搬到一个新的虚拟环境中 https://blog.csdn.net/m0_37967652/article/details/122…

tcp和udp的区别(附java实现)

TCP和UDP的区别 TCP&#xff08;Transmission Control Protocol&#xff09;和UDP&#xff08;User Datagram Protocol&#xff09;是两种不同的网络传输协议&#xff0c;它们在数据传输时有一些重要的区别。 TCP TCP是面向连接的协议&#xff0c;它在通信之前需要建立连接&…

InternLM第2节课笔记

轻松玩转书生浦语大模型趣味Demo InternLM模型全链条开源 InternLM-7B和InternLM-20B Lagent&#xff1a;智能体&#xff08;agent&#xff09;框架 浦语灵笔&#xff1a;InternLM-Xcomposer-7B 视觉-语言大模型 模型下载 Hugging Face huggingface-cli OpenXLab python…

【C++】- 类和对象(!!C++类基本概念!this指针详解)

类和对象 引入类类的定义类的访问限定操作符类的作用域类的实例化类对象模型this指针 引入类 在 C中&#xff0c;引入了一个新的定义----------类。类是一种用户自定义的数据类型&#xff0c;用于封装数据和行为。类可以看作是一个模板或蓝图&#xff0c;描述了一组相关的数据和…

第15课 利用openCV实现人脸识别

这节课&#xff0c;我们再来看一个简单且实用的例子&#xff1a;人脸识别。这个小例子可以让你进一步领略openCV的强悍。 1.复制demo14并改名为demo15。 2.修改capImg函数&#xff1a; int fmle::capImg() {// 加载人脸检测分类器cv::CascadeClassifier faceCascade;faceCas…

UEditor在编辑对齐方式时产生额外空行问题

一、问题描述 一个关于UEditor富文本编辑器的问题&#xff1a;在编辑内容对齐方式后保存后浏览器显示的段落上下会比原先多出一些间距。 下面是对齐编辑后&#xff0c;未保存前的的HTML&#xff1a; 保存后&#xff0c;实际会多出一个段落空行&#xff1a; 二、问题调查 经…

基于B/S架构的数字孪生智慧监所可视化监管系统

1 前言 物联网技术的发展使云计算技术得到了迅猛的发展及广泛的应用&#xff0c;智能体系的创建已经成为监狱发展的必然趋势。 智慧监狱的创建、智能化管理的推行是监狱管理的创新&#xff0c;也是监狱整体工作水平提升的具体体现。 1.1 建设背景 近年来&#xff0c;司法部不…

CISSP 第7章:PKI和密码学应用

第七章 PKI和密码学应用 7.1 非对称密码学 对称密码系统具有共享的秘钥系统&#xff0c;从而产生了安全秘钥分发的问题 非对称密码学使用公钥和私钥对&#xff0c;无需支出复杂密码分发系统 7.1.1 公钥与私钥 7.1.2 RSA&#xff08;兼具加密和数字签名&#xff09; RSA算法依赖…

ctrl + v获取图片和文字

1、效果实现 1.1、做法 容器监听paste事件。原生js则document.addEventListener(paste)&#xff0c;vue则paste 监听paste事件的回调函数有个参数e&#xff0c;获取e.clipboardData粘贴的文字信息 e.clipboardData.getData("text/plain")粘贴的图片信息 e.clipboard…

委托QAbstractItemDelegate

参考&#xff1a;QT(7)-初识委托_qt 委托-CSDN博客 一、 1、 模型&#xff1a;负责“组织”数据&#xff1b; 视图&#xff1a;负责“显示”数据&#xff1b; 委托&#xff1a;负责“修改”数据&#xff1b; 2、委托&#xff1a;在QT的MV模型中&#xff0c;处理特定类型的…

c++拷贝控制

文章目录 拷贝构造函数的基本概念定义语法何时使用拷贝构造函数示例代码运行结果注意事项 拷贝赋值运算符的基本概念定义语法何时使用拷贝赋值运算符示例代码运行结果注意事项 析构函数的基本概念定义语法何时调用析构函数示例代码运行结果注意事项 三/五法则三法则 (Rule of T…

【SpringCloud】之配置中心(进阶使用)

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是君易--鑨&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的博客专栏《SpringCloud开发之远程消费》。&#x1f3af;&a…

精彩推荐 |【Java技术专题】「重塑技术功底」攻破Java技术盲点之剖析动态代理的实现原理和开发指南(上)

攻破Java技术盲点之剖析动态代理的实现原理和开发指南 背景介绍静态代理和动态代理动态代理与静态代理的区别 进入正题重温&#xff1a;静态代理实现静态代理案例静态代理的弊端 重温&#xff1a;动态代理Java动态代理InvocationHandlerJava动态代理的实现下面看具体的代码实例…

Blazor项目如何调用js文件

以下是来自千问的回答并加以整理&#xff1a;&#xff08;说一句&#xff0c;文心3.5所给的回答不完善&#xff0c;根本运行不起来&#xff0c;4.0等有钱了试试&#xff09; 在Blazor项目中引用JavaScript文件&#xff08;.js&#xff09;以实现与JavaScript的互操作&#xff…