前面学习了容器运行时containerd的基本使用,containerd的架构,namespace, cgroup, rootfs等容器背后的技术。 本节做一个阶段性的小节。此时,如果有人问"容器是什么?",我们可能会给出以下的回答:

  • 容器实际上是一种特殊的进程。它使用namespace进行隔离,使用cgroup进行资源限制,并且它还以联合文件系统的形式挂载了单独的rootfs。
  • 为了更方便的准备运行容器所需的资源和管理容器的生命周期,还需要容器引擎如containerd。
  • 容器镜像实际上就是一种特殊的文件系统,它包含容器运行所需的程序、库、资源配置等所有内容,构建后内容保持不变。在启动容器时镜像会挂载为容器的rootfs。

既然容器仅仅是一种特殊的进程,下面我们实际去探索一下它的存在。继续前面启动的redis容器为例,可以使用nerdctl inspect <container id>ctr c info <container id>查看一下容器的信息。 下面的命令可以打印出容器在宿主机上的进程id:

1nerdctl inspect 8102f | grep Pid
2            "Pid": 27582,

容器作为一种特殊的操作系统进程,可以在系统的/proc/<process-id>中感受它的存在:

1ls /proc/27582
2attr       auxv    clear_refs  comm             cpuset  environ  fd      gid_map  limits    map_files  mem        mounts      net  numa_maps  oom_score      pagemap      projid_map  sched      sessionid  smaps  stat   status   task    uid_map
3autogroup  cgroup  cmdline     coredump_filter  cwd     exe      fdinfo  io       loginuid  maps       mountinfo  mountstats  ns   oom_adj    oom_score_adj  personality  root        schedstat  setgroups  stack  statm  syscall  timers  wchan

/proc/27582/ns目录下对应了容器的各个namespace:

1ll /proc/27582/ns
2total 0
3lrwxrwxrwx 1 ipc -> ipc:[4026532172]
4lrwxrwxrwx 1 mnt -> mnt:[4026532170]
5lrwxrwxrwx 1 net -> net:[4026532175]
6lrwxrwxrwx 1 pid -> pid:[4026532173]
7lrwxrwxrwx 1 user -> user:[4026531837]
8lrwxrwxrwx 1 uts -> uts:[4026532171]

/proc/27582/cgroup文件对应了容器的11种cgroup:

 1cat /proc/27582/cgroup
 211:hugetlb:/default/8102f7fbee26792830e54e80b3488714ac559e092c59beb2e311cf8e88f475d6
 310:perf_event:/default/8102f7fbee26792830e54e80b3488714ac559e092c59beb2e311cf8e88f475d6
 49:devices:/default/8102f7fbee26792830e54e80b3488714ac559e092c59beb2e311cf8e88f475d6
 58:memory:/default/8102f7fbee26792830e54e80b3488714ac559e092c59beb2e311cf8e88f475d6
 67:freezer:/default/8102f7fbee26792830e54e80b3488714ac559e092c59beb2e311cf8e88f475d6
 76:cpuacct,cpu:/default/8102f7fbee26792830e54e80b3488714ac559e092c59beb2e311cf8e88f475d6
 85:blkio:/default/8102f7fbee26792830e54e80b3488714ac559e092c59beb2e311cf8e88f475d6
 94:pids:/default/8102f7fbee26792830e54e80b3488714ac559e092c59beb2e311cf8e88f475d6
103:net_prio,net_cls:/default/8102f7fbee26792830e54e80b3488714ac559e092c59beb2e311cf8e88f475d6
112:cpuset:/default/8102f7fbee26792830e54e80b3488714ac559e092c59beb2e311cf8e88f475d6
121:name=systemd:/default/8102f7fbee26792830e54e80b3488714ac559e092c59beb2e311cf8e88f475d6

而对于rootfs,容器是使用mount namespace实现的。mount namespace与挂载操作结合使用,处于不同mount namespace中的进程看到的是不同的挂载点视图。 这样容器进程的rootfs就和宿主机系统以及其他容器进程隔离区分开来了。