zoukankan      html  css  js  c++  java
  • 14. 深入解析Pod对象(一)

    14. 深入解析Pod对象(一)

    """
    通过前面的讲解,大家应该都知道: 
    Pod,而不是容器,它是 Kubernetes 项目中的最小编排单位。将这个设计落实到 API 对象上,容器(Container)就成了 Pod 属性里的一个普通的字段。那么,一个很自然的问题就是:到底哪些属性属于 Pod 对象,而又有哪些属性属于 Container 呢?
    """
    

    14.1 那些属性属于Pod对象,又有哪些属性属于Container(容器)呢?

    要彻底理解这个问题,你就一定要牢记我在上一篇文章中提到的一个结论:Pod 扮演的是传统部署环境里“虚拟机”的角色。这样的设计,是为了使用户从传统环境(虚拟机环境)向 Kubernetes(容器环境)的迁移,更加平滑。

    而如果你能把 Pod 看成传统环境里的“机器”、把容器看作是运行在这个“机器”里的“用户程序”,那么很多关于 Pod 对象的设计就非常容易理解了。

    比如,凡是调度、网络、存储,以及安全相关的属性,基本上是 Pod 级别的。

    这些属性的共同特征是,它们描述的是“机器”这个整体,而不是里面运行的“程序”。比如,配置这个“机器”的网卡(即:Pod 的网络定义),配置这个“机器”的磁盘(即:Pod 的存储定义),配置这个“机器”的防火墙(即:Pod 的安全定义)。更不用说,这台“机器”运行在哪个服务器之上(即:Pod 的调度)。

    下面给大家介绍一下pod的几个重要字段:

    1. NodeSelector : 它是一个供用户将 Pod 与 Node 进行绑定的字段,用法如下所示:

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

    它表示当前的这个pod资源 永远只能运行在携带了“disktype: ssd”标签(Label)的节点上;否则,它将调度失败。另外这个字段一般由调度器负责设置,但用户也可以设置它来“骗过”调度器,当然这个做法一般是在测试或者调试的时候才会用到。

    2. 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
    

    3. hareProcessNamespace=true: 共享了同一个pod中的 PID Namespace。用法如下:

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

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

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

    $ kubectl create -f nginx.yaml
    

    接下来,我们使用 kubectl attach 命令,连接到 shell 容器的 tty 上:

    $ kubectl attach -it nginx -c shell
    

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

    $ kubectl attach -it nginx -c shell
    / # 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。

    4. hostNetwork、hostIPC、hostPID都为True时,表示这个Pod里的所有容器,会直接使用宿主机的网络,直接与宿主机进行IPC通信,看到宿主机里正在运行的所有进程。用法如下:

    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 通信、看到宿主机里正在运行的所有进程。

    Containers属性、Init Containers属性 都是属于pod对于docker容器的定义。

    initContainers与Containers的区别,在于前者的优先级会先于所有的Containes,并且严格按照定义的顺序执行。

    关于container的定义和docker相比没有什么太大的区别。比如Image(镜像)、Command(启动命令)、workingDir(容器的工作目录)、Ports(容器要开发的端口),以及 volumeMounts(容器要挂载的 Volume)都是构成 Kubernetes 项目中 Container 的主要字段。,不过在这里,还有这么几个属性值得你额外关注。

    1. ImagePullPolicy 字段

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

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

    而如果它的值被定义为 Never 或者 IfNotPresent,则意味着 Pod 永远不会主动拉取这个镜像,或者只在宿主机上不存在这个镜像时才拉取。

    2. Lifecycle 字段

    它定义的是 Container Lifecycle Hooks。顾名思义,Container Lifecycle Hooks 的作用,是在容器状态发生变化时触发一系列“钩子”。我们来看这样一个例

    apiVersion: v1
    kind: Pod
    metadata:
      name: lifecycle-demo
    spec:
      containers:
      - name: lifecycle-demo-container
        image: nginx
        lifecycle:
          postStart:
            exec:
              command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
          preStop:
            exec:
              command: ["/usr/sbin/nginx","-s","quit"]
    

    这是一个来自 Kubernetes 官方文档的 Pod 的 YAML 文件。它其实非常简单,只是定义了一个 nginx 镜像的容器。不过,在这个 YAML 文件的容器(Containers)部分,你会看到这个容器分别设置了一个 postStart 和 preStop 参数。这是什么意思呢?

    postStart: 它指在容器启动后,立刻执行一个指定的操作。需要明确的是,postStart 定义的操作,虽然是在 Docker 容器 ENTRYPOINT 执行之后,但它并不严格保证顺序。也就是说,在 postStart 启动时,ENTRYPOINT 有可能还没有结束

    preStop :它指容器被杀死之前(比如,收到了 SIGKILL 信号)。而需要明确的是,preStop 操作的执行,是同步的。所以,它会阻塞当前的容器杀死流程,直到这个 Hook 定义操作完成之后,才允许容器被杀死,这跟 postStart 不一样

    pod的生命周期的关键字

    status

    Pod 生命周期的变化,主要体现在 Pod API 对象的Status 部分,这是它除了 Metadata 和 Spec 之外的第三个重要字段。其中,pod.status.phase,就是 Pod 的当前状态,我们可以使用

    # kubectl describe  pod 资源名称
    # 比如:kubectl  describe  pod lifecycle-demo
    Name:               lifecycle-demo
    Namespace:          default
    Priority:           0
    PriorityClassName:  <none>
    Node:               node02/192.168.81.153
    Start Time:         Sun, 04 Aug 2019 10:55:02 +0800
    Labels:             <none>
    Annotations:        <none>
    Status:             Running
    IP:                 10.2.4.8
    Containers:
      lifecycle-demo-container:
        Container ID:   docker://f0036a43f267b0e2dad7caa3683131631c61f493d85d94710b6080f047385642
        Image:          nginx
        Image ID:       docker-pullable://nginx@sha256:eb3320e2f9ca409b7c0aa71aea3cf7ce7d018f03a372564dbdb023646958770b
        Port:           <none>
        Host Port:      <none>
        State:          Running
          Started:      Sun, 04 Aug 2019 10:55:18 +0800
        Ready:          True
        Restart Count:  0
        Environment:    <none>
        Mounts:
          /var/run/secrets/kubernetes.io/serviceaccount from default-token-sczx8 (ro)
    Conditions:
      Type              Status
      Initialized       True 
      Ready             True 
      ContainersReady   True 
      PodScheduled      True 
    Volumes:
      default-token-sczx8:
        Type:        Secret (a volume populated by a Secret)
        SecretName:  default-token-sczx8
        Optional:    false
    QoS Class:       BestEffort
    Node-Selectors:  <none>
    Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                     node.kubernetes.io/unreachable:NoExecute for 300s
    Events:
      Type    Reason     Age    From               Message
      ----    ------     ----   ----               -------
      Normal  Pulling    7m34s  kubelet, node02    pulling image "nginx"
      Normal  Scheduled  7m34s  default-scheduler  Successfully assigned default/lifecycle-demo to node02
      Normal  Pulled     7m18s  kubelet, node02    Successfully pulled image "nginx"
      Normal  Created    7m18s  kubelet, node02    Created container
      Normal  Started    7m18s  kubelet, node02    Started container
    

    它有如下几种可能的情况:

    1. Pending。这个状态意味着,Pod 的 YAML 文件已经提交给了 Kubernetes,API 对象已经被创建并保存在 Etcd 当中。但是,这个 Pod 里有些容器因为某种原因而不能被顺利创建。比如,调度不成功。
    2. Running。这个状态下,Pod 已经调度成功,跟一个具体的节点绑定。它包含的容器都已经创建成功,并且至少有一个正在运行中。
    3. Succeeded。这个状态意味着,Pod 里的所有容器都正常运行完毕,并且已经退出了。这种情况在运行一次性任务时最为常见。
    4. Failed。这个状态下,Pod 里至少有一个容器以不正常的状态(非 0 的返回码)退出。这个状态的出现,意味着你得想办法 Debug 这个容器的应用,比如查看 Pod 的 Events 和日志。
    5. Unknown。这是一个异常状态,意味着 Pod 的状态不能持续地被 kubelet 汇报给 kube-apiserver,这很有可能是主从节点(Master 和 Kubelet)间的通信出现了问题。
    Conditions

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

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

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

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

  • 相关阅读:
    P4281 [AHOI2008]紧急集合 / 聚会
    P2622 关灯问题II
    CF1092F Tree with Maximum Cost
    10.28记
    威尔逊定理及证明
    CF895C Square Subsets
    洛谷 P5556 圣剑护符
    Multi-nim结论及证明
    AT2667 [AGC017D] Game on Tree
    洛谷 P4643 [国家集训队]阿狸和桃子的游戏
  • 原文地址:https://www.cnblogs.com/plf-Jack/p/11300020.html
Copyright © 2011-2022 走看看