docker-容器镜像(容器中的文件系统)

出门莫恨无人随,书中车马多如簇。这篇文章主要讲述docker-容器镜像(容器中的文件系统)相关的知识,希望能为你提供帮助。
本篇内容是学习了张磊老师和孟凡杰老师的内容进行的实验汇总。
Namespace的作用是隔离
Cgroup的作用是资源限制
那么容器中的文件系统又是怎么回事呢????
1.不仅仅是开启Mount Namespace由于上面我们学习了Namespace,所以我们可能会想到这是由于Mnt Namespace,所以每个容器中的文件系统才能够相互隔离,互不干扰。那实际真的是这样吗?
1.1先查看下宿主机上信息
查看一下宿主机上的 /tmp目录

vagrant@ubuntu-focal:~$ sudo -i
root@ubuntu-focal:~# ll /tmp/
total 44
drwxrwxrwt 11 root root 4096 Jan 23 08:34 ./
drwxr-xr-x 20 root root 4096 Jan 23 08:34 ../
drwxrwxrwt2 root root 4096 Jan 23 08:34 .ICE-unix/
drwxrwxrwt2 root root 4096 Jan 23 08:34 .Test-unix/
drwxrwxrwt2 root root 4096 Jan 23 08:34 .X11-unix/
drwxrwxrwt2 root root 4096 Jan 23 08:34 .XIM-unix/
drwxrwxrwt2 root root 4096 Jan 23 08:34 .font-unix/
drwx------3 root root 4096 Jan 23 08:34 snap.lxd/
drwx------3 root root 4096 Jan 23 08:34 systemd-private-bf43bcade3ec45a69d7fd23b0b0514f5-systemd-logind.service-5Q497g/
drwx------3 root root 4096 Jan 23 08:34 systemd-private-bf43bcade3ec45a69d7fd23b0b0514f5-systemd-resolved.service-YkKmZe/
drwx------3 root root 4096 Jan 23 08:34 systemd-private-bf43bcade3ec45a69d7fd23b0b0514f5-systemd-timedated.service-urwvti/

查看一下挂载情况,没有/tmp的挂载记录
root@ubuntu-focal:~# mount -l | grep tmpfs
udev on /dev type devtmpfs (rw,nosuid,noexec,relatime,size=482912k,nr_inodes=120728,mode=755)
tmpfs on /run type tmpfs (rw,nosuid,nodev,noexec,relatime,size=100012k,mode=755)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
tmpfs on /run/snapd/ns type tmpfs (rw,nosuid,nodev,noexec,relatime,size=100012k,mode=755)
tmpfs on /run/user/1000 type tmpfs (rw,nosuid,nodev,relatime,size=100008k,mode=700,uid=1000,gid=1000)

查看一下进程信息,没有/bin/bash进程,因为后面我们会运行这个程序
root@ubuntu-focal:~# ps -ef|grep /bin/bash
root149014410 09:15 pts/000:00:00 grep --color=auto /bin/bash

1.2仅开启Mount Namespace
1.2.1准备程序下面我们做一个实验,准备一段程序ns.c
我的环境是ubuntu 20.04,需要安装一下gcc
程序解析:
在main函数中,通过clone()系统调用创建了一个新的子进程container_main,并声明要为他开启Mount Namespace (即CLONE_NEWNS flag)。
这个子进程执行的是“/bin/bash”程序,这个程序运行在了Mount Namespace的隔离环境中。
#define _GNU_SOURCE
#include < sys/mount.h>
#include < sys/types.h>
#include < sys/wait.h>
#include < stdio.h>
#include < sched.h>
#include < signal.h>
#include < unistd.h>
#define STACK_SIZE (1024 * 1024)
static char container_stack[STACK_SIZE];
char* const container_args[] =
"/bin/bash",
NULL
;

int container_main(void* arg)

printf("Container - inside the container!\\n");
execv(container_args[0], container_args);
printf("Somethings wrong!\\n");
return 1;


int main()

printf("Parent - start a container!\\n");
int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWNS | SIGCHLD , NULL);
waitpid(container_pid, NULL, 0);
printf("Parent - container stopped!\\n");
return 0;

1.2.2程序打包并执行执行程序就进入了一个子进程中,在这个子进程中执行ls /tmp,发现/tmp目录下的内容和上面宿主机的内容是一样的。
$ gcc -o ns ns.c
$ ./ns
Parent - start a container!
Container - inside the container!

编译程序
root@ubuntu-focal:~# gcc -o ns ns.c

执行程序,就进入这个子进程中。
root@ubuntu-focal:~# ./ns
Parent - start a container!
Container - inside the container!

发现多了/bin/bash子进程
root@ubuntu-focal:/opt# ps -ef|grep /bin/bash
root189418930 09:22 pts/000:00:00 /bin/bash
root191018940 09:22 pts/000:00:00 grep --color=auto /bin/bash

查看/tmp目录,没有变化
root@ubuntu-focal:~# ll /tmp
total 40
drwxrwxrwt 10 root root 4096 Jan 23 08:40 ./
drwxr-xr-x 20 root root 4096 Jan 23 08:34 ../
drwxrwxrwt2 root root 4096 Jan 23 08:34 .ICE-unix/
drwxrwxrwt2 root root 4096 Jan 23 08:34 .Test-unix/
drwxrwxrwt2 root root 4096 Jan 23 08:34 .X11-unix/
drwxrwxrwt2 root root 4096 Jan 23 08:34 .XIM-unix/
drwxrwxrwt2 root root 4096 Jan 23 08:34 .font-unix/
drwx------3 root root 4096 Jan 23 08:34 snap.lxd/
drwx------3 root root 4096 Jan 23 08:34 systemd-private-bf43bcade3ec45a69d7fd23b0b0514f5-systemd-logind.service-5Q497g/
drwx------3 root root 4096 Jan 23 08:34 systemd-private-bf43bcade3ec45a69d7fd23b0b0514f5-systemd-resolved.service-YkKmZe/

查看挂载情况
挂在记录没有改变,因没有挂载操作
root@ubuntu-focal:~# mount -l | grep tmpfs
udev on /dev type devtmpfs (rw,nosuid,noexec,relatime,size=482912k,nr_inodes=120728,mode=755)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
tmpfs on /run type tmpfs (rw,nosuid,nodev,noexec,relatime,size=100012k,mode=755)
tmpfs on /run/lock type tmpfs (rw,nosuid,nodev,noexec,relatime,size=5120k)
tmpfs on /run/snapd/ns type tmpfs (rw,nosuid,nodev,noexec,relatime,size=100012k,mode=755)
tmpfs on /run/user/1000 type tmpfs (rw,nosuid,nodev,relatime,size=100008k,mode=700,uid=1000,gid=1000)
tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
root@ubuntu-focal:~#

从上面情况可以看出:
仅开启Mount Namespace ,容器进程看到的文件系统和宿主机完全一样。
仔细思考一下:Mount Namespace修改的是容器进程对文件系统“挂载点”的认知。即只有发生挂载操作后,文件系统才会发生变化。
1.3开启Mount Namespace时,伴随着挂载操作
在创建新的进程时,除了开启Mount namespace,我们还可以告诉新的进程,有哪些目录需要重新挂载,这里我们假如重新挂载/tmp目录。
1.3.1准备程序【docker-容器镜像(容器中的文件系统)】对上面的c程序的container_main方法中新增一行mount操作
root@ubuntu-focal:/opt# cat nsnew.c

#define _GNU_SOURCE
#include < sys/mount.h>
#include < sys/types.h>
#include < sys/wait.h>
#include < stdio.h>
#include < sched.h>
#include < signal.h>
#include < unistd.h>
#define STACK_SIZE (1024 * 1024)
static char container_stack[STACK_SIZE];
char* const container_args[] =
"/bin/bash",
NULL
;

int container_main(void* arg)

printf("Container - inside the container!\\n");
mount("none", "/tmp", "tmpfs", 0, "");
execv(container_args[0], container_args);
printf("Somethings wrong!\\n");
return 1;


int main()

printf("Parent - start a container!\\n");
int container_pid = clone(container_main, container_stack+STACK_SIZE,

    推荐阅读