PodKubernetes项目里定义的最小可调度单元,是Kubernetes对应用程序的抽象。在这篇文章里我将会介绍KubernetesPod的基本概念,使用方式,生命周期以及如何使用Pod部署应用。读这篇文章的朋友我会默认你已经了解Kubernete是用来解决什么问题的,以及电脑上已经安装了Minikube这个能试验Kubernetes功能的工具。如果尚未做好这些准备工作,推荐先去看下面的两篇文章做好准备工作后再来学习这里的内容。

你一定要了解的Kubernetes

运行在笔记本上的Kubernetes集群

什么是Pod

KubernetesAPI对象模型中,Pod是最小的API对象,换一个专业点的的说法可以这样描述:Pod,是 Kubernetes 的原子调度单位。在集群中,Pod表示正在运行的应用进程。Pod的内部可以有一个或多个容器,同属一个Pod的容器将会共享:

  • 网络资源

  • 相同的IP

  • 存储

  • 应用到Pod上的自定义配置

可以看到PodKubernetes定义出来的一个逻辑概念,可以用另外一种方式来理解Pod:一种特定于应用程序的“逻辑主机”,其中包含一个或多个紧密协作的容器。例如,假设我们在Pod中有一个应用程序容器和一个日志记录容器。日志记录容器的唯一工作是从应用程序容器中提取日志。将两个容器放置同一个Pod里可消除额外的通信时间,因为它们位于同一个"主机",因此所有内容都是本地的并且它们共享所有资源,就跟在同一台物理服务器上执行这些操作一样。

此外也不是所有有“关联”的容器都属于同一个Pod。比如,应用容器和数据库虽然会发生访问关系,但并没有必要、也不应该部署在同一台机器上,它们更适合做成两个Pod

Pod的模型

根据Pod里的容器数量可以将Pod分为两种类型:

  • 单容器模型。由于PodKubernetes可识别的最小对象,Kubernetes管理调度Pod而不是直接管理容器,所以即使只有一个容器也需要封装到Pod里。

  • 多容器模型。在这个模型中,Pod可以容纳多个紧密关联的容器以共享Pod里的资源。这些容器作为单一的,凝聚在一起的服务单元工作。

每个Pod运行应用程序的单个实例。如果需要水平扩展/缩放应用程序(例如运行多个副本),则可以为每个实例使用一个Pod。这与在单个Pod中运行同一应用程序的多个容器不同。

还需要提的一点是,Pod本身不具有调度功能。如果所在的节点发生故障或者你要维护节点,则Pod是不会自动调度到其他节点了。Kubernetes用一系列控制器来解决Pod的调度问题,Deployment就是最基础的控制器。通常我们都是在定义的控制器的配置里通过PodTemplate定义要控制的Pod,让控制器和所管控的Pod一起被创建出来(这部分内容后面单独写文章讨论)。

Pod生命周期的阶段

一个Pod的状态会告诉我们它当前正处于生命周期的哪个阶段,Pod的生命周期有5个阶段:

  • Pending:等待状态表明至少有一个Pod内的容器尚未创建。

  • Running:所有容器已经创建完成,并且Pod已经被调度到了一个Node上。此时Pod内的容器正在运行,或者正在启动或重新启动。

  • Succeeded:Pod中的所有容器均已成功终止,并且不会重新启动。

  • Faild: 所有容器均已终止,至少有一个容器发生了故障。失败的容器以非零状态退出。

  • Unknown:无法获得Pod的状态。

在实践中使用Pod

我们已经讨论了Pod在理论上的含义,现在让我们看看它在实际中长什么样。我们将首先浏览一个简单的Pod定义YAML文件,然后部署一个示例应用程序来展示如何使用它。

Pod的YAML文件

Kubernetes里所有的API对象都由四部分组成:

  • apiVersion -- 当前使用的Kubernetes的API版本。

  • kind -- 你想创建的对象的种类。

  • metadata -- 元数据,用于唯一表示当前的对象,比如name、namespace等。

  • spec -- 我们的Pod的指定配置,例如镜像名称,容器名称,数据卷等。

apiVersionkindmetadata是必填字段,适用于所有Kubernetes对象,而不仅仅是podspec里指定的内容(spec也是必需字段)会因对象而异。下面的示例显示了Pod的YAML文件大概长什么样子。

apiVersion: "api version"
kind: "object to create"
metadata:                   name: "Pod name"labels:app: "label value"
spec:                       containers:- name: "container name"image: "image to use for container"

关于YAML的语法可以参考前面的文章:YAML,另一种标记语言?不止是标记语言!

理解了Pod配置文件的模板后,接下来我们看看如何使用配置文件创建上面说的两种模型的Pod

单容器Pod

下面的pod-1.yaml是个单容器Pod的清单文件。它会运行一个Nginx容器。

apiVersion: v1
kind: Pod
metadata:name: first-podlabels:app: myapp
spec:containers:- name: my-first-podimage: nginx

接下来,我们通过运行Kubectl create -f pod-1.yaml将清单文件部署到本地的Kubernetes集群中。然后,我们运行kubectl get pods以确认我们的Pod运行正常。

kubectl get pods
NAME                                          READY     STATUS    RESTARTS   AGE
first-pod                                      1/1       Running   0          45s

可以到PodNginx容器里执行以下service nginx status命令确保Nginx在正常运行。

kubectl exec first-pod -- service nginx status
nginx is running.

这会在Pod里执行service nginx status指令,类似docker exec命令。

现在,我们通过运行kubectl delete pod first-pod删除刚才创建的Pod

kubectl delete pod first-pod
pod "firstpod" deleted

多容器Pod

下面我们将部署一个更复杂的Pod:一个拥有两个容器的Pod,这些容器相互协作作为一个实体工作。其中一个容器每10秒将当前日期写入一个文件,而另一个Nginx容器则为我们展示这些日志。这个PodYAML如下:

apiVersion: v1
kind: Pod
metadata:name: multi-container-pod # pod的名称
spec:volumes:- name: shared-date-logs  # 为Pod里的容器创建一个共享数据卷emptyDir: {}containers:- name: container-writing-dates # 第一个容器的名称image: alpine # 容器的镜像command: ["/bin/sh"]args: ["-c", "while true; do date >> /var/log/output.txt; sleep 10;done"] # 每10秒写入当前时间volumeMounts:- name: shared-date-logsmountPath: /var/log # 将数据卷挂在到容器的/var/log目录- name: container-serving-dates # 第二个容器的名字image: nginx:1.7.9 # 容器的镜像ports:- containerPort: 80 # 定义容器提供服务的端口volumeMounts:- name: shared-date-logsmountPath: /usr/share/nginx/html # 将数据卷挂载到容器的/usr/share/nginx/html

上面通过volumes指令定义了Pod内的数据卷

  volumes:- name: shared-date-logs  # 为Pod里的容器创建一个数据卷emptyDir: {}

第一个容器将数据卷挂载到了/var/log/每隔10秒往output.txt文件里写入时间,而第二个容器通过将数据卷挂载到/usr/share/nginx/html伺服了这个日志文件。

执行kubectl create -f pod-2.yaml创建这个多容器Pod

kubectl create -f pod-2.yaml
pod "multi-container-pod" created

然后确保Pod已经正确部署:

kubectl get pods
NAME                                          READY     STATUS    RESTARTS   AGE
multi-container-pod                           2/2       Running   0          1m

通过运行kubectl describe pod podName,查看Pod的详细信息,里面会包含两个容器的信息。(下面的内容只截取了容器相关的信息)

Containers:container-writing-dates:Container ID:  docker://e5274fb901cf276ed5d94b...Image:         alpineImage ID:      docker-pullable://alpine@sha256:621c2f39...Port:          Host Port:     Command:/bin/shArgs:-cwhile true; do date >> /var/log/output.txt; sleep 10;doneState:          RunningStarted:      Sat, 1 Aug 2020 11:31:44 +0800Ready:          TrueRestart Count:  0Environment:    Mounts:/var/log from shared-date-logs (rw)/var/run/secrets/Kubernetes.io/serviceaccount from default-token-8dl5j (ro)container-serving-dates:Container ID: docker://f9c85f3fe3...Image:          nginx:1.7.9Image ID:       docker-pullable://nginx@sha256:e3456c851...Port:           80/TCPHost Port:      0/TCPState:          RunningStarted:      Sat, 1 Aug 2020 11:31:44 +0800Ready:          TrueRestart Count:  0Environment:    Mounts:/usr/share/nginx/html from shared-date-logs (rw)/var/run/secrets/Kubernetes.io/serviceaccount from default-token-8dl5j (ro)

两个容器都在运行,下面我们将进到Pod里确保两个容器都在执行分配的作业。

通过运行kubectl exec -it multi-container-pod -c container-serving-dates -- bash连接到Nginx容器里。

在容器内运行curl'http://localhost:80/output.txt',它应该返回时间日志文件的内容给我们。(如果容器中未安装curl,请先运行apt-get update && apt-get install curl,然后再次运行curl'http://localhost:80/output.txt'。)

curl 'http://localhost:80/app.txt'
Sat Aug 1  11:31:44 CST 2020
Sat Aug 1  11:31:54 CST 2020
Sat Aug 1  11:32:04 CST 2020

SideCar模式

除了上面说的那些之外,我们可以在一个Pod中按照顺序启动一个或多个辅助容器,来完成一些独立于主进程(主容器)之外的工作,完成工作后这些辅助容器会依次退出,之后主容器才会启动,这种容器设计模式叫做sidecar

比如对于前端Web应用,如果把构建后的Js项目放到Nginx镜像的/usr/share/nginx/html目录下,NginxJs应用做成一个镜像运行容器,每次应用有更新或者Nginx要做升级、更新配置操作都需要重新做一个镜像,非常麻烦。

有了Pod之后,这样的问题就很容易解决了。我们可以把前端Web应用和Nginx分别做成镜像,然后把它们作为一个Pod里的两个容器"组合"在一起。这个Pod的配置文件如下所示:

apiVersion: v1
kind: Pod
metadata:name: web-2
spec:initContainers:- image: kevinyan/front-app:v2name: frontcommand: ["cp", "/www/application/*", "/app"]volumeMounts:- mountPath: /appname: app-volumecontainers:- image: nginx:1.7.9name: nginxports:- containerPort: 80 # 定义容器提供服务的端口volumeMounts:- mountPath: /usr/share/nginx/htmlname: app-volumevolumes:- name: app-volumeemptyDir: {}

所有spec.initContainers定义的容器,都会比spec.containers定义的用户容器先启动。并且,Init容器会按顺序逐一启动,直到它们都启动并且退出了,用户容器才会启动。所以,这个Init类型的容器启动后,执行了一句"cp /www/application/* /app",把应用包拷贝到"/app"目录下,然后退出。这个"/app"目录,挂载了一个名叫app-volumeVolume。接下来Nginx容器,同样声明了挂载app-volume到自己的"/usr/share/nginx/html"目录下。由于这个Volume 是被Pod里的容器共享的所以等Nginx容器启动时,它的目录下就一定会存在前端项目的文件。这个文件正是上面的Init容器启动时拷贝到Volume里面的。

这就是容器设计模式里最常用的一种模式:sidecar。顾名思义,sidecar指的就是我们可以在一个Pod中,启动一个辅助容器,来完成一些独立于主进程(主容器)之外的工作。

总结

Pod把多个紧密关联的容器组织在一起,让他们共享自己的资源,这点有些像是这些容器的"主机",只不过这个"主机"是个逻辑概念。当你需要把一个运行在虚拟机里的应用迁移到容器中时,一定要仔细分析到底有哪些进程(组件)运行在这个虚拟机里。然后,你就可以把整个虚拟机想象成为一个 Pod,把这些进程分别做成容器镜像,把有顺序关系的容器,定义为 Init Container。这才是更加合理的、松耦合的容器编排诀窍,也是从传统应用架构,到“微服务架构”最自然的过渡方式。

最后关于Docker In Docker这种把整个应用塞到一个容器里的方法的弊端请查看之前的文章:Docker容器的"单进程模型"。

- END -

关注公众号,获取更多精选技术原创文章

Kubernetes Pod入门指南相关推荐

  1. Kubernetes Ingress入门指南和实践练习

    Ingress也是Kubernetes项目里的一种 API 对象,它公开了从集群外部到集群内Service的 HTTP 和 HTTPS 路由,这些路由由 Ingress 资源上定义的规则控制. int ...

  2. Kubernetes Helm入门指南

    什么是Helm?这可不是暗黑破坏神里装备的名称:头盔,而是Kubernetes的一个包管理工具,用来简化Kubernetes应用的部署和管理.我们Helm和Kubernetes的关系,我们可以理解成y ...

  3. Serverless Kubernetes 快速入门指南

    为什么80%的码农都做不了架构师?>>>    摘要: 5月,阿里云宣布推出Serverless Kubernetes服务.开发者可在5秒内创建集群.30秒部署应用上线.用户无需管理 ...

  4. 浅析Kubernetes Pod重启策略和健康检查

    使用Kubernetes的主要好处之一是它具有管理和维护集群中容器的能力,几乎可以提供服务零停机时间的保障.在创建一个Pod资源后,Kubernetes会为它选择worker节点,然后将其调度到节点上 ...

  5. Kubernetes入门指南-基础篇

    Kubernetes入门指南-基础篇 基础入门 kubernetes简介 kubernetes是一个平台 kubernetes架构 kubernetes不是什么 核心组件 kubernetes基本概念 ...

  6. 2021年最新 k8s安装部署步骤 kubernetes从入门到实践 K8S实战容器化迁移实战教程 K8S存储之Ceph分布式存储系统 K8S架构师实战指南

    2021年最新 k8s安装部署步骤 kubernetes从入门到实践 K8S实战容器化迁移实战教程 K8S存储之Ceph分布式存储系统 K8S架构师实战指南

  7. k8s之Pod详解(五)【Kubernetes(K8S) 入门进阶实战完整教程,黑马程序员K8S全套教程(基础+高级)】

    参考于Kubernetes(K8S) 入门进阶实战完整教程,黑马程序员K8S全套教程(基础+高级) Pod Pod的结构 每个Pod中都可以包含一个或者多个容器 这些容器可以分为两类: 用户自定义用的 ...

  8. Calico on Kubernetes 从入门到精通

    第一部分 How about Calico About Calico Calico为容器和虚拟机工作负载提供一个安全的网络连接. Calico可以创建并管理一个3层平面网络,为每个工作负载分配一个完全 ...

  9. Kubernetes 网络入门

    原文作者:Brlan Ehlert of F5 原文链接:Kubernetes 网络入门 转载来源:NGINX 官方网站 NodePort.LoadBalancer.Ingress controlle ...

最新文章

  1. jQuery-this与$(this)的区别
  2. php error 2,一起搞懂PHP的错误和异常(二)
  3. 数学之美番外篇:快排为什么那样快
  4. 需要我们了解的SQL Server阻塞原因与解决方法 - sym_cn
  5. The Web Audio autoplay policy will be re-enabled in 音频无法播放
  6. 最新版Scrum指南已发布
  7. 【人工智能】给初学者们讲解人工神经网络(ANN)
  8. OpenShift 4 Hands-on Lab (10) 限制集群资源的使用量
  9. Java网络通信编程从基础到框架
  10. LR11录制手机/pad App脚本多种方法介绍(Mobile App补丁包)
  11. js替换问题replace和replaceAll
  12. pd 生成mysql数据库sql时加上备注
  13. hdoj4540:威威猫系列故事——打地鼠(dp基础题-数塔思想)
  14. Flash计时器次数为什么设置1次的重要性
  15. gps高斯utm_高斯投影与UTM投影的区别
  16. CDA数据分析师-LEVEL I考试-分享
  17. 【编译汇编链接】COFF文件及结构说明
  18. HDLBITS 练习 卡诺图化简部分
  19. 阿泰水晶报表补空行(分组)
  20. opboot怎么刷入固件_竞斗云系列四:Opboot1.09+128M固件刷机

热门文章

  1. 固态电池技术取得新突破,充电一分钟续航800公里
  2. 网络访问保护(NAP)技术之详解
  3. 斐波那契 (Fibonacci)数列
  4. 中文乱码问题解决方法总结
  5. Spring Batch_Parallel Steps
  6. vsftp 简易部署使用
  7. spring cloud微服务分布式云架构-commonservice-config配置服务搭建
  8. python服务器环境搭建(2)——安装相关软件
  9. SQL Server2008 用编写脚本自动生成的Sql语言出现 “列名显示无效 ”错误
  10. Silkroad 与 Tesseract 通信协议 QuestionModel