通过《initrd&init进程》我们知道rootfs 是文件系统的根目录,其包含了操作系统所需的所有文件和目录,包括程序、库文件、配置文件、设备文件等,它是系统启动时必须加载的文件系统之一。当系统启动后,内核会首先挂载 rootfs 到 / 目录下,然后开始运行 init 进程,执行各种初始化工作。
git clone git://git.busybox.net/busybox
## 使用默认配置
make defconfig
## 或者自定义配置
make menuconfig
make install
## 去下载交叉编译环境
wget https://releases.linaro.org/components/toolchain/binaries/6.4-2018.05/arm-linux-gnueabi/gcc-linaro-6.4.1-2018.05-x86_64_arm-linux-gnueabi.tar.xz
## 解压
tar xvf gcc-linaro-6.4.1-2018.05-x86_64_arm-linux-gnueabi.tar.xz -C /opt/
## 配置动态编译
make menuconfig
Settings --->
--- Build Options
(arm-linux-gnueabi-) Cross compiler prefix
## 编译
exports ARCH=arm
exports CROSS_COMPILE=arm-linux-gnueabi-
make
make install
## 复制busybox编译好的进 rootfs文件
cp _install/* ../rootfs/
## 查看你新环境命令要支持的库
ldd bin/sh
linux-vdso.so.1 (0x00007ffd8c19f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f714889a000)
libresolv.so.2 => /lib/x86_64-linux-gnu/libresolv.so.2 (0x00007f7148680000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f714828f000)
/lib64/ld-linux-x86-64.so.2 (0x00007f7148f3f000)
## 创建文件,并把库同路径移过来
mkdir lib lib64
cp /lib/x86_64-linux-gnu/*.so.* lib/x86_64-linux-gnu/
cp /lib64/*.so.* lib64/
## 如果是交叉编译的话移的是交叉环境里的库
cp /opt/gcc-linaro-6.4.1-2018.05-x86_64_arm-linux-gnueabi/arm-linux-gnueabi/lib ../rootfs -rap
## 初始化配置
mkdir etc
cp ./examples/bootfloppy/etc/* etc
mkdir dev proc sys tmp var
## 修改/etc/init.d/rcS
PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
export PATH LD_LIBRARY_PATH
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
## 修改/etc/fstab 主要是配置一些基本的文件系统挂载信息
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
使用rootfs主要有两种方式,chroot 与pivot_root
chroot 就是可以改变某进程的根目录,使这个进程不能访问目录之外的其他目录。
sudo chroot .
pivot_root把当前进程的root文件系统放在put_old目录,而使new_root成为新的root文件系统
改变当前工作目录的所有进程或线程的工作目录. 这个跟chroot的就有很大的区别,chroot是只改变即将运行的某进程的根目录。pviot_root主要是把整个系统切换到一个新的root目录,然后去掉对之前rootfs的依赖,以便于可以umount 之前的文件系统(pivot_root需要root权限)
unshare --mount --fork /bin/bash #需要有独立的命名空间
mkdir /new-root
mount -t tmpfs mytmpfs /new-root #new-root是一个独立的挂载点
cd /new-root
mkdir old-root #注意可以不创建old-root文件夹直接使用tmp文件夹
cp -r /ushare/busybox/* /new-root/ #new_root文件夹里面有完整rootfs的各种文件
cd ..
pivot_root /new-root/ /new-root/old-root
cd /
- 必须配合namespace使用
- 有了pivot_root,各厂商操作可以制作自己的rootfs(也就是镜像),提供给docker之前的容器商使用
构建镜像的前提是必须依赖于基础镜像(是各大厂商提供的),docker中主要有两种方式
第一种方式,相当于基于基础镜像安装插件,然后再打包个镜像出来
第二种方式,编写配置文件,运行时去解析文件的内容构建出来
docker commit这种镜像构建方式通常用在下面两个场景中:
除了这两种场景,我不建议你使用docker commit来构建生产现网环境的镜像。原因如下:
假设一个镜像文件的大小是 500MB,启动 100 个容器的话,就需要下载 500MB*100= 50GB 的文件,并且占用 50GB 的磁盘空间
解决这个问题就要用到 UnionFS – 联合文件系统。其实用下面这张图就能明白它的本质:
图中上面就是我们说的启动100个容器需要50GB的方式,下面就是使用了联合文件系统 – 即文件共享!
从图中可以看到所有APP都共用"ubuntu:18.04"发行版文件系统,这样如果一个镜像文件的大小是 500MB,操作系统是400M,APP是100M的话,100个容器,就只需要 400MB + 100MB * 100 = 1G400M左右,是远远小于50GB。
UnionFS 有很多种,Docker 目前支持的联合文件系统包括 OverlayFS, AUFS, Btrfs, VFS, ZFS 和 Device Mapper
> docker history golang:1.19.3-alpine
IMAGE CREATED CREATED BY SIZE COMMENT
c50491847fcb 6 months ago /bin/sh -c #(nop) WORKDIR /go 0B
<missing> 6 months ago /bin/sh -c mkdir -p "$GOPATH/src" "$GOPATH/b… 0B
6 months ago /bin/sh -c #(nop) ENV PATH=/go/bin:/usr/loc… 0B
6 months ago /bin/sh -c #(nop) ENV GOPATH=/go 0B
6 months ago /bin/sh -c set -eux; apk add --no-cache --v… 343MB
6 months ago /bin/sh -c #(nop) ENV GOLANG_VERSION=1.19.3 0B
6 months ago /bin/sh -c #(nop) ENV PATH=/usr/local/go/bi… 0B
6 months ago /bin/sh -c set -eux; if [ -e /etc/nsswitch.… 0B
6 months ago /bin/sh -c apk add --no-cache ca-certificates 515kB
6 months ago /bin/sh -c #(nop) CMD [" /bin/sh"] 0B
<missing> 6 months ago /bin/sh -c #(nop) ADD file:57d621536158358b1… 5.29MB
docker history 是操作顺序是从下往上看的, 如最后一条
<missing> 6 months ago /bin/sh -c #(nop) ADD file:57d621536158358b1… 5.29MB
即对就dockerFile的第一条 from alpine
file:57d621536158358b1…
对应的UnionFS 的文件ID
《<linux> busybox制作rootfs》
《Busybox制作基本rootfs》
《chroot与pivot_root总结 完整的chroot与pivot_root使用例子》
《关于制作Docker镜像?| Dockerfile快速开始》
《深入学习docker – 联合文件系 OverlayFS》