红帽企业 Linux(RHEL)的镜像模式使用与容器化应用相同的工具、技能和模式,提供更易于构建、交付和运行的操作系统。本文将介绍镜像模式背后的概念,并帮助用户了解在开源容器运动(OCI)容器镜像中打包操作系统所需掌握的基本概念。
以下步骤和流程将帮助您通过构建和部署自定义镜像的方式,从实践角度更好地理解 RHEL 镜像模式背后的概念。
要求:
- 所有命令均在 订阅的 RHEL 9.x 系统(笔记本电脑、虚拟机(VM)等均可)上运行,并且至少具有 10 GB 的可用磁盘空间。请记住,根据所创建镜像的大小和数量,可能需要更大的磁盘空间。
- 具有生产或开发人员订阅的红帽帐户(可在 此处获取免费的开发人员订阅)。
容器注册表 - 本例使用 quay.io 作为发布内容的注册表,但您可以选择利用其他托管注册表服务或在本地运行注册表。您可以在 此处轻松快速地创建 quay.io 帐户。
开始使用
首先确认您的系统已订阅,以获取 RHEL 内容。
$ sudo subscription-manager register
接下来,我们将安装 Podman。我们建议使用现有的最新版本,但任何 v4.* 或更新版本都可行。请注意,其他容器工具(如 Docker 或容器管道工具)可以在生产环境中运行。本例将使用 Podman 来讲解相关概念,但请记住,其他工具可能更适合您的环境。
$ sudo dnf -y install podman
现在,是时候通过 registry.redhat.io 进行身份验证了。首先访问 https://access.redhat.com/terms-based-registry,并单击“新建服务帐户”。从此处单击新条目的名称,然后在终端中复制/粘贴“docker login”指令,将 docker 命令替换为 podman。如需了解更多信息,请单击 此处查看完整说明。使用镜像构建器将容器镜像转换为磁盘镜像时,需要提升 podman 使用权限。继续使用/不使用 sudo 对注册表进行身份验证。
$ podman login registry.redhat.io
#repeat with sudo
$ sudo podman login registry.redhat.io
Bootc 容器镜像在技术上与应用容器有两个重要区别:
- bootc 镜像在容器内使用 OSTree
- bootc 镜像具有内核和足够的其他软件包,可用于启动物理机或虚拟机。
应用容器基础镜像通常包含与硬件管理无关的最小软件包集合。而且,与红帽通用基础镜像(UBI)不同,RHEL bootc 镜像根据与 RHEL 相同的许可条款进行分发。
我们来拉取 rhel-bootc
基础镜像。
$ podman pull registry.redhat.io/rhel9/rhel-bootc:9.4
创建 Containerfile
现在,让我们来看一个 Containerfile 示例。您可能将它们称为 Dockerfile。我们先从简单操作开始,安装一个 lamp 堆栈。将以下文本保存为名为 Containerfile 的新文件:
FROM registry.redhat.io/rhel9/rhel-bootc:9.4
#install the lamp components
RUN dnf module enable -y php:8.2 nginx:1.22 && dnf install -y httpd mariadb mariadb-server php-fpm php-mysqlnd && dnf clean all
#start the services automatically on boot
RUN systemctl enable httpd mariadb php-fpm
#create an awe inspiring home page!
RUN echo '<h1 style="text-align:center;">Welcome to image mode for RHEL</h1> <?php phpinfo(); ?>' >> /var/www/html/index.php
现在,我们描述了一个简单的操作系统,它将在端口 80 上运行 Web 服务器,并提供数据库和 php。我们来构建容器镜像:
构建镜像
$ podman build -f Containerfile -t quay.io/[my_account]/lamp-bootc:latest
注:
-t
将标记镜像。此示例假定 quay.io 是正在使用的注册表。请根据您使用的注册表进行调整。
-f
将指示 Podman 使用我们的 Containerfile。
测试镜像
我们已经有了镜像,接下来快速测试一下。由于我们的镜像是一个容器,因此运行速度很快,我们可以验证是否有任何拼写错误,因为如果有错误,会发出相应的错误信息。为简单起见,我们为它取一个简短名称(lamp):
$ podman run -d --rm --name lamp -p 8080:80 quay.io/[my_account]/lamp-bootc:latest /sbin/init
容器将启动,此时无需担心登录问题。打开浏览器,验证能否通过 http://[your_ip_address]:8080 查看所提供的网页。如果页面未加载,请仔细检查防火墙规则。如果您使用的是本地系统,环回地址应该可以正常工作。在本例中,我们将启动 systemd。但是,对于许多测试场景,直接启动应用会更加高效。快速进行测试和验证是使用容器来定义操作系统镜像的最显著优势之一。
您可以使用 podman exec
命令和之前设置的名称来进入正在运行的容器实例的 shell 环境。
$ podman exec -it lamp /bin/bash
停止使用相同名称的实例:
$ podman stop lamp
推送到注册表
接下来,登录 quay.io 进行身份验证,将镜像推送到注册表,并将存储库配置为可 公开访问。
$ podman login quay.io
$ podman push quay.io/[my_account]/lamp-bootc:latest
至此,我们已经创建了一个可部署的分层镜像,并且可以通过多种方式将它安装到主机上:我们可以使用 RHEL 的安装程序并启动裸机系统(通过 USB、PXE 等进行部署),也可以使用镜像构建器将容器镜像转换为可引导镜像。请注意,一旦“安装”了此容器,未来的更新将在发布时直接从容器注册表应用。因此,安装过程只发生一次。
通过 KVM/QEMU 与 Qcow2 磁盘镜像进行部署
本示例将使用镜像构建器将容器镜像转换为 qcow2 格式的磁盘。我们的示例假定镜像位于可公开访问的存储库中。请参阅 镜像构建器文档,了解如何利用私有存储库中的镜像。除了 qcow2 外,还可以使用其他镜像格式。
首先,创建一个 config.json
文件,以便对生成的磁盘进行配置。在本例中, config.json
将包含您要创建的用户。请将您自己的 SSH 密钥和密码粘贴到本示例中。
{
"blueprint": {
"customizations": {
"user": [
{
"name": "cloud-user",
"password": "changeme",
"key": "ssh-rsa AAAAB3Nz..........",
"groups": [
"wheel"
]
}
]
}
}
}
接下来,将 config.json
与我们的 lamp 容器一起传递到镜像构建器:
$ sudo podman run --rm -it --privileged \
-v .:/output \
-v $(pwd)/config.json:/config.json \
--pull newer \
registry.redhat.io/rhel9/bootc-image-builder:9.4 \
--type qcow2 \
--config /config.json \
quay.io/[my_account]/lamp-bootc:latest
镜像就绪后,我们可以使用 libvirt(或直接使用 qemu)来运行
virt-install \
--name lamp-bootc \
--memory 4096 \
--vcpus 2 \
--disk qcow2/disk.qcow2 \
--import \
--os-variant rhel9.4
当虚拟机运行时,您可以通过浏览器访问 http://[your_instance_ip_address] 来验证站点是否正常运行。
使用 AMI 磁盘镜像部署到 AWS
在本例中,我们需要确认 cloud-init 在之前创建的 lamp Containerfile 中可用。这就是容器工作流的优势所在,我们可以轻松为用例创建一个分层镜像。我们将演示分层构建,但如果更方便的话,也可以编辑原始 Containerfile 以包含 cloud-init。
FROM quay.io/[my_account]/lamp-bootc:latest
#install cloud-init for AWS
RUN dnf install -y cloud-init && dnf clean all
构建并推送镜像:
$ podman build -f Containerfile -t quay.io/[my_account]/lamp-bootc-aws:latest
$ podman push quay.io/[my_account]/lamp-bootc-aws:latest
我们将依靠 cloud-init 来注入用户和 ssh 密钥,这样就可以跳过上述 KVM 示例中的 config.json
步骤。(创建 cloud-init 配置不在本文档的讨论范围内)。通过使用 cloud-init,我们可以避免在镜像中包含硬编码凭据,从而增强安全态势。接下来,运行镜像构建器以创建 AMI:
$ sudo podman run --rm -it --privileged \
--pull=newer \
--security-opt label=type:unconfined_t \
-v $XDG_RUNTIME_DIR/containers/auth.json:/run/containers/0/auth.json \
-v $HOME/.aws:/root/.aws:ro \
--env AWS_PROFILE=default \
registry.redhat.io/rhel9/bootc-image-builder:9.4:latest \
--type ami \
--aws-ami-name lamp-bootc-aws \
--aws-bucket bootc-bucket \
--aws-region us-east-1 \
quay.io/[my_account]/lamp-cloud-init-bootc:latest
可以使用其他选项来配置 AWS 的属性。更多详情,请参阅此 链接。
发布过程成功完成后,启动您的镜像,并在浏览器中访问 http://[your_instance_ip_address],一定会让您大吃一惊。
通过 Kickstart 安装到裸机
如您所见,可以通过多种方式安装容器。本节介绍 kickstart 的使用方式,这在使用 ISO、PXE 或 USB 驱动器进行裸机部署方面非常常见。本指南假定您对 kickstart 概念有一定的了解,因此不会详细介绍。在下面的示例中插入与用户、密码和 ssh 密钥相关的详细信息。支持添加其他选项,但请注意,使用此工作流时,%packages 部分不可用,因为我们要将实例替换为容器镜像。请从 此网站下载适用于您的架构的 9.4 Boot ISO。
text
network --bootproto=dhcp --device=link --activate
# Basic partitioning
clearpart --all --initlabel --disklabel=gpt
reqpart --add-boot
part / --grow --fstype xfs
# Here's where we reference the container image to install - notice the kickstart
# has no `%packages` section! What's being installed here is a container image.
ostreecontainer --url quay.io/[my_account]/lamp-bootc:latest
firewall --disabled
services --enabled=sshd
# optionally add a user
user --name=cloud-user --groups=wheel --plaintext --password=changemme
sshkey --username cloud-user "ssh-ed25519 AAAAC3Nza....."
# if desired, inject a SSH key for root
rootpw --iscrypted locked
sshkey --username root "ssh-ed25519 AAAAC3Nza....." #paste your ssh key here
reboot
将此配置文件复制到 Web 服务器,更新密码和 SSH 密钥,使用安装介质启动任何物理或虚拟系统,然后将以下内容附加到内核参数:
inst.ks=http://path_to_my_kickstart
按下 ctrl-x 以使用此选项启动。
如果 HTTP 服务器不可用,您可以使用大多数 python 安装中提供的 http 服务器模块。在存放 kickstart 文件的目录中,运行:
$ python -m http.server
在另一种方法中,不使用 HTTP 服务器来托管 kickstart 文件,而是将 kickstart 注入到安装程序 ISO 中。lorax 软件包中包含一个名为 mksiso 的实用程序,它可以将此文件嵌入 ISO 中。这对于直接从 U 盘启动非常有用,并且可以避免编辑启动菜单。 运行: mkksiso --ks /PATH/TO/KICKSTART /PATH/TO/ISO /PATH/TO/NEW-ISO
推送更新
这个案例的一个关键方面是,安装或部署是一次性任务。 这种模式的大部分价值体现在“Day 2”,即可以通过将镜像推送到注册表来完成更改。 自动更新默认处于开启状态!当然,这可以轻松针对维护期进行配置,或者可以完全禁用。若要试用,只需对 Containerfile 进行更改,然后重复构建和推送步骤,使新镜像在您的注册表中可用。& systemd 单元的默认计时器将在运行一小时后启动,但您也可以提前运行“bootc upgrade”来获取更新。
后续步骤
您已经通过一个简单的示例了解 RHEL 的镜像模式,接下来您可以探索自己的一些用例,并考虑使用容器工具对操作系统部署进行版本控制和管理时可以获得的可能性和运维效率优势。请务必查看我们的 bootc 示例存储库,它将有助于启用多个平台并实现一些实用场景。此外,如果您准备深入了解,建议您查看 完整文档。
关于作者
Ben Breard is a Senior Principal Product Manager at Red Hat, focusing on Red Hat Enterprise Linux and Edge Offerings.
产品
工具
试用购买与出售
沟通
关于红帽
我们是世界领先的企业开源解决方案供应商,提供包括 Linux、云、容器和 Kubernetes。我们致力于提供经过安全强化的解决方案,从核心数据中心到网络边缘,让企业能够更轻松地跨平台和环境运营。