Contents

Kubernetes Note 01

Contents
  • 容器技术的核心功能,就是通过约束和修改进程的动态表现,从而为其创造出一个“边界”
  • Cgroups 技术是用来制造约束的主要手段,而 Namespace 技术则是用来修改进程视图的主要方法
  • Docker 容器这个听起来玄而又玄的概念,实际上是在创建容器进程时,指定了这个进程所需要启用的一组 Namespace 参数
  • 容器就只能“看”到当前 Namespace 所限定的资源、文件、设备、状态,或者配置
  • 容器,其实是一种特殊的进程而已
  • Docker 项目帮助用户启动的,还是原来的应用进程,只不过在创建这些进程时,Docker 为它们加上了各种各样的 Namespace 参数
  • 这些进程就会觉得自己是各自 PID Namespace 里的第 1 号进程,只能看到各自 Mount Namespace 里挂载的目录和文件,只能访问到各自 Network Namespace 里的网络设备,就仿佛运行在一个个“容器”里面,与世隔绝
    • 进程隔离:pid namespace
    • 网络隔离:net namespace
    • 挂载点隔离:mount namespace
    • 进程间通信隔离:ipc namespace
    • 独立的用户、用户组:user namespace
    • 独立的 hostname、domain name:uts namespace
  • 用户运行在容器里的应用进程,跟宿主机上的其他进程一样,都由宿主机操作系统统一管理,只不过这些被隔离的进程拥有额外设置过的 Namespace 参数
  • 基于 Linux Namespace 的隔离机制相比于虚拟化技术也有很多不足之处,其中最主要的问题就是:隔离得不彻底
  • 容器只是运行在宿主机上的一种特殊的进程,那么多个容器之间使用的就还是同一个宿主机的操作系统内核
  • 在 Linux 内核中,有很多资源和对象是不能被 Namespace 化的,最典型的例子就是:时间
  • Linux Cgroups 就是 Linux 内核中用来为进程设置资源限制的一个重要功能
  • Linux Cgroups 的全称是 Linux Control Group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等
  • Cgroups 给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下
    • mount -t cgroup
  • 一个正在运行的 Docker 容器,其实就是一个启用了多个 Linux Namespace 的应用进程,而这个进程能够使用的资源量,则受 Cgroups 配置的限制
  • 如何修复容器中的 top 指令以及 /proc 文件系统中的信息呢?
    • 通过 lxcfs 来实现隔离, 容器启动的时候通过 -v 参数将 lxcfs /proc 目录挂载到容器的 /proc 目录
  • Mount Namespace 修改的,是容器进程对文件系统“挂载点”的认知, 它对容器进程视图的改变,一定是伴随着挂载操作(mount)才能生效。
  • chroot - “change root file system”,即改变进程的根目录到你指定的位置
  • 挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统,就是所谓的“容器镜像”。它还有一个更为专业的名字,叫作:rootfs(根文件系统)
  • Docker 项目来说,它最核心的原理实际上就是为待创建的用户进程:
    • 启用 Linux Namespace 配置;
    • 设置指定的 Cgroups 参数;
    • 切换进程的根目录(Change Root
  • Docker 项目在最后一步的切换上会优先使用 pivot_root 系统调用,如果系统不支持,才会使用 chroot
  • Union File System 也叫 UnionFS,最主要的功能是将多个不同位置的目录联合挂载(union mount)到同一个目录下
  • OverlayFS is a modern union filesystem that is similar to AUFS, but faster and with a simpler implementation.
  • OverlayFS layers two directories on a single Linux host and presents them as a single directory. These directories are called layers and the unification process is referred to as a union mount.
  • 默认情况下,Docker 会为你提供一个隐含的 ENTRYPOINT,即:/bin/sh -c
  • 一个进程的每种 Linux Namespace,都在它对应的 /proc/[进程号]/ns 下有一个对应的虚拟文件,并且链接到一个真实的 Namespace 文件上
  • 一个进程,可以选择加入到某个进程已有的 Namespace 当中,从而达到“进入”这个进程所在容器的目的,这正是 docker exec 的实现原理
    • 操作所依赖的,乃是一个名叫 setns() 的 Linux 系统调用
  • Docker 还专门提供了一个参数,可以让你启动一个容器并“加入”到另一个容器的 Network Namespace 里,这个参数就是 -net
    • docker run -it --net container:ae62c8b7f159 busybox ifconfig
    • 如果 --net=host,就意味着这个容器不会为进程启用 Network Namespace, 它会和宿主机上的其他普通进程一样,直接共享宿主机的网络栈
  • docker commit,实际上就是在容器运行起来后,把最上层的“可读写层”,加上原先容器镜像的只读层,打包组成了一个新的镜像
  • 由于使用了联合文件系统,在容器里对镜像 rootfs 所做的任何修改,都会被操作系统先复制到这个可读写层,然后再修改。这就是所谓的:Copy-on-Write
  • Init 层的存在,就是为了避免执行 docker commit 时,把 Docker 自己对 /etc/hosts 等文件做的修改,也一起提交掉
  • Volume 机制,允许将宿主机上指定的目录或者文件,挂载到容器里面进行读取和修改操作
  • 当容器进程被创建之后,尽管开启了 Mount Namespace,但是在执行 chroot(或者 pivot_root)之前,容器进程一直可以看到宿主机上的整个文件系统.
  • 在 rootfs 准备好之后,在执行 chroot 之前,把 Volume 指定的宿主机目录,挂载到指定的容器目录在宿主机上对应的目录(即 /var/lib/docker/aufs/mnt/[可读写层 ID]/test)上,这个 Volume 的挂载工作就完成了
  • 由于执行这个挂载操作时,“容器进程”已经创建了,也就意味着此时 Mount Namespace 已经开启了。所以,这个挂载事件只在这个容器里可见。在宿主机上,是看不见容器内部的这个挂载点的。这就保证了容器的隔离性不会被 Volume 打破
    • 这里使用到的挂载技术,就是 Linux 的绑定挂载(bind mount)机制, 绑定挂载实际上是一个 inode 替换的过程
  • 一个“容器”,实际上是一个由 Linux Namespace、Linux Cgroups 和 rootfs 三种技术构建出来的进程的隔离环境