kubernetes Pod介绍

原创
半兽人 发表于: 2018-11-20   最后更新时间: 2021-11-09 16:08:25  
{{totalSubscript}} 订阅, 17,159 游览

Pod是Kubernetes的最重要也最基本的概念,如图所示是Pod的组成示意图,我们看到每个Pod都有一个特殊的被称为“根容器”的Pause容器。Pause容器对应的镜像属于Kubernetes平台的一部分,除了Pause容器,每个Pod还包含一个或多个紧密相关的用户业务容器。

kubernetes Pod介绍

为什么Kubernetes会设计出一个全新的Pod概念并且Pod有这样特殊的组成结构?

原因之一:在一组容器作为一个单元的情况下,我们难以对“整体”简单地进行判断及有效地进行行动。比如,一个容器死亡了,此时算是整体死亡么?引入业务无关并且不易死亡的Pause容器作为Pod的根容器,以它的状态代表整体容器组的状态,就简单、巧妙地解决了这个难题。

原因之二:Pod里的多个业务容器共享Pause容器的IP,共享Pause容器挂接的Volume,这样既简化了密切关联的业务容器之间的通信问题,也很好地解决了它们之间的文件共享问题。

Kubernetes为每个Pod都分配了唯一的IP地址,称之为Pod IP,一个Pod里的多个容器共享Pod IP地址。Kubernetes要求底层网络支持集群内任意两个Pod之间的TCP/IP直接通信,这通常采用虚拟而层网络技术来实现,例如Flannel、Open vSwitch等,因此我们需要牢记一点:在Kubernetes里,一个Pod里的容器与另外主机上的Pod容器能够直接通信。

Pod其实有两种类型:普通的Pod及静态Pod(Static Pod),后者比较特殊,它并不存放在Kubernetes的etcd存储里,而是存放在某个具体的Node上的一个具体文件中,并且只在此Node上启动运行。而普通的Pod一旦被创建,就会被放入到etcd中存储,随后会被Kubernetes Master调度到某个具体的Node上并进行绑定(Binding),随后该Pod被对应的Node上的kubelet进程实例化成一组相关的Docker容器并且启动起来。在默认情况下,当Pod里的某个容器停止时,Kubernetes会自动检测到这个问题并且重新启动这个Pod(重启Pod里的所有容器),如果Pod所在的Node宕机,则会将这个Node上的所有Pod重新调度到其他节点上。Pod、容器与Node的关系图如图所示。

screenshot

Kubernetes里的所有资源对象都可以采用yaml或者JSON格式的文件来定义或描述,下面是我们在之前Hello World例子里用到的myweb这个Pod的资源定义文件:

apiVersion: v1
kind: Pod
metadata:
  name: myweb
spec:
  containers:
    - name: myweb
      image: tomcat:9.0.53-jdk8-openjdk
      ports:
        - containerPort: 8080
      env:
        - name: MYSQL_SERVICE_HOST
          value: 'mysql'
        - name: MYSQL_SERVICE_PORTT
          value: '3306'

Kind为Pod表明这是一个Pod的定义,metadata里的name属性为Pod的名字,metadata里还能定义资源对象的标签(Label),这里表明myweb拥有一个name=myweb标签(Label)。Pod里所包含的容器组的定义是在spec中,这里定义了一个名字为myweb、对应镜像为tomcat:9.0.53-jdk8-openjdk的容器,该容器注入了名为MYSQL_SERVICE_HOST='mysql'MYSQL_SERVICE_PORT='3306'的环境变量(env关键字),并且在8080端口(containerPort)上启动容器进程。

Pod的IP加上这里的容器端口(containerPort),就组成了一个新的概念 -- Endpoint,它代表着此Pod里的一个服务进程的对外通信地址。

我们所熟悉的Docker Volume在Kubernetes里也有对应的概念 --- Pod Volume,后者有一些扩展,比如可以用分布式文件系统GlusterFS实现后端存储功能;Pod Volume是定义在Pod之上,然后被各个容器挂载到自己的文件系统中。

顺便提一下Kubernetes的Event概念,Event是一个事件的记录,记录了事件的最早产生时间、最后重现时间重复次数发起者类型,以及导致此事件的原因等众多信息。Event通常会关联到某个具体的资源对象上,是排查故障的重要参考信息,之前我们看到Node的描述信息包括了Event,而Pod同样有Event记录,用来发现某个Pod迟迟无法创建时,可以用kubectl describe pod xxxx来查看它的描述信息,用来定位问题的原因,比如下面这个Event记录信息表明Pod里的一个容器被探针检测失败一次:

Events:
    FirstSeen   LastSeen    Count   From    SubobjectPath   Type    Reason  Message
    ---------   --------    -----   ----    -------------   ----    ------  -------
    10h     12m     32  {kubelet k8s-node-1} spec.container{kube2sky}   Warning Unhealthy   Liveness probe failed: Get https://172.17.1.2:8080/healthz:net/https: request canceled {Client.Timeout exceeded while awaiting headers}

每个Pod都可以对其能使用的服务器上的计算资源设置限额,当前可以设置限额的计算资源有CPU与Memory两种,其中CPU的资源单位为CPU(Core)的数量,是一个绝对值而非相对值。

一个CPU的配额对于绝大多数容器来说是相当大的一个资源配额了,所以,在Kubernetes里,通常以千分之一的CPU配额为最小单位,用m来表示。通常一个容器的CPU配额被定义为100~300m,即占用0.1~0.3个CPU。由于CPU配额是一个绝对值,所以无论在拥有一个Core的机器上,还是在拥有48个Core的机器上,100m这个配额所代表的CPU的使用量都是一样的。与CPU配额类似,Memory配额也是一个绝对值,它的单位是内存字节数。

在Kubernetes里,一个计算资源进行配额限定需要设定以下两个参数。

  • Request:该资源的最小申请量,系统必须满足要求。
  • Limits:该资源最大允许使用量,不能被突破,当容器试图使用超过这个量的资源时,可能会被Kubernetes Kill并重启。

通常我们会把Request设置为一个比较小的数值,符合容器平时的工作负载情况下的资源需求,而把Limit设置为负载均衡情况下资源占用的最大量。比如下面这些定义,表明MySQL容器申请最少0.25个CPU及64MiB内存,在运行过程中MySQL容器所能使用的资源配额最大为0.5个CPU及128MiB内存:

spec:
   containers:
   - name: db
     image: mysql
     resources:
       requests:
        memory: "64Mi"
        cpu: "250m"
       limits:
        memory: "128Mi"
        cpu: "500m"

最后给出Pod及Pod周边对象的示意图作为总结,如图所示,后面部分涉及这张图里的对象和概念,以进一步加强理解。

screenshot

更新于 2021-11-09
在线,12分钟前登录

人间何世 1年前

大神请教下,pod的yaml中cpu 内存不设置时,可以无限制使用。那么yaml中不设置大页内存,pod可以能使用host机器上的大页吗?是不是也是无限制使用。我试了下,好像yaml中要设置了才能使用大页, 就算我用了hostNetwork: true,也是要设置了才能用。请教下,有没有方法,pod里面可以直接使用host机上面的大页内存,不用挂载进来就能用

半兽人 -> 人间何世 1年前

不行的,虽然 HugePages 的申请方式与默认的内存相差不多,但是它实际上是操作系统单独管理的特殊资源,Linux 会在 /proc/meminfo 中单独展示 HugePages 的相关数据,而 Kubernetes 也会认为大页是不同于内存的独立资源。
所以必须挂载使用。

半兽人 -> 半兽人 1年前

在补一句:

设计者:我们认为,应用程序试图使用多个巨大页面尺寸的情况很少。

人间何世 -> 半兽人 1年前

但是,我有一个docker容器,然后我单独用--host=net跑起来,发现容器里面的程序是可以使用大页的。然后,我把这个容器用k8s pod跑起来,就发现使用不了了。很奇怪,k8s pod最终不也是用docker跑的吗,docker能使用大页,为什么pod跑起来使用不了。

大神,有这方面的了解吗

骉騳马 2年前

Pod的IP加上这里的容器端口(containerPort),就组成了一个新的概念 -- Endpoint,那如果一个pod里面有多个容器运行在不同的端口上,是不是可以说这个pod里面有多个endpoint

半兽人 -> 骉騳马 2年前

不,还是只有一个endpoint,因为多个容器是共享资源的。

骉騳马 -> 半兽人 2年前

那这个不就与文章中那句话矛盾了吗,POD IP和不同的容器端口,不是应该可以组成不同的endpoint吗,还是说一个pod里面的多个容器一定是运行在相同的端口上的?

半兽人 -> 骉騳马 2年前

端口是针对负载均衡的,svc的,可参考:kubernetes中什么是endpoint?

骉騳马 -> 半兽人 2年前

有点明白了,感谢大佬解答

我没懂那一个pod里面到底能不能有多个container

wellhor 2年前
spec:
   containers:
   - name: db
     image: mysql
     resources:
       requests: #这里应该是requests
        memory: "64Mi"
        cpu: "250m"
       limits:
        memory: "128Mi"
        cpu: "500m"
半兽人 -> wellhor 2年前

粗糙的我,感谢提醒,已更正。

小孙 2年前

你好,我想问下上面pod的yaml格式中有两个spec,第一个指什么

Lance.Wu -> 小孙 2年前

这个例子是错的,Pod类型没有两个Spec。

只有deployment和StatefulSet下面的第一个spec描述的是关联pod集合的基本标识。包括(Pod管理策略、实例数、标签选择器、关联服务、更新策略、磁盘挂载等。)spec.template.spec才是Pod相关内容。

半兽人 -> 小孙 2年前

@Lance.Wu说的是对的,例子是错误的,已经更正了。

小孙 -> Lance.Wu 2年前

多谢,我还以为自己理解能力有问题。。。。

小孙 -> 半兽人 2年前

多谢多谢。。

landi 2年前

然后被各个容器挂载到自己的文件系统忠的 -> 中的

半兽人 -> landi 2年前

感谢提醒,已更正。

夜雨 2年前

第一行末尾错别字:“特殊的被成为” -> “特殊的被称为”

半兽人 -> 夜雨 2年前

感谢,已修正,那么多人都没人发现,只有你认真读了。

麦奇 3年前

博主好强啊

半兽人 -> 麦奇 3年前

为了生活!

写的很好,很容易理解,第一次看就明白了了

多了个

泓一大师 3年前

好喜欢类似“为什么Kubernetes会设计出一个全新的Pod概念并且Pod有这样特殊的组成结构?”这样的内容,nice啊

半兽人 -> 泓一大师 3年前

我决定给这句话加粗...

泓一大师 -> 半兽人 3年前

我决定给你点个赞,并且想问一下这篇文章提到的helloword在哪里。。

半兽人 -> 泓一大师 3年前
apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
  labels:
    app: pod-demo
spec:
  containers:
    - name: pod-container-name
      image: nginx
      ports:
        - containerPort: 80
          name: http-server
查看kubernetes更多相关的文章或提一个关于kubernetes的问题,也可以与我们一起分享文章