《深入剖析kubernetes》学习笔记(1)——容器基础

05-06. 容器与进程

  • 容器技术的核心在于对进程的隔离和限制,为其创造出一个“边界”,
    • linux的命名空间Namespace,使得进程只能看到当前Namespace下限定的资源,例如pid, Mount, IPC, Network, User, UTS
      • Namespace是linux创建进程时的可选参数
    • linux的Cgroups (Linux Control Group),限制一个进程组能使用的资源上线,例如CPU、内存、磁盘和网络等
      • Cgroups以文件系统的方式暴露给用户使用,/sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统
      • 使用时,在每个子系统下新建一个控制组(子目录下新建一个目录,操作系统会自动为其填充资源限制文件),将需要限制的进程的PID填写入tasks文件中
  • 容器只是一个单进程模型
    • 一个正在运行的 Docker 容器,就是一个启用了多个Namespace 的应用进程,而这个进程能够使用的资源量,又受到 Cgroups 配置的限制
    • 容器本身的设计,就是希望容器和应用能够同生命周期,避免容器正常运行,但应用却已经挂了的情况
  • 容器与虚拟机技术的对比
    • 优势:容器更加敏捷和高性能
    • 缺点:容器之间的隔离不够彻底,多个容器间共享宿主机操作系统内核,内核中有些资源无法用namespace隔离,造成了安全隐患;新型容器技术可更好的在隔离与性能间平衡。

07. 容器镜像

  • 关于Mount Namespace

    • Mount Namespace和其他Namespace的不同:如果只是启用Mount Namespace,容器进程仍能看到宿主机上全部文件;容器进程对文件系统的视图改变是挂载操作(mount)带来的。
    • Mount Namespace改变的是进程对文件系统“挂载点”的认识。例如,由于容器启用了mount namespace,则宿主机上无法感知容器的挂载行为。
  • 容器镜像是什么

    • 容器进程启动后,使用pivot_root或者chroot命令重新挂载进程的根目录"/",一般会在根目录下挂载完整操作系统的文件系统
    • 挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统就是容器镜像,也叫做根文件系统(rootfs)
    • rootfs只包含操作系统的文件、配置和目录,不含操作系统内核
    • rootfs提供了容器运行的所有依赖,故才有它的的重要特性——一致性。
  • 联合文件系统(Union File System)

    • 联合挂载(union mount):将多个不同位置目录A、B挂载到同一个目录C下,原目录A、B下所有内容都会合并到新目录C下,在C中的修改会在A、B中生效
      • mount -t aufs -o dirs=./A:./B none ./C
    • 常见的有vfs、deviceMapper、overlay、overlay2、aufs,通过docker info命令可以查看docker采用的是哪种union fs,目前新版本docker一般都用overlay2
  • 容器镜像的分层结构

    • Dockerfile中的每一条指令,都会为镜像生成一个层,即一个增量rootfs
    • 用命令docker image insepct <image-name>:<tag-name>可以看到“RootFS”字段下镜像的分层信息
    • 对overlay2而言,镜像文件各层存储在/var/lib/docker/image/var/lib/docker/overlay2/目录下【该目录下文件含义参考文章
    • 镜像的多个层会被联合挂载成为一个完整的文件系统,可将各层从下往上分为三部分:
      • 只读层(镜像层)
        • 不希望被程序修改的内容,以只读方式挂载
      • init层
        • 对应于配置文件的修改,例如/etc/下的一些配置信息,未修改时为空。docker commit时不会提交该层内容
      • 可读写层(容器层)
        • 用户的增删改操作都记录在这里
        • 修改操作只作用在本层,不会实际修改只读层的内容,要修改的文件会先被复制到可读写层然后再修改。被联合挂载时,只读层的相同文件会被可读写层覆盖,这叫做copy-on-write
        • 其中的删除动作不会真正删除文件,而只是标记某文件不可见,术语叫做whiteout,从而不影响只读层的内容

08. 重新认识容器

  • docker exec能够进入容器的原理:

    通过setns() 的 Linux 系统调用,一个进程可以加入另一个进程的NameSpace中,从而达到“进入”容器的目的

  • Volume 机制,将宿主机上指定的目录或者文件,挂载到容器里面进行读取和修改操作

    • 两种声明方式
      • docker run -v /test ...不指定宿主机目录,则docker创建临时目录挂载到容器/test上
      • docker run -v /home:/test ...指定将宿主机的/home目录挂载到容器的/test上
    • 挂载操作的时机:在容器创建之后,要求
      1. Mount Namespace已经开启,从而宿主机观察不到挂载点的存在,确保隔离性不被打破
      2. 联合挂载操作已经完成,即要求容器所需的rootfs已经准备好
      3. chroot或者pivot_root执行之前,从而容器进程可以看到宿主机的整个文件系统
  • 容器中的挂载,采用的是bind mount(绑定挂载)机制

    • 例如,语句docker run -v /home:/test ...将宿主机的/home目录挂载到容器的/test目录上
    • 这也就是为何,一旦执行 umount 命令,容器的/test 目录原先的内容就会恢复:因为修改真正发生在的位置,是宿主机的 /home 目录
    • 如果/test目录下本来就有内容,那么这些内容在挂载后在/home下也可见,这是docker的copydata功能
    • 容器/test目录里修改的内容,不会被docker commit提交
      • 因为docker commit发生在宿主机空间,而由于Mount Namespace的存在,宿主机无法感知/test的挂载操作,它所看到的容器/test目录始终没变,当然无法提交。

09. kubernetes的角色

  • 一个正在运行的容器,可以分为两部分看待
    1. 容器的静态视图,即“容器镜像”,是联合挂载的rootfs
    2. 容器的动态视图,即"容器运行时",是由Namespace和Cgroups共同组成的隔离环境
  • 对开发者而言,更需要关心的是容器的静态视图
  • 如何容器化一个应用?需要考虑:
    1. 应用于应用之间的关系,例如需要本地通信的部署在同一个pod里、需要相互访问的需要定义Service暴露访问入口,等等
    2. 应用运行的形态,例如一次性运行的Job、守护进程DaemonSet等等
  • kubernetes完全基于”声明式API“的方式来描述容器化的业务和容器间的关系
  • kubernetes最擅长的是提供容器的编排功能,即按照用户意愿和系统规则,自动化处理容器间的各种关系
posted @ 2021-01-29 16:24  lwjj  阅读(463)  评论(0编辑  收藏  举报