kubernete编排技术一:pod

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: kubernete编排技术一:pod

微信图片_20221212115013.jpg在之前的文章《kubernete中的原子调度单位:pod中提到过,如果把kubernete比作linux操作系统,那pod就是虚拟机,pod里面的容器就是虚拟机上的进程。这个类比可以说非常形象。在Linux上,进程并不是完全独立的,一些进程之间存在着一些关联,比如一个springboot应用和一个日志收集服务。pod正是使用了容器进程之间的这些关系,做的编排。


在kubernete上创建pod


下面的yaml文件springboot-mybatis.yaml定义了一个参数replicas: 2,这个参数的意思就是创建2个pod,image: zjj2006forever/springboot-mybatis:1.2则定义了pod中运行这容器的镜像。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: springboot-mybatis-deployment
spec:
  selector:
    matchLabels:
      app: springboot-mybatis
  replicas: 2
  template:
    metadata:
      labels:
        app: springboot-mybatis
    spec:
      containers:
      - name: spingboot-mybatis
        imagePullPolicy: IfNotPresent
        image: zjj2006forever/springboot-mybatis:1.2
        ports:
        - containerPort: 8300

执行下面命令这两个pod就被创建出来


kubectl apply -f springboot-mybatis.yaml

我们用命令可以查看到

[root@master k8s]# kubectl get pods --all-namespaces
NAMESPACE     NAME                                             READY   STATUS    RESTARTS   AGE
default       springboot-mybatis-deployment-5b78f66997-6fbqk   1/1     Running   0          63s
default       springboot-mybatis-deployment-5b78f66997-qg5ng   1/1     Running   0          62s

pod的本质


pod是一个逻辑上的概念,不是一个物理存在。pod的本质是有关联关系的一组容器调度在一起,这些容器可以共享linux的networknamespace和volume。那为什么需要pod呢?

我们举一个例子,假如我们有3个容器,container1是一个springboot应用,container2负责收集container1的日志,container3负责对container2的日志进行分析处理。我们如果想把这3个容器部署在同一个node上,每个容器需要分配1G的内存。


但我们目前有2个node,node1有2.5G内存,node2有3G内存,如果没有pod的逻辑存在,container1和container2调度到了node1上,但是container3调度到node1上时发现内存不够而失败了。如果我们有了pod,我们把这3个容器编排在一个pod里面,pod会直接被调度到3G内存的node2上。


pod里面的容器是怎么共享namespace的?在之前的文章《浅谈kubernete中的flannel网络插件》文章中介绍过,pod中有一个infra的容器,在pod创建时这个容器总是第一个被创建。这个容器镜像使用的是k8s.gcr.io/pause,占用空间非常小,解压后也就100多k。在pod启动时,先创建出这个infra容器,用这个容器控制住networknamespace,这样其他容器启动时共享这个网络就可以了。


pod里面的容器是怎么共享volume?还是上面3个容器的例子,我们编写一个yaml文件,代码如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: springboot-mybatis-deployment
spec:
  selector:
    matchLabels:
      app: springboot-mybatis
  replicas: 2
  template:
    metadata:
      labels:
        app: springboot-mybatis
    spec:
    volumes:
      - name: boot-log
      hostPath:      
        path: /tmp/boot-log
      containers:
      - name: spingboot-mybatis
        imagePullPolicy: IfNotPresent
        image: zjj2006forever/springboot-mybatis:1.2
        ports:
        - containerPort: 8300
    volumeMounts:
        - name: boot-log
          mountPath: /logs
    - name: spingboot-log-accumulate
        imagePullPolicy: IfNotPresent
        image: zjj2006forever/springboot-log-accumulate:v1
        ports:
        - containerPort: 8400
    volumeMounts:
        - name: boot-log
          mountPath: /accumulate
    - name: spingboot-log-analysis
        imagePullPolicy: IfNotPresent
        image: zjj2006forever/springboot-log-analysis:v1
        ports:
        - containerPort: 8500
    volumeMounts:
        - name: boot-log
          mountPath: /analysis

上面的yaml文件中,我们定义了3个container,分别是应用容器spingboot-mybatis,日志收集spingboot-log-accumulate,日志分析spingboot-log-analysis,从上面的文件定义中我们可以看到,这3个容器都挂载了boot-log这个volum,对应宿主机目录/tmp/boot-log,本质上就是/tmp/boot-log这个目录被绑定在了上面3个容器中,这样上面3个容器就可以通过这个目录访问其他容器的绑定目录了。即spingboot-log-accumulate可以访问spingboot-mybatis的/logs,spingboot-log-analysis可以访问spingboot-log-accumulate的/accumulate。


所以:容器的本质其实是一组共享了networknamespace和volume的容器的集合。


pod的关键属性


pod是kubernete中最小的调度单位。在kubernete中,调度、网络、存储以及安全等属性,都是pod级别的。下面看一下pod的几个重要属性

apiVersion: apps/v1
kind: Deployment
metadata:
  name: springboot-mybatis-deployment
spec:
  shareProcessNamespace: true
  hostNetwork: true
  nodeSelector:
    hostname: worker1
  selector:
    matchLabels:
      app: springboot-mybatis
  hostAliases:  
  - ip: "10.1.2.3"
    hostnames:    
  - "foo.remote"    
  - "bar.remote"
  replicas: 2
  template:
    metadata:
      labels:
        app: springboot-mybatis
    spec:
      containers:
      - name: spingboot-mybatis
        imagePullPolicy: IfNotPresent
        image: zjj2006forever/springboot-mybatis:1.2
        ports:
        - containerPort: 8300
    lifecycle:
     postStart:        
      exec:          
       command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]      
     preStop:        
      exec:          
       command: ["/usr/sbin/nginx","-s","quit"]

1.shareProcessNamespace代表pod内容器共享pid namespace,hostNetwork代表共享宿主机网络

2.NodeSelector代表绑定宿主机标签,宿主机标签可以用下面命令查看

[root@master ~]# kubectl get nodes --show-labels
NAME      STATUS   ROLES    AGE   VERSION   LABELS
master    Ready    master   17h   v1.17.3   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master,kubernetes.io/os=linux,node-role.kubernetes.io/master=
worker1   Ready    <none>   17h   v1.17.3   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=worker1,kubernetes.io/os=linux

3.hostAliases定义了host文件,上面yaml文件创建pod后,pod内的hosts文件会增加内容如下:

/ # cat etc/hosts
10.1.2.3 foo.remote
10.1.2.3 bar.remote

4.ImagePullPolicy


Always:默认,创建pod是总是拉取镜像

Never:从不拉取

IfNotPresent:宿主机上不存在镜像时拉取


5.lifecycle:它是一个hook,在容器发生变化是触发一个事件。

postStart表示容器启动时触发一个操作,容器启动时立即触发,不等容器启动完成

preStop表示在容器被杀死之前触发一个操作,触发这个操作结束后才执行杀死容器的动作,比如这里可以触发eureka优雅发布。

注:

pod的生命周期状态主要有以下几种

Pending:创建不成功

Running:pod创建成功,并且里面至少一个容器在运行中

Succeeded:pod中容器运行完毕正常退出

Failed:pod里至少一个容器创建不成功

Unknown:异常


pod的健康检查


修改之前部署springboot的yaml文件如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: springboot-mybatis-deployment
spec:
  selector:
    matchLabels:
      app: springboot-mybatis
  replicas: 2
  template:
    metadata:
      labels:
        app: springboot-mybatis
    spec:
      containers:
      - name: spingboot-mybatis
        imagePullPolicy: IfNotPresent
        image: zjj2006forever/springboot-mybatis:1.2
        ports:
        - containerPort: 8300
        livenessProbe:
          httpGet:
           path: /actuator/info
           port: 18082
          initialDelaySeconds: 5
          periodSeconds: 5

启动pod

    kubectl apply -f springboot-mybatis.yaml

    查看容器状态:

    [root@master k8s]# kubectl get pod springboot-mybatis-deployment-dcd7f8bbf-9wfxl
    NAME                                            READY   STATUS    RESTARTS   AGE
    springboot-mybatis-deployment-dcd7f8bbf-9wfxl   1/1     Running   3          77s
    [root@master k8s]# kubectl describe pod springboot-mybatis-deployment-dcd7f8bbf-9wfxl
    Name:         springboot-mybatis-deployment-dcd7f8bbf-9wfxl
    Namespace:    default
    Priority:     0
    Node:         worker1/192.168.59.140
    Start Time:   Fri, 03 Jul 2020 03:56:44 -0400
    Labels:       app=springboot-mybatis
                  pod-template-hash=dcd7f8bbf
    Annotations:  <none>
    Status:       Running
    IP:           10.244.1.19
    IPs:
      IP:           10.244.1.19
    Controlled By:  ReplicaSet/springboot-mybatis-deployment-dcd7f8bbf
    Containers:
      spingboot-mybatis:
        Container ID:   docker://19c4082ed706a80c308069ba3355d7192704ad518ced0e075d424bb6ebb16865
        Image:          zjj2006forever/springboot-mybatis:1.2
        Image ID:       docker-pullable://zjj2006forever/springboot-mybatis@sha256:bf43bc9d1d4bdb33d82a206282c8f82be3679847d1011806b72e3634ebe67564
        Port:           8300/TCP
        Host Port:      0/TCP
        State:          Waiting
          Reason:       CrashLoopBackOff
        Last State:     Terminated
          Reason:       Error
          Exit Code:    143
          Started:      Fri, 03 Jul 2020 03:57:42 -0400
          Finished:     Fri, 03 Jul 2020 03:58:02 -0400
        Ready:          False
        Restart Count:  3
        Liveness:       http-get http://:18082/actuator/info delay=5s timeout=1s period=5s #success=1 #failure=3
        Environment:    <none>
        Mounts:
          /var/run/secrets/kubernetes.io/serviceaccount from default-token-qk5nc (ro)
    Conditions:
      Type              Status
      Initialized       True 
      Ready             False 
      ContainersReady   False 
      PodScheduled      True 
    Volumes:
      default-token-qk5nc:
        Type:        Secret (a volume populated by a Secret)
        SecretName:  default-token-qk5nc
        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   Scheduled  85s                 default-scheduler  Successfully assigned default/springboot-mybatis-deployment-dcd7f8bbf-9wfxl to worker1
      Normal   Killing    28s (x3 over 68s)   kubelet, worker1   Container spingboot-mybatis failed liveness probe, will be restarted
      Normal   Pulled     27s (x4 over 84s)   kubelet, worker1   Container image "zjj2006forever/springboot-mybatis:1.2" already present on machine
      Normal   Created    27s (x4 over 84s)   kubelet, worker1   Created container spingboot-mybatis
      Normal   Started    26s (x4 over 84s)   kubelet, worker1   Started container spingboot-mybatis
      Warning  Unhealthy  18s (x10 over 78s)  kubelet, worker1   Liveness probe failed: Get http://10.244.1.19:18082/actuator/info: dial tcp 10.244.1.19:18082: connect: connection refused

    下面这句可以看出,失败了3次,从上面的Events中也可以看出这个被删除重新创建的过程

      Liveness:       http-get http://:18082/actuator/info delay=5s timeout=1s peri

      pod健康检查失败后默认会重启pod,所以这时查看pod状态,发现重启了4次

      [root@master k8s]# kubectl get pods --all-namespaces
      NAMESPACE     NAME                                            READY   STATUS    RESTARTS   AGE
      default       springboot-mybatis-deployment-dcd7f8bbf-9wfxl   1/1     Running   4          7m6s
      default       springboot-mybatis-deployment-dcd7f8bbf-q7nhp   1/1     Running   4          7m6s

      注意:

      1.kubernete中pod的restartPolicy默认是Always,即只要容器status不是RUNNING,就自动重启容器。除此之外,还有OnFailure(只有容器异常时才自动重启)和Never(从来不重启容器)。

      2.在一个有多个容器的pod中,只有所有的容器都不是RUNNING状态时,pod才会执行restartPolicy,否则pod状态一直是RUNNING

      3.livenessProbe有多种方式,比如http,tcp,也可以在容器中执行命令来判断

      4.在我们定义的yaml文件中,我们定义了kind: Deployment,如果我们定义了kind: pod,那就只能在当前宿主机重启pod,这样如果当前宿主机故障,就会一直调度失败。但是kind: Deployment这种方式是可以调度到其他宿主机节点上的。


      总结


      pod是kubernete中最重要的概念,把pod类比成操作系统上的虚拟机、pod中的容器类比成虚拟机上运行的进程,是非常恰当的。kubernete强大的编排功能,原子单位是pod,pod是kubernete中的原子编排和调度对象。

      相关实践学习
      通过Ingress进行灰度发布
      本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
      容器应用与集群管理
      欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
      相关文章
      |
      Kubernetes 固态存储 调度
      Kubernetes(k8s)容器编排Pod调度策略
      Kubernetes(k8s)容器编排Pod调度策略
      201 0
      |
      1月前
      |
      存储 Kubernetes 调度
      深度解析Kubernetes中的Pod生命周期管理
      深度解析Kubernetes中的Pod生命周期管理
      |
      7月前
      |
      存储 Kubernetes 监控
      使用Kubernetes进行容器编排:技术详解与实践
      【5月更文挑战第16天】Kubernetes,简称K8s,是开源容器编排系统,用于自动化部署、扩展和管理容器化应用。核心概念包括节点、Pod(最小部署单元)、服务、标签和副本集。其特点有高可用性、可扩展性、自动化和可移植性。实践使用涉及安装配置集群、编写YAML部署清单、应用部署、监控管理和扩展更新。Kubernetes帮助提升应用的可用性、可扩展性和可移植性。
      |
      Kubernetes 应用服务中间件 nginx
      Kubernetes(k8s)容器编排Pod介绍和使用
      Kubernetes(k8s)容器编排Pod介绍和使用
      269 0
      |
      7月前
      |
      Kubernetes 应用服务中间件 Apache
      理解Kubernetes中的Pod — 容器协同工作
      当你在Kubernetes中部署一个应用程序时,你通常会使用Pod作为最小的可部署单元。Pod是一个可以包含一个或多个容器的组。这些容器在Pod内部共享网络和存储,并可以通过localhost直接通信。这种设计使得它们能够协同工作,共享数据,并能够一起被调度和管理。
      224 1
      |
      Kubernetes 数据中心 Docker
      揭秘Kubernetes:通过容器编排实现业务成功
      揭秘Kubernetes:通过容器编排实现业务成功
      揭秘Kubernetes:通过容器编排实现业务成功
      |
      存储 Kubernetes Linux
      深入剖析Kubernetes:容器编排与 Kubernetes 核心特性剖析
      深入剖析Kubernetes:容器编排与 Kubernetes 核心特性剖析
      342 0
      深入剖析Kubernetes:容器编排与 Kubernetes 核心特性剖析
      |
      设计模式 Kubernetes Cloud Native
      【探索 Kubernetes|作业管理篇 系列 7】探究 Pod 有什么用,为什么需要它
      【探索 Kubernetes|作业管理篇 系列 7】探究 Pod 有什么用,为什么需要它
      118 1
      |
      Kubernetes 安全 API
      【探索 Kubernetes|作业管理篇 系列 9】Pod 的服务对象(下)
      【探索 Kubernetes|作业管理篇 系列 9】Pod 的服务对象(下)
      122 0
      |
      编解码 运维 Kubernetes
      【探索 Kubernetes|作业管理篇 系列 9】Pod 的服务对象(上)
      【探索 Kubernetes|作业管理篇 系列 9】Pod 的服务对象(上)
      147 0