前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Kubernetes Pod入门指南

Kubernetes Pod入门指南

作者头像
KevinYan
发布2020-08-10 10:14:06
4440
发布2020-08-10 10:14:06
举报
文章被收录于专栏:网管叨bi叨网管叨bi叨

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文件大概长什么样子。

代码语言:javascript
复制
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容器。

代码语言:javascript
复制
apiVersion: v1
kind: Pod
metadata:
  name: first-pod
  labels:
    app: myapp
spec:
  containers:
  - name: my-first-pod
    image: nginx

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

代码语言:javascript
复制
kubectl get pods
NAME                                          READY     STATUS    RESTARTS   AGE
first-pod                                      1/1       Running   0          45s

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

代码语言:javascript
复制
kubectl exec first-pod -- service nginx status
nginx is running.

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

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

代码语言:javascript
复制
kubectl delete pod first-pod
pod "firstpod" deleted

多容器Pod

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

代码语言:javascript
复制
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-logs
      mountPath: /var/log # 将数据卷挂在到容器的/var/log目录
  - name: container-serving-dates # 第二个容器的名字
    image: nginx:1.7.9 # 容器的镜像
    ports:
      - containerPort: 80 # 定义容器提供服务的端口
    volumeMounts:
    - name: shared-date-logs
      mountPath: /usr/share/nginx/html # 将数据卷挂载到容器的/usr/share/nginx/html 

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

代码语言:javascript
复制
  volumes:
  - name: shared-date-logs  # 为Pod里的容器创建一个数据卷
    emptyDir: {}

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

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

代码语言:javascript
复制
kubectl create -f pod-2.yaml
pod "multi-container-pod" created

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

代码语言:javascript
复制
kubectl get pods
NAME                                          READY     STATUS    RESTARTS   AGE
multi-container-pod                           2/2       Running   0          1m

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

代码语言:javascript
复制
Containers:
  container-writing-dates:
    Container ID:  docker://e5274fb901cf276ed5d94b...
    Image:         alpine
    Image ID:      docker-pullable://alpine@sha256:621c2f39...
    Port:          
    Host Port:     
    Command:
      /bin/sh
    Args:
      -c
      while true; do date >> /var/log/output.txt; sleep 10;done
    State:          Running
      Started:      Sat, 1 Aug 2020 11:31:44 +0800
    Ready:          True
    Restart Count:  0
    Environment:    
    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.9
    Image ID:       docker-pullable://nginx@sha256:e3456c851...
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Sat, 1 Aug 2020 11:31:44 +0800
    Ready:          True
    Restart Count:  0
    Environment:    
    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'。)

代码语言:javascript
复制
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的配置文件如下所示:

代码语言:javascript
复制
apiVersion: v1
kind: Pod
metadata:
  name: web-2
spec:
  initContainers:
  - image: kevinyan/front-app:v2
    name: front
    command: ["cp", "/www/application/*", "/app"]
    volumeMounts:
    - mountPath: /app
      name: app-volume
  containers:
  - image: nginx:1.7.9
    name: nginx
    ports:
      - containerPort: 80 # 定义容器提供服务的端口
    volumeMounts:
    - mountPath: /usr/share/nginx/html
      name: app-volume
  volumes:
  - name: app-volume
    emptyDir: {}

所有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 -

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-08-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 网管叨bi叨 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是Pod
  • Pod的模型
  • Pod生命周期的阶段
  • 在实践中使用Pod
    • Pod的YAML文件
      • 单容器Pod
        • 多容器Pod
        • SideCar模式
        • 总结
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档