镜像是一个只读的容器模板,含有启动docker容器所需的文件系统结构及内容
Docker以镜像和在镜像基础上构建的容器为基础,以容器开发、测试、发布的单元将应用相关的所有组件和环境进行封装,避免了应用在不同平台间迁移所带来的依赖问题,确保了应用在生产环境的各阶段达到高度一致的实际效果。
+ bootfs
主要包含bootloader和kernel, bootloader主要是引导加载kernel, 当容器启动成功后,kernel被加载到内存中后而引导文件系统则会被卸载unmount
+ rootfs
是容器在启动时内部进程可见的文件系统,通常包含一个操作系统运行所需的文件系统
+ 传统linux在内核启动时首先会挂载一个只读的rootfs,检测器完整性之后再切换为读写模式
+ docker在挂载rootfs时也将其设为只读模式,挂载完毕后利用联合挂载技术在已有的只读rootfs上再挂载一个读写层。
+ 只有运行中文件系统发生变化,才会把变化的内容写到读写层,并隐藏只读层中的老版本文件
+ rootfs包含的就是典型Linux系统中的 /dev,/proc,/bin, /etc等标准目录和文件。
为了适应不同平台不同场景的存储需求,Docker提供了各种基于不同文件系统实现的存储驱动来管理实际的镜像文件
镜像在设计上将元数据和文件存储完全隔离。Docker管理元数据采用的也正是从上至下repository、image、layer是3个层次。 所以repository与image两个元数据并无物理上的镜像文件与之对应,layer则存在物理上的镜像文件与之对应。
为支持写时复制特性,根据不同操作系统底层的支持提供不同的存储驱动
存储目录
/var/lib/docker
/aufs aufs驱动工作的目录
/diff mount-id容器层,文件系统所有层的存储目录(下载的镜像内容就保存在这里)和容器层文件的差异变化会在这里出现。
/mount-id-init 最后一个只读层,用于挂载并重新生成dev/etc所列文件,这些文件与容器内的环境息息相关,但不适合被打包作为镜像的文件内容,
又不应该直接修改在宿主机文件上,所以设计了mountID-init层单独处理这些文件。这一层只在容器启动时添加。
/layers mount-id存储上述所有aufs层之间的关系等元数据,记录该层所依赖的所有其它层
/mnt aufs文件系统的挂载点,graphdriver会将diff中属于容器镜像的所有层目录以只读方式挂到mnt
/container 容器配置文件目录
/image
/aufs 存储镜像与镜像层元数据信息,真正的镜像层内容保存在aufs/diff
/imagedb/content 存储所有镜像的元数据
/layerdb 存储所有镜像层和容器层的元数据
/mounts 存储容器层元数据
/init-id init层id,这个layer存放的位置
/mount-id mount层id,这个layer存放的位置
/parent 父layer的chain-id
/share256 存储镜像层元数据
/cache-id 该层数据存放的位置,在对应驱动目录下
/diff 标识每一个layer
/parent 标识父layer的chain-id
/size 存放layer的数据大小
/tar-split.json.gz 存放layer层的json信息
/repositories.json 记录镜像仓库中所有镜像的repository和tag名
/volumes volumes的工作目录,存放所有volume数据和元数据
读写层、volumes、init-layer、只读层这几部分结构共同组成了一个容器所需的文件系统。
diff-id:通过docker pull下载镜像时,镜像的json文件中每一个layer都有一个唯一的diff-id
chain-id:chain-id是根据parent的chain-id和自身的diff-id生成的,假如没有parent,则chain-id等于diff-id,假如有parent,则chain-id等于sha256sum( “parent-chain-id diff-id”)
cache-id:随机生成的64个16进制数。cache-id标识了这个layer的数据具体存放位置
volume是存在于一个或多个容器中的特定文件或文件夹,这个目录以独立联合文件系统的形式存在于宿主机中
同一个namespace下的进程可以感知彼此的变化,而对外界进程一无所知
例子
mkdir newroot
cd newroot
cp -r /bin/ bin
chroot newroot
exit
根据需求把一系列的系统任务和子任务整合到按资源划分等级的不同组内,从而为系统资源管理提供一个统计的框架
task
表示系统的一个进程或线程
cgroup
按某种资源控制标准划分而成的任务组,包含一个或多个子系统
subsystem
资源调度器,cpu子系统可以控制cpu分配时间(/sys/fs/cgroup/cpu/docker/)
hierachy
层级是由一系列cgroup以一个树状结构排列而成,每个层级通过绑定对应的子系统进行资源控制
通过虚拟网卡实现2个namespace通信
1、创建虚拟网络环境
ip netns add net0
ip netns add net1
2、在虚拟的net0环境中执行
ip netns exec net0 ifconfig -a
ip netns exec net0 ping localhost
ip netns exec net0 ip link set lo up
ip netns exec net0 ping localhost
3、创建一对虚拟网卡
ip link add type veth
4、把veth0移动到net0环境里面,把veth1移动到net1环境里面
ip link set veth0 netns net0
ip link set veth1 netns net1
4、配置虚拟网卡
ip netns exec net0 ip link set veth0 up
ip netns exec net0 ip address add 10.0.1.1/24 dev veth0
ip netns exec net1 ip link set veth1 up
ip netns exec net1 ip address add 10.0.1.2/24 dev veth1
5、测试
ip netns exec net0 ping -c 3 10.0.1.2
ip netns exec net0 ping -c 3 10.0.1.1
ip netns exec net1 ping -c 3 10.0.1.1
通过网桥实现多个namespace通信及外网访问原理
1、创建虚拟网络环境并连接网线
ip netns add net0
ip netns add net1
ip netns add bridge
ip link add type veth
ip link set dev veth0 name net0-bridge netns net0
ip link set dev veth1 name bridge-net0 netns bridge
ip link add type veth
ip link set dev veth0 name net1-bridge netns net1
ip link set dev veth1 name bridge-net1 netns bridge
2、在bridge中创建虚拟网桥
ip netns exec bridge brctl addbr br
ip netns exec bridge ip link set dev br up
ip netns exec bridge ip link set dev bridge-net0 up
ip netns exec bridge ip link set dev bridge-net1 up
ip netns exec bridge brctl addif br bridge-net0
ip netns exec bridge brctl addif br bridge-net1
ip netns exec bridge brctl show
3、配置虚拟环境网卡
ip netns exec net0 ip link set dev net0-bridge up
ip netns exec net0 ip address add 10.0.1.1/24 dev net0-bridge
ip netns exec net1 ip link set dev net1-bridge up
ip netns exec net1 ip address add 10.0.1.2/24 dev net1-bridge
4、测试
ip netns exec net0 ping -c 3 10.0.1.2
ip netns exec net1 ping -c 3 10.0.1.1
ip netns exec bridge ping -c 3 10.0.1.2
5、需要给当前网络环境配置一个网卡ip不然没有网络路由网络不可达
ip netns exec bridge ip address add 10.0.1.3/24 dev br
6、想要ping宿主机网络怎么办?
ip netns exec bridge ping 192.168.99.100
ip link add A type veth peer name B
ip link set B netns bridge
ip netns exec bridge ip link set dev B up
ip link set A up
6、给AB网卡配置ip
ip netns exec bridge ip address add 172.22.0.11/24 dev B
ip address add 172.22.0.10/24 dev A
7、设置bridge默认网关
ip netns exec bridge route add default gw 172.22.0.10
ip netns exec bridge ping 192.168.99.100
8、设置net0默认网关
ip netns exec net0 ping 192.168.99.100
ip netns exec net0 route add default gw 10.0.1.3
ip netns exec net0 ping 192.168.99.100 不通
9、地址伪装
ip netns exec bridge iptables -t nat -A POSTROUTING -o B -j MASQUERADE
ip netns exec net0 ping 192.168.99.100
10、让虚拟网卡访问外网
ip netns exec net0 ping 8.8.8.8
iptables -t filter -I FORWARD -o A -j ACCEPT
iptables -t filter -I FORWARD -i A -j ACCEPT
iptables -t nat -A POSTROUTING -o eth0 -s 172.22.0.0/24 -j MASQUERADE
11、vbox访问mac地址
ip netns exec bridge ping 192.168.99.1
iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
ip netns exec bridge ping 192.168.99.1
影响网络连通的几个要素
bridge
默认设置,libnetwork将创建出来的容器连接到docker网桥。其与外界使用NAT.
操作例子
docker network create br3
docker run -itd --name busybox-bridge --net=br3 busybox
docker run -itd --name busybox-bridge-none busybox
docker network connect br3 busybox-bridge-none
查看容器网络和宿主机网桥及其上端口
host
libnetwork不为docker容器创建网络协议栈及独立的network namespace。
host驱动很好的解决了容器与外界通信的地址转换问题,但也降低了容器与容器建、容器与宿主机之间的网络隔离性,引起网络资源竞争的冲突。
例子
docker run -itd --name busybox-host --net=host busybox
例子
docker run -itd --name busybox busybox docker run -itd --name busybox-container --net=container:busybox-bridge busybox
例子
docker run -itd --name busybox-none --net=none busybox
DNAT来实现外部访问容器
docker run -itd -p 9901:991 --name busybox-dnat busybox
云平台厂家
如果你从头看到尾那真是太棒了,如果你也对docker技术感兴趣欢迎popo(hzchenzhiliang@corp.netease.com)联系交流。
相关阅读:Docker容器的原理与实践(上)
本文来自网易实践者社区,经作者陈志良授权发布。