一、容器的实质(特殊进程)

二、隔离与限制

namespaces是为了模仿虚拟机的”看”,cgroups是为了模仿虚拟机的”用”。namespace解决可见性问题,cgroup解决资源隔离问题。

namespces(隔离)

概念:是一种资源逻辑隔离机制。
它的“视线”被系统做了限制,只看”看到”某些指定的内容。对于宿主机来说,这些被“隔离”的进程跟其他进程没有太大区别。
Docker本身并没有对应用进程进行隔离,也没有创建所谓的“容器”,而是通过宿主机的操作系统通过namespace对应用进程进行隔离,通过cgroups对被隔离的应用进程限制相关资源属性。(namespace是对进程的隔离,cgroup是对系统资源的隔离)
虚拟机与容器的区别:
虚拟机需要借助GuestOS才能运行应用,容器实际上就是OS的进程,一组文件和运行环境,更加简单。相对而言更精细一些。
性能优势:
敏捷”和“高性能”是容器相较于虚拟机最大的优势。(敏捷是指快速打包,快速发布;高性能是指容器进程本来就是系统里的普通进程,没有虚拟化层的性能损失。 但缺点是没有虚拟化层的隔离性,隔离不彻底)
不能被隔离的资源:内核和时间,在容器中使用settimeofday(2)可以修改时间,但是修改完之后会同步到宿主机

隔离性

  • 查看当前系统的 namespace:lsns –t
  • 查看某进程的 namespace:ls -la /proc//ns/
  • 进入某 namespace 运行命令:nsenter -t -n ip addr

    Pid namespace

  • 不同用户的进程就是通过 Pid namespace 隔离开的,且不同 namespace 中可以有相同 Pid。

  • 有了 Pid namespace, 每个 namespace 中的 Pid 能够相互隔离。

    net namespace

  • 网络隔离是通过 net namespace 实现的, 每个 net namespace 有独立的 network devices, IPaddresses, IP routing tables, /proc/net 目录。

  • Docker 默认采用 veth 的方式将 container 中的虚拟网卡同 host 上的一个 docker bridge: docker0 连接在一起。

    ipc namespace

  • Container 中进程交互还是采用 linux 常见的进程间交互方法 (interprocess communication – IPC), 包括常见的信号量、消息队列和共享内存。

  • container 的进程间交互实际上还是 host上 具有相同 Pid namespace 中的进程间交互,因此需要在 IPC资源申请时加入 namespace 信息 - 每个 IPC 资源有一个唯一的 32 位 ID。

    mnt namespce

    mnt namespace 允许不同 namespace 的进程看到的文件结构不同,这样每个 namespace 中的进程所看
    到的文件目录就被隔离开了。

    uts namespace

    UTS(“UNIX Time-sharing System”) namespace允许每个 container 拥有独立的 hostname 和
    domain name, 使其在网络上可以被视作一个独立的节点而非 Host 上的一个进程。

    user namespace

    每个 container 可以有不同的 user 和 group id, 也就是说可以在 container 内部用 container 内部的用户
    执行程序而非 Host 上的用户。

    cgroups(限制)

    cgroups就是一个子系统目录加上一组资源限制文件的组合。

    • 资源限制:限制任务使用的资源总额,并在超过这个配额时发出提示。
    • 优先级分配:分配CPU时间片数量及磁盘 IO 带宽大小、控制任务运行的优先级。
    • 资源统计:统计系统资源使用量,如 CPU 使用时长、内存用量等。
    • 任务控制:对任务执行挂起、恢复等操作。 ```shell

$ mount -t cgroup cpuset on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset) cpu on /sys/fs/cgroup/cpu type cgroup (rw,nosuid,nodev,noexec,relatime,cpu) cpuacct on /sys/fs/cgroup/cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpuacct) blkio on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio) memory on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory) …

$ ls /sys/fs/cgroup/cpu cgroup.clone_children cpu.cfs_period_us cpu.rt_period_us cpu.shares notify_on_release cgroup.procs cpu.cfs_quota_us cpu.rt_runtime_us cpu.stat tasks ``` 作用:限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。
cgroups 是Linux内核提供的一种可以限制单个进程或者多个进程所使用资源的机制
Cgroups每个一个子系统都有独有的资源限制能力:

  • cpu 子系统,主要限制进程的 cpu 使用率。
  • cpuacct 子系统,可以统计 cgroups 中的进程的 cpu 使用报告。
  • cpuset 子系统,可以为 cgroups 中的进程分配单独的 cpu 节点或者内存节点。
  • memory 子系统,可以限制进程的 memory 使用量。
  • blkio 子系统,可以限制进程的块设备 io。
  • devices 子系统,可以控制进程能够访问某些设备。
  • net_cls 子系统,可以标记 cgroups 中进程的网络数据包,然后可以使用 tc 模块(traffic control)对数据包进行控制。
  • freezer 子系统,可以挂起或者恢复 cgroups 中的进程。
  • ns 子系统,可以使不同 cgroups 下面的进程使用不同的 namespace。

每个subsystem背后都有相应的内核模块来配合它完成对资源的控制。
Cgroups分为三个组件:

  • 控制组:一个cgroups包括一组进程,可以在cgroups上增加 subsystem的参数配置,将一组进程与cgroups关系。
  • subsystem:子系统是一组资源控制模块,控制节点中进程的资源占用。
  • hierarchy层级数:把cgroups串成一个树形结构

疑问:
1.容器启动实际是PID=1的进程,后续创建的进程在宿主机能查到进程吗?
2.在一个容器中,你没办法同时运行两个不同的应用,除非你能事先找到一个公共的 PID=1 的程序来充当两个不同应用的父进程,这也是为什么很多人都会用 systemd 或者 supervisord 这样的软件来代替应用本身作为容器的启动进程。

三、容器镜像