• 深入剖析Kubernetes学习笔记:Pod(13)


    一、为什么我们会需要 Pod?

    是啊,我们在前面已经花了很多精力去解读 Linux 容器的原理、分析了 Docker 容器的本质,终于,“Namespace 做隔离,Cgroups 做限制,rootfs 做文件系统”这样的“三句箴言”可以朗朗上口了,

    1、为什么 Kubernetes 项目又突然搞出一个 Pod 来呢?

    要回答这个问题,我们还是要一起回忆一下我曾经反复强调的一个问题:容器的本质到底是什么?

    你现在应该可以不假思索地回答出来:容器的本质是进程。

    没错。容器,就是未来云计算系统中的进程;容器镜像就是这个系统里的“.exe”安装包。

    2、那么 Kubernetes 呢?

    你应该也能立刻回答上来:Kubernetes 就是操作系统!

    非常正确。,

    1、进程组

    1、Linux 

    不难发现,在一个真正的操作系统里,进程并不是“孤苦伶仃”地独自运行的,而是以进程组的方式,“有原则地”组织在一起。
    比如,这里有一个叫作 rsyslogd 的程序,它负责的是 Linux 操作系统里的日志处理。
    可以看到,rsyslogd 的主程序 main,和它要用到的内核日志模块 imklog 等,同属于 1632 进程组。这些进程相互协作,共同完成 rsyslogd 程序的职责。

    注意:我在本篇中提到的“进程”,比如,rsyslogd 对应的 imklog,imuxsock 和 main,严格意义上来说,其实是 Linux 操作系统语境下的“线程”。这些线程,或者说,轻量级进程之间,可以共享文件、信号、数据内存、甚至部分代码,从而紧密协作共同完成一个程序的职责。所以同理,我提到的“进程组”,对应的也是 Linux 操作系统语境下的“线程组”。这种命名关系与实际情况的不一致,是 Linux 发展历史中的一个遗留问题。对这个话题感兴趣的同学,可以阅读这篇技术文章来了解一下。

    2、Kubernetes

    2、rsyslogd 应用给容器化

    1、容器化

    再次强调一下:容器的“单进程模型”,并不是指容器里只能运行“一个”进程,而是指容器没有管理多个进程的能力。这是因为容器里 PID=1 的进程就是应用本身,其他的进程都是这个 PID=1 进程的子进程。可是,用户编写的应用,并不能够像正常操作系统里的 init 进程或者 systemd 那样拥有进程管理的功能。比如,你的应用是一个 Java Web 程序(PID=1),然后你执行 docker exec 在后台启动了一个 Nginx 进程(PID=3)。可是,当这个 Nginx 进程异常退出的时候,你该怎么知道呢?这个进程退出后的垃圾收集工作,又应该由谁去做呢?

     2、Docker Swarm

     成组调度没有被妥善处理

     不完美的解决办法

     3、Kubernetes 项目

     超亲密关系

    二、Pod 的实现原理

    1、首先,关于 Pod 最重要的一个事实是:它只是一个逻辑概念。

    也就是说,Kubernetes 真正处理的,还是宿主机操作系统上 Linux 容器的 Namespace 和 Cgroups,而并不存在一个所谓的 Pod 的边界或者隔离环境。

    那么,Pod 又是怎么被“创建”出来的呢?

    答案是:Pod,其实是一组共享了某些资源的容器。

    具体的说:Pod 里的所有容器,共享的是同一个 Network Namespace,并且可以声明共享同一个 Volume。

    那这么来看的话,一个有 A、B 两个容器的 Pod,不就是等同于一个容器(容器 A)共享另外一个容器(容器 B)的网络和 Volume 的玩儿法么?

    这好像通过 docker run --net --volumes-from 这样的命令就能实现嘛,比如:

    $ docker run --net=B --volumes-from=B --name=A image-A ...

    但是,你有没有考虑过,如果真这样做的话,容器 B 就必须比容器 A 先启动,这样一个 Pod 里的多个容器就不是对等关系,而是拓扑关系了。

    2、 Infra 容器

    在这个 Pod 中,Infra 容器永远都是第一个被创建的容器,而其他用户定义的容器,则通过 Join Network Namespace 的方式,与 Infra 容器关联在一起。这样的组织关系,可以用下面这样一个示意图来表达:

    1、占用极少的资源

    2、用户容器就可以加入到 Infra 容器

     这也就意味着,对于 Pod 里的容器 A 和容器 B 来说:

     3、而对于同一个 Pod 里面的所有用户容器来说

     4、网络插件

     5、共享 Volume

     比如下面这个例子:

    apiVersion: v1
    kind: Pod
    metadata:
      name: two-containers
    spec:
      restartPolicy: Never
      volumes:
      - name: shared-data
        hostPath:      
          path: /data
      containers:
      - name: nginx-container
        image: nginx
        volumeMounts:
        - name: shared-data
          mountPath: /usr/share/nginx/html
      - name: debian-container
        image: debian
        volumeMounts:
        - name: shared-data
          mountPath: /pod-data
        command: ["/bin/sh"]
        args: ["-c", "echo Hello from the debian container > /pod-data/index.html"]

    在这个例子中,debian-container 和 nginx-container 都声明挂载了 shared-data 这个 Volume。而 shared-data 是 hostPath 类型。所以,它对应在宿主机上的目录就是:/data。而这个目录,其实就被同时绑定挂载进了上述两个容器当中。

    这就是为什么,nginx-container 可以从它的 /usr/share/nginx/html 目录中,读取到 debian-container 生成的 index.html 文件的原因。

    三、容器设计模式

    Pod 这种“超亲密关系”容器的设计思想,实际上就是希望,当用户想在一个容器里跑多个功能并不相关的应用时,应该优先考虑它们是不是更应该被描述成一个 Pod 里的多个容器。

    为了能够掌握这种思考方式,你就应该尽量尝试使用它来描述一些用单个容器难以解决的问题。

    1、第一个最典型的例子是:WAR 包与 Web 服务器。

    1、用例描述

    我们现在有一个 Java Web 应用的 WAR 包,它需要被放在 Tomcat 的 webapps 目录下运行起来。

    2、用 Docker 来做这件事情

    假如,你现在只能用 Docker 来做这件事情,那该如何处理这个组合关系呢?

    1、方法一

    2、方法二

    3、有了 Pod 之后,这样的问题就很容易解决了

    我们可以把 WAR 包和 Tomcat 分别做成镜像,然后把它们作为一个 Pod 里的两个容器“组合”在一起

    apiVersion: v1
    kind: Pod
    metadata:
      name: javaweb-2
    spec:
      initContainers:
      - image: geektime/sample:v2
        name: war
        command: ["cp", "/sample.war", "/app"]
        volumeMounts:
        - mountPath: /app
          name: app-volume
      containers:
      - image: geektime/tomcat:7.0
        name: tomcat
        command: ["sh","-c","/root/apache-tomcat-7.0.42-v2/bin/start.sh"]
        volumeMounts:
        - mountPath: /root/apache-tomcat-7.0.42-v2/webapps
          name: app-volume
        ports:
        - containerPort: 8080
          hostPort: 8001 
      volumes:
      - name: app-volume
        emptyDir: {}

    1、定义两个镜像

     2、Init Container

     3、启动流程

    所以,等 Tomcat 容器启动时,它的 webapps 目录下就一定会存在 sample.war 文件:这个文件正是 WAR 包容器启动时拷贝到这个 Volume 里面的,而这个 Volume 是被这两个容器共享的。 

    4、sidecar

    2、第二个例子,则是容器的日志收集。

    1、需求描述

    比如,我现在有一个应用,需要不断地把日志文件输出到容器的 /var/log 目录中。

    2、解决思路

    这时,我就可以把一个 Pod 里的 Volume 挂载到应用容器的 /var/log 目录上。

    然后,我在这个 Pod 里同时运行一个 sidecar 容器,它也声明挂载同一个 Volume 到自己的 /var/log 目录上。

    这样,接下来 sidecar 容器就只需要做一件事儿,那就是不断地从自己的 /var/log 目录里读取日志文件,转发到 MongoDB 或者 Elasticsearch 中存储起来。这样,一个最基本的日志收集工作就完成了。

    3、sidecar 的主要工作

    四、容器与虚拟机

    1、容器和虚拟机没有任何相似的地方

    但实际上,无论是从具体的实现原理,还是从使用方法、特性、功能等方面,容器与虚拟机几乎没有任何相似的地方;
    也不存在一种普遍的方法,能够把虚拟机里的应用无缝迁移到容器中。
    因为,容器的性能优势,必然伴随着相应缺陷,即:它不能像虚拟机那样,完全模拟本地物理机环境中的部署方法。

    所以,这个“上云”工作的完成,最终还是要靠深入理解容器的本质,即:进程。

    2、容器的本质:进程

    实际上,一个运行在虚拟机里的应用,哪怕再简单,也是被管理在 systemd 或者 supervisord 之下的一组进程,
    而不是一个进程。这跟本地物理机上应用的运行方式其实是一样的。
    这也是为什么,从物理机到虚拟机之间的应用迁移,往往并不困难。

    可是对于容器来说,一个容器永远只能管理一个进程。更确切地说,一个容器,就是一个进程。
    这是容器技术的“天性”,不可能被修改。所以,将一个原本运行在虚拟机里的应用,“无缝迁移”到容器中的想法,实际上跟容器的本质是相悖的。

    这也是当初 Swarm 项目无法成长起来的重要原因之一:一旦到了真正的生产环境上,Swarm 这种单容器的工作方式,就难以描述真实世界里复杂的应用架构了。

    3、可以这么理解Pod的本质

    所以,你现在可以这么理解Pod的本质:

    Pod,实际上是在扮演传统基础设施里“虚拟机”的角色;而容器,则是这个虚拟机里运行的用户程序。

    所以下一次,当你需要把一个运行在虚拟机里的应用迁移到 Docker 容器中时,一定要仔细分析到底有哪些进程(组件)运行在这个虚拟机里。

    1. 然后,你就可以把整个虚拟机想象成为一个 Pod,
    2. 把这些进程分别做成容器镜像,
    3. 把有顺序关系的容器,定义为 Init Container。

    这才是更加合理的、松耦合的容器编排诀窍,也是从传统应用架构,到“微服务架构”最自然的过渡方式。

    注意:Pod 这个概念,提供的是一种编排思想,而不是具体的技术方案。所以,如果愿意的话,你完全可以使用虚拟机来作为 Pod 的实现,然后把用户容器都运行在这个虚拟机里。比如,Mirantis 公司的virtlet 项目就在干这个事情。甚至,你可以去实现一个带有 Init 进程的容器项目,来模拟传统应用的运行方式。这些工作,在 Kubernetes 中都是非常轻松的,也是我们后面讲解 CRI 时会提到的内容。

    相反的,如果强行把整个应用塞到一个容器里,甚至不惜使用 Docker In Docker 这种在生产环境中后患无穷的解决方案,恐怕最后往往会得不偿失

  • 相关阅读:
    JeecgBoot 2.4 微服务正式版发布,基于SpringBoot的低代码平台
    JeecgBoot 常见问题Q&A
    docker安装rabbitmq延时队列插件
    docker安装nacos
    docker安装xxl-job-admin
    docker安装rabbitmq
    低代码开发平台有哪些?
    对比 jeecgboot 和国内外其它低代码平台的区别
    JimuReport积木报表 — API数据源报表带参制作
    JimuReport积木报表 — API数据源报表制作
  • 原文地址:https://www.cnblogs.com/luoahong/p/12337455.html
Copyright © 2020-2023  润新知