自己动手写docker-2

2.基础技术

2.1 linux namespace
  • namespace 方便隔离一系列系统资源,pid,user_id, network等,(chroot 创造目录监狱)
    • user_id:因为不同的用户很多时候会需要root权限,不可能都授予他们,namespace可以做user_id级别的隔离,使用户在namespace里面是有root权限的
    • pid:每个namespace都有一个init进程(pid=1),是初始化这个namespace的进程
    • 其他略

linux 支持的namespace

namespace api的基本系统调用

  • clone()创建新进程,根据上图的参数判断创建什么类型(类型掩码),同时子进程会被包含进去
  • unshare()将进程移出namespace
  • setns()将进程加入到namespace
// 不完整的ex,以下为调用后截图为
package main

import (
	"log"
	"os"
	"os/exec"
	"syscall"
)

func main() {
	cmd := exec.Command("bash")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,
	}
	//cmd.SysProcAttr.Credential = &syscall.Credential {Uid: uint32(1) , Gid:uint32(1)}
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stdout

	if err := cmd.Run(); err != nil {
		log.Fatal(err)
	}
}

复制代码

GO 创建UTS namespace

GO 创建IPC namespace

  • 隔离System IPC 和 POSIX mq
  • 效果可以通过ipcs比较是否一致

GO 创建PID namespace

  • 相关的系统调用对应的c函数有clone,unshare,setns
    • 对于clone会新建子进程,子进程进入新的namespace
    • 对于unsharesetns,除了PID namespace,其他namespace,进程会进入新的namespace,而对于pid namespace,该进程创建的子进程才会进入新的pid namespace,因为,很多库文件会认为进程的pid是个常量,变化会引起崩溃,即,一但进程创建,和pid namespace的关系就确定了

GO 创建Mount namespace

  • 不同namespace种文件系统层次不一样,mount()unmount()只会影响当前目录,类似chroot但是更加灵活,是最先实现的NS
  • 补充在Mount namespace里执行mount -t proc proc /proc 是因为新的namespace 并没由将proc虚拟文件挂载到/proc,直接访问会访问全局的,挂载了之后会有局部的/proc挂载目录,可能是因为COW,在新的namespace mount不会报已存在,所以和pid namespace一起创建可以看到局部的pid

network namespace

  • 一般一个物理网络的设备最多存在于一个network namespace,默认是在root namespace, 并且,如果新创建的namespace 被释放(即所有内部进程终止,并且namespace 文件没有被挂载或者打开),这个namespace的物理网卡会重新回到root namespace 而不是父进程的namespace
  • 通常docker用过创建veth对来实现

2.2 linux Cgroup

namespace 帮助进程隔离出单独空间,cgroup限制每个空间可用资源

linux Cgroup提供了对一组进程及将来子进程的资源限制,控制和统计能力,这些资源包括CPU,内存,存储和网络等

Cgroup的组件

  • cgroup:一个cgroup包含一组进程,可以在cgroup上增加Linux subsystem的各种参数配置,将一组进程和subsystem关联
  • subsystem 定义了资源的控制,对cgroup中的进程做相应的限制
    • lssubsys -a 查看kernel支持哪些
    • 系统默认为每个subsystem创建了一个hierarchy,通过类似mount | grep memory 能看到
  • hierarchy 把一组cgroup串成一个树状结构,使cgroup可以继承
  • 可以简单的通过挂载cgroup文件系统来创建
    • mount -t cgroup -o none,name=cgroup-test cgroup-test
  • 一个subsystem只能附加到一个hierarchy上
  • 一个hierarchy可以添加多个subsystem
  • 一个进程可以在多个不在一个hierarchy的cgroup中
  • fork的子进程默认在父进程cgroup中,但可以移出

docker 使用cgroup,docker创建容器时如果指定了 -m ,则会在默认的subsystem(ex:/sys/fs/cgroup/memory/)下创建(./docker/容器id子cgroup)

其他 tip:/proc/self/exe 会一直起一个执行自己的子进程(即shell)

2.3 Union File System

使用branch将不同的文件系统的文件和目录“透明的”覆盖,形成一个单一一致的文件系统,通过COW对文件读写

有意思的是,现有的graphdriver中只有少部分是真正的有写时复制语义的联合文件系统:Overlay的两个版本,从Docker早期就存在的aufs。记住联合文件系统只是一个基于文件的接口,通过把一组目录交错起来来,形成一个单一视图。所以与它不是一个真正的文件系统,如ext4或者xfs,它仅仅是站在一个已有的文件系统上提供了这些功能。在一些场景,对于底层文件系统是有要求的,并且Docker也会同时检查请求的联合文件系统和底层的文件系统,来保证它们是兼容的。

现在的linux上docker 默认使用overlay2而不是AUFS

AUFS 重写了早期的Union FS, 提高可靠性和性能,增加了写分支的负载均衡

AUFS 是Docker选用的第一种存储驱动,可以快速启动,高效利用存储和内存

image layer 和 AUFS

  • Docker image 是由一系列read-only layer组成的
    • docker history $image 可以查看image的变化

container layer 和 AUFS

  • 启动一个container时,docker会为其创建一个read-only的init layer来存储有关内容,也会创建一个read-write的layer执行写操作
    • AUFS时,删除一个文件,
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值