[从零开始学Kubernetes] 3.Pod-Kubernetes最小调度单元

Pod是K8s中的最小调度单元。可以在一个Pod里部署多个容器。同个Pod中共享网络资源、存储资源以及命名空间等。
在Pod中,所有容器都被同一安排和调度,并运行在共享的上下文中。对于具体应用而言,Pod是它们的逻辑主机,Pod包含业务相关的多个应用容器。

从《从零开始学容器》中我们知道,一个容器类似于一个进程,那么容器就不能像使用Vm一样使用。所以,Pod对于容器的编排起着重要作用。

Pod的特点

  1. 网络:每一个Pod都会被指派一个唯一的Ip地址,在Pod中的每一个容器共享网络命名空间,包括Ip地址和网络端口。在同一个Pod中的容器可以同locahost进行互相通信。当Pod中的容器需要与Pod外的实体进行通信时,则需要通过端口等共享的网络资源。
  2. 存储:Pod能够被指定共享存储卷的集合,在Pod中所有的容器能够访问共享存储卷,允许这些容器共享数据。存储卷也允许在一个Pod持久化数据,以防止其中的容器需要被重启。

Pod的声明

在K8s中,不直接创建Pod,每个Pod都是通过控制器和一个API模版配置来管理。而一个API模板有元数据(metadata)规范(spec)状态(status)

1. 元数据(metadata)

metadata中包含3个对该对象至关重要的元信息: 命名空间(namespace)、对象名(name)和对象ID(uid)

  • namespace: Kubernetes 中比较重要的一个概念,是对一组资源和对象的抽象集合,namespace 主要用于逻辑上的隔离
    内置的namespace如下:
名称描述
default这是默认的缺省命名空间
kube-system主要是部署集群最关键的核心组件,比如一般会将 CoreDNS 声明在这个 namespace 中
kube-public是由 kubeadm 创建出来的,主要是保存一些集群 bootstrap 的信息,比如 token 等
kube-node-lease从 v1.12 版本开始开发的,到 v1.14 版本变为 beta 可用版本,在 v1.17 的时候已经正式 GA 了,它要用于 node 汇报心跳(我们在第一节课已经解释过了心跳的概念),每一个节点都会有一个对应的 Lease 对象
  • name: 标识对象的名称
  • uid: 系统自动生成,由K8s内部标识使用

2. 规范(Spec)

在 Spec 中描述了该对象的详细配置信息,即用户希望的状态(Desired State)。Kubernetes 中的各大组件会根据这个配置进行一系列的操作,将这种定义从“抽象”变为“现实”,我们称之为调和(Reconcile)。用户不需要过度关心怎么达到终态,也不用参与。

3. 状态(Status)

在这个字段里面,包含了该对象的一些状态信息,会由各个控制器定期进行更新。也是不同控制器之间进行相互通信的一个渠道。在 Kubernetes 中,各个组件都是分布式部署的,围绕着 kube-apiserver 进行通信,那么不同组件之间进行信息同步,就可以通过 status 进行。像 Node 的 status 就记录了该节点的一些状态信息,其他的控制器,就可以通过 status 知道该 Node 的情况,做一些操作,比如节点宕机修复、可分配资源等。

Pod的配置文件.yaml

创建文件study_two_container.yaml

apiVersion: v1 #指定当前描述文件遵循v1版本的Kubernetes API
kind: Pod #我们在描述一个pod
metadata:
  name: c-containers #指定pod的名称
  namespace: default #指定当前描述的pod所在的命名空间
  labels: #指定pod标签
    app: c-containers
  annotations: #指定pod注释
    version: v1
    releasedBy: chensy
    purpose: demo
spec:
  containers:
    - name: c-containers #容器的名称
      image: registry.cn-hangzhou.aliyuncs.com/chensyf/container:1.0 #创建容器所使用的镜像
      ports:
        - containerPort: 9000 #应用监听的端口
    - name: c-nginx
      image: nginx:1.7.9
      ports:
        - containerPort: 80

Pod各字段说明

1. apiVersion

与k8s集群版本有关,使用 kubectl api-versions即可查看当前集群支持的版本
其中:

名称描述
extensions/v1beta1k8s 1.6版本以前使用
apps/v1beta11.6~1.9版本使用
apps/v11.9版本以后使用
2. Kind

资源类别,有如下类别

类别名称
资源对象Pod、ReplicaSet、ReplicationController、Deployment、StatefulSet、DaemonSet、Job、CronJob、HorizontalPodAutoscaling
配置对象Node、Namespace、Service、Secret、ConfigMap、Ingress、Label、ThirdPartyResource、 ServiceAccount
存储对象Volume、Persistent Volume
策略对象SecurityContext、ResourceQuota、LimitRange
3. Spec

资源清单

Spec(Object):详细定义对象,固定值就写Spec
spec.containers:Spec对象的容器列表定义,是个列表
spec.containers[].name(String):定义容器的名字
spec.containers[].image(String):容器用到的镜像名称

主要的属性:
spec.containers[].name(String):容器的名称
spec.containers[].imagePullPolicy(String):定义镜像拉取策略,有Always(每次都尝试重新拉取镜像)、Never(仅使用本地镜像)、IfNotPresent(如果本地有镜像就使用本地镜像,没有则拉取镜像)三个值可选,默认是Always
spec.containers[].command:指定容器启动命令,因为是数组可以指定多个,不指定则使用镜像打包时使用的启动命令
spec.containers[].args:指定容器启动命令参数,因为是数组可以指定多个
spec.containers[].workingDir(String):指定容器的工作目录
spec.containers[].volumeMounts:指定容器内部的存储卷配置
spec.containers[].volumeMounts[].name(String):指定被容器挂载的存储卷的名称
spec.containers[].volumeMounts[].mountPath(String):指定被容器挂载的存储卷的路径
spec.containers[].volumeMounts[].readOnly(String):设置存储卷路径的读写模式,true或者false,默认为读写模式
spec.containers[].ports:指定容器需要用到的端口列表
spec.containers[].ports[].name(String):指定端口名称
spec.containers[].ports[].containerPort(String):指定容器需要监听的端口号
spec.containers[].ports[].hostPort(String):指定容器所在主机需要监听的端口号,默认跟containerPort相同,注意设置了hostPort,同一台主机无法启动该容器的相同副本(因为主机的端口号不能相同,会冲突)
spec.containers[].ports[].protocol(String):指定端口协议,支持TCP和UDP,默认值是TCP
spec.containers[].env:指定容器运行前需要设置的环境变量列表
spec.containers[].env[].name(String):指定环境变量名称
spec.containers[].env[].value(String):指定环境变量值
spec.containers[].resources(Object):指定资源限制和资源请求的值
spec.containers[].resources.limits(Object):指定设置容器运行时资源的运行上限
spec.containers[].resources.limits.cpu(String):指定cpu的限制,单位为core数,将用于docker run --cpu-shares参数
spec.containers[].resources.limits.memory(String):指定mem内存的限制
spec.containers[].resources.requests(Object):指定容器启动和调度时的限制设置
spec.containers[].resources.requests.cpu(String):cpu请求,单位为core数,容器启动时初始化可用数量
spec.containers[].resources.requests.memory(String):内存请求,容器启动的初始化可用数量

额外属性
spec.restartPolicy(String):定义Pod的重启策略,
可选值为

  1. Always(Pod一旦终止运行,则无论容器是如何终止的,kubelet服务都将重启它)、
  2. OnFailure(只有Pod以非零码终止时,kubelet才会重启该容器,如果是正常结束,退出码为0,则kubelet将不会重启它)、
  3. Never(Pod终止后,kubelet将退出码报告给master,不会重启该Pod)

spec.nodeSelector(Object):定义Node的Label过滤标签,以key:value格式指定
spec.imagePullSecrets(Object):定义pull镜像时使用secret名称,以name:secretkey格式指定
spec.hostNetwork(Boolean):定义是否使用主机网络模式,默认值为false,设置true表示使用宿主机网络,不使用docker网桥,同时设置了true将无法在同一台宿主机上启动第二个副本

创建Pod

使用命令kubectl apply -f study_two_container.yaml创建Pod

查看Pod状态

[root@kubernetes yaml]# kubectl get pods
NAME           READY   STATUS              RESTARTS   AGE
c-containers   0/2     ContainerCreating   0          2m46s

使用命令kubectl describe pod twocontainers查看详情描述

[root@kubernetes yaml]# kubectl describe pod c-containers
Name:         c-containers
Namespace:    default
Priority:     0
Node:         kubernetes.node01.local/10.10.10.122
Start Time:   Wed, 16 Dec 2020 09:04:18 +0800
Labels:       app=c-containers
Annotations:  cni.projectcalico.org/podIP: 10.110.166.3/32
              cni.projectcalico.org/podIPs: 10.110.166.3/32
              purpose: demo
              releasedBy: chensy
              version: v1
Status:       Pending

....................省略

可以看到此时的Pod处于Pending状态, 处于Pending状态的两个原因:

  1. Pod还未被调度
  2. Pod内容器镜像在待运行的节点上不存在,需要从镜像中心拉取

K8s对Pod的健康检查

Kubernetes 中提供了一系列的健康检查,可以定制调用,来帮助解决类似的问题,称之为 Probe(探针)。

目前有如下三种 Probe:

  • livenessProbe可以用来探测容器是否真的在“运行”,即“探活”。如果检测失败的话,这个时候 kubelet 就会停掉该容器,容器的后续操作会受到其重启策略的影响。

  • readinessProbe常常用于指示容器是否可以对外提供正常的服务请求,即“就绪”,比如 nginx 容器在 reload 配置的时候无法对外提供 HTTP 服务。

  • startupProbe则可以用于判断容器是否已经启动好,就比如上面提到的容器启动慢的例子。我们可以通过参数,保证有足够长的时间来应对“超长”的启动时间。 如果检测失败的话,同livenessProbe的操作。这个 Probe 是在 1.16 版本才加入进来的,到 1.18 版本变为 beta。也就是说如果你的 Kubernetes 版本小于 1.18 的话,你需要在 kube-apiserver 的启动参数中,显式地在 feature gate 中开启这个功能。可以参考这个文档查看如何配置该参数。

Kubernetes容器的生命周期

在Kubernetes的生命周期有两种,容器启动之后和容器被终止之前

  • PostStart 可以在容器启动之后就执行。但需要注意的是,此 hook 和容器里的 ENTRYPOINT 命令的执行顺序是不确定的。
  • PreStop 则在容器被终止之前被执行,是一种阻塞式的方式。执行完成后,Kubelet 才真正开始销毁容器。

例子:

apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
  namespace: demo
spec:
  containers:
  - name: lifecycle-demo-container
    image: nginx:1.19
    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的Init容器

在 Kubernetes 中还有一种特殊的容器,即 init 容器。看名字就知道,这个容器工作在正常容器(为了方便区分,我们这里称为应用容器)启动之前,通常用来做一些初始化工作,比如环境检测、OSS 文件下载、工具安装,等等。

应用容器专注于业务处理,其他一些无关的初始化任务就可以放到 init 容器中。这种解耦有利于各自升级,也降低相互依赖。

一个 Pod 中允许有一个或多个 init 容器。init 容器和其他一般的容器非常像,其与众不同的特点主要有:

  • 总是运行到完成,可以理解为一次性的任务,不可以运行常驻型任务,因为会 block 应用容器的启动运行;

  • 顺序启动执行,下一个的 init 容器都必须在上一个运行成功后才可以启动;

  • 禁止使用 readiness/liveness 探针,可以使用 Pod 定义的activeDeadlineSeconds,这其中包含了 Init Container 的启动时间;

  • 禁止使用 lifecycle hook。

例子:

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  namespace: demo
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox:1.31
    command: [‘sh’, ‘-c’, ‘echo The app is running! && sleep 3600‘]
  initContainers:
  - name: init-myservice
    image: busybox:1.31
    command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
  - name: init-mydb
    image: busybox:1.31
    command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值