mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
1367 字
4 分钟
如何制作一个标准的产品镜像
2023-06-29

某安全厂商向客户交付产品时,每台服务器都要运维人员手动安装操作系统、配置环境、部署应用,50 台机器需要整整一周。制作标准 ISO(International Organization for Standardization,光盘镜像) 产品镜像后,插入 U 盘即可自动完成全量安装,50 台机器半天搞定。

一、什么是产品镜像#

产品镜像通常指的是在软件开发过程中,将一个产品的源代码、配置文件、依赖库等所有必要的文件打包成的一个可执行文件或安装包,用于方便分发、备份以及自动部署和测试。

常见的服务器产品镜像格式包括:

格式特点适用场景
RPM软件包格式Linux 软件分发
Docker 镜像容器化封装应用部署
qcow2虚拟机磁盘格式虚拟机环境
ISO光盘镜像,可启动裸机安装、自动化部署

二、为什么选择 ISO 镜像#

ISO 镜像提供了最大的软件一致性——无论在何处部署都能保证相同的配置和性能。每次版本升级都能自主管控操作系统层面的所有软件和配置信息。

典型应用场景:

  • 批量装机:数据中心一键安装数百台服务器
  • 离线部署:无法访问外网的环境
  • 版本固化:特定版本的软件栈锁定
  • 合规要求:需要验证每个组件来源的场景
  • OEM(Original Equipment Manufacturer) 预装:硬件厂商预装软件栈
  • 等保合规:安全加固后的标准化环境

三、关键工具链#

1. kickstart#

kickstart 是 Red Hat 系 Linux 的无人值守安装配置文件:

# 生成 kickstart 配置模板
system-config-kickstart
# 验证 kickstart 语法
ksvalidator -v RHEL7 ks.cfg

kickstart 核心配置项:

# 安装模式
install
url --url="http://mirror.centos.org/7/os/x86_64"
# 文本模式安装
text
# 键盘和语言
keyboard us
lang zh_CN.UTF-8
# 网络配置
network --bootproto=dhcp --device=eth0 --activate
network --hostname=product-server
# 时区
timezone Asia/Shanghai --utc
# 认证
auth --enableshadow --passalgo=sha512
rootpw --iscrypted $6$rounds=4096$salt$hash
# 安全配置
firewall --enabled --service=ssh
selinux --enforcing
# 分区配置
zerombr
clearpart --all --initlabel
part /boot --fstype=xfs --size=500
part pv.01 --size=1 --grow
volgroup vg_main pv.01
logvol / --vgname=vg_main --size=1 --grow --name=lv_root
logvol swap --vgname=vg_main --size=4096 --name=lv_swap
# 引导装载程序
bootloader --location=mbr --append="rhgb quiet"
# 软件包选择
%packages
@^minimal-environment
chrony
curl
wget
vim
bash-completion
%end
# 安装后脚本
%post --log=/root/ks-post.log
echo "Installation completed" >> /root/completed
systemctl enable chronyd
%end

2. mkisofs 和 xorriso#

mkisofsxorriso 是打包 ISO 的核心工具,后者是前者的 GNU 替代品,支持更丰富的 UEFI 启动选项。

# 使用 mkisofs 打包
mkisofs -o product.iso \
-b isolinux/isolinux.bin \
-c isolinux/boot.cat \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-eltorito-platform 0x80 \
-eltorito-platform 0x00 \
-eltorito-boot isolinux.bin \
-no-emul-boot \
-rock \
-joliet \
-joliet-long \
-output-charset utf-8 \
RR_moved \
boot.cat \
EFI \
images \
LiveOS \
repositories \
isolinux

UEFI(Unified Extensible Firmware Interface) 启动需要额外处理:

# 支持 UEFI + BIOS 双启动的 ISO
xorriso -as mkisofs \
-o product.iso \
-isohybrid-mbr /usr/share/syslinux/isohdpfx.bin \
-c isolinux/boot.cat \
-b isolinux/isolinux.bin \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-eltorito-alt-boot \
-e images/efiboot.img \
-no-emul-boot \
-isohybrid-gpt-basdat \
-rock -joliet -joliet-long \
-output-charset utf-8 \
/path/to/iso-root

四、构建流程#

1. 准备源仓库#

# 同步官方仓库到本地
reposync --repoid=baseos --repoid=appstream -a x86_64 --download_path=/mnt/local-repo
# 创建本地 repo 文件
cat > /etc/yum.repos.d/local.repo <<EOF
[local-baseos]
name=Local BaseOS
baseurl=https://mirror.centos.org/centos/7/os/x86_64/
enabled=1
gpgcheck=0
EOF

离线仓库的完整搭建流程:

# 1. 创建仓库目录结构
mkdir -p /mnt/local-repo/{baseos,appstream,extras}
# 2. 同步仓库(需要联网环境)
reposync --repoid=baseos -p /mnt/local-repo/
reposync --repoid=appstream -p /mnt/local-repo/
# 3. 生成 repodata
createrepo_c /mnt/local-repo/baseos/
createrepo_c /mnt/local-repo/appstream/
# 4. 添加自定义 RPM 包
cp /path/to/product-1.0.0.el7.x86_64.rpm /mnt/local-repo/extras/Packages/
createrepo_c --update /mnt/local-repo/extras/
# 5. 验证仓库可用性
yum --disablerepo="*" --enablerepo="local-*" list available

2. 定制 rootfs#

rootfs(Root Filesystem,根文件系统) 是操作系统启动后的完整目录结构,定制 rootfs 即在基础系统上注入产品专属配置和文件。

# 解压基础镜像
mkdir -p /tmp/rootfs
cd /tmp/rootfs
tar -xf /path/to/runtime.tar.gz --strip-components=1
# 注入产品定制
cp /path/to/product.conf etc/product.conf
cp /path/to/startup.sh /usr/local/bin/
chmod +x /usr/local/bin/startup.sh
# 安装额外依赖(chroot 方式)
mount --bind /dev /tmp/rootfs/dev
mount --bind /proc /tmp/rootfs/proc
mount --bind /sys /tmp/rootfs/sys
chroot /tmp/rootfs /bin/bash -c "yum install -y product-pkg"
umount /tmp/rootfs/{dev,proc,sys}
# 打包定制 rootfs
tar -czf custom-rootfs.tar.gz .

rootfs 定制清单:

# 产品定制通常包含以下内容
/etc/product.conf # 产品配置文件
/etc/systemd/system/product.service # systemd 服务
/usr/local/bin/startup.sh # 启动脚本
/opt/product/ # 产品安装目录
/var/lib/product/data/ # 数据目录
/etc/security/limits.d/product.conf # 资源限制
/etc/sysctl.d/product.conf # 内核参数
/etc/logrotate.d/product # 日志轮转

3. 生成 ISO#

# 完整打包命令
xorriso \
-report_about NONE \
-osirrox "iso_level=3" \
-joliet "joliet=u8" \
-compliance "joliet_long=+放心" \
-rockridge "on" \
-boot_image any keep \
-boot_image any partition_table/gpt_efi_size=4M \
-efi-boot-part "--efi-boot-image" \
-efi-boot-nature "any" \
-append_partition 2 0xEF "boot/efi.img" \
-boot_image any modify "boot/grub/efi.conf" \
-outdev /tmp/product.iso \
-map overlay / \
-boot_image any cat_path "boot.cat"

4. 验证 ISO#

# 挂载 ISO 验证内容
mount -o loop /tmp/product.iso /mnt/iso
ls -la /mnt/iso/
# 检查 kickstart 文件
ksvalidator /mnt/iso/ks.cfg
# 计算校验和
sha256sum /tmp/product.iso > product.iso.sha256
# 在虚拟机中测试安装
virt-install \
--name test-install \
--ram 2048 \
--vcpus 2 \
--disk size=20 \
--cdrom /tmp/product.iso \
--os-variant centos7 \
--noautoconsole

五、Docker 镜像最佳实践#

虽然本文主要讨论 ISO 镜像,但 Docker 镜像同样是产品交付的重要形式。以下是制作高质量 Docker 镜像的最佳实践。

1. Dockerfile 编写规范#

Dockerfile 是构建 Docker 镜像的指令文件,每条指令对应一个镜像层。

# 1. 选择合适的基础镜像
FROM python:3.11-slim AS base
# 2. 设置元数据
LABEL maintainer="team@example.com"
LABEL version="1.0.0"
LABEL description="Product Service"
# 3. 设置环境变量
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
APP_HOME=/app
# 4. 创建非 root 用户
RUN groupadd -r appuser && useradd -r -g appuser appuser
WORKDIR $APP_HOME
# 5. 先复制依赖文件,利用缓存层
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 6. 再复制应用代码
COPY --chown=appuser:appuser . .
# 7. 切换到非 root 用户
USER appuser
# 8. 声明端口
EXPOSE 8000
# 9. 健康检查
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
# 10. 启动命令
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]

2. 多阶段构建#

Multi-stage Build(多阶段构建) 是减小镜像体积的关键技术,构建阶段的工具链不会进入最终镜像。

# 阶段一:构建
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
# 阶段二:运行
FROM node:20-alpine AS runtime
WORKDIR /app
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=builder --chown=appuser:appgroup /app/package.json ./
USER appuser
EXPOSE 3000
CMD ["node", "dist/main.js"]

Go 语言的多阶段构建效果更显著:

# 构建阶段:使用完整 Go 环境
FROM golang:1.22-alpine AS builder
RUN apk add --no-cache git ca-certificates
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/server
# 运行阶段:scratch 镜像,只有二进制
FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /app/server /server
EXPOSE 8080
ENTRYPOINT ["/server"]

多阶段构建镜像大小对比:

方式镜像大小
单阶段 Go~800MB
多阶段 alpine~15MB
多阶段 scratch~5MB
单阶段 Node~1.2GB
多阶段 Node~150MB

3. 镜像体积优化技巧#

技巧说明效果
多阶段构建构建工具不进入最终镜像显著减小
.dockerignore排除 .git、node_modules 等无关文件减小构建上下文
合并 RUN 指令RUN apt-get update && apt-get install减少镜像层数
清理缓存rm -rf /var/lib/apt/lists/*减小 50-100MB
alpine 基础镜像使用 musl 代替 glibc减小 80MB
distroless 镜像只包含应用运行时依赖减小 50MB
—no-cache-dirpip install 不缓存减小 20-50MB
npm ci —production只安装生产依赖减小 100MB+
# .dockerignore 示例
.git
.github
node_modules
__pycache__
*.pyc
.pytest_cache
.env
.env.*
docker-compose*.yml
Dockerfile*
README.md

六、安全加固#

1. 镜像安全扫描#

Trivy 是 Aqua Security 开源的容器镜像漏洞扫描工具,支持操作系统包和应用依赖的全面检测。

# 使用 Trivy 扫描漏洞
trivy image product-service:1.0.0
# 扫描并输出报告
trivy image --format json --output report.json product-service:1.0.0
# 只显示高危和严重漏洞
trivy image --severity HIGH,CRITICAL product-service:1.0.0
# CI 中集成:发现高危漏洞则失败
trivy image --exit-code 1 --severity HIGH,CRITICAL product-service:1.0.0

2. Dockerfile 安全清单#

# 不以 root 运行
USER appuser
# 不存储密钥
# 使用 Docker secrets 或环境变量传入敏感信息
# 固定基础镜像版本
FROM python:3.11.7-slim # 而非 python:3.11 或 python:latest
# 使用 COPY 而非 ADD
COPY app.py /app/ # ADD 会自动解压和下载,有安全隐患
# 最小化安装
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
ca-certificates && \
rm -rf /var/lib/apt/lists/*
# 危险做法
# FROM python:latest # 版本不可控
# ADD https://... /app/ # 远程下载有供应链风险
# USER root # root 运行有提权风险
# ENV DB_PASSWORD=xxx # 硬编码密钥

3. ISO 镜像安全加固#

SELinux(Security-Enhanced Linux) 是 Linux 内核的强制访问控制安全模块,应在产品镜像中默认启用。

# 1. 安全加固 kickstart 配置
# 启用 SELinux
selinux --enforcing
# 配置防火墙
firewall --enabled --service=ssh
# 禁用不必要的服务
%post
systemctl disable avahi-daemon
systemctl disable cups
systemctl disable bluetooth
# 安全内核参数
cat >> /etc/sysctl.d/99-security.conf <<EOF
net.ipv4.ip_forward = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.log_martians = 1
kernel.exec-shield = 1
EOF
# 文件权限加固
chmod 600 /etc/ssh/sshd_config
chmod 700 /root
%end

七、CI/CD 集成#

1. GitHub Actions 构建 Docker 镜像#

.github/workflows/docker-build.yml
name: Build Docker Image
on:
push:
tags: ['v*']
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Security scan
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}
severity: 'HIGH,CRITICAL'
exit-code: '1'

2. GitHub Actions 构建 ISO 镜像#

.github/workflows/build-iso.yml
name: Build ISO
on:
push:
tags: ['v*']
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build ISO in container
run: |
docker build -t iso-builder -f Dockerfile.iso .
docker run --rm \
-v ${{ github.workspace }}:/workspace \
iso-builder \
bash -c "mkisofs -o /workspace/product.iso /workspace/rr_moved"
- name: Generate checksum
run: |
sha256sum product.iso > product.iso.sha256
- name: Upload ISO artifact
uses: actions/upload-artifact@v4
with:
name: product-iso
path: |
product.iso
product.iso.sha256
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: |
product.iso
product.iso.sha256

3. 构建流水线完整示例#

# 完整的镜像构建 + 测试 + 发布流水线
name: Image Pipeline
on:
push:
branches: [main]
tags: ['v*']
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests
run: |
docker build -t product-test .
docker run --rm product-test pytest tests/
security-scan:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Trivy scan
uses: aquasecurity/trivy-action@master
with:
image-ref: product-test
severity: 'HIGH,CRITICAL'
exit-code: '1'
build-and-push:
needs: [test, security-scan]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/checkout@v4
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
ghcr.io/${{ github.repository }}:${{ github.ref_name }}
ghcr.io/${{ github.repository }}:latest

八、版本管理#

1. 镜像版本命名规范#

product-name:1.2.3-ubuntu22.04-20260315
字段说明:
├── product-name 产品名称
├── 1.2.3 语义化版本号
├── ubuntu22.04 基础系统版本
└── 20260315 构建日期

2. 版本更新检查清单#

  • 更新 CHANGELOG.md
  • 更新版本号(package.json / setup.py / Cargo.toml)
  • 更新基础镜像版本
  • 运行完整测试套件
  • 安全扫描通过
  • 更新文档和部署指南
  • 创建 Git tag
  • 构建并发布镜像
  • 生成 SHA256 校验和

九、常见问题与排查#

问题原因解决方案
ISO 无法启动引导记录缺失检查 isolinux.bin 路径
UEFI 无法启动缺少 EFI 分区添加 efi.img 和 GPT 分区
kickstart 不执行引导参数未指定 ks添加 inst.ks= 参数
仓库找不到包repodata 未更新运行 createrepo_c —update
Docker 镜像过大未使用多阶段构建拆分 builder 和 runtime 阶段
容器内时区不对默认 UTC设置 TZ 环境变量
非 root 无法绑定端口1024 以下端口需要特权使用 8000+ 端口或 NET_BIND_SERVICE

十、参考资料#


参考#

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

如何制作一个标准的产品镜像
https://blog.souloss.com/posts/deploy/deploy-how-to-build-standard-product-image/
作者
Souloss
发布于
2023-06-29
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时