Kubernetes(简称K8S)是一个开源的容器编排平台,用于自动化容器化应用的部署、扩展和管理。在Kubernetes中,Pod是最小的部署单元。理解Pod的概念对于掌握Kubernetes至关重要。本篇文章将详细解释什么是Kubernetes Pod,并通过实际例子帮助读者更好地理解这一概念。
一、什么是 Kubernetes Pod?
在了解 Kubernetes Pod 概念之前,先来了解容器容器,众所周知,是一个自包含的环境,用于打包应用程序及其依赖项。通常,一个容器运行单个进程(尽管也有方法可以运行多个进程)。每个容器都有一个IP地址,并且可以附加存储卷以及控制CPU和内存资源等。这些都是通过命名空间和控制组(namespaces and control groups)的概念实现的。
Kubernetes 是一个用于部署、扩展和管理容器化应用程序的容器编排系统,它有自己运行容器的方式,我们称之为 Pod。Pod 是 Kubernetes 中最小的可部署单元,代表一个应用程序的单个实例。
例如,如果你想运行 Nginx 应用程序,你可以将它运行在一个 Pod 中。
1.那么,Pod 与容器有何不同呢?
容器是一个单独的单位。然而,Pod 可以包含多个容器。你可以将 Pod 想象成一个可以同时容纳一个或多个容器的盒子。
Pod 提供了更高层次的抽象,允许你将多个容器作为一个单元进行管理。在这里,每个容器不再单独获得 IP 地址,而是 Pod 获得一个唯一的 IP 地址,并且运行在 Pod 内的容器通过 localhost 在不同端口上相互连接。
这意味着 Kubernetes Pod 内的容器共享以下内容:
- 网络命名空间:Pod 内的所有容器通过 localhost 进行通信。
- IPC 命名空间:所有容器使用共享的进程间通信命名空间。
- UTS 命名空间:所有容器共享相同的主机名。
2.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 对象。
我们现在已经看到了一个基本的Pod YAML清单。需要注意的是,这个清单文件支持许多参数。我们将逐步探索这些额外的参数与实践的方法。
现在我们对Pod有了一些基本的了解,让我们创建一个Pod。
三、创建Pod
你可以用两种方法创建pod:
- 使用kubectl命令式命令:主要用于学习和测试目的。命令式命令有其自身的局限性。
- 声明式方法:使用YAML方式。在开发项目时,YAML清单文件用于部署pods。
让我们看看这两个方式。我们将使用以下内容创建一个NGINX pod:
- pod的名称是web-server-pod
- 它应该有标签:app: web-server和environment: production
- 添加一个注释来描述pod。
- 使用nginx:1.14.2容器镜像。
- 暴露集装箱端口80。
方法1:使用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后,您将看到pod的运行状态,如下所示。在我们的例子中,pod中只有一个容器。所以它显示1/1就绪并运行。
如果你想知道运行pod的所有细节,可以使用kubectl describe pod。
kubectl describe pod web-server-pod
在下面的输出中,你可以看到pod的所有细节。它的IP地址、命名空间、容器细节、QoS类等。
这里是描述命令显示的所有重要pod信息的图形视图。
现在让我们使用以下命令删除pod。
kubectl delete pod web-server-pod
方法2:使用声明式YAML创建Pod
在实际项目中,你将不得不通过声明的方法来创建pods。
让我们看看如何使用YAML清单文件创建pod。
创建名为nginx的文件。内容如下:
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
四、访问在 Pod 中运行的应用程序
现在我们有了一个运行中的pod和Nginx web服务器。整个想法是部署和访问在pod中运行的应用程序。
Kubectl提供了一个port-forward命令来从本地工作站访问Kubernetes集群中运行的pods。
我们有一个名为web-server-pod的运行pod。让我们通过port-forward命令访问它。
现在,如果您打开浏览器并访问http://localhost:8080,您应该会看到如下所示的Nginx主页。网页由我们的Nginx web服务器pod提供服务。
现在你可以按CTRL+C断开端口转发。
以下是运行kubectl port-forward时发生的情况:
- Kubectl绑定本地系统中的指定端口。在我们的例子中是8080。
- 然后,它与Kubernetes集群API通信,以建立到所需节点的隧道(单个HTTP连接),然后到指定的pod和容器端口(80)。
注意:kubectl端口转发更多的是一个调试实用程序。你需要使用Kubernetes服务对象来公开在pod中运行的应用程序。我们将在另一个博客中实际地研究Kubernetes service 的概念。
五、访问 Pod Shell
我们已经学习了如何访问在pod中运行的应用程序。
现在如果你想进入Pod shell怎么办?
有许多用例需要终端访问pod。一个主要用例是调试和故障排除。
这就是kubectl exec命令派上用场的地方。
您可以使用以下命令访问web-server-pod的shell。
kubectl exec -it web-server-pod -- /bin/sh
在下面的输出中,我正在pod内执行whoami命令。
六、Pod 的生命周期
关于pod你应该知道的另一个重要概念是它的生命周期。pod通常由ReplicaSet controller、Deployment controller等控制器管理。当您使用YAML创建单个pod时,它不受任何控制器的管理。在这两种情况下,pod都会经历不同的生命周期阶段。Pod的生命周期包括以下几个阶段:
- Pending:Pod已被Kubernetes API Server接受,但还没有被调度到Node上。
- Running:Pod已被调度到Node上,所有容器都已启动。
- Succeeded:Pod中的所有容器都正常终止,且不会再被重启。
- Failed:Pod中的某个容器意外终止,且不会再被重启。
- Unknown:由于某种原因,无法获取Pod的状态。
如果你通过kubectl describe pod命令查看Pod的详细信息,你可以看到Pod的状态。这里有一个例子。
七、Pod 功能
我们已经部署了一个简单的Nginx pod,配置非常少。但是,pod具有许多用于资源管理、配置、机密、可用性、安全性等方面的特性。
如果你是初学者,一次性学习所有这些概念将是多余的。在使用与pod相关的对象(如具有实际用例的Deployment)时,学习所有这些概念更有意义。
此外,您需要通过实际用例详细了解每个特性。
以下是与pod相关的主要特性:
- Resource Requests and Limits: Pod CPU/内存分配
- Labels: 附加在pod上的键值对,用于对资源进行分类。
- Selectors: 根据标签对资源进行分组。
- Liveness, Readiness和Startup Probes: 容器运行状况检查
- ConfigMaps: 用于配置管理
- Secrets: 用于秘密管理
- Volumes: 持久数据存储
- Init Containers: 在主容器之前运行的容器。
- Ephemeral Containers: 添加到pod中的临时容器,用于调试或故障排除。
- Service Account: :用于限制对Kubernetes对象和资源的访问。
- SecurityContext:主机权限和特权。
- Affinity and Anti-Affinity Rules: 跨节点的Pod放置控制。
- Pod Preemption & Priority: 设置Pod调度和驱逐的优先级。
- Pod Disruption Budget: 在自愿中断期间需要运行的Pod副本的最小数量。
- 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是容器编排的基本单元,包含一个或多个共享网络和存储的容器。通过理解Pod的概念和生命周期,我们可以更有效地在Kubernetes中部署和管理应用。本文通过一个简单的Nginx Pod示例展示了如何创建和访问Pod,希望能帮助读者更好地理解Kubernetes Pod的基本原理。