13. 使用Docker构建根文件系统

我们的SDK使用Ubuntu20.04作为标准开发环境,但是由于不同版本的Ubuntu镜像构建环境不同, 导致我们在构建不同版本的根文件系统时要频繁安装新的构建环境,不仅浪费了大量时间,还容易导致构建失败。

为了解决以上问题,我们借助Docker来隔离我们的根文件系统构建环境。

13.1. 什么是Docker

Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中, 然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化。 容器是完全使用沙箱机制,相互之间不会有任何接口。

简单理解,Docker就是一个小型的虚拟化系统,可以起到与主机环境隔离的作用。 下图是docker的logo,是一个小鲸鱼上托着很多集装箱,很生动形象的描述了docker的作用。

../../_images/docker-logo.png

docker的官网是 https://www.docker.com/

13.2. Docker的安装

在不同的操作系统上安装Docker有不同的方法,我们主要使用的是Ubuntu操作系统。 其他系统的安装方法可以参考官方文档 https://docs.docker.com/engine/install/

我们在Ubuntu虚拟机上安装 Docker Engine 即可,具体安装过程如下

13.2.1. 卸载旧版本

在尝试安装新版本之前卸载旧版本

1
sudo apt-get remove docker docker-engine docker.io containerd runc

13.2.2. 使用存储库安装

在新主机上首次安装 Docker Engine 之前,需要设置 Docker 存储库。之后就可以从存储库安装和更新 Docker。

13.2.2.1. 设置存储库

  • 更新apt包索引并安装相关软件包以允许apt通过HTTPS使用docker存储库:

1
2
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release
  • 添加 Docker 的官方 GPG 密钥:

1
2
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
  • 设置存储库:

1
2
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

13.2.2.2. 安装 Docker engine

1
2
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

13.2.2.3. 验证安装完成

使用以下命令打印出版本号即为安装成功

1
2
3
4
sudo docker -v

# 打印出版本号
Docker version 20.10.22, build 3a2c30b

13.3. 创建本地docker镜像

由于Docker的镜像服务器在国外,访问速度很慢,我们使用本地Dockerfile来创建Docker镜像。

本地Dockerfile存放在Ubuntu根文件系统构建的脚本仓库的ubuntu22.04分支下,我们克隆相应的分支。

1
git clone --branch=ubuntu22.04 --depth=1 https://github.com/LubanCat/ubuntu.git

然后进入克隆的ubuntu目录下,执行 docker build 命令构建Docker镜像,build_rootfs:2204是我们设置的镜像名称。

1
2
3
cd ubuntu/Docker

sudo docker build -t build_rootfs:2204 .
../../_images/dockerfile01.png ../../_images/dockerfile02.png

等待docker镜像构建完成以后,我们用下面命令查看构建好的docker镜像。

../../_images/dockerfile03.png

我们可以看到镜像名是build_rootfs,他的TAG是2204,和我们设置的符合。他的镜像ID是4fa5fe7845df,大小是278M。

13.4. 创建docker容器

执行 docker run 命令运行docker镜像,并将SDK挂载到运行docker镜像的容器中,进入工作目录。

1
2
3
sudo docker run --name build_rootfs -it --privileged -v /home/jiawen/RK356X_LINUX_SDK:/works build_rootfs:2204 /bin/bash

cd works/
  • docker run :运行容器。

  • –name build_rootfs:设置容器的名称。

  • -it:以交互模式运行容器。

  • –privileged:以特权模式运行容器。

  • -v /home/jiawen/RK356X_LINUX_SDK:/works 设置挂载到容器的目录,:前是宿主机的路径,:后是挂载到容器的路径,使用绝对路径。这里把整个SDK挂载到容器的/works目录下。

  • build_rootfs:2204 容器使用的镜像,这里指定了镜像的名称,使用镜像ID也可以。

  • /bin/bash 交互模式中使用的shell解释器。

../../_images/docker01.png

图中可以看到,执行完运行运行容器的命令后,我们从jiawen@dev120变成了root@27ddbf0ffab2,这说明我们现在已经进入了容器,以root用户运行,容器ID是27ddbf0ffab2。

注意此时不要关闭当前的终端,关闭中断则失去了和当前容器的连接。

13.5. 构建根文件系统

根文件系统的构建方法和在虚拟机中是一样的,我们可以查看当前根文件系统构建脚本仓库中的readme文件,这里做简单演示。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 进入ubuntu根文件系统构建脚本仓库
cd /works/ubuntu

# 安装相关构建依赖
apt-get install binfmt-support qemu-user-static
dpkg -i ubuntu-build-service/packages/*
apt-get install -f

# 构建镜像
./mk-base-ubuntu.sh
./mk-ubuntu-rootfs.sh

运行完成以上命令后,Ubuntu根文件系统就构建完成了。

13.6. docker的相关操作命令

13.6.1. 退出当前容器

在当前终端运行 exit 即可停止并退出当前容器

13.6.2. 查看当前正在运行的容器

1
sudo docker ps

-a 选项,查看所有容器,包括退出的和正在运行的。

13.6.3. 重新运行停止的容器并进入容器

1
sudo docker start build_rootfs

重新运行停止的容器,可以指定容器名称,也可以指定容器ID

1
sudo docker attach 27ddbf0ffab2

进入正在运行的容器,可以指定容器名称,也可以指定容器ID

13.6.4. 删除容器

1
sudo docker rm build_rootfs

删除容器,可以指定容器名称,也可以指定容器ID

-f 选项,强制删除未停止的容器

13.6.5. 删除镜像

1
sudo docker rmi build_rootfs:2204

删除镜像,可以指定镜像名称:TAG,也可以指定镜像ID