按照Docker官网,容器是运行在宿主机上的一个进程,但与宿主机上的其他进程相隔离;
这种隔离机制使用了内核中的namespace和cgroups功能;
Linux通过将系统的资源放置在不同的namespace下,实现资源的隔离;
| 类型 | 解释 |
|---|---|
| Network | 隔离网络资源 |
| Mount | 隔离文件系统的挂载点 |
| UTS | 隔离主机名和域名信息 |
| IPC | 隔离进程间通信 |
| PID | 隔离进程ID |
| User | 隔离用户和用户组ID |
clone系统调用:创建子进程
# flags: 控制新创建的进程隔离的资源
int clone(int (*child_func)(void *), void *child_stack, int flags, void *arg);
| flag | 隔离资源 | 描述 |
|---|---|---|
| CLONE_NEWCGROUP | 子进程的cgroup资源和当前进程隔离 | 隔离Cgroup根目录下不同层级目录的权限 |
| CLONE_NEWIPC | 子进程的ipc资源和当前进程隔离 | 隔离当前在不同进程间传递和交换信息的范围 |
| CLONE_NEWNET | …network… | 隔离子进程的网络栈,路由表,防火墙规则等 |
| CLONE_NEWNS | …mount… | 隔离文件系统的挂载点 |
| CLONE_NEWPID | …pid… | 隔离进程的ID空间 |
| CLONE_NEWUSER | …user… | 隔离用户uid,gid在宿主机中的权限 |
| CLONE_NEWUTS | …UTS… | 隔离子进程的主机名,hostname和NIS域名 |
(NIS域名:Network information service,用共享网络信息的集中存储)
# 查看当前进程树
pstree -p

# 查看当前所有进程
# 在linux中一切皆文件,如下图我们可以看出进程本身其实也只是一个文件
ls /proc

# 查看pid=1的进程的namespace
ls -al /proc/1/ns

#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include #define STACK_SIZE (1024 * 1024)static char container_stack[STACK_SIZE];
char* const container_args[] = {"/bin/bash",NULL
};int pipefd[2];void set_map(char* file, int inside_id, int outside_id, int len) {FILE* mapfd = fopen(file, "w");if (NULL == mapfd) {perror("open file error");return;}fprintf(mapfd, "%d %d %d", inside_id, outside_id, len);fclose(mapfd);
}void set_uid_map(pid_t pid, int inside_id, int outside_id, int len) {char file[256];sprintf(file, "/proc/%d/uid_map", pid);set_map(file, inside_id, outside_id, len);
}void set_gid_map(pid_t pid, int inside_id, int outside_id, int len) {char file[256];sprintf(file, "/proc/%d/gid_map", pid);set_map(file, inside_id, outside_id, len);
}int container_main()
{char ch;close(pipefd[1]);read(pipefd[0], &ch, 1);sethostname("container",10);/* Mount Namespace */mount("proc", "/proc", "proc", 0, NULL);mount("none", "/tmp", "tmpfs", 0, "");execv(container_args[0], container_args);return 1;
}int main()
{const int gid=getgid(), uid=getuid();pipe(pipefd);int container_pid = clone(container_main, container_stack+STACK_SIZE,CLONE_NEWCGROUP|CLONE_NEWIPC|CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWUSER | SIGCHLD, NULL);set_uid_map(container_pid, 0, uid, 1);set_gid_map(container_pid, 0, gid, 1);close(pipefd[1]);waitpid(container_pid, NULL, 0);return 0;
}