镜像制作工具diskimage-builder介绍

2022-12-07,,,

简介

diskimage-builder(简称dib)是一款用于构建系统镜像的工具,它被设计用于OpenStack的TripleO项目,支持qocw2、vhd、raw等主流镜像格式。

在众多系统镜像构建工具中,dib与众不同的地方在于其对元素(element)的设计。在dib中,所有想要构建的实体都被抽象为一个个的元素,元素与元素之间相互依赖,形成一种类似树的结构。dib拥有一些内置元素,位于diskimage-builder/elements目录中,可以通过ELEMENTS_PATH环境变量指定额外的元素目录。

例如:使用dib构建镜像时指定centos-minimal元素。

graph TD
centos-minimal-->yum-minimal
yum-minimal-->redhat-common
yum-minimal-->rpm-distro
yum-minimal-->yum
redhat-common-->package-installs
redhat-common-->sysprep
yum-->install-bin
package-installs-->install-bin
package-installs-->pkg-map

与yum包管理器中的rpm包类似,当构建系统镜像时指定centos-minimal元素时,dib会解析该元素的所有依赖元素,生成所有需要构建的元素,然后按顺序安装它们,最终生成一个完整的镜像。

概念

系统镜像

系统镜像指包含了可运行系统的虚拟磁盘文件。磁盘虚拟化是云计算的基础技术之一,dib支持的系统镜像格式有:qcow2,vhd,raw。在完成系统镜像构建后,dib会输出一个如上格式的虚拟磁盘文件,里面包含了构建好的系统。

如果要构建一个可启动的系统镜像,需要在构建时添加vm元素:disk-image-create <distro> vm

元素

构建镜像需要给dib传递一系列的元素,这些元素决定了镜像该如何构建。

dib有着各种各样的元素。某些元素提供了一个root文件系统,例如ubuntu、fedora等等;另一些元素则在此基础上修改,并最终创建出我们需要的镜像;还有一些比较特殊的元素,例如vm,此元素会为镜像创建一个bootloader,确保镜像是可启动的。

输出格式

默认情况下dib会创建qcow2格式的镜像,可以通过-t <format>参数指定需要的镜像格式,多种格式以逗号分隔。目前dib支持如下格式:

qcow2:qemu支持的镜像格式之一,虚拟化中主流的镜像格式
tar:归档格式
tgz:归档与压缩结合的格式
squashfs:基于Linux内核的压缩只读文件系统
vhd:Hyper-V支持的一种镜像格式
docker:docker支持的镜像格式,可被docker import导入
raw:裸镜像格式

镜像布局

镜像文件与真正的硬盘一样,拥有分区、lvm、磁盘加密等等布局,这些布局在镜像构建的初始就应该做好,后续对镜像的改动也几乎不会去修改这些布局。

dib提供了一些针对镜像布局的元素,例如:vm,当使用该元素时还需额外指定一个block-device-*的元素,可选mbr、gpt以及efi,用来表示分区格式。如下命令创建了一个gpt格式的镜像文件。

disk-image-create -o centos vm block-device-gpt centos-minimal

默认情况下,定义镜像布局的配置位于各block-device-*元素目录的block-device-default.yaml文件中,如需额外配置,可以通过DIB_BLOCK_DEVICE_CONFIG环境变量指定一个文件路径。

export DIB_BLOCK_DEVICE_CONFIG=file:///path/to/config

若构建镜像时不指定vm元素,那么镜像中将只包含root文件系统,没有分区信息。

镜像布局从上往下分为5个级别,分别代表着不同的布局划分步骤,以block-device-gpt元素的镜像布局配置文件为例:

- local_loop: # Level 0
name: image0 - partitioning: # Level 1
base: image0
label: gpt
partitions:
- name: BSP
type: 'EF02'
size: 8MiB
- name: root
flags: [ boot ]
size: 100%
mkfs: # Level 2
type: ext4
mount: # Level 3
mount_point: /
fstab: # Level 4
options: "defaults"
fsck-passno: 1

其中:

Level 0

Local Loop:该模块用于生成一个本地镜像文件

name:镜像文件的名称,必选
size:虚拟磁盘的大小,可选
directory:镜像文件所在的位置,可选
Level 1
Partitioning:该模块用于为已有块设备生成分区

base:块设备的名称,一般指定为Local Loop模块中镜像文件的名称,必选
label:分区表类型,可选mbr或gpt,必选
align:分区对齐,仅mbr分区需要,可选
partitions:分区列表,每一个列表元素描述了一个分区
name:分区的名称,必选
flags:分区的标识,可选boot或primary,仅mbr分区需要,可选
size:分区的大小,可选绝对值,如10GiB、1.75TB,或者相对值,如33%,相对值的话将依据剩余空闲空间计算,必选
type:记录在分区表中的分区类型,MBR分区的默认值为0x83,GPT分区的默认值为8300,可选
LVM:该模块用于为已有分区生成逻辑卷
pvs:物理卷的列表,每个列表元素描述了一个物理卷(Physical Volume)

name:物理卷的名称,必选
base:分区的名称,LVM在此分区上创建物理卷,必选
options:创建物理卷时的可选选项列表,即传递给pvcreate命令的参数列表,可选
vgs:卷组的列表,每个列表元素描述了一个卷组(Volume Group)
name:卷组的名称,必选
base:物理卷的名称列表,LVM在这些物理卷上创建卷组,必选
options:创建卷组时的可选选项列表,即传递给vgcreate命令的参数列表,可选
lvs:逻辑卷的列表,每个列表元素描述了一个逻辑卷(Logical Volume)
name:逻辑卷的名称,必选
base:卷组的名称,LVM在此卷组上创建逻辑卷,必选
size:逻辑卷的精确大小,与lvcreate命令的-L参数有着同样的语法,可选,size和extents参数必须二选一
extents:逻辑卷的相对大小,与lvcreate命令的-l参数有着同样的语法,可选,size和extents参数必须二选一
options:创建逻辑卷的可选选项列表,即传递给lvcreate命令的参数列表,可选
Level 2
Mkfs:该模块用于为已有分区创建文件系统

base:分区的名称,Mkfs在此分区上创建文件系统,必选
name:文件系统的名称,必选
type:文件系统的类型,比如ext4或xfs,必选
label:文件系统的标识,可被grub和fstab使用,默认和名称相同,可选
opts:创建文件系统的可选选项列表,即传递给mkfs命令的参数列表,可选
uuid:文件系统的uuid,目前支持ext2、ext3、ext4、xfs
Level 3
Mount:该模块用于挂载一个文件系统

base:文件系统的名称,Mount会挂载此文件系统,必选
name:挂载点的名称,必选
mount_point:挂载点的路径,必选
Level 4
fstab:该模块用于创建fstab入口

base:挂载点的名称,用于写入fstab,必选
name:fstab入口的名称,必选
options:特殊的挂载选项,对应fstab中的第四列,默认为default,可选
dump-freq:文件系统是否需要导出,对应fstab的第五列,默认为0,可选
fsck-passno:是否需要运行fsck,该工具用来检测/修复文件系统,对应fstab的第六列,默认为2,可选

执行阶段

每个元素下有许多目录,这些目录以阶段命名,dib会在不同的阶段执行这些目录下的脚本,这些脚本有着两位数数字的前缀,并会以数字的顺序执行。

dib共有如下阶段:

    root.d:初始化根文件系统,该阶段的主要工作是获取根文件系统的文件,并放置于工作区域($TARGET_ROOT)中。该阶段依赖于各发行版,也可以在已有镜像上定制。

    运行于:chroot外面
    输入:
    $ARCH=i386|amd64|armhf|arm64
    $TARGET_ROOT=/path/to/target/workarea
    extra-data.d:从宿主机环境中获取额外数据,这些数据会在镜像构建中使用。该阶段通常用来复制配置文件至工作区域($TMP_MOUNT_PATH)中,比如复制yum repo至$TMP_MOUNT_PATH/etc/yum.repos.d
    运行于:chroot外面
    输入:
    $TMP_HOOKS_PATH:表示chroot里面的/tmp/in_target.d目录
    pre-install.d:在chroot里面运行代码。该阶段用于在定制镜像之前做一些事先配置工作,比如说在配置dnf包管理工具、更新包缓存、安装python基础环境等等。
    运行于:chroot里面
    install.d:运行于pre-install.d之后。该阶段用于安装包,也可以做一些镜像特定的操作。
    运行于:chroot里面
    post-install.d:运行于install.d之后。该阶段往往用来做一些清理工作,比如说清理安装缓存。
    运行于:chroot里面
    post-root.d:在chroot外面运行代码。该阶段用来执行一些不能在chroot里面做且需要在安装步骤之后做的事情,根文件系统位于$TMP_BUILD_DIR/mnt目录下。
    运行于:chroot外面
    block-device.d:自定义镜像所在的块设备。在目标树生成之后执行,该步骤暂时没看到元素在使用。
    运行于:chroot外面
    输入:
    $IMAGE_BLOCK_DEVICE={path}
    $TARGET_ROOT={path}
    输出:
    $IMAGE_BLOCK_DEVICE={path}
    pre-finalise.d:该步骤用来重新挂载文件系统,到此步骤时根文件系统已经复制到最终的文件系统中,该文件系统位于$TMP_BUILD_DIR/mnt
    运行于:chroot外面
    finalise.d:该步骤是根文件系统构建的最后一步,该步骤会运行chroot到最终的文件系统中,然后执行一些脚本。该步骤往往用来生成grub配置。
    运行于:chroot里面
    cleanup.d:最后的清理工作作为收尾,该步骤用来清理一些临时配置。
    运行于:chroot外面
    输入:
    $ARCH=i386|amd64|armhf|arm64
    $TARGET_ROOT=/path/to/target/workarea

只有拥有可执行权限的文件才会执行,所以阶段目录中也可保存其他的文件,不过处于惯例,一般只在阶段目录中保存可执行脚本,数据保存在其他位置中。

除了这些阶段以外,元素还拥有其他特定的目录/文件:

environment.d/:该目录用于存放环境变量,每个阶段执行前都会加载该目录下的环境变量文件。注意不要在文件中添加如set -x这样的全局标志,这样会影响到所有的脚本。
element-deps:该文件用来保存依赖的元素列表,以换行符分隔。
element-provides:该文件用来保存本元素的别名列表,以换行符分隔。举例说表示分区类型的元素有block-device-mbr、block-device-gpt等等,上层元素需要依赖mbr、gpt中的某个分区,却不知道到底依赖其中的哪一个,若mbr、gpt元素都在element-provides文件中写入名为block-device的别名,那么上层元素写入依赖的时候只需要指定block-device元素就可以了。最后在镜像构建时通过指定如xxx block-device-mbrxxx block-device-gpt的方式来真正区分时候哪一个分区。

安装类型

同一个软件,通常会有多种不同的安装方式,例如源代码安装、分发包安装、pip安装等等。在dib中,默认的软件安装方式是源代码安装(source),可以通过添加--install-type参数或DIB_DEFAULT_INSTALLTYPE环境变量修改。

dib中的元素可以定义不同的软件包安装方式,格式为<install-dir-prefix>-<install-type>-install,以nova元素为例,该元素同时提供了source和package两种方式:

# package方式
nova/install.d/nova-package-install/74-nova
# source方式
nova/install.d/nova-source-install/74-nova

dib也可以针对单个元素的软件包安装方式进行修改,环境变量的格式为DIB_INSTALLTYPE_<install_dir_prefx>,例如:

export DIB_INSTALLTYPE_nova=package

示例

centos7-minimal

docker run -it --rm --name dib --privileged -v /dev:/dev af.frankming.com.cn/docker-drpd/openstack/centos-binary-openstack-base:train bash
dnf install -y yum-utils e4fsprogs kpartx qemu-img gdisk
pip install ironic-python-agent-builder diskimage-builder mkdir -p /tmp/repo
echo '[base]
name=CentOS-$releasever - Base
baseurl=http://10.1.14.235/centos/$releasever/os/$basearch/
gpgcheck=0 #released updates
[updates]
name=CentOS-$releasever - Updates
baseurl=http://10.1.14.235/centos/$releasever/updates/$basearch/
gpgcheck=0 #additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
baseurl=http://10.1.14.235/centos/$releasever/extras/$basearch/
gpgcheck=0 #additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus
baseurl=http://10.1.14.235/centos/$releasever/centosplus/$basearch/
gpgcheck=0
enabled=0 [epel]
name=Extra Packages for Enterprise Linux 7 - $basearch
baseurl=http://10.1.14.235/epel/7/$basearch
enabled=1
gpgcheck=0
' > /tmp/repo/base.repo export DIB_YUM_MINIMAL_BOOTSTRAP_REPOS=/tmp/repo disk-image-create vm block-device-gpt centos-minimal

centos7

docker run -it --rm --name dib --privileged -v /dev:/dev af.frankming.com.cn/docker-drpd/openstack/centos-binary-openstack-base:train bash
dnf install -y yum-utils e4fsprogs kpartx qemu-img gdisk
pip install ironic-python-agent-builder diskimage-builder export DIB_DISTRIBUTION_MIRROR=http://mirrors.frankming.com.cn/centos/
export DIB_CLOUD_IMAGES=/data/images/CentOS-7-x86_64-GenericCloud.qcow2
export DIB_LOCAL_IMAGE=/data/images/CentOS-7-x86_64-GenericCloud.qcow2
export IMAGE_NAME=centos7
export DIB_EPEL_MIRROR=http://mirrors.frankming.com.cn/epel
export DIB_EPEL_DISABLED=1
export DIB_CLOUD_INIT_DATASOURCES="ConfigDrive, OpenStack"
# /usr/local/lib/python3.9/site-packages/diskimage_builder/elements/yum/pre-install.d/01-00-centos-python3
# yum install -y http://10.33.41.25/CI/openstack-train/others/python36-PyYAML-3.13-1.el7.x86_64.rpm
disk-image-create centos7 vm cloud-init-datasources dhcp-all-interfaces iscsi-boot dracut-regenerate block-device-efi -o $IMAGE_NAME

centos8

docker run -it --rm --name dib --privileged -v /dev:/dev af.frankming.com.cn/docker-drpd/openstack/centos-binary-openstack-base:train bash
dnf install -y yum-utils e4fsprogs kpartx qemu-img gdisk
pip install ironic-python-agent-builder diskimage-builder export DIB_YUM_MINIMAL_BOOTSTRAP_REPOS=/etc/yum.repos.d
export DIB_RELEASE=8
disk-image-create vm block-device-gpt centos-minimal

ipa-centos8

docker run -it --rm --name dib --privileged -v /dev:/dev af.frankming.com.cn/docker-drpd/openstack/centos-binary-openstack-base:train bash
dnf install -y yum-utils e4fsprogs kpartx qemu-img gdisk
pip install ironic-python-agent-builder diskimage-builder export DIB_YUM_MINIMAL_BOOTSTRAP_REPOS=/etc/yum.repos.d
export DIB_RELEASE=8
export ELEMENTS_PATH=/usr/local/share/ironic-python-agent-builder/dib
export DIB_DEFAULT_INSTALLTYPE=package
export DIB_EPEL_MIRROR=http://mirrors.frankming.com.cn/epel
export DIB_EPEL_DISABLED=1
export DIB_DEV_USER_USERNAME=cloud
export DIB_DEV_USER_PWDLESS_SUDO=yes
export DIB_DEV_USER_PASSWORD=frankming@123++
disk-image-create -o ipa-centos8-stable-train ironic-python-agent-ramdisk centos-minimal devuser stable-interface-names
# ipa-arm64,arm64无biosdevname包,无法使用stable-interface-names元素
# disk-image-create -a aarch64 -o ipa-centos8-stable-train-aarch64 ironic-python-agent-ramdisk centos-minimal devuser

ipa-debian

docker run --privileged -it --rm --cap-add=SYS_ADMIN --device-cgroup-rule="b 7:* rmw" --name test af.frankming.com.cn/docker-drpd/openstack/debian-base:bullseye bash

pip install ironic-python-agent-builder
apt update && apt install -y qemu-utils sudo debootstrap git rsync cpio export DIB_DISTRIBUTION_MIRROR=http://mirrors.frankming.com.cn/debian/
export DIB_DEBIAN_SECURITY_MIRROR=http://mirrors.frankming.com.cn/debian-security/
export DIB_DEFAULT_INSTALLTYPE=source
export DIB_DEV_USER_USERNAME=cloud
export DIB_DEV_USER_PWDLESS_SUDO=yes
export DIB_DEV_USER_PASSWORD=frankming@2022++
echo 'ironic-python-agent tar /tmp/ironic-python-agent http://10.33.41.25/CI/openstack-train/others/ironic-python-agent-train.tar.gz *' > /usr/local/share/ironic-python-agent-builder/dib/ironic-python-agent-ramdisk/source-repository-ironic-python-agent
echo 'ironic-lib tar /tmp/ironic-lib http://10.33.41.25/CI/openstack-train/others/ironic-lib-stable-train.tar.gz *' > /usr/local/share/ironic-python-agent-builder/dib/ironic-python-agent-ramdisk/source-repository-ironic-lib
echo 'requirements tar /tmp/requirements http://10.33.41.25/CI/openstack-train/others/requirements-stable-victoria.tar.gz *' > /usr/local/share/ironic-python-agent-builder/dib/ironic-python-agent-ramdisk/source-repository-requirements
ironic-python-agent-builder -o my-ipa debian -e devuser -e stable-interface-names

注意事项

Cannot open: https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm. Skipping.

centos7独有

文件位于diskimage_builder\elements\yum\pre-install.d\01-00-centos-python3,内网环境需将该行注释,且配置DIB_YUM_MINIMAL_BOOTSTRAP_REPOS环境变量需要有epel仓库

容器中运行需添加--privileged选项

mount -o size=20G -o remount /dev

mount -o size=20G -o remount /dev/shm

dib无法直接得知需要的程序依赖,可能出现构建到一半才报错无此命令的情况。如果通过pip安装,更是需要手动把所有的依赖程序都安装上。

理想的系统镜像构建工具还是得类似于docker那样,通过dockerfile直观、简便地构建。

二次开发后执行发现脚本没执行?

windows下文件无rwx权限管理,所有文件默认无w权限,所以dib执行时将脚本文件当成普通文件,跳过执行

cpio -idmv < xxx.cpio

同类型工具

Oz

image-bootstrap

imagefactory

参考文档

Tool support for image creation — Virtual Machine Image Guide documentation (openstack.org)

镜像制作工具diskimage-builder介绍的相关教程结束。

《镜像制作工具diskimage-builder介绍.doc》

下载本文的Word格式文档,以方便收藏与打印。