Pod的基础概念

一、资源限制

      Pod 是 kubernetes 中最小的资源管理组件,Pod 也是最小化运行容器化应用的资源对象。一个 Pod 代表着集群中运行的一个进程。kubernetes 中其他大多数组件都是围绕着 Pod 来进行支撑和扩展 Pod 功能的,例如用于管理 Pod 运行的 StatefulSet 和 Deployment 等控制器对象,用于暴露 Pod 应用的 Service 和 Ingress 对象,为 Pod 提供存储的 PersistentVolume 存储资源对象等。

二、Pod 的两种使用方式

       一个 Pod 中运行一个容器。每个 Pod 中一个容器的模式是最常见的用法,在这种使用方式中,你可以把 Pod想象成是单个容器的封装,kubernetes 管理的是 Pod 而不是直接管理容器。
在一个 Pod 中同时运行多个容器。一个 Pod中也可以同时封装几个需要紧密耦合互相协作的容器,它们之间共享资源。这些在同一个 Pod 中的容器可以互相协作成为一个 service单位,比如一个容器共享文件,另一个 sidecar 容器来更新这些文件。Pod 将这些容器的存储资源作为一个实体来管理。

三、Pod 中几个重要字段的含义和用法

1、NodeSelector

是一个供用户将 Pod 与 Node 进行绑定的字段

apiVersion: v1
kind: Pod
...
spec:
 nodeSelector:
   disktype: ssd

这样的一个配置,意味着这个 Pod 永远只能运行在携带了“disktype: ssd”标签(Label)的节点上;否则,它将调度失败

2、NodeName

一旦 Pod 的这个字段被赋值,Kubernetes 项目就会被认为这个 Pod 已经经过了调度,调度的结果就是赋值的节点名字。所以,这个字段一般由调度器负责设置,但用户也可以设置它来“骗过”调度器,当然这个做法一般是在测试或者调试的时候才会用到

3、HostAliases

义了 Pod 的 hosts 文件(比如 /etc/hosts)里的内容

apiVersion: v1
kind: Pod
...
spec:
  hostAliases:
  - ip: "10.1.2.3"
    hostnames:
    - "foo.remote"
    - "bar.remote"
...

在这个 Pod 的 YAML 文件中,我设置了一组 IP 和 hostname 的数据。这样,这个 Pod 启动后,/etc/hosts 文件的内容将如下所示:

cat /etc/hosts
# Kubernetes-managed hosts file.
127.0.0.1 localhost
...
10.244.135.10 hostaliases-pod
10.1.2.3 foo.remote
10.1.2.3 bar.remote

最下面两行记录,就是我通过 HostAliases 字段为 Pod 设置的。需要指出的是,在 Kubernetes 项目中,如果要设置 hosts 文件里的内容,一定要通过这种方法。否则,如果直接修改了 hosts 文件的话,在 Pod 被删除重建之后,kubelet 会自动覆盖掉被修改的内容。

除了上述跟“机器”相关的配置外,你可能也会发现,凡是跟容器的 Linux Namespace 相关的属性,也一定是 Pod 级别的。这个原因也很容易理解:Pod 的设计,就是要让它里面的容器尽可能多地共享 Linux Namespace,仅保留必要的隔离和限制能力。这样,Pod 模拟出的效果,就跟虚拟机里程序间的关系非常类似了。

例子,在下面这个 Pod 的 YAML 文件中,我定义了 shareProcessNamespace=true:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  shareProcessNamespace: true
  containers:
  - name: nginx
    image: nginx
  - name: shell
    image: busybox
    stdin: true
    tty: true

这就意味着这个 Pod 里的容器要共享 PID Namespace。

而在这个 YAML 文件中,我还定义了两个容器:一个是 nginx 容器,一个是开启了 tty 和 stdin 的 shell 容器。

如果不在yaml中设置tty和stdin字段, 那么使用这个命令时会报错

我在前面介绍容器基础时,曾经讲解过什么是 tty 和 stdin。而在 Pod 的 YAML 文件里声明开启它们俩,其实等同于设置了 docker run 里的 -it(-i 即 stdin,-t 即 tty)参数。

如果你还是不太理解它们俩的作用的话,可以直接认为 tty 就是 Linux 给用户提供的一个常驻小程序,用于接收用户的标准输入,返回操作系统的标准输出。当然,为了能够在 tty 中输入信息,你还需要同时开启 stdin(标准输入流)。

于是,这个 Pod 被创建后,你就可以使用 shell 容器的 tty 跟这个容器进行交互了。我们一起实践一下:

kubectl create -f nginx.yaml

这样,我们就可以在 shell 容器里执行 ps 指令,查看所有正在运行的进程:

kubectl attach -it nginx -c shell
或者
kubectl exec -ti nginx -c shell sh
/ # ps ax
PID   USER     TIME  COMMAND
    1 root      0:00 /pause
    8 root      0:00 nginx: master process nginx -g daemon off;
   14 101       0:00 nginx: worker process
   15 root      0:00 sh
   21 root      0:00 ps ax

可以看到,在这个容器里,我们不仅可以看到它本身的 ps ax 指令,还可以看到 nginx 容器的进程,以及 Infra 容器的 /pause 进程。这就意味着,整个 Pod 里的每个容器的进程,对于所有容器来说都是可见的:它们共享了同一个 PID Namespace。

类似地,凡是 Pod 中的容器要共享宿主机的 Namespace,也一定是 Pod 级别的定义,比如:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  hostNetwork: true
  hostIPC: true
  hostPID: true
  containers:
  - name: nginx
    image: nginx
  - name: shell
    image: busybox
    stdin: true
    tty: true

在这个 Pod 中,我定义了共享宿主机的 Network、IPC 和 PID Namespace。这就意味着,这个 Pod 里的所有容器,会直接使用宿主机的网络、直接与宿主机进行 IPC 通信、看到宿主机里正在运行的所有进程。

当然,除了这些属性,Pod 里最重要的字段当属“Containers”了。而在上一篇文章中,我还介绍过“Init Containers”。其实,这两个字段都属于 Pod 对容器的定义,内容也完全相同,只是 Init Containers 的生命周期,会先于所有的 Containers,并且严格按照定义的顺序执行。

Kubernetes 项目中对 Container 的定义,和 Docker 相比并没有什么太大区别。我在前面的容器技术概念入门系列文章中,和你分享的 Image(镜像)、Command(启动命令)、workingDir(容器的工作目录)、Ports(容器要开发的端口),以及 volumeMounts(容器要挂载的 Volume)都是构成 Kubernetes 项目中 Container 的主要字段。不过在这里,还有这么几个属性值得你额外关注。

首先,是 ImagePullPolicy 字段。它定义了镜像拉取的策略。而它之所以是一个 Container 级别的属性,是因为容器镜像本来就是 Container 定义中的一部分。

ImagePullPolicy 的值默认是 Always,即每次创建 Pod 都重新拉取一次镜像。另外,当容器的镜像是类似于 nginx 或者 nginx:latest 这样的名字时,ImagePullPolicy 也会被认为 Always。

四、Pod 对象在Kubernetes中的生命周期

Pod 生命周期的变化,主要体现在 Pod API 对象的 Status 部分,这是它除了 Metadata 和 Spec 之外的第三个重要字段。其中,pod.status.phase,就是 Pod 的当前状态,它有如下几种可能的情况:

  • Pending。这个状态意味着,Pod 的 YAML 文件已经提交给了 Kubernetes,API 对象已经被创建并保存在 Etcd 当中。但是,这个 Pod 里有些容器因为某种原因而不能被顺利创建。比如,调度不成功。

  • Running。这个状态下,Pod 已经调度成功,跟一个具体的节点绑定。它包含的容器都已经创建成功,并且至少有一个正在运行中。

  • Succeeded。这个状态意味着,Pod 里的所有容器都正常运行完毕,并且已经退出了。这种情况在运行一次性任务时最为常见。

  • Failed。这个状态下,Pod 里至少有一个容器以不正常的状态(非 0 的返回码)退出。这个状态的出现,意味着你得想办法 Debug 这个容器的应用,比如查看 Pod 的 Events 和日志。

  • Unknown。这是一个异常状态,意味着 Pod 的状态不能持续地被 kubelet 汇报给 kube-apiserver,这很有可能是主从节点(Master 和 Kubelet)间的通信出现了问题。

更进一步地,Pod 对象的 Status 字段,还可以再细分出一组 Conditions(状态)。这些细分状态的值包括:PodScheduled、Ready、Initialized,以及 Unschedulable。它们主要用于描述造成当前 Status 的具体原因是什么。

比如,Pod 当前的 Status 是 Pending,对应的 Condition 是 Unschedulable,这就意味着它的调度出现了问题。

而其中,Ready 这个细分状态非常值得我们关注:它意味着 Pod 不仅已经正常启动(Running 状态),而且已经可以对外提供服务了。这两者之间(Running 和 Ready)是有区别的,你不妨仔细思考一下。

Pod 的这些状态信息,是我们判断应用运行情况的重要标准,尤其是 Pod 进入了非“Running”状态后,你一定要能迅速做出反应,根据它所代表的异常情况开始跟踪和定位,而不是去手忙脚乱地查阅文档。

猜你喜欢

转载自blog.csdn.net/TTSuzuka/article/details/129203168