跳转至

28 - 自动化部署与镜像管理(debootstrap / cloud-init / Packer)

前提条件

  • 已完成 Ansible 基础配置(控制节点与被管节点连通)
  • 以 root 身份登录,或 ops 用户执行 sudo -i 切换至 root 环境
  • 系统运行在 Debian 12 Bookworm
  • KVM/QEMU 已安装(Packer QEMU 构建需要,参见第 25 章)
  • 建议准备一台干净虚拟机或云实例用于测试 cloud-init

全局参数

主机名 linuxdc,IP 192.168.1.100/24,SSH 端口 2222,运维用户 ops

三种工具定位

工具 用途 输出产物 典型场景
debootstrap 构建最小 Debian 根文件系统 目录 / tarball chroot、LXC 模板、离线环境
cloud-init 云实例首次启动个性化初始化 运行时配置 AWS / Azure / GCP / Proxmox 实例
Packer 自动化构建标准化机器镜像 qcow2 / AMI / VMDK 等 批量部署、不可变基础设施

详细步骤

1. debootstrap — 构建最小根文件系统

apt install -y debootstrap

创建最小 Debian 12 根文件系统(使用国内镜像加速):

mkdir -p /opt/chroot-bookworm
debootstrap --arch=amd64 bookworm /opt/chroot-bookworm \
    https://mirrors.tuna.tsinghua.edu.cn/debian/

进入 chroot 环境进一步定制:

# 挂载必要的虚拟文件系统
mount -t proc  proc    /opt/chroot-bookworm/proc
mount --rbind  /sys    /opt/chroot-bookworm/sys
mount --rbind  /dev    /opt/chroot-bookworm/dev

chroot /opt/chroot-bookworm /bin/bash

在 chroot 内执行(此时已是新系统环境):

apt update
apt install -y vim locales systemd-sysv openssh-server

# 配置 locale
dpkg-reconfigure locales    # 选择 en_US.UTF-8 或 zh_CN.UTF-8

# 设置 root 密码
passwd root

exit    # 退出 chroot

清理并卸载:

umount -R /opt/chroot-bookworm/proc
umount -R /opt/chroot-bookworm/sys
umount -R /opt/chroot-bookworm/dev

打包为 tarball(可导入 LXC 或作为容器基础镜像):

tar -czf /opt/debian-bookworm-minimal.tar.gz \
    -C /opt/chroot-bookworm .
ls -lh /opt/debian-bookworm-minimal.tar.gz

检查点

tarball 文件存在,大小通常在 100–300 MB 之间。解压后 chroot 进入,cat /etc/debian_version 显示 12.x

2. cloud-init — 云实例初始化

安装(在作为云模板的机器上):

apt install -y cloud-init

cloud-init user-data 配置示例:

创建测试配置文件:

vim /tmp/test-cloud-config.yaml
#cloud-config

# 设置主机名
hostname: linuxdc-node
fqdn: linuxdc-node.local

# 创建运维用户
users:
  - name: ops
    groups: sudo
    shell: /bin/bash
    sudo: "ALL=(ALL) NOPASSWD:ALL"
    ssh_authorized_keys:
      - "ssh-ed25519 AAAAC3... ops@linuxdc"    # 替换为实际公钥

# 安装基础软件包
packages:
  - vim
  - htop
  - git
  - curl

# 首次启动执行命令
runcmd:
  - [ systemctl, enable, --now, ssh ]
  - apt update && apt full-upgrade -y
  - echo "cloud-init completed at $(date)" >> /var/log/cloud-init-custom.log

# 时区
timezone: Asia/Shanghai

本地模拟测试:

# 清除上次运行记录
cloud-init clean --logs

# 以指定配置文件运行 init 阶段
cloud-init init --local

# 查看执行日志
cat /var/log/cloud-init.log | tail -30
cloud-init status

生产使用方式

云平台(AWS / GCP / Azure / Proxmox)在创建实例时,将 user-data 内容粘贴到对应的配置字段。实例首次启动时 cloud-init 自动读取并执行,此后标记为已完成,不再重复执行(除非执行 cloud-init clean)。

cloud-init 数据源类型:

数据源 平台
DataSourceEC2 AWS EC2
DataSourceAzure Microsoft Azure
DataSourceGCE Google Cloud
DataSourceOpenStack OpenStack / Proxmox
DataSourceNoCloud 本地测试(从文件或 ISO 读取)

3. Packer — 自动化镜像构建

安装(HashiCorp 官方 apt 源):

apt install -y wget gnupg

wget -O- https://apt.releases.hashicorp.com/gpg \
    | gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg

echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
    https://apt.releases.hashicorp.com $(lsb_release -cs) main" \
    | tee /etc/apt/sources.list.d/hashicorp.list

apt update
apt install -y packer
packer version

创建项目目录:

mkdir -p ~/packer-debian/http
cd ~/packer-debian

Packer HCL 配置文件(debian12.pkr.hcl):

vim debian12.pkr.hcl
packer {
  required_plugins {
    qemu = {
      version = ">= 1.0.0"
      source  = "github.com/hashicorp/qemu"
    }
  }
}

variable "ssh_password" {
  default   = "packer-build-temp"
  sensitive = true
}

source "qemu" "debian12" {
  # ISO 需提前下载到本地,从官网获取 checksum
  iso_url      = "file:///opt/iso/debian-12-amd64-netinst.iso"
  iso_checksum = "sha256:见官方校验页面"

  ssh_username     = "ops"
  ssh_password     = var.ssh_password
  ssh_timeout      = "30m"
  shutdown_command = "echo '${var.ssh_password}' | sudo -S shutdown -P now"

  disk_size        = "20000"
  format           = "qcow2"
  accelerator      = "kvm"
  headless         = true
  vm_name          = "debian12-template"
  memory           = 2048
  cpus             = 2

  boot_wait    = "5s"
  boot_command = [
    "<esc><wait>",
    "install auto=true priority=critical preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg<enter><wait>"
  ]

  http_directory   = "http"
  output_directory = "output-debian12"
}

build {
  sources = ["source.qemu.debian12"]

  # 基础系统更新
  provisioner "shell" {
    inline = [
      "apt-get update",
      "apt-get full-upgrade -y",
      "apt-get install -y qemu-guest-agent cloud-init openssh-server",
      "systemctl enable qemu-guest-agent cloud-init",
      "apt-get clean"
    ]
    execute_command = "echo '${var.ssh_password}' | sudo -S bash -c '{{ .Path }}'"
  }

  # 安全加固(使用已有 Ansible playbook)
  provisioner "ansible" {
    playbook_file = "../ansible/playbooks/template-hardening.yml"
    user          = "ops"
    extra_arguments = [
      "--extra-vars", "ansible_become_pass=${var.ssh_password}"
    ]
  }
}

ISO checksum 必须校验

iso_checksum 字段必须填写从 Debian 官方网站(https://www.debian.org/CD/verify)获取的真实 SHA256 值,不可省略或填写占位符。Packer 会在构建开始前验证 ISO 完整性,校验失败则终止构建。

执行构建:

# 初始化插件
packer init .

# 语法检查
packer validate .

# 构建(--on-error=ask 出错时暂停便于调试)
packer build --on-error=ask .

构建完成后产物:output-debian12/debian12-template.qcow2,可直接导入 KVM / Proxmox / OpenStack。

实践任务

  1. debootstrap 创建最小 Debian 12 chroot 环境,进入后安装 openssh-server,打包为 tarball
  2. 在一台虚拟机上安装 cloud-init,编写包含用户创建和软件包安装的 user-data,执行 cloud-init clean && cloud-init init --local 模拟运行
  3. 安装 Packer,创建项目目录,编写基于本地 ISO 的 QEMU 构建模板,执行 packer validate . 验证语法
  4. (可选)完整执行 packer build,将 Ansible hardening playbook 集成为 provisioner,输出 qcow2 镜像

自测问题

1. debootstrap 和 Packer 在构建系统镜像时的主要区别是什么?

debootstrap 是 Debian 专用的底层工具,直接从 APT 源提取软件包构建最小根文件系统(目录形式),适合 chroot、LXC、离线环境,输出为目录或 tarball,不含引导程序。Packer 是平台无关的镜像自动化构建工具,驱动虚拟化引擎(QEMU / VMware / AWS 等)运行完整的 OS 安装流程,然后通过 provisioner 执行配置,输出为可直接启动的磁盘镜像(qcow2 / AMI / VMDK),适合生产机器模板。两者可以组合:用 debootstrap 生成基础 rootfs,再由 Packer 打包成完整磁盘镜像。

2. cloud-init 的 user-data 和 meta-data 分别用于什么?

user-data 是用户提供的个性化配置内容(#cloud-config 格式的 YAML 或 shell 脚本),用于定义主机名、用户、SSH 密钥、软件包、运行命令等实例初始化逻辑,由用户在创建实例时写入。meta-data 是云平台提供的实例元信息(实例 ID、IP 地址、区域、标签等),由云平台自动注入,cloud-init 读取后用于配置主机网络、生成唯一主机名等。两者通过不同的数据源渠道提供(HTTP 元数据服务 / ISO / 文件),用户通常只需编写 user-data。

3. Packer 的 provisioner 有哪些常见类型?ansible provisioner 的优势是什么?

Provisioner 说明
shell 在构建实例内执行 shell 脚本或内联命令
file 上传文件到构建实例
ansible 调用 Ansible playbook 对构建实例执行配置
ansible-local 在构建实例内部运行 Ansible(需预装)
chef-solo / puppet 调用 Chef / Puppet 配置管理

ansible provisioner 的优势:复用已有的 playbook 和 roles(无需重写为 shell 脚本);任务幂等,构建失败可安全重试;配置即代码,变更有版本记录;同一 playbook 既可用于 Packer 构建时配置,也可用于运行时的配置漂移修复,保持一致性。

4. 生产环境中为什么推荐将 Packer 构建的镜像作为所有新实例的起点?

标准化镜像确保所有新实例从相同的已知良好状态启动:安全加固(内核参数、SSH 配置、防火墙规则)已内置,不依赖实例启动后的手动配置;软件包版本固定,避免"同批次不同机器安装了不同版本"的漂移问题;启动速度更快(无需在线安装大量软件包);镜像经过测试和扫描(Trivy、Lynis),安全基线有保障。这是"不可变基础设施"理念的核心实践:实例不应被就地修改,配置变更通过构建新镜像并替换实例来实现。

总结

debootstrap 适合轻量本地根文件系统构建,cloud-init 实现云实例的无人值守个性化初始化,Packer 将整个镜像构建流程代码化。三者配合 Ansible,构成"基础设施即代码"流水线的核心组件:标准化镜像 → 自动化部署 → 配置管理,实现从代码提交到生产实例的全链路自动化。