一 pod 基础概念介绍
1,pod 是什么
Pod是kubernetes中最小的资源管理组件,Pod也是最小化运行容器化应用的资源对象。一个Pod代表着集群中运行的一个进程。kubernetes中其他大多数组件都是围绕着Pod来进行支撑和扩展Pod功能的,例如,用于管理Pod运行的StatefulSet和Deployment等控制器对象,用于暴露Pod应用的Service和Ingress对象,为Pod提供存储的PersistentVolume存储资源对象等。
2,Pod使用方式
●一个Pod中运行一个容器。“每个Pod中一个容器”的模式是最常见的用法;在这种使用方式中,你可以把Pod想象成是单个容器的封装,kuberentes管理的是Pod而不是直接管理容器。
●在一个Pod中同时运行多个容器。一个Pod中也可以同时封装几个需要紧密耦合互相协作的容器,它们之间共享资源。这些在同一个Pod中的容器可以互相协作成为一个service单位,比如一个容器共享文件,另一个“sidecar”容器来更新这些文件。Pod将这些容器的存储资源作为一个实体来管理。(只适用于收集日志,监控 )
3,如何解决一个pod 多容器通信
pause容器
一个Pod下的容器必须运行于同一节点上。现代容器技术建议一个容器只运行一个进程,该进程在容器中PID命令空间中的进程号为1,可直接接收并处理信号,进程终止时容器生命周期也就结束了。若想在容器内运行多个进程,需要有一个类似Linux操作系统init进程的管控类进程,以树状结构完成多进程的生命周期管理。运行于各自容器内的进程无法直接完成网络通信,这是由于容器间的隔离机制导致,k8s中的Pod资源抽象正是解决此类问题,Pod对象是一组容器的集合,这些容器共享Network、UTS及IPC命令空间,因此具有相同的域名、主机名和网络接口,并可通过IPC直接通信。
4,pod 组成
pause容器(理解为 pod 里的 管理员) 也可以叫基础容器 父容器
每个Pod都有一个特殊的被称为“基础容器”的Pause容器。Pause容器对应的镜像属于Kubernetes平台的一部分,除了Pause容器,每个Pod还包含一个或者多个紧密相关的用户应用容器。
5, k8s 中的 pod
- containerPort:
- 定义: 这是指定在 Pod 规格(spec)中容器级别的端口,代表容器内部应用程序监听的端口。它告诉 Kubernetes 容器正在监听哪个端口以便接收网络请求。
- 用途: 当 Kubernetes 管理容器时,会用到此信息来了解容器期望接收网络连接的端口,尽管它并不直接用于 Service 路由,但它对于理解容器的网络需求是必要的。
- targetPort:
- 定义: 这是 Service 定义的一部分,指定 Service 应该如何将接收到的流量路由到后端 Pods 的具体端口上。它可以是一个数字或一个字符串(对应于 PodSpec 中的端口名称)。
- 用途: 即便
targetPort
可以与containerPort
相同,但它提供了灵活性,允许你将 Service 流量定向到容器的不同端口,或者在复杂的配置中使用端口名称进行路由。
- port(或称为
servicePort
):
- 定义: 这是在 Service 定义中指定的逻辑端口,用于集群内部的通信。它是 Service 的一部分,集群内的其他组件可以通过这个端口访问 Service,而无需知道后端 Pod 的具体细节。
- 用途: 作为 Service 的内部访问点,它简化了服务发现过程,使得服务调用方只需要知道 Service 的名字和这个端口,而不需要关心后端 Pod 的 IP 地址或端口。
- nodePort:
- 定义: 当 Service 类型设置为
NodePort
时,Kubernetes 会在每个节点上开放一个特定范围内的静态端口(默认通常是 30000-32767),并将其绑定到 Service 的port
上。 - 用途:
nodePort
允许外部流量通过任意节点的 IP 地址加上这个端口直接访问到 Service。这为集群外部的客户端提供了一种访问 Service 的方式,而无需设置更复杂的负载均衡器或入口控制器。
总结起来,这四个概念描述了 Kubernetes 中网络流量从外部到容器内部的路由路径,以及集群内部的服务发现机制。containerPort
关注容器自身,targetPort
和 port
服务于 Service 的定义和内部路由,而 nodePort
则扩展了服务的可访问性至集群外部。
二 pause容器
1,pause容器 是什么
Pod资源中针对各容器提供网络命令空间等共享机制的是底层基础容器pause,基础容器(也可称为父容器)pause就是为了管理Pod容器间的共享操作,这个父容器需要能够准确地知道如何去创建共享运行环境的容器,还能管理这些容器的生命周期。为了实现这个父容器的构想,kubernetes中,用pause容器来作为一个Pod中所有容器的父容器。这个pause容器有两个核心的功能,一是它提供整个Pod的Linux命名空间的基础。二来启用PID命名空间,它在每个Pod中都作为PID为1进程(init进程),并回收僵尸进程。
2,pause容器作用
pause容器使得Pod中的所有容器可以共享两种资源:网络和存储。
●网络:
每个Pod都会被分配一个唯一的IP地址。Pod中的所有容器共享网络空间,包括IP地址和端口。Pod内部的容器可以使用localhost互相通信。Pod中的容器与外界通信时,必须分配共享网络资源(例如使用宿主机的端口映射)。
●存储:
Pod可以指定多个共享的Volume。Pod中的所有容器都可以访问共享的Volume。Volume也可以用来持久化Pod中的存储资源,以防容器重启后文件丢失。
3, pause容器功能
- 在pod中担任Linux命名空间(如网络命令空间)共享的基础;
- 启用PID命名空间,开启init进程。
- 协调他的容器生命周期
- 提供健康检查和生存探针
4, pause容器 的意义
●原因一:在一组容器作为一个单元的情况下,难以对整体的容器简单地进行判断及有效地进行行动。比如,一个容器死亡了 那么引入与业务无关的Pause容器作为Pod的基础容器,以它的状态代表着整个容器组的状态,这样就可以解决该问题。
●原因二:Pod里的多个应用容器共享Pause容器的IP,共享Pause容器挂载的Volume,这样简化了应用容器之间的通信问题,也解决了容器之间的文件共享问题。
三 Pod 分类
1,自主式Pod
这种Pod本身是不能自我修复的,当Pod被创建后(不论是由你直接创建还是被其他Controller),都会被Kuberentes调度到集群的Node上。直到Pod的进程终止、被删掉、因为缺少资源而被驱逐、或者Node故障之前这个Pod都会一直保持在那个Node上。Pod不会自愈。如果Pod运行的Node故障,或者是调度器本身故障,这个Pod就会被删除。同样的,如果Pod所在Node缺少资源或者Pod处于维护状态,Pod也会被驱逐。(没有存到etcd)
2,控制器管理的Pod
Kubernetes使用更高级的称为Controller的抽象层,来管理Pod实例。Controller可以创建和管理多个Pod,提供副本管理、滚动升级和集群级别的自愈能力。例如,如果一个Node故障,Controller就能自动将该节点上的Pod调度到其他健康的Node上。虽然可以直接使用Pod,但是在Kubernetes中通常是使用Controller来管理Pod的。
四 pod 如何通信
1,同一个主机中的Pod通信
- 共享网络环境:所有Pod都处在同一个物理主机上,因此它们共享主机的网络栈,但各自拥有独立的IP地址。
- 虚拟网络设备:每个Pod有自己的网络空间(网络命名空间),并通过虚拟以太网接口(veth pair)与主机的网络环境相连。这就像每个Pod有一根“虚拟网线”连接到一起。
- 直接IP通信:当一个Pod需要与同主机上的另一个Pod通信时,它直接使用对方Pod的IP地址发送数据包。因为它们都在同一台机器上,所以数据不需要离开主机就能到达目标Pod。
- 系统自动路由:操作系统会根据目标IP地址识别出这是同主机内的通信,然后通过内部的虚拟网络路径直接将数据传递给目标Pod,这个过程对于用户和应用来说是透明的。
简单来说,就像是住在同一栋楼里的两户人家,他们虽然门牌号不同(各自有独立IP),但因为同在一栋楼(同一主机),可以直接按门牌号(IP地址)互寄信件(发送数据),无需走出大楼。
可以通过localhost(即127.0.0.1)或者直接使用Pod的IP地址进行通信,因为它们共享网络命名空间。但推荐使用Kubernetes提供的Pod的IP地址进行通信
2,不同主机间的Pod通信
对于跨节点的Pod通信,通常需要通过Kubernetes Service来实现:
- Cluster IP Service:Kubernetes会为每个定义的Service自动分配一个虚拟IP地址(Cluster IP),并通过iptables或其他网络插件(如Calico、Flannel等)将流量路由到后端Pod上。不同节点上的Pod可以通过这个Cluster IP访问到服务,而无需关心后端Pod的实际位置或IP地址。
- NodePort Service:如果需要从集群外部访问Pod,可以使用NodePort类型的服务,它会在每个节点上开放一个特定的端口,通过这个端口可以路由到Service对应的Pod上。
- LoadBalancer Service(云环境)或ExternalIP(本地或自建集群):在需要更高水平的负载均衡时,可以使用LoadBalancer Service(适用于云提供商),它会在公有云上创建一个负载均衡器,并将流量分发到多个节点。对于非云环境,可以手动配置ExternalIP来达到类似效果。
3,同一个Pod内部容器间通信
pause 容器
在同一个Pod中的多个容器之间通信非常直接,因为它们共享同一个网络命名空间。这意味着它们本质上是在同一个“网络环境下”,可以像在同一台机器上的进程一样互相通信。下面是几个关键点:
- 共享网络栈:Pod中的所有容器共享同一个网络栈,包括IP地址、端口空间、以及网络设备。因此,容器间可以使用
localhost
或者Pod的IP地址进行通信。 - 端口访问:容器可以绑定到不同的端口,但因为它们共享网络命名空间,可以从任一容器通过localhost加上对应的端口号访问其他容器的服务。
- 通信示例:如果容器A运行了一个web服务在端口8080上,容器B可以直接通过
http://localhost:8080
来访问容器A的服务,无需任何特殊的网络配置。 - 共享卷通信:虽然不是直接的网络通信方式,但通过共享卷(Volumes),容器之间也可以交换文件或状态信息,实现数据层面的通信。
- 无需额外配置:由于网络命名空间的共享,容器间通信无需配置额外的网络路由或服务发现机制,这也是将紧密相关的服务放在同一Pod中的优势之一。
总结来说,在同一个Pod内的容器通信十分简便,几乎就如同它们是运行在同一台机器上的不同进程,可以直接通过本地环回地址(localhost)或者Pod的IP来互相通信。
五 Pod中 容器的分类
1,基础容器(infrastructure container)
每次创建 Pod 时候就会创建,运行的每一个Pod都有一个 pause-amd64 的基础容器自动会运行,对于用户是透明的 用于维护整个 Pod 网络和存储空间
2,初始化容器(initcontainers)
2.1 初始化容器是什么
Init容器必须在应用程序容器启动之前运行完成,而应用程序容器是并行运行的,所以Init容器能够提供了一种简单的阻塞或延迟应用容器的启动的方法。
2.2 初始化容器特点
Init 容器与普通的容器非常像,除了以下两点:
●Init 容器总是运行到成功完成为止 (循环)
●每个 Init 容器都必须在下一个 Init 容器启动之前成功完成启动和退出
如果 Pod 的 Init 容器失败,k8s 会不断地重启该 Pod,直到 Init 容器成功为止。然而,如果 Pod 对应的重启策略(restartPolicy)为 Never,它不会重新启动。
2.3 Init 的容器作用
因为init容器具有与应用容器分离的单独镜像,其启动相关代码具有如下优势:
●Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。例如,没有必要仅为了在安装过程中使用类似 sed、 awk、 python 或 dig 这样的工具而去FROM 一个镜像来生成一个新的镜像。
●Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。
●应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。
●Init 容器能以不同于Pod内应用容器的文件系统视图运行。因此,Init容器可具有访问 Secrets 的权限,而应用容器不能够访问。
●由于 Init 容器必须在应用容器启动之前运行完成,因此 Init 容器提供了一种机制来阻塞或延迟应用容器的启动, (打个比方,tomcat 必须基于jdk)
直到满足了一组先决条件。一旦前置条件满足,Pod内的所有的应用容器会并行启动。
3, 应用容器(Maincontainer)
并行启动
六 Init容器实例
1,官网示例
https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/init-containers/
2,演示Init容器
2.1 写一个 yaml 文件
不管顺序 都是先看初始化容器
初始化容器 从上往下
apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp spec: containers: - name: myapp-container image: busybox:1.28 command: ['sh', '-c', 'echo The app is running! && sleep 3600'] initContainers: - name: init-myservice image: busybox:1.28 command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;'] - name: init-mydb image: busybox:1.28 command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
这段YAML配置文件定义了一个Kubernetes Pod资源对象,详细解释如下:
apiVersion: v1
:指定了该资源对象使用的API版本是v1,这是Kubernetes核心API的一个稳定版本,用于定义基础资源如Pods。kind: Pod
:声明了资源的对象类型是Pod,Pod是Kubernetes中最小的可部署的单元,可以包含一个或多个共享网络和存储空间的容器。metadata:
部分提供了关于此Pod的元数据:
name: myapp-pod
:为Pod指定了一个名称,即myapp-pod
。labels:
定义了一组标签(key-value对),这里只有一个标签app: myapp
,用于标识Pod属于哪个应用,便于通过标签选择器(label selectors)进行操作或配置Service等资源。
spec:
部分描述了Pod期望的状态配置:
containers:
列表定义了Pod中运行的主容器集合。
- 第一个容器:
name: myapp-container
:容器的名称。image: busybox:1.28
:指定容器使用的镜像是busybox:1.28
,这是一个轻量级的Linux发行版,常用于测试和基础命令行操作。command: ['sh', '-c', 'echo The app is running! && sleep 3600']
:容器启动时执行的命令,这里先打印一条消息,然后让容器睡眠3600秒(1小时),模拟一个持续运行的服务。
initContainers:
列表定义了初始化容器集合,这些容器会在应用容器启动之前运行,并且必须全部成功退出后,应用容器才会启动。
init-myservice
:等待名为myservice
的服务解析成功,通过nslookup命令检查,如果服务未就绪则每隔2秒重试。init-mydb
:与上述类似,但等待的是名为mydb
的服务。通过这样的配置,Pod定义了一个主要的容器
myapp-container
来运行应用,并且在启动应用容器之前,会先执行两个初始化容器来确保依赖的服务(myservice
和mydb
)已经准备就绪。这种方式确保了服务间的依赖关系得到妥善处理,提高了应用部署的健壮性。
2.2 执行yaml 查看结果
执行
查看pod 信息 kubectl describe pod myapp-pod
或者 直接看日志 可以看到一直在等待 init 容器
也可以查看pod 状态 看到
2.3 准备 service
apiVersion: v1 kind: Service metadata: name: myservice spec: ports: - protocol: TCP port: 80 targetPort: 9376
查看pod 显示init 容器已经准备好一个
2.4 准备mydb
apiVersion: v1 kind: Service metadata: name: mydb spec: ports: - protocol: TCP port: 80 targetPort: 9377
查看pod 应用容器running
3, 特别说明
●在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容器的名称必须唯一;与任何其它容器共享同一个名称,会在验证时抛出错误。
六 镜像拉取策略(image PullPolicy)
Pod 的核心是运行容器,必须指定容器引擎,比如 Docker,启动容器时,需要拉取镜像,k8s 的镜像拉取策略可以由用户指定
1,镜像拉取策略有哪些
IfNotPresent:在镜像已经存在的情况下,kubelet 将不再去拉取镜像,仅当本地缺失时才从仓库中拉取,默认的镜像拉取策略
Always:每次创建 Pod 都会重新拉取一次镜像
Never:Pod 不会主动拉取这个镜像,仅使用本地镜像
注意:对于标签为“:latest”的镜像文件,其默认的镜像获取策略即为“Always”;而对于其他标签的镜像,其默认策略则为“IfNotPresent”。
2, yaml 语法
imagePullPolicy: Always
apiVersion: v1 kind: Pod metadata: name: private-image-test-1 spec: containers: - name: uses-private-image image: $PRIVATE_IMAGE_NAME imagePullPolicy: Always command: [ "echo", "SUCCESS" ]
七 重启策略(restartPolicy)
当 Pod 中的容器退出时通过节点上的 kubelet 重启容器。适用于 Pod 中的所有容器。
1,重启策略 有哪些
Always:当容器终止退出后,总是重启容器,默认策略
OnFailure:当容器异常退出(退出状态码非0)时,重启容器;正常退出则不重启容器
(比如 exit 3 非正常代码 echo$? 非0 是非正常退出 )
Never:当容器终止退出,从不重启容器
#注意:K8S 中不支持重启 Pod 资源,只有删除重建
2,yaml 语法
restartPolicy: Never
#注意:跟container同一个级别
apiVersion: v1 kind: Pod metadata: name: foo spec: containers: - name: busybox image: busybox args: - /bin/sh - -c - sleep 30; exit 3 restartPolicy: Never
文章知识点与官方