深入刨析容器(四):深入理解容器镜像

文章详细介绍了容器如何通过Namespace和Cgroups实现与宿主机的隔离,尤其是MountNamespace在文件系统隔离中的作用。通过代码示例展示了如何创建一个新的挂载命名空间,并解释了为何容器进程仍能看到宿主机的文件系统。接着,文章讨论了chroot和rootfs的概念,以及Docker如何利用AuFS实现层的概念,以实现更高效的文件系统隔离和镜像分层。最后,提到了DockerVolume如何处理数据持久化和共享。

容器通过Namespace和Cgroups将自己与宿主机隔离,那么容器里的进程看到文件系统又是什么样子的呢?容器里的程序应该看到完全独立的文件系统,这样它就可以在自己的容器目录(比如 /tmp)下进行操作,而完全不会受宿主机以及其他容器的影响。

但真的是这样情况吗?

一听到文件系统的隔离我们就能想到Mount Namespace。那我们接下来就来讲讲它。

1.Mount Namespace

Mount Namespace:用来隔离各个进程看到的挂载点视图,在不同的Namespace进程中,看到的文件系统层次是不一样的。

我们来个小验证对这个问题进行验证下:在创建子进程时开启指定的 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("Something's 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;
}

这段代码的功能非常简单:在 main 函数里,我们通过 clone() 系统调用创建了一个新的子进程 container_main,并且声明要为它启用 Mount Namespace(即:CLONE_NEWNS 标志)。

而这个子进程执行的,是一个“/bin/bash”程序,也就是一个 shell。所以这个 shell 就运行在了 Mount Namespace 的隔离环境中。

来一起编译下程序:

$ gcc -o ns ns.c
$ ./ns
Parent - start a container!
Container - inside the container!

这样我们就进入了容器的内部,这时我们执行ls查看文件,发现/tmp目录下的内容和宿主机完全一样,

$ ls /tmp
# 你会看到好多宿主机的文件

即使开启了Mount Namespace。容器进程看到的文件也和宿主机的文件一样。

原因是:我们需要真正的“挂载”操作后才,进程的视图才会被改变,在此之前,新创建的容器直接继承宿主机的各个挂载点,解决办法是,在创建进程时除了声明要启用 Mount Namespace 之外,我们需要先告诉容器进程,我们要挂载哪个目录。


int container_main(void* arg)
{
  printf("Container - inside the container!\n");
  // 如果你的机器的根目录的挂载类型是shared,那必须先重新挂载根目录
  // mount("", "/", NULL, MS_PRIVATE, "");
  mount("none", "/tmp", "tmpfs", 0, "");
  execv(container_args[0], container_args);
  printf("Something's wrong!\n");
  return 1;
}

可以看到,在修改后的代码里

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值