制作ubuntu rootfs镜像
1,简介
在项目开发过程中,搭建项目运行环境是至关重要的一步,也是项目伊始需要决定的是事情,一般情况下市面上的操作系统有基于嵌入式的实时操作系统和基于服务器版本的linux系统,有关系统的选择主要基于CPU的性能和项目的要求。
项目要求
项目要求为基于RK356x芯片,内核版本为4.19.219 ,制作ubuntu系统与客户进行接口对接,选择ubuntu系统的原因是需要ubuntu的环境能够通过apt库进行程序在线安装,方便程序管理。
2,rootfs镜像
1,下载ubuntu-base基础根文件系统
ubuntu官方基础根文件系统下载地址:
2,选择ubuntu根文件系统
根据项目内核版本为4.19.219,可选的ubuntu系统为ubuntu-18,但是当前ubuntu-18系统已经停止维护了,有些相关的apt库下载时会导致下载安装时会失败,维护成本较高,所以选择ubuntu-20系统,rk3568为arm64架构,最后的下载路径为:
http://cdimage.ubuntu.com/ubuntu-base/releases/20.04/release/ubuntu-base-20.04.5-base-arm64.tar.gz
3,制作根文件系统
1,获取主机环境文件
[root@gk-test ubuntu-20.04]$ cd /root
[root@gk-test ubuntu-20.04]$ mkdir ubuntu-20.04
[root@gk-test ubuntu-20.04]$ cd ubuntu-20.04
[root@gk-test ubuntu-20.04]$ mkdir package
[root@gk-test ubuntu-20.04]$ cd package
[root@gk-test ubuntu-20.04]$ apt install -y qemu-user-static
[root@gk-test ubuntu-20.04]$ cp -fpR /usr/bin/qemu-aarch64-static .
使用以下内容分别生成resolv.conf和sources.list文件
resolv.conf
# This is /run/systemd/resolve/stub-resolv.conf managed by man:systemd-resolved(8).
# Do not edit.
#
# This file might be symlinked as /etc/resolv.conf. If you're looking at
# /etc/resolv.conf and seeing this text, you have followed the symlink.
#
# This is a dynamic resolv.conf file for connecting local clients to the
# internal DNS stub resolver of systemd-resolved. This file lists all
# configured search domains.
#
# Run "resolvectl status" to see details about the uplink DNS servers
# currently in use.
#
# Third party programs should typically not access this file directly, but only
# through the symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a
# different way, replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.
nameserver 127.0.0.53
options edns0 trust-ad
search .
sources.list
deb http://mirrors.ustc.edu.cn/ubuntu-ports/ focal main multiverse restricted universe
deb http://mirrors.ustc.edu.cn/ubuntu-ports/ focal-backports main multiverse restricted universe
deb http://mirrors.ustc.edu.cn/ubuntu-ports/ focal-proposed main multiverse restricted universe
deb http://mirrors.ustc.edu.cn/ubuntu-ports/ focal-security main multiverse restricted universe
deb http://mirrors.ustc.edu.cn/ubuntu-ports/ focal-updates main multiverse restricted universe
deb-src http://mirrors.ustc.edu.cn/ubuntu-ports/ focal main multiverse restricted universe
deb-src http://mirrors.ustc.edu.cn/ubuntu-ports/ focal-backports main multiverse restricted universe
deb-src http://mirrors.ustc.edu.cn/ubuntu-ports/ focal-proposed main multiverse restricted universe
deb-src http://mirrors.ustc.edu.cn/ubuntu-ports/ focal-security main multiverse restricted universe
deb-src http://mirrors.ustc.edu.cn/ubuntu-ports/ focal-updates main multiverse restricted universe
2,创建脚本
通过脚本进行制作可以省掉很多重复操作,在操作过程中用到了四个脚本
-
ch-mount.sh
-
mk-base-ubuntu.sh
-
mk-rootfs-ubuntu.sh
-
mk-image.sh
挂载根文件系统中的/proc, /sys/, /dev, /dev/pts目录,主要用于chroot命令切换到文件系统中安装基本应用
[root@gk-test ubuntu-20.04]$ cat ch-mount.sh
#!/bin/bash
function mnt() {
echo "MOUNTING"
sudo mount -t proc /proc ${2}/proc
sudo mount -t sysfs /sys ${2}/sys
sudo mount -o bind /dev ${2}/dev
sudo mount -o bind /dev/pts ${2}/dev/pts
}
function umnt() {
echo "UNMOUNTING"
sudo umount ${2}/proc
sudo umount ${2}/sys
sudo umount ${2}/dev/pts
sudo umount ${2}/dev
}
if [ "$1" == "-m" ] && [ -n "$2" ] ;
then
mnt $1 $2
elif [ "$1" == "-u" ] && [ -n "$2" ];
then
umnt $1 $2
else
echo ""
echo "Either 1'st, 2'nd or both parameters were missing"
echo ""
echo "1'st parameter can be one of these: -m(mount) OR -u(umount)"
echo "2'nd parameter is the full path of rootfs directory"
echo ""
echo "For example: ch-mount.sh -m /media/sdcard"
echo ""
echo 1st parameter : ${1}
echo 2nd parameter : ${2}
fi
使用chroot命令进入文件系统并安装基础应用工具
[root@gk-test ubuntu-20.04]$ cat mk-base-ubuntu.sh
#!/bin/bash
ARCH=arm64
TARGET_ROOTFS_DIR="binary"
PACKAGE_DIR="package"
if [ ! -e ubuntu-base-20.04.5-base-$ARCH.tar.gz ]; then
wget -c http://cdimage.ubuntu.com/ubuntu-base/releases/20.04/release/ubuntu-base-20.04.5-base-$ARCH.tar.gz
fi
# create new rootfs
rm -rf $TARGET_ROOTFS_DIR
mkdir -p $TARGET_ROOTFS_DIR
tar -xzf ubuntu-base-20.04.5-base-$ARCH.tar.gz -C $TARGET_ROOTFS_DIR/
# network settings
cp -fpR $PACKAGE_DIR/sources.list $TARGET_ROOTFS_DIR/etc/apt/sources.list
cp -fpR $PACKAGE_DIR/resolv.conf $TARGET_ROOTFS_DIR/etc/
cp -fpR $PACKAGE_DIR/qemu-aarch64-static $TARGET_ROOTFS_DIR/usr/bin/
# mount
./ch-mount.sh -m $TARGET_ROOTFS_DIR
# chroot into system
cat << EOF | sudo chroot $TARGET_ROOTFS_DIR
# set user password
passwd root << IEOF
admin
admin
IEOF
# Export env vars
echo "LANG=en_US.UTF-8" >> /etc/environment
# allow root login
sed -i '/pam_securetty.so/s/^/# /g' /etc/pam.d/login
# hostname
echo "rk356x" > /etc/hostname
# set localtime
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# os-release
echo $(date)${@:+ - $@} >> /etc/os-release
# apt install
apt update
apt install -y net-tools openssh-server ifupdown alsa-utils ntp network-manager
apt install -y gdb inetutils-ping libssl-dev
apt install -y vsftpd tcpdump can-utils i2c-tools strace vim iperf3 ethtool
apt install -y netplan.io toilet htop pciutils usbutils curl whiptail gnupg
apt install -y bc xinput gdisk parted gcc sox libsox-fmt-all gpiod
apt install -y libgpiod-dev python3-pip python3-libgpiod guvcview
apt install -y rsyslog sudo dialog apt-utils ntp evtest acpid
apt install -y build-essential libjansson-dev libxml2-dev uuid-dev lrzsz curl tftp dhcpd
apt install -y autoconf libtool libtool-bin make cmake git
apt install -y lsb-release ca-certificates apt-transport-https software-properties-common gnupg2
apt install -y pkg-config unzip yasm
apt install -y libjpeg-dev liblzma-dev liblz-dev zlib1g-dev
apt install -y sqlite3 libsqlite3-dev
apt install -y libnewt-dev libssl-dev libncurses5-dev iputils-ping
apt install -y curl tftp telnet isc-dhcp-server dnsmasq bridge-utils
apt clean
# sync flash
sync
EOF
# umount
./ch-mount.sh -u $TARGET_ROOTFS_DIR
用于在后续开发中更新文件系统内容,这样就不用每次都花大量时间下载基础环境
[root@gk-test ubuntu-20.04]$ cat mk-rootfs-ubuntu.sh
#!/bin/bash
TARGET_ROOTFS_DIR="binary"
./ch-mount.sh -m $TARGET_ROOTFS_DIR
cat << EOF | sudo chroot $TARGET_ROOTFS_DIR
apt install -y mlocate
apt install -y xterm
sync
EOF
./ch-mount.sh -u $TARGET_ROOTFS_DIR
DATE=$(date +%Y%m%d)
tar zcf ubuntu-base-gaoke-$DATE.tar.gz $TARGET_ROOTFS_DIR
./mk-image.sh $TARGET_ROOTFS_DIR
将文件系统打包成镜像,在脚本mk-rootfs-ubuntu.sh中运行
[root@gk-test ubuntu-20.04-1]$ cat mk-image.sh
#!/bin/bash -e
DEST=$1
if [ -z $DEST ]; then
echo "input destination filename"
exit 0
fi
TARGET_ROOTFS_DIR=$DEST
ROOTFSIMAGE=ubuntu-rootfs.img
echo Making rootfs!
if [ -e ${ROOTFSIMAGE} ]; then
rm ${ROOTFSIMAGE}
fi
# Apparent size + maxium alignment(file_count * block_size) + maxium journal size
IMAGE_SIZE_MB=$(( $(sudo du --apparent-size -sm ${TARGET_ROOTFS_DIR} | cut -f1) + \
$(sudo find ${TARGET_ROOTFS_DIR} | wc -l) * 4 / 1024 + 64 ))
echo "1, IMAG_SIZE_MB: ${IMAGE_SIZE_MB}"
# Extra 10%
IMAGE_SIZE_MB=$(( $IMAGE_SIZE_MB * 110 / 100 ))
echo "2, IMAG_SIZE_MB: ${IMAGE_SIZE_MB}"
sudo mkfs.ext4 -d ${TARGET_ROOTFS_DIR} ${ROOTFSIMAGE} ${IMAGE_SIZE_MB}M
echo Rootfs Image: ${ROOTFSIMAGE}
运行脚本
[root@gk-test ubuntu-20.04]$ ./mk-base-ubuntu.sh
[root@gk-test ubuntu-20.04]$ ./mk-rootfs-ubuntu.sh
生成ubuntu-rootfs.img文件
查看镜像内容
1,创建挂载点
[root@gk-test ubuntu-20.04]$ mkdir mnt
2,挂载镜像
[root@gk-test ubuntu-20.04]$ mount -o loop ubuntu-rootfs.img mnt
3,如果需要修改镜像内容,则先挂载系统文件到挂载点
[root@gk-test ubuntu-20.04]$ ./ch-mount.sh -m mnt
4, 切换文件系统环境,并进入文件系统进行修改
[root@gk-test ubuntu-20.04]$ chroot mnt
5,修改完成后,退出后需要卸载挂载点
[root@gk-test ubuntu-20.04]$ ./ch-mount.sh -u mnt
[root@gk-test ubuntu-20.04]$ umount mnt