在拥有了自己的Distrobuilder后(还没有?参见:为Incus构建Distrobuilder ),我们来一起构建用于Incus的容器镜像,实现容器镜像自由吧!
一定会有人疑惑:既然已经有了LXC镜像站,为什么还需要自己构建镜像呢?
这是因为,本文希望描述一个全程可控 的,避免过度抽象细节的,创建Incus容器镜像的方法。
预先准备
需要在系统上安装distrobuilder
,可以使用snap
下载,也可以自己构建:为Incus构建Distrobuilder 。
案例1: Alpine Linux镜像
准备根文件系统(rootfs)
既然我们在讨论可控的构建过程,那么这一定包括一个可控的根文件系统(Root
FileSystem, rootfs)。
让我们打开downloads
| Alpine
Linux ,下拉找到MINI ROOT FILESYSTEM
项目,下载对应架构的根文件系统。
例如,对于64位系统来说,我们将需要下载alpine-minirootfs-3.20.2-x86_64.tar.gz
文件。中间的版本号请不要介意。
能不能用镜像站完成这一下载呢?又或者能不能用自己打包的Alpine
Linux根文件系统呢?当然可以!这正是可控过程的魅力所在。
当然,distrobuilder实际上也已将下载rootfs的过程封装在程序中。就Alpine
Linux来说,distrobuilder下载的rootfs和我们现在手动下载的是同一个文件。
如果更希望让distrobuilder代劳,请跳过当前这一步骤,后面会再展开介绍。
准备构建配置模板
构建镜像时需要的许多信息都由模板文件提供,如镜像的名称、类型、发行版,还有需要安装的软件包、执行的动作等等。
在distrobuilder中,镜像的模板文件是一个YAML文件,标准格式在官方仓库doc/examples/scheme.yaml 中给出,文末也附有该文件复制过来的内容:
只不过,格式文件里,有非常多对键值。看起来一头雾水对吧?没关系,加法做不通我们可以做减法。
转到lxc/lxc-ci/images ,这一目录下的镜像配置文件,就是Incus官方镜像服务器上,镜像构建所采用的配置文件。我们目前正在构建Alpine
Linux,所以我们直接复制alpine.yaml
文件中的内容到本地。由于内容太长,同样地,原始内容放在文末。
这文件也太长了吧?而且仔细一看,还有很多似乎我们不太用得上的配置项,例如适用于虚拟机镜像的命令,在容器中是用不到的。因此,让我们来进一步修改这些配置。
修改构建配置文件
Image: 容器镜像配置
首先,文件的第一节image
部分,主要定义了镜像的名称和版本号等信息。
为了避免与官方构建的Alpine
Linux镜像名称冲突,我们可以稍微修改一下这部分内容:
1 2 3 4 image: distribution: "Custom Alpinelinux" name: custom-alpine release: 3.20
Source: 镜像rootfs来源配置
配置文件第二节,source
部分,主要定义了用于构建容器镜像的rootfs如何获得。由于各Linux发行版的rootfs定义与下载地址都有差异,因此distrobuilder预定义了许多Source ,用于解析各种操作系统的rootfs下载规则。
对于Alpine
Linux,distrobuilder已经定义好了alpinelinux-http
这一Source,因此如果希望distrobuilder帮我们自动下载rootfs,此处可定义如下:
1 2 3 4 source: downloader: alpinelinux-http same_as: 3.12 url: https://mirrors.hust.edu.cn/alpine/
其中,URL可以是任意Alpine
Linux镜像站,以上例子使用了华中科大镜像站。不过,URL也可以file://
开头,指向本地已经下载好的rootfs文件包。
如你所见,示例配置文件包含了一大段GPG公钥,用于验证下载的rootfs。如果信任下载源与下载文件完整性,并希望删掉keys
部分以缩简配置文件,请在source
节内加上skip_verification: true
选项。
不过,既然我们正在尽可能追求可控,我们一定会想:
alpinelinux-http
源在下载rootfs文件之外,是否还有额外的操作/Tricks?
不考虑后文安装软件包等定制操作,在当前这一步是否有通用于所有Linux发行版rootfs的方法?
是否可以利用已预先准备好的rootfs?
尽管根据sources/alpine-http.go 源代码,就目前来说,并没有什么下载之外的额外小Tricks。但到目前为止,distrobuilder最新版3.0并没有直接提供使用现有rootfs目录直接构建容器系统的选项。如果直接在配置文件中删除source
一节,进行构建时也会报错。
但是,distrobuilder的确提供了一种使用任意rootfs文件包的Source,即rootfs-http
,相关源代码可见sources/rootfs-http.go 。简单来说只需要提供一个指向rootfs包的URL,本地网络皆可。
因此,上述source
节也可以改为(使用file://
指向本地文件时需要使用绝对路径):
1 2 3 source: downloader: rootfs-http url: file:///absolute/path/to/alpine-minirootfs-3.20.2-x86_64.tar.gz
Target: 目标特定配置
如果仅希望构建Incus容器镜像,不需要LXC镜像和虚拟机镜像,可以直接把这一节大幅精简:
如有需要,请直接参阅Targets
- distrobuilder documentation 官方文档。
Files: 文件生成规则配置
和上面类似地,如果不需要Incus虚拟机镜像,仅仅需要保留用于Incus容器的部分,可以直接删除掉所有包含以下标记的虚拟机专用文件生成规则。
Packages:
软件包安装预定义配置
这部分将定义Incus在构建镜像时,需要使用何种包管理器,安装哪些软件包,大部分内容可以直接照抄示例。同上,可以删掉所有虚拟机限定的配置。
重点讨论一下软件源相关配置。官方手册中,与定制软件源相关的选项位于packages
节下,可以通过添加repositories
节设置额外的 软件源。例如:
1 2 3 4 5 6 7 8 packages: repositories: - name: hust url: |- https://mirrors.hust.edu.cn/alpine/v3.20/main https://mirrors.hust.edu.cn/alpine/v3.20/community
但是,这种方法会将新软件源附加到原本的软件源后,并不会替换掉速度可能非常缓慢的官方软件源。
如果希望替换掉rootfs中的官方软件源,我们可以不采用这种方案,请往下看。
Actions: 自定义操作
在这一部分,我们可以定义在容器构建的不同的时机要执行的操作(Action) 。
目前,distrobuilder提供的执行时机(触发器/Trigger)包括:
post-unpack
: 在rootfs被解压释放后执行。
post-update
:
如果packages.update
为true
,在包管理器完成更新后执行。
post-packages
:
在包管理器安装完所有指定的包后执行。
post-files
:
在files
配置块执行完成后执行。这一部分默认仅在build-lxc
,
build-incus
, pack-lxc
和pack-incus
操作中执行。如果希望在build-dir
操作中也执行这一块,需要指定--with-post-files
选项。
例如,如果我们希望把rootfs中官方的软件源配置为镜像站,则可以添加一个post-unpack
操作,内容如下:
1 2 3 4 5 6 actions: - trigger: post-unpack action: |- #!/bin/sh set -eux sed -i 's/dl-cdn.alpinelinux.org/mirrors.hust.edu.cn/g' /etc/apk/repositories
该命令会在rootfs解压挂载后,容器执行apk update
更新软件源之前执行。
Mappings: 架构名称映射配置
这部分主要是告诉Distrobuilder如何处理不同架构名称之间的映射关系,如amd64
与x86_64
,aarch64
与arm64
等。
这部分按照模板直接保留就行,详情见Mappings
- distrobuilder documentation 官方文档。
不得不感慨一下,Linux由于各种历史包袱和不一致的规范,有时会略显混乱。
最终配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 image: name: custom-alpine distribution: "Custom Alpinelinux" release: 3.20 source: downloader: rootfs-http url: file:///absolute/path/to/alpine-minirootfs-3.20.2-x86_64.tar.gz targets: incus: files: - path: /etc/hostname generator: hostname - path: /etc/hosts generator: hosts - path: /etc/network/interfaces generator: dump content: |- auto eth0 iface eth0 inet dhcp hostname $(hostname) - path: /etc/inittab generator: dump content: |- # /etc/inittab ::sysinit:/sbin/openrc sysinit ::sysinit:/sbin/openrc boot ::wait:/sbin/openrc default ::respawn:/sbin/getty 38400 console tty1::respawn:/sbin/getty 38400 tty1 tty2::respawn:/sbin/getty 38400 tty2 tty3::respawn:/sbin/getty 38400 tty3 tty4::respawn:/sbin/getty 38400 tty4 ::ctrlaltdel:/sbin/reboot ::shutdown:/sbin/openrc shutdown - path: /etc/inittab generator: template name: inittab content: |- # /etc/inittab ::sysinit:/sbin/openrc sysinit ::sysinit:/sbin/openrc boot ::wait:/sbin/openrc default ::respawn:/sbin/getty 38400 console ::ctrlaltdel:/sbin/reboot ::shutdown:/sbin/openrc shutdown - name: meta-data generator: cloud-init variants: - cloud - name: network-config generator: cloud-init content: |- version: 1 config: - type: physical name: eth0 subnets: - type: dhcp control: auto variants: - cloud - name: user-data generator: cloud-init variants: - cloud - name: vendor-data generator: cloud-init variants: - cloud packages: manager: apk update: true cleanup: true sets: - packages: - alpine-base - logrotate - doas action: install - packages: - cloud-init - openssh - e2fsprogs-extra action: install variants: - cloud - packages: - py3-pyserial - py3-netifaces action: install variants: - cloud releases: - 3.17 - 3.18 - 3.19 - 3.20 - edge actions: - trigger: post-unpack action: |- #!/bin/sh set -eux sed -i 's/dl-cdn.alpinelinux.org/mirrors.hust.edu.cn/g' /etc/apk/repositories - trigger: post-packages action: |- #!/bin/sh set -eux rm -f /var/cache/apk/* - trigger: post-packages action: |- #!/bin/sh set -eux sed -i 's/#rc_sys=""/rc_sys="lxc"/' /etc/rc.conf sed -i 's/-lxc//' /etc/init.d/localmount for svc_name in bootmisc syslog devfs; do ln -s /etc/init.d/${svc_name} /etc/runlevels/boot/${svc_name} done for svc_name in networking crond; do ln -s /etc/init.d/${svc_name} /etc/runlevels/default/${svc_name} done types: - container - trigger: post-files action: |- #!/bin/sh set -eux setup-cloud-init variants: - cloud mappings: architecture_map: alpinelinux
我们将最终的配置文件保存,随便起个名字,比方说alpine.yaml
即可。
开始构建
新建rootfs
和images
两个文件夹,分别用于暂存解压的rootfs,以及构建生成的镜像文件。
1 2 mkdir rootfsmkdir images
首先需要执行的是build-dir
指令。
1 sudo distrobuilder build-dir alpine.yaml rootfs
再接着执行pack-incus
指令。
1 sudo distrobuilder pack-incus alpine.yaml rootfs images
等待一切完成,images
文件夹下就存放着构建好的容器镜像了。
此时一定有人会问:为什么要分两步?为什么不直接执行build-incus
指令?
答案当然是可以的。
1 sudo distrobuilder build-incus alpine.yaml images
有什么区别呢?我们来看看Distrobuilder开发者在论坛中的讨论 :
Oops, I said build
instead of pack
here as
that’s likely what you actually want to
use.build-incus
is equivalent
of build-dir + pack-incus
.
The reason why we do it in two steps in our CI is because we produce
both LXC and Incus images so that lets us use the same rootfs for both.
But if all you care about is the LXD/Incus image, just
use build-incus
directly.
导入Incus并开始使用
拥有了镜像,只需要导入Incus就可以开始使用了。
1 incus image import images/incus.tar.xz images/rootfs.squashfs --alias custom-alpine/3.20
命令末尾的--alias
选项用于给镜像定义一个别名。如果没有别名,我们就只能用镜像的哈希指代镜像了。
接着创建实例,启动镜像。
1 2 incus launch local :custom-alpine/3.20 test-alp incus exec test-alp -- /bin/ash
附录
配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 image: description: |- here goes the image description distribution: distro release: release architecture: x86_64 expiry: 30d variant: default name: distro-release-x86_64 serial: some-random-string source: downloader: ubuntu-http url: http://archive.ubuntu.com keys: - 0xdeadbeaf keyserver: http://keyserver.ubuntu.com variant: default suite: suite same_as: bionic skip_verification: false components: - main targets: lxc: create_message: |- You just created an {{ image.description }} container. To enable SSH, run: apt install openssh-server No default root or user password are set by LXC. config: - type: all before: 5 content: |- lxc.include = LXC_TEMPLATE_CONFIG/ubuntu.common.conf - type: user before: 5 content: |- lxc.include = LXC_TEMPLATE_CONFIG/ubuntu.userns.conf - type: all after: 4 content: |- lxc.include = LXC_TEMPLATE_CONFIG/common.conf - type: user after: 4 content: |- lxc.include = LXC_TEMPLATE_CONFIG/userns.conf - type: all content: |- lxc.arch = {{ image.architecture_personality }} incus: vm: size: 2147483648 filesystem: ext4 files: - generator: dump path: /some/path content: |- here goes the content name: name mode: 0644 gid: 1000 uid: 1000 template: properties: key: value when: - always templated: true releases: - a - b architectures: - x86_64 variants: - default - generator: hostname path: /etc/hostname - generator: hosts path: /etc/hosts - generator: remove path: /root/file - generator: template name: foo content: |- Here goes the content template: properties: key: value when: - create - copy packages: manager: apt custom_manager: clean: cmd: mgr flags: - clean install: cmd: mgr flags: - install remove: cmd: mgr flags: - remove refresh: cmd: mgr flags: - refresh update: cmd: mgr flags: - update flags: - --yes update: true cleanup: false sets: - packages: - gnupg action: install early: true - packages: - vim action: install releases: - a - b architectures: - x86_64 variants: - default - packages: - lightdm action: install flags: - --no-install-recommends - packages: - grub action: remove repositories: - name: reponame url: |- deb http://archive.ubuntu.com/ubuntu {{ image.release }}-updates main restricted universe multiverse type: type key: 0xdeadbeaf releases: - a - b architectures: - x86_64 variants: - default actions: - trigger: post-unpack action: |- #!/bin/sh do something after the rootfs has been unpacked - trigger: post-files action: |- #!/bin/sh do something after the files section has been processed - trigger: post-update action: |- #!/bin/sh do something after packages have been processed - trigger: post-packages action: |- #!/bin/sh do something after the packages section has been processed releases: - a - b architectures: - x86_64 variants: - default mappings: architectures: a: b c: d architecture_map: debian environment: clear_defaults: true variables: - key: FOO value: bar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 image: distribution: "alpinelinux" source: downloader: alpinelinux-http same_as: 3.12 url: https://mirror.csclub.uwaterloo.ca/alpine/ keys: - |- -----BEGIN PGP PUBLIC KEY BLOCK----- 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 bcgRRcklNr8mTzJH =ckew -----END PGP PUBLIC KEY BLOCK----- targets: lxc: create_message: | You just created an {{ image.description }} container. config: - type: all before: 5 content: |- lxc.include = LXC_TEMPLATE_CONFIG/alpine.common.conf - type: user before: 5 content: |- lxc.include = LXC_TEMPLATE_CONFIG/alpine.userns.conf - type: all after: 4 content: |- lxc.include = LXC_TEMPLATE_CONFIG/common.conf - type: user after: 4 content: |- lxc.include = LXC_TEMPLATE_CONFIG/userns.conf - type: all content: |- lxc.arch = {{ image.architecture_personality }} incus: vm: filesystem: ext4 files: - path: /etc/hostname generator: hostname - path: /etc/hosts generator: hosts - generator: fstab types: - vm - generator: incus-agent types: - vm - path: /etc/default/grub generator: dump pongo: true content: |- # Set the recordfail timeout GRUB_RECORDFAIL_TIMEOUT=0 GRUB_TIMEOUT=0 GRUB_CMDLINE_LINUX_DEFAULT="console=tty1 console=ttyS0 modules=sd-mod,usb-storage,{{ targets.incus.vm.filesystem }} rootfstype={{ targets.incus.vm.filesystem }}" GRUB_TERMINAL=console GRUB_DISABLE_OS_PROBER=true types: - vm - path: /etc/network/interfaces generator: dump content: |- auto eth0 iface eth0 inet dhcp hostname $(hostname) - path: /etc/inittab generator: dump content: |- # /etc/inittab ::sysinit:/sbin/openrc sysinit ::sysinit:/sbin/openrc boot ::wait:/sbin/openrc default ::respawn:/sbin/getty 38400 console tty1::respawn:/sbin/getty 38400 tty1 tty2::respawn:/sbin/getty 38400 tty2 tty3::respawn:/sbin/getty 38400 tty3 tty4::respawn:/sbin/getty 38400 tty4 ::ctrlaltdel:/sbin/reboot ::shutdown:/sbin/openrc shutdown - path: /etc/inittab generator: template name: inittab content: |- # /etc/inittab ::sysinit:/sbin/openrc sysinit ::sysinit:/sbin/openrc boot ::wait:/sbin/openrc default ::respawn:/sbin/getty 38400 console ::ctrlaltdel:/sbin/reboot ::shutdown:/sbin/openrc shutdown - name: meta-data generator: cloud-init variants: - cloud - name: network-config generator: cloud-init content: |- version: 1 config: - type: physical name: eth0 subnets: - type: dhcp control: auto variants: - cloud - name: user-data generator: cloud-init variants: - cloud - name: vendor-data generator: cloud-init variants: - cloud packages: manager: apk update: true cleanup: true sets: - packages: - alpine-base - logrotate - doas action: install - packages: - cloud-init - openssh - e2fsprogs-extra action: install variants: - cloud - packages: - py3-pyserial - py3-netifaces action: install variants: - cloud releases: - 3.17 - 3.18 - 3.19 - 3.20 - edge - packages: - acpi - gcc - grub-efi - linux-virt - udev action: install types: - vm actions: - trigger: post-packages action: |- #!/bin/sh set -eux rm -f /var/cache/apk/* - trigger: post-packages action: |- #!/bin/sh set -eux sed -i 's/#rc_sys=""/rc_sys="lxc"/' /etc/rc.conf sed -i 's/-lxc//' /etc/init.d/localmount for svc_name in bootmisc syslog devfs; do ln -s /etc/init.d/${svc_name} /etc/runlevels/boot/${svc_name} done for svc_name in networking crond; do ln -s /etc/init.d/${svc_name} /etc/runlevels/default/${svc_name} done types: - container - trigger: post-files action: |- #!/bin/sh set -eux for svc_name in acpid bootmisc hostname hwclock loadkmap modules networking swap sysctl syslog urandom; do ln -fs /etc/init.d/${svc_name} /etc/runlevels/boot/${svc_name} done for svc_name in devfs dmesg hwdrivers mdev udev udev-settle udev-trigger; do ln -fs /etc/init.d/${svc_name} /etc/runlevels/sysinit/${svc_name} done target=/boot/grub/grub.cfg grub-mkconfig -o "${target}" sed -i "s#root=[^ ]*#root=${DISTROBUILDER_ROOT_UUID}#g" "${target}" TARGET="x86_64" [ "$(uname -m)" = "aarch64" ] && TARGET="arm64" grub-install --target=${TARGET}-efi --no-nvram --removable grub-install --target=${TARGET}-efi --no-nvram apk fix types: - vm - trigger: post-files action: |- #!/bin/sh set -eux for svc_name in sshd; do ln -fs /etc/init.d/${svc_name} /etc/runlevels/default/${svc_name} done echo "datasource_list: ['NoCloud', 'ConfigDrive', 'LXD', 'None']" > /etc/cloud/cloud.cfg.d/99_lxc.cfg types: - vm variants: - cloud - trigger: post-files action: |- #!/bin/sh set -eux setup-cloud-init variants: - cloud mappings: architecture_map: alpinelinux