在本指南中,我使用实际示例详细介绍 Kubernetes Pod 概念。如果你想了解如下内容,本指南特别适合你:
- Pod 核心概念
- 如何创建 Pod
- 访问 Pod
- Pod 关联对象
本指南的目的是让您了解如何构建 Pod,并部署 Pod 和访问在其上运行的应用程序。此外,还有许多与 Pod 对象相关的概念。因此,我提供了与 Pod 相关的所有信息和概念,以进一步构建您所学的基础知识。
注意:在开始探索 Kubernetes Pod 之前,请确保您对 Linux 容器概念有充分的了解。
什么是 Kubernetes Pod?
在了解 Kubernetes Pod 概念之前,让我们先了解一下容器。
众所周知,容器是一个独立的环境,我们在其中打包应用程序及其依赖项。通常,容器运行单个进程(尽管有多种方法可以运行多个进程)。每个容器都有一个 IP 地址,可以附加卷并控制 CPU 和内存资源等。所有这些都是通过命名空间和控制组(cgroups)的概念发生的。
Kubernetes 是一个用于部署、扩展和管理容器化应用程序的容器编排系统,它有自己的容器运行方式。我们称之为 Pod。 Pod 是 Kubernetes 中最小的可部署单元,代表应用程序的单个实例。
例如,如果您想运行 Nginx 应用程序,则可以在 Pod 中运行它。
那么它与容器有什么不同呢?容器是一个单一的单元。但是,一个 Pod 可以包含多个容器。您可以将 Pod 视为一个可以将一个或多个容器容纳在一起的盒子。
Pod 提供了更高级别的抽象,允许您将多个容器作为一个单元进行管理。这里,不再是每个容器分别一个 IP,而是 Pod 整体获取一个 IP,然后,Pod 内的多个不同的容器相互之间,使用 localhost 通信。
这意味着 Kubernetes pod 内的容器共享以下内容:
- Network namespace:网络命名空间 – Pod 内的所有容器都通过 localhost 进行通信。
- IPC namespace:IPC 命名空间:所有容器都使用共享的进程间通信命名空间。
- UTS namespace:UTS 命名空间:所有容器共享相同的主机名。
Pod 内的容器之间不共享什么?
- 默认情况下,PID 命名空间不共享,但是 kubernetes 提供了使用 shareProcessNamespace 选项在 pod 内的容器之间启用进程共享的选项。
- 挂载命名空间不在容器之间共享。每个容器都有自己的私有文件系统和目录。但是,Pod 挂载卷在容器之间共享。
简而言之,以下是您应该了解 pod 的知识:
- Pod 是 Kubernetes 中最小的可部署单元。
- Pod 本质上是短暂的;它们可以被创建、删除和更新。
- 一个 Pod 可以有多个容器;一个 Pod 内可以运行的容器数量没有限制。
- 每个 Pod 都有一个唯一的 IP 地址。
- Pod 使用 IP 地址相互通信。
- Pod 内的容器使用不同端口,通过 localhost 进行连接。
- Pod 内运行的容器应具有不同的端口号,以避免端口冲突。
- 您可以为 Pod 内运行的每个容器设置 CPU 和内存资源。
- Pod 内的容器共享相同的卷挂载。
- pod内的所有容器都调度在同一个节点上;它不能跨越多个节点。
- 如果有多个容器,则在 Pod 启动期间,所有主容器都会并行启动。而 Pod 内的 init 容器按顺序运行。
Pod YAML(对象定义)
现在我们对 Pod 有了基本的了解,让我们看看如何定义 Pod。 Pod 是原生 Kubernetes 对象,如果要创建 pod,则需要以 YAML 格式声明 pod 要求。您还可以使用 kubectl 命令创建 pod。我们将在后面的主题中看到这一点。
以下是创建 Nginx Web 服务器 Pod 的 Pod YAML 示例。此 YAML 只是 pod 的声明性所需状态。
apiVersion: v1
kind: Pod
metadata:
name: web-server-pod
labels:
app: web-server
environment: production
annotations:
description: This pod runs the web server
spec:
containers:
- name: web-server
image: nginx:latest
ports:
- containerPort: 80
让我们来理解一下这个 pod YAML。一旦您了解了基本的 YAML,您就会更轻松地使用 Pod 和相关对象,例如部署(Deployment)、守护进程集(Daemonset)、状态集(Statefulset)等。每个 Kubernetes 对象都有一些通用的参数集。这些值会根据我们正在创建的对象类型而变化。
让我们看一下 Kubernetes pod 对象。
参数 | 描述 |
---|---|
apiVersion | pod 的 API 版本。在我们的例子中,它是 v1 |
kind | 对象的种类,这里是 Pod |
metadata | 元数据用于唯一标识和描述容器 – 标签(表示 Pod 的键值对集)。这类似于云环境中的标记。每个对象都必须使用标准标签进行标记。它有助于对对象进行分组。 – name(Pod 的名称) – namespace (pod 的命名空间) – 注解(键值格式的附加数据) |
spec | 在“spec”部分下,我们声明了 pod 的所需状态。这些是我们希望在 pod 中运行的容器的规格。 |
containers | 在容器下,我们声明 pod 内容器的所需状态。容器镜像、公开端口等。 |
现在,我们已经查看了一个基本的 Pod YAML 清单。请务必注意,此清单支持许多参数。我们将通过动手实践的方法逐步探索这些附加参数。
现在我们已经对 Pod 有了基本的了解,让我们创建一个 Pod。
创建 Pod(实例)
您可以通过两种方式创建容器:
- 使用 kubectl 命令:主要用于学习和测试目的。命令有其自身的局限性。
- 声明性方法:使用 YAML 清单。正儿八经做项目时,使用 YAML 部署 Pod。
让我们看一下这两个选项。我们将创建一个具有以下内容的 NGINX pod:
- Pod 的名称是 web-server-pod
- 它应该有标签 app: web-server 和 environment: production
- 添加注释来描述容器。
- 使用 nginx:1.14.2 容器镜像。
- 公开容器端口 80。
使用 kubectl 命令创建 Pod
对于所讨论的 pod 要求,这里是 kubectl 命令。
kubectl run web-server-pod \
--image=nginx:1.14.2 \
--restart=Never \
--port=80 \
--labels=app=web-server,environment=production \
--annotations description="This pod runs the web server"
在这里,Pod 部署在默认命名空间中。您可以获取已部署的 pod kubectl 的状态。
kubectl get pods
部署容器后,您将看到容器正在运行状态,如下所示。在我们的示例中,pod 内只有一个容器。因此,它显示 1/1 准备就绪并正在运行。
查看一个 Pod 的描述
如果你想知道正在运行的 pod 的所有细节,你可以使用 kubectl 来查看这个 pod 的描述。
kubectl describe pod web-server-pod
在以下输出中,您可以看到有关容器的所有详细信息。它的 IP 地址、命名空间、容器详细信息、QoS 类等。
以下是 describe 命令显示的所有重要 Pod 信息的图形视图。
现在,让我们使用以下命令删除 pod。
kubectl delete pod web-server-pod
使用声明式 YAML 创建 Pod
在正儿八经做项目时,您主要是通过声明式方法创建 pod。让我们看看如何使用 YAML 清单创建一个 pod。创建一个包含以下内容的文件 nginx.yaml。
apiVersion: v1
kind: Pod
metadata:
name: web-server-pod
labels:
app: web-server
environment: production
annotations:
description: This pod runs the web server
spec:
containers:
- name: web-server
image: nginx:1.14.2
ports:
- containerPort: 80
现在,要部署清单,您需要使用文件名执行以下 kubectl 命令。
kubectl create -f nginx.yaml
我们是否应该记住每个参数来创建 YAML?不。您可以使用 –dry-run 标志创建 YAML 文件。下面是一个示例。
kubectl run nginx-pod --image=nginx:1.14.2 --dry-run=client -o yaml
您也可以通过重定向输出把它写入文件。
kubectl run nginx-pod --image=nginx:1.14.2 --dry-run=client -o yaml > nginx-pod.yaml
访问在 Pod 中运行的应用程序
现在我们有一个带有 Nginx Web Server 的运行 pod。整个想法是部署和访问在 pod 中运行的应用程序。
Kubectl 提供了一个端口转发命令,用于从本地工作站访问 Kubernetes 集群中正在运行的 Pod。
我们有一个正在运行的 pod,名为 web-server-pod。让我们通过 port-forward 命令访问它。
kubectl port-forward pod/web-server-pod 8080:80
您应该会看到如下所示的输出。
现在,如果您进入浏览器并访问 http://localhost:8080,您应该会看到 Nginx 主页,如下所示。该网页由我们的 Nginx Web Server 的 pod 提供服务。
现在,您可以通过按 CTRL+C 断开端口转发。
运行 kubectl port-forward 时,发生了什么:
- Kubectl 绑定本地系统中的指定端口。在我们的例子中,它是 8080。
- 然后,它与 Kubernetes 集群 API 通信,以建立到所需节点的隧道(单个 HTTP 连接),然后连接到指定的 Pod 和容器端口,即 80。
注意:kubectl 端口转发更像是一个调试实用程序。您需要使用 Kubernetes Service 对象来公开在 Pod 中运行的应用程序。我们将在另一篇博客中实际了解 Kubernetes 服务概念
访问 Pod Shell
我们已经学习了如何访问在 pod 中运行的应用程序。现在,如果您想访问 pod shell,该怎么办?在许多用例中,您需要终端访问容器。一个主要场景是调试和故障排除。这就是 kubectl exec 命令派上用场的地方。您可以使用以下命令访问 web-server-pod 的 shell。
kubectl exec -it web-server-pod -- /bin/sh
在以下输出中,我正在 pod 内执行 whoami 命令。
注意:容器镜像通常被设计为非常小,因此您可能会发现无法执行在普通 Linux 系统上执行的所有命令。此限制取决于镜像的生成方式以及容器镜像中包含的工具程序。
Pod 生命周期
关于 Pod 你应该知道的另一个重要概念是它的生命周期。
Pod 通常由 ReplicaSet Controller、Deployment Controller 等控制器管理。使用 YAML 创建单个 Pod 时,它不受任何控制器的管理。在这两种情况下,Pod 都会经历不同的生命周期阶段。
以下是 Pod 生命周期阶段。
- Pending:表示 Pod 创建请求成功,但调度正在进行中。例如,它正在下载容器映像。
- Running:容器已成功运行并按预期运行。例如,Pod 是服务客户端请求。
- Succeeded:容器内的所有容器都已成功终止。例如,成功完成 CronJob 对象。
- Failed:所有 Pod 都已终止,但至少有一个容器因失败而终止。例如,由于配置问题,在 Pod 内运行的应用程序无法启动,并且容器以非零退出代码退出。
- Unknown:容器状态未知。例如,集群无法监控 Pod 的状态。
如果描述容器,则可以查看容器的阶段。下面是一个示例。
如果您想了解更多信息,请查看有关 Pod 生命周期 的详细博客。
Pod 功能特性
我们部署了一个简单的 Nginx pod,配置非常少。但是,Pod 在资源管理、配置、机密、可用性、安全性等方面具有许多功能。
如果你是初学者,一口气学会所有这些概念就太过分了。在实际用例中使用与 Pod 相关的对象(如部署)时,学习所有这些概念更有意义。
此外,您需要通过实际用例详细了解每个功能。以下是与容器相关的主要功能。
- Resource Requests and Limits: 资源请求和限制:Pod CPU/内存分配
- Labels: 标签:附加到 Pod 的键值对,用于对资源进行分类。
- Selectors: 选择器:根据标签对资源进行分组。
- Liveness, Readiness, and Startup Probes: 存活、就绪和启动探测:容器运行状况检查
- ConfigMaps: 用于配置管理
- Secrets: 用于密钥管理
- Volumes: 卷:持久性数据存储
- Init Containers: 初始化容器:在主容器之前运行的容器。
- Ephemeral Containers: 临时容器:添加到容器中的临时容器,用于调试或故障排除目的。
- Service Account: 服务帐户:限制对 Kubernetes 对象和资源的访问。
- SecurityContext: 主机权限和特权。
- Affinity and Anti-Affinity Rules: 亲和和反亲和规则:跨节点的 Pod 放置控制
- Pod Preemption & Priority: Pod 抢占和优先级:设置 Pod 调度和逐出的优先级。
- Pod Disruption Budget: 容器中断预算:在自愿中断期间需要运行的容器副本的最小数量。
- Container Life Cycle Hooks: 容器生命周期钩子:根据 Pod 的生命周期阶段变化执行自定义脚本。
全面的 Pod YAML 配置
注意:我给出以下示例仅供参考。不要被所有参数所淹没。它并不像看起来那么复杂。一旦你了解了基础知识,就会很容易。
如果您添加我上面列出的 pod 功能,您将获得一个全面的 pod YAML 配置,如下所示。此外,这些选项将与 Deployment、Statefulset 等对象一起使用。
apiVersion: v1
kind: Pod
metadata:
name: web-server-pod
spec:
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', 'echo "Init container started!"']
containers:
- name: web-server
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
- name: secret-volume
mountPath: /etc/my-secret
- name: configmap-volume
mountPath: /etc/config
securityContext:
capabilities:
add: ["NET_ADMIN", "SYS_TIME"]
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
readinessProbe:
httpGet:
path: /index.html
port: 80
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet:
path: /index.html
port: 80
initialDelaySeconds: 15
periodSeconds: 20
startupProbe:
httpGet:
path: /index.html
port: 80
failureThreshold: 30
periodSeconds: 10
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo 'PostStart'"]
preStop:
exec:
command: ["/bin/sh", "-c", "echo 'PreStop'"]
serviceAccountName: nginx-service-account
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
shareProcessNamespace: true
volumes:
- name: shared-data
emptyDir: {}
- name: secret-volume
secret:
secretName: nginx-secret
- name: configmap-volume
configMap:
name: nginx-configmap
Pod 关联对象
在 Kubernetes 上运行应用程序时,我们不会运行单个 pod。因为 Kubernetes 是关于扩展和维护 Pod 的可用性的。因此,如果您运行单个 Pod,它将是单点故障。因为 Pod 本身无法直接缩放。正如我们在 Kubernetes 架构中所讨论的,我们需要像 Replicaset 这样的控制器来确保始终运行所需数量的 Pod。
Kubernetes 具有与不同用例相关的 Pod 的不同类型的对象。
以下是与 Pod 相关的重要对象。
- Replicaset:保持一组稳定的 Pod 副本在任何给定时间运行。
- Deployment: 部署:运行无状态应用程序,如 Web 服务器、API 等
- StatefulSets: 运行有状态应用程序,如分布式数据库。
- Daemonsets: 守护程序集:在所有 Kubernetes 节点上运行代理。
- Jobs: 作业:用于批处理
- CronJobs: 计划作业
总结
在本指南中,我们了解了 Kubernetes Pod 的所有核心概念。正如我在介绍中提到的,在 kubernetes 生产级实现方面,pod 有很多功能。
相关阅读:
本文翻译自:https://devopscube.com/kubernetes-pod/
译者:秦晓辉,开源项目 Open-Falcon、Nightingale 创始人,极客时间专栏《运维监控实战笔记》作者,目前在创业,为客户提供可观测性产品和解决方案,欢迎联系做产品技术交流:联系我们交流可观测性产品和方案