本文 首发于 🌱 煎茶转载 请注明 来源

前置知识

  • Dockerfile 中可以通过 FROM scratch 引用一个docker内置的 空镜像
  • Docker 容器的内核都是 共享 宿主操作系统的 内核,容器启动后 docker 会自动在容器内建立系统目录: dev , etc , proc , run , sys 及系统文件;
  • Docker 容器内是一个 隔离 的基于宿主系统内核的运行环境(或理解为操作系统)。Docker 内的操作系统是以 动态库、静态库、可执行程序及其他资源文件 形态体现,如CentOS就是将CentOS的各种系统库、工具库及程序文件打包成Docker镜像。
  • 一个最小的能在 Docker 运行的程序可以通过静态编译实现,由于没有任何依赖(包括操作系统依赖,不含内核),可以直接在一个只包含该程序的 Docker 容器中启动起来;
  • 而一个动态编译的程序,通常引用了 系统库 和其他 第三方库。其中系统库主要有: ld-linux , libdl , libm , libc , libm。这种情况下,就必须按照linux约定将系统库及第三方库放到镜像的 /lib/lib64 目录下(现代系统通常都用64位,64位库放到 /lib64 下,注意 /lib64 是到 /usr/lib64 的软链接)。如果依赖库不全,docker 容器启动的时候会报错: standard_init_linux.go:175: exec user process caused "no such file or directory

注:前置知识来源于: 《基于busybox构建最小linux Docker镜像系统》,文章主体根据实际情况发展推进。

此前对 Docker 的理解仅仅停留在:拉取一个基础镜像 → 拷入程序和运行库 → 运行。但最近需要在 SW64 平台验证 Docker 并跑业务,软硬件供应商无法提供配套镜像站,因此需要从零做适配该架构的镜像。

申威(英语:ShenWeiSunway)是江南计算技术研究所开发的微处理器系列。此种处理器所使用架构的细节仍然不得而知。申威原本属于Alpha阵营,指令集也是基于Alpha进行扩展。

在该架构上所有的软件程序都需要使用源码重编,即使是 Docker 镜像也不例外,因为该平台从 CPU 指令集开始就是独立的一套东西,与当前流行的 X86 ,ARM 无法通用

为了构建该平台的 Docker 测试镜像,有两种方案:

  • 基于 busybox 构建带有常用 Linux 命令的镜像;
  • 基于当前操作系统直接打包构建镜像。

为了从更底层了解 Docker 构建的原理和方法,本次介绍基于 busybox 构建的方法和流程。

构建环境

  • CPU: SW1621
  • OS: Uniontech OS Server 20 Enterprise

构建步骤

Step1: 编译准备 busybox:

BusyBox是一个遵循GPL协议、以自由软件形式发行的应用程序。Busybox在单一的可执行文件中提供了精简的Unix工具集,可运行于多款POSIX环境的操作系统,例如Linux(包括Android)、Hurd、FreeBSD等等。由于BusyBox可执行文件的文件比较小,使得它非常适合使用于嵌入式系统。作者将BusyBox称为“嵌入式Linux的瑞士军刀”。 —— BusyBox By Wikipedia

首先获取源码:

$ cd ~/kvm
$ wget https://busybox.net/downloads/busybox-1.32.1.tar.bz2
#下载备用链接: https://od.srpr.cc/acgg0/busybox-1.32.1.tar.bz2
# 可使用 --no-check-certificate 参数跳过证书验证
$ tar -jxvf busybox-1.32.1.tar.bz2    #解压
$ cd busybox-1.32.1

之后编译:

# 编译busybox
$ make menuconfig
#修改配置如下:(空格键勾选)
Settings –>
  Build Options
   [*] Build static binary(no share libs)

# 编译
$ make -j $((`nproc`-1))
# 这一步会将编译成果整理到 _install 目录下
$ sudo make install

至此,可以看到在 _install 下已经有了我们需要的最基本的目录结构以及配套最基础的 Unix 工具集 :

$ tree ./_install/ -d
../_install/
├── bin
├── sbin
└── usr
    ├── bin
    └── sbin

5 directories

Step2: 准备所有资源:

我们先将目录中所有内容拷贝到一个单独的文件夹中,方便后面制作镜像:

$ cp -r ../busybox-1.32.1/_install/* ~/minios

再完善几个目录:

mkdir usr/lib
mkdir usr/lib64
mkdir usr/local
mkdir usr/include
mkdir var/
mkdir var/lib
mkdir var/run
mkdir var/local
mkdir var/log
mkdir tmp
ln -s usr/lib lib
ln -s usr/lib64 lib64

最终大概是这个目录架构:

$ tree ./minios/ -d
./minios/
├── bin
├── lib -> usr/lib
├── lib64 -> usr/lib64/
├── sbin
├── tmp
├── usr
│   ├── bin
│   ├── include
│   ├── lib
│   ├── lib64
│   ├── local
│   └── sbin
└── var
    ├── lib
    ├── local
    ├── log
    └── run

17 directories

至此,构建镜像所需的内容已经准备完毕。

Step3: 制作镜像 :

首先编写 Dockerfile ,内容如下:

FROM scratch
MAINTAINER Tianlun Song
ADD ./ /
RUN rm /Dockerfile

之后制作镜像:

$ docker build -t minios .
Sending build context to Docker daemon  3.152MB
Step 1/4 : FROM scratch
 ---> 
Step 2/4 : MAINTAINER Tianlun Song
 ---> Running in 3a47980ef7e4
Removing intermediate container 3a47980ef7e4
 ---> 5e9c29f1462d
Step 3/4 : ADD ./ /
 ---> 2a1fa08aa40c
Step 4/4 : RUN rm /Dockerfile
 ---> Running in 29d515878dcb
Removing intermediate container 29d515878dcb
 ---> 18fe0bfbae07
Successfully built 18fe0bfbae07
Successfully tagged minios:latest

注意这一步编写 Dockerfile 到制作镜像都是在 minios 目录下完成的, build 时注意后面的 .,这是将当前目录作为构建上下文,千万不要搞错。

如果一切顺利,这里应该就能看到制作好的镜像了。

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
minios              latest              18fe0bfbae07        32 minutes ago      2.94MB

Step4: 启动镜像:

准备这么多,启动很简单:

$ docker run --rm -it minos /bin/sh

成功启动就可以看到一个最基本的 Unix 终端环境,并且可以使用 busybox 提供的这些最基本的命令。

/ # ls
bin      dev      etc      lib      lib64    linuxrc  proc     sbin     sys      tmp      usr      var
/ # ping 119.29.29.29
PING 119.29.29.29 (119.29.29.29): 56 data bytes
64 bytes from 119.29.29.29: seq=0 ttl=49 time=22.725 ms
64 bytes from 119.29.29.29: seq=1 ttl=49 time=21.562 ms
^C
--- 119.29.29.29 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 21.562/22.143/22.725 ms
/ # 

总结

本文介绍了基于 busybox 编译构建最基本 docker 镜像的方法,不受 CPU 架构的限制,通过这一过程也可加深对于 Docker 的理解,有问题欢迎留言。

参考文献