2.4 Pod

2.4 Pod #

2.4.1 什么是 Pod #

当容器进入到现实的生产环境中时,容器的隔离性就带来了一些麻烦。因为很少有应用是完全独立运行的,经常需要几个进程互相协作才能完成任务。比如可能有多个应用结合得非常紧密以至于无法把它们拆开,但是将它们都放在同一个容器中又不是一种好的做法,因为容器的理念是对应用的独立封装,它里面就应该是一个进程、一个应用,如果里面有多个应用,不仅违背了容器的初衷,也会让容器更难以管理。

为了解决多应用联合运行的问题,同时还要不破坏容器的隔离,就需要在容器外面再建立一个 “收纳舱”,让多个容器既保持相对独立,又能够小范围共享网络、存储等资源,而且永远是 “绑在一起” 的状态。这就是 Pod 的初衷,实际上,“spec.containers” 字段其实是一个数组,里面允许定义多个容器。

Pod 是对容器的 “打包”,里面的容器是一个整体,总是能够一起调度、一起运行,绝不会出现分离的情况。Pod 属于 Kubernetes,可以在不触碰下层容器的情况下任意定制修改。Kubernetes 让 Pod 去编排处理容器,然后把 Pod 作为应用调度部署的最小单位,Pod 也因此成为了 Kubernetes 世界里的 “原子”,基于 Pod 就可以构建出更多更复杂的业务形态了。

2.4.2 YAML 描述 Pod #

可以理解为所有的 API 对象都天然具有 apiVersion、kind、metadata、spec 这四个基本组成部分,当然也包括 Pod。

在使用 Docker 创建容器的时候,可以不给容器起名字,但在 Kubernetes 里,Pod 必须要有一个名字,这也是 Kubernetes 里所有资源对象的一个约定。通常会为 Pod 名字统一加上 pod 后缀,这样可以和其他类型的资源区分开。

name 只是一个基本的标识,信息有限,所以 labels 字段就很有用,它可以添加任意数量的 Key-Value,给 Pod “贴” 上归类的标签,结合 name 就更方便识别和管理。比如:

apiVersion: v1
kind: Pod
metadata:
  name: busy-pod
  labels:
    owner: xiaobinqt
    env: demo
    region: north
    tier: back

“metadata” 一般写上 name 和 labels 就足够了,但是 “spec” 字段由于需要管理、维护 Pod 这个基本调度单元,里面有非常多的关键信息,厂常见的有 containers、hostname、restartPolicy 等字段。

containers #

containers 是一个数组,里面的每一个元素又是一个 container 对象,也就是容器。container 对象必须要有一个 name 表示名字,还要有一个 image 字段来说明它使用的镜像,这两个字段是必须要有的,否则会报数据验证错误。

container 对象的其他字段还有:

  • ports:列出容器对外暴露的端口,和 Docker 的 -p 参数有点像。

  • imagePullPolicy:指定镜像的拉取策略,可以是 Always/Never/IfNotPresent,一般默认是 IfNotPresent,也就是说只有本地不存在才会远程拉取镜像,可以减少网络消耗。

  • env:定义 container 的环境变量,和 Dockerfile 里的 ENV 指令有点类似,但它是运行时指定的,更加灵活可配置。

  • command:定义容器启动时要执行的命令,相当于 Dockerfile 里的 ENTRYPOINT 指令。

  • args:它是 command 运行时的参数,相当于 Dockerfile 里的 CMD 指令。

hostname #

TODO

restartPolicy #

TODO


下面的 spec 部分,添加 env、command、args 等字段:

spec:
  containers:
    - image: busybox:latest
      name: busy
      imagePullPolicy: IfNotPresent
      env:
        - name: os
          value: "ubuntu"
        - name: debug
          value: "on"
      command:
        - /bin/echo
      args:
        - "$(os), $(debug)"

指定使用镜像 busybox:latest,拉取策略是 IfNotPresent ,然后定义了 os 和 debug 两个环境变量,启动命令是 /bin/echo,参数里输出刚才定义的环境变量。

2.4.3 kubectl 操作 Pod #

apply,delete #

kubectl apply、kubectl delete 这两个命令可以使用 -f 参数指定 YAML 文件创建或者删除 Pod,例如:

kubectl apply -f busy-pod.yml
kubectl delete -f busy-pod.yml

在 delete 删除 pod 时也可以使用 YAML 里定义了 “metadata.name” 字段:

kubectl delete pod busy-pod

logs #

可以使用 kubectl logs 可以查看 Pod 日志

kubectl logs busy-pod

运行状态 #

使用命令 kubectl get pod 可以查看 Pod 列表和运行状态:

kubectl get pod

READY 栏显示的是 Pod 内部的容器状态,格式是 x/y,表示 Pod 里总共定义了 y 个容器,其中 x 个是正常的(ready)。

describe pod #

如果某个 Pod 运行有点不正常,比如状态是 “CrashLoopBackOff”,可以使用命令 kubectl describe 来检查它的详细状态:

kubectl describe pod busybox-pod

比如有 yaml 描述:

apiVersion: v1
kind: Pod
metadata:
  name: busybox-pod

spec:
  containers:
    - image: busybox:latest
      name: busy
      imagePullPolicy: IfNotPresent
      env:
        - name: os
          value: "ubuntu"
        - name: debug
          value: "on"
      command:
        - /bin/echo
      args:
        - "$(os), $(debug)"

对于这个 busybox-pod,因为它只执行了一条 echo 命令就退出了,而 Kubernetes 默认会重启 Pod,所以就会进入一个反复停止 - 启动的循环错误状态。

cp,exec #

kubectl 也提供与 docker 类似的 cp 和 exec 命令,kubectl cp 可以把本地文件拷贝进 Pod,kubectl exec 是进入 Pod 内部执行 Shell 命令:

echo 'aaa' > a.txt
kubectl cp a.txt ngx-pod:/tmp

准确地说,“kubectl cp”、“kubectl exec” 操作的应该是 Pod 里的容器,需要用 “-c” 参数指定容器名,不过因为大多数 Pod 里只有一个容器,所以就省略了。

kubectl exec 的命令格式与 Docker 有一点小差异,需要在 Pod 后面加上 --,把 kubectl 的命令与 Shell 命令分隔开:

kubectl exec -it ngx-pod -- sh