Docker
Docker
我现在的Ubuntu是20.04版本的,我要开发编译飞凌嵌入式的SDK(22.04),如果不想重新装一个22.04版本的Ubuntu,那就装一个Docker
但是野火的教程是专门为了“制作纯净的 Ubuntu 根文件系统”设计的,默认使用 Docker 的 root 权限,在编译 U-Boot 和内核(Linux 源码) 时,如果用 root 权限编译,生成的所有文件(.o, .bin, .img)在你的宿主机上也会变成 root 拥有。以后你不用 sudo 就连删都删不掉,非常麻烦
因此我们这里自己创建一个专门用来开发OK3576的容器,这个容器是为了“编译整套底层源码(U-Boot、Kernel)”设计的,在 Dockerfile 中通过 USER_ID 和 GROUP_ID 创建了一个和你宿主机一模一样的普通用户
安装Docker
使用存储库安装
在新主机上首次安装 Docker Engine 之前,需要设置 Docker 存储库。之后就可以从存储库安装和更新 Docker。
设置存储库
更新apt包索引并安装相关软件包以允许apt通过HTTPS使用docker存储库
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg lsb-release
添加 Docker 的官方 GPG 密钥
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
设置存储库
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
安装 Docker engine
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
验证安装完成
sudo docker -v

创建 Dockerfile
在现有的 Ubuntu 20.04 电脑上,新建一个空白目录,然后在里面创建一个名为 Dockerfile 的文件(没有任何后缀名),并将以下内容复制进去
# 使用官方 Ubuntu 22.04 作为基础镜像
FROM ubuntu:22.04
# 避免在安装软件包时弹出时区或键盘设置对话框
ENV DEBIAN_FRONTEND=noninteractive
# 1. 更新源并安装飞凌 OK3576 官方要求的所有依赖库
RUN apt-get update && apt-get install -y \
build-essential libncurses5-dev ncurses-dev lzop net-tools \
openssh-server vim git fakeroot libsqlite3-dev \
ssh make gcc libssl-dev liblz4-tool expect expect-dev g++ \
patchelf chrpath gawk texinfo diffstat binfmt-support \
qemu-user-static live-build bison flex cmake gcc-multilib \
g++-multilib unzip device-tree-compiler \
libgucharmap-2-90-dev bzip2 expat gpgv2 cpp-aarch64-linux-gnu \
libgmp-dev libmpc-dev bc python-is-python3 python2 \
sudo locales tzdata cpio \
&& rm -rf /var/lib/apt/lists/*
# 2. 设置本地化字符集(防止后续 Python 脚本报 UTF-8 编码错误)
RUN locale-gen en_US.UTF-8
ENV LANG=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
# 3. 接收宿主机用户的 UID 和 GID
ARG USER_ID=1000
ARG GROUP_ID=1000
# 4. 创建一个与宿主机同 UID 的普通用户,赋予 sudo 免密权限
RUN groupadd -g ${GROUP_ID} buildgroup && \
useradd -u ${USER_ID} -g ${GROUP_ID} -m -s /bin/bash builduser && \
echo "builduser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/builduser
# 5. 切换到普通用户并设置工作目录
USER builduser
WORKDIR /workdir

构建 Docker 镜像
在刚才保存 Dockerfile 的目录下,打开终端,执行以下命令来构建镜像。 (这里使用了 (id -g) 自动获取你当前用户的 ID,传入容器中),命令最后有一个 . (点),代表使用当前目录的 Dockerfile
docker build --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g) -t rk3576-builder:22.04 .
如果显示权限问题,Docker 的后台服务(Daemon)默认是以 root 权限运行的。作为一个普通的系统用户,没有权限去和 Docker 的通信套接字(/var/run/docker.sock)直接对话

解决方法 把当前用户加入到 docker 用户组中,这是 Docker 官方推荐的“安装后配置”步骤
将当前用户加入 docker 组
sudo usermod -aG docker $USER
刷新用户组权限
newgrp docker
敲击下面这个命令,如果不加 sudo 也没有报错,就说明可以了
docker ps

重新构建Docker镜像

SDK准备
把OK3576用户资料中的源码文件和交叉编译工具链拷贝到Ubuntu中

可以通过FileZilla传

在SDK目录解压
cat ok3576-linux-source.tar.bz2.0* > OK3576_ubuntu_source.tar.bz2

等待运行完成
tar -vxf OK3576_ubuntu_source.tar.bz2
解压完成,然后就可以把这几个文件删了ok3576-linux-source.tar.bz2*

启动并进入编译容器
需要把SDK的目录“映射”(挂载)到容器里
docker run -it --rm -v /home/okay/文档/Linux/Forlinx_SDK/ok3576-linux-source:/workdir rk3576-builder:22.04 /bin/bash
看到下面这个信息说明已经在一个纯净的 Ubuntu 22.04 环境中了

编译SDK
该源码编译需要开发环境运行内存 18G 及以上,第一次要进行整体编译,后面可以根据实际情况单独编译
全编译
在SDK源码目录下执行下面命令,编译完成后,系统镜像会在output/update/Image/ 文件夹中生成update.img
./build.sh chip //设置环境变量 ,这里选择ok3576
./build.sh //进行全编译
第一次编译时会报错

提示我们需要下载rsync,我们直接在容器里执行
sudo apt-get update
sudo apt-get install rsync
安装完后再次运行编译命令就可以了,选择对应的板卡和系统

然后执行全编译命令,等待编译完成即可

编译到后面会报错,是因为当前正在尝试编译构建 Debian 12 (Bookworm) 版本的根文件系统(Rootfs)。但是,咱们目前使用的 Ubuntu 22.04 官方软件源里自带的 live-build 工具版本太老了,还不认识 Bookworm 这个新系统。

在当前的 Docker 容器终端里,手动从源码安装最新版的 live-build 为了防止污染你的源码目录,先退到 /tmp 目录去下载和安装,装完再回到代码目录。
# 1. 卸载掉系统里版本太老的 live-build
sudo apt-get remove -y live-build
# 2. 切换到临时目录
cd /tmp
# 3. 从 Debian 官方仓库拉取支持 Bookworm 的新版源码
# (注意:这里的 %20 是原厂脚本输出的,直接复制执行即可)
git clone https://salsa.debian.org/live-team/live-build.git --depth 1 -b debian/1%20230131
# 4. 进入源码目录并删掉可能引起编译错误的说明文档目录
cd live-build
rm -rf manpages/po/
# 5. 编译并安装新版 live-build
sudo make install -j8
# 6. 安装完成后,回到你的代码工作目录
cd /workdir
# 7.安装curl
sudo apt-get install -y curl
运行完上面的命令后重新执行编译命令编译代码
又报错了,这是因为“单纯编译内核(Kernel)不需要特权,但构建根文件系统(Rootfs)时,必须赋予最高级别的 —privileged 特权
普通的 Docker 容器出于安全限制,是绝对禁止在容器内执行 mount 挂载命令的,所以系统无情地拒绝了你,报了 permission denied

解决 由于我们之前启动容器加了 —rm 参数,退出后容器会销毁,之前手动装的 rsync、curl 和新版 live-build 需要重新配置一下 先在终端输入exit退出Docker,回到Ubuntu20.04 加上超级特权重新启动容器
docker run -it --rm --privileged -v /home/okay/文档/Linux/Forlinx_SDK/ok3576-linux-source:/workdir rk3576-builder:22.04 /bin/bash
一键恢复之前装过的依赖 进入容器后直接把下面这整段代码一次性复制粘贴进去并回车,会自动把之前缺的工具全补齐
sudo apt-get update && \
sudo apt-get install -y rsync curl && \
sudo apt-get remove -y live-build && \
cd /tmp && \
git clone https://salsa.debian.org/live-team/live-build.git --depth 1 -b debian/1%20230131 && \
cd live-build && \
rm -rf manpages/po/ && \
sudo make install -j8 && \
cd /workdir
完成后再次编译

到目前为止,所有的分区镜像文件都已经构建完了,就差打包成update.img了
到最后构建的时候还会报错,原因是我们的Docker还缺少了一个环境依赖包
sudo apt-get update
sudo apt-get install -y bsdmainutils bsdextrautils
再次打包
./build.sh updateimg
打包成功

然后直接exit退出Docker,Ubuntu的SDK目录下就是编译出来的文件了

单独编译
下面是单独编译内核镜像
./build.sh chip //设置环境变量 ,这里选择ok3576
./build.sh kernel //编译内核
完美Docker
前面配置的Docker在编译过程中还会缺少很多环境依赖包和工具,下面是完美的Docker配置
Dockerfile
# 使用官方 Ubuntu 22.04 作为基础镜像
FROM ubuntu:22.04
# 避免在安装软件包时弹出交互对话框
ENV DEBIAN_FRONTEND=noninteractive
# 第一步:安装飞凌官方指定的依赖 + 我们踩坑发现的隐藏依赖
RUN apt-get update && apt-get install -y \
build-essential libncurses5-dev ncurses-dev lzop net-tools \
openssh-server vim git fakeroot libsqlite3-dev \
ssh make gcc libssl-dev liblz4-tool expect expect-dev g++ \
patchelf chrpath gawk texinfo diffstat binfmt-support \
qemu-user-static live-build bison flex cmake gcc-multilib \
g++-multilib unzip device-tree-compiler \
libgucharmap-2-90-dev bzip2 expat gpgv2 cpp-aarch64-linux-gnu \
libgmp-dev libmpc-dev bc python-is-python3 python2 \
sudo locales tzdata cpio ca-certificates \
rsync \
curl \
bsdmainutils bsdextrautils \
&& rm -rf /var/lib/apt/lists/*
# 👆 上面新增了 rsync (防 check-sdk 报错), curl (防网络检查报错),
# bsdmainutils 和 bsdextrautils (提供 hexdump,防 rkImageMaker 报错)
# 第二步:提前在镜像里修复 live-build 版本过低不支持 Bookworm 的问题
RUN apt-get update && apt-get remove -y live-build && \
cd /tmp && \
git clone https://salsa.debian.org/live-team/live-build.git --depth 1 -b debian/1%20230131 && \
cd live-build && \
rm -rf manpages/po/ && \
make install -j8 && \
cd / && rm -rf /tmp/live-build && \
rm -rf /var/lib/apt/lists/*
# 第三步:设置本地化字符集(防止 Python 脚本乱码)
RUN locale-gen en_US.UTF-8
ENV LANG=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
# 第四步:接收宿主机用户的 UID 和 GID,避免编译产物变成 root 权限
ARG USER_ID=1000
ARG GROUP_ID=1000
RUN groupadd -g ${GROUP_ID} buildgroup && \
useradd -u ${USER_ID} -g ${GROUP_ID} -m -s /bin/bash builduser && \
echo "builduser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/builduser
# 切换到普通用户
USER builduser
WORKDIR /workdir
构建镜像
docker build --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g) -t rk3576-builder:ultimate .
启动Docker
docker run -it --rm --privileged -v /home/okay/文档/Linux/Forlinx_SDK/ok3576-linux-source:/workdir rk3576-builder:ultimate /bin/bash
这个Docker是通用的,不是只能编译Forlinx的SDK,其他的都可以,只不过其他的可能需要安装其他额外的依赖,直接在Docker里面安装就行了,只不过每次退出再进来要重新安装,不想那么麻烦的话可以固定在Dockerfile里
评论