在所有云供应商中,您都获得了基于模板的自动化构建的虚拟机——如何为 VMWare vSphere 构建自定义模板?在这种情况下,HashiCorp Packer 是您想要的工具。这篇文章将介绍创建基于打包程序的虚拟机模板的主要概念

什么是打包机?

Packer 映像允许您在几秒钟内启动完全配置和配置的机器,而不是几分钟或几小时。这不仅有利于生产,也有利于开发,因为开发虚拟机也可以在几秒钟内启动,而无需等待通常更长的配置时间。

由于 Packer 为多个平台创建相同的映像,因此您可以在 AWS 中运行生产,在 OpenStack 等私有云中进行暂存/QA,并在 VMware 或 VirtualBox 等桌面虚拟化解决方案中进行开发。每个环境都运行相同的机器映像,提供终极的可移植性。

Packer 在构建映像时为机器安装和配置所有软件。如果这些脚本中有错误,它们会被及早发现,而不是在机器启动后几分钟。

构建机器映像后,可以快速启动该机器映像并进行冒烟测试以验证一切正常。如果是,您可以确信从该映像启动的任何其他计算机都将正常运行。

Packer 可以非常轻松地利用所有这些优势。

基于 Ubuntu 的示例

安装打包程序

要开始使用 Packer,请下载预构建的二进制文件。安装 Packer 后,通过打开新的命令提示符或控制台并检查 Packer 是否可用来验证安装是否有效:


$ packer
usage: packer [--version] [--help] <command> [<args>]

Available commands are:
    build       build image(s) from template
    fix         fixes templates from old versions of packer
    inspect     see components of a template
    validate    check that a template is valid
    version     Prints the Packer version


ESXi 配置

要在 VMWare ESXi 6 及更高版本中使用上层模板,您必须对 ESXi 主机进行一些修改。ESXi 主机需要一些配置才能让 Packer 工作。Packer 通过 SSH 进行通信,所以首先我们需要打开它。其次,我们将启用从主机发现访客 IP 的选项,然后最终允许远程 VNC 连接。

启用 SSH

在 Web UI 中,导航到“管理”,然后是“服务”选项卡。找到名为“TSM-SSH”的条目,并启用它。您可能希望在默认情况下启用它与主机一起启动。您可以在“操作”下拉列表中执行此操作(它嵌套在“策略”中)。

启用“访客 IP 黑客”

在 ESXi 主机上运行以下命令:


esxcli system settings advanced set -o /Net/GuestIPHack -i 1


这允许 Packer 从 ESXi 推断来宾 IP,而无需 VM 自行报告。

在防火墙上打开 VNC 端口

Packer 使用 VNC 连接到 VM,因此我们将打开一系列端口以允许它连接到它。

首先,确保我们可以编辑防火墙配置:


chmod 644 /etc/vmware/firewall/service.xml
chmod +t /etc/vmware/firewall/service.xml


然后将我们要打开的范围附加到文件的末尾:


<service id="1000">
  <id>packer-vnc</id>
  <rule id="0000">
    <direction>inbound</direction>
    <protocol>tcp</protocol>
    <porttype>dst</porttype>
    <port>
      <begin>5900</begin>
      <end>6000</end>
    </port>
  </rule>
  <enabled>true</enabled>
  <required>true</required>
</service>


最后,恢复权限并重新加载防火墙:


chmod 444 /etc/vmware/firewall/service.xml
esxcli network firewall refresh


模板定义

用于定义我们想要构建的镜像以及如何构建的配置文件在 Packer 术语中称为模板。模板的格式是简单的 JSON。JSON 在人工可编辑和机器可编辑之间取得了最佳平衡,允许轻松制作手工模板和机器生成的模板。

我们将从创建整个模板开始,然后简要介绍每个部分。创建一个文件 example.json 并用以下内容填充它:


{
  "builders": [{
    "name": "Ubuntu-19.04",
    "type": "vmware-iso",
    "vm_name": "Ubuntu-19.04",
    "guest_os_type": "ubuntu-64",
    "tools_upload_flavor": "linux",
    "headless": true,

    "iso_urls": ["iso/ubuntu-19.04-server-amd64.iso",
      "http://cdimage.ubuntu.com/ubuntu/releases/19.04/release/ubuntu-19.04-server-amd64.iso"
    ],
    "iso_checksum": "7e8a0d07522f591dfee9bc9fcd7c05466763161e6cb0117906655bce1750b2fa",
    "iso_checksum_type": "sha256",

    "cpus": 2,
    "memory": 4096,
    "disk_size": 20140,

    "boot_wait": "10s",
    "boot_command": [
      "<esc><wait>",
      "<esc><wait>",
      "<enter><wait>",
      "/install/vmlinuz",
      " initrd=/install/initrd.gz ",
      "auto=true ",
      "url=https://raw.githubusercontent.com/infralovers/packer-preseed/master/ubuntu.cfg ",
      "fb=false ",
      "auto=true ",
      "language=en ",
      "locale=en_US ",
      "priority=critical ",
      "keymap=us ",
      "netcfg/get_hostname={{ .Name }} ",
      "netcfg/get_domain=vm ",
      "debconf/frontend=noninteractive ",
      "debian-installer/country=AT ",
      "console-setup/ask_detect=false ",
      "console-keymaps-at/keymap=us ",
      "DEBCONF_DEBUG=5 ",
      "<enter>"
    ],

    "ssh_username": "vagrant",
    "ssh_password": "vagrant",
    "ssh_port": 22,
    "ssh_wait_timeout": "20m",
    "shutdown_command": "echo 'shutdown -P now' > shutdown.sh; echo 'vargant'|sudo -S sh 'shutdown.sh'",

    "vnc_disable_password": true,
    "format": "vmx",
    "remote_type": "esx5",
    "remote_host": "{{user `esxi_host`}}",
    "remote_datastore": "{{user `esxi_datastore`}}",
    "remote_username": "{{user `esxi_username`}}",
    "remote_password": "{{user `esxi_password`}}",
    "keep_registered": true,
    "skip_export": true

  }]
}


当您删除json中的remote_ * 键时,您还可以开始使用 VMWare Fusion 构建映像。在进行初始工作时,这对于保持循环紧密非常有用,因为调试 debconf 或 kickstart 文件更容易进入本地 devloop 在基于 Ubuntu 的示例中,引导开关 DEBCONF_DEBUG用于在发现设置时在安装日志上输出未设置或设置为无效值。

建立形象

使用正确验证的模板,是时候构建您的第一个映像了。这是通过使用模板文件调用 packer build 来完成的。输出应类似于下图。请注意,此过程通常需要几分钟时间。由于模板使用 esxi 特定数据的变量,因此必须在构建时使用-var参数设置这些变量。


packer build -var "esxi_host=YOUR-ESXI" -var "esxi_datastore=YOUR_DEFAULT_DATASTORE" -var "esxi_username=ESXI_USERNAME" -var "esxi_password=ESXI_PASSWORD" ubuntu.json


供应打包程序模板

上面的命令只会使用preseed 文件生成默认安装的 Ubuntu 19.04 映像,该文件只会生成能够使用sudo的用户。

因此,此设置的下一步是进行一些自定义配置。为此,打包程序能够启动配置程序。使用这些方法,您可以:

  • 设置配置(例如安装 ansible 和依赖项)
  • 进行自定义配置(例如使用 ansible playbook)
  • 删除配置工具(例如删除 ansible)

完整的模板将是这样的:


{
  "builders": [{
   ...
  }],
  "provisioners": [{
      "type": "shell",
      "execute_command": "echo 'vagrant' | {{.Vars}} sudo -S -E bash '{{.Path}}'",
      "script": "scripts/setup.sh"
    },
    {
      "type": "ansible-local",
      "playbook_dir": "ansible",
      "playbook_file": "ansible/main.yml",
      "extra_arguments": ["--extra-vars \"root_password={{user `root_password`}} user_password={{user `user_password`}}\""]
    },
    {
      "type": "shell",
      "execute_command": "echo 'vagrant' | {{.Vars}} sudo -S -E bash '{{.Path}}'",
      "script": "scripts/cleanup.sh"
    }
  ]
}


当地的布局就像


|-- ansible
|   |-- ansible.cfg
|   |-- main.yml
|   |-- roles
|-- scripts
|-- ubuntu.json
`-- variables.json


在 ansible/main.yml 中,您可以定义您的剧本以安装默认工具和库(例如 cloud-init )并设置自定义配置项。

打包机后处理

当运行上层构建过程时,结果是一个定制的 VMWare 机器,它已准备好运行 - 但我们希望获得一个 VMWare 模板来使用此构建生成虚拟机。为此,Packer 安装了后处理器。在我们的用例中,我们将使用 vsphere 后处理器以及最终生成模板的 vsphere-template 处理器。vsphere 后处理器暂停之前生成的虚拟机并将其传输到指定目录。之后,vsphere 模板后处理器将虚拟机转换为机器模板供以后使用。


{
    "builders": [{
   ...
  }],
  "provisioners": [{
  }],
  "post-processors": [
  [{
        "type": "vsphere",
        "cluster": "{{user `esxi_vsphere_cluster`}}",
        "host": "{{user `esxi_vsphere_host`}}",
        "datacenter": "{{user `esxi_vsphere_dc`}}",
        "username": "{{user `esxi_vsphere_username`}}",
        "password": "{{user `esxi_password`}}",
        "datastore": "{{user `esxi_datastore`}}",
        "vm_name": "T_Ubuntu",
        "vm_network": "VM Network",
        "vm_folder": "/Templates",
        "disk_mode": "thin",
        "insecure": "true",
        "overwrite": "true"
      },
      {
        "type": "vsphere-template",
        "host": "{{user `esxi_vsphere_host`}}",
        "insecure": "true",
        "datacenter": "{{user `esxi_vsphere_dc`}}",
        "username": "{{user `esxi_vsphere_username`}}",
        "password": "{{user `esxi_password`}}",
        "folder": "/Templates"
      }
    ]
  ]
}