前言

网上有一个老哥用 packer 制作镜像的博客里开篇就提到[1]

Failure is success in progress.

—— Albert Einstein

不要害怕失败,在用 packer 的过程中你可能会失败很多次。我就经历了 virtualbox 安装失败、启动不了虚拟机,provisioning 阶段失败,ks.cfg 找不到,安装系统的时候失败……

手动创建 Vagrant Base Box 我也经历了十几次失败,打包的镜像不能 add,识别不了系统,SSH连接不上……

参考资料

互联网上有一些好资源:

如果你想了解手动创建 Vagrant Base Box 的过程和注意事项请查看 Vagrant 的官方文档以及theurbanpenguin的视频教程:

如果你想学习 Packer,我推荐你阅读 packer 官方教程

缘起

用过 Vagrant 就不会再想重复在虚拟机里装系统了。只需要一条命令就能立刻启动一个刚安装好的虚拟机,这比手动配置虚拟机并安装操作系统要快多了。在 Vagrantfile 里面可以定义 Provision,初次启动虚拟机的时候配置好环境。在 Git 仓库里带上 Vagrantfile,大家就能一键启动一个一模一样的开发环境。

如果你想定制 Vagrant Box,或者你使用的操作系统没有网上公开的 Vagrant Box 可用,你要创建一个 Vagrant Base Box。vagrant package可以将虚拟机打包成一个 Vagrant Box,但是只支持 VirtualBox 和 Hyper-V。vagrant package需要你手动配置虚拟机并安装好操作系统,配置 SSH 等,要么你基于现有的 vagrant box 启动一个机器,做一点修改然后再重新打包。手动配置,必须基于现有的 vagrant box,只支持 virtualbox 和 hyperv,这些都是创建 Vagrant Box 的痛点。

Packer 支持各种机器,通过 HCL 配置文件自动化创建机器的镜像。

我首先通过 Vagrant 的官方文档和 Youtube 上的视频教程,以及网上的各种博客学会了手动创建 Vagrant Base Box

阅读 Packer 官方教程,通过 Packer Docker 镜像教程学习了 Packer 的基本概念。使用 VirtualBox-iso Builder 和 Packer 的 vagrant 插件,实现一键从 ISO 安装镜像到 Vagrant Box。

Packer 官方教程没有直接讲如何从 ISO 安装镜像到 Virtual Box 的 Vagrant Box。Bento 项目里有各种 Linux 发行版制作 Vagrant Box 的代码,这就是基础设施即代码(IaC)的好处,想知道别人怎么配的,看代码就行了。

使用 Packer 镜像构建过程透明可追溯,避免“黑盒”操作(如手动修改镜像后忘记记录)。写文档记录如何配置环境十分重要,光有如何配置环境的文档还不够,文档作者在写的过程中很容易出现疏漏。如果在环境配置过程中做了某个修改后忘记记录,别人就无法复现你的环境了。又或者有的人文档写得不太好,别人跟着他的文档操作根本不能成功(有的人写文档也没想要别人能成功复现)。换句话说,文档记录的配置过程只是你的一面之词。只有配置代码化,任何人都能通过你给的代码启动一个一模一样的环境。这才算是完全透明可追溯的环境。HCL 配置文件本身就是代码,支持 Git 管理、代码审查和迭代优化。将镜像构建过程代码化(HCL),实现一键生成标准化系统镜像。

从一个 template.pkr.hcl 开始

Docker 启动一个容器镜像比虚拟机快得多,学习 Packer 可以从定制 Docker 容器开始[2]

// teamplate.pkr.hcl
packer {
required_plugins {
docker = {
version = ">= 1.0.8"
source = "github.com/hashicorp/docker"
}
}
} source "docker" "ubuntu" {
image = "ubuntu:jammy"
commit = true
} build {
name = "learn-packer"
sources = [
"source.docker.ubuntu"
]
}

使用 packer 你不需要知道所有的 HCL 语法细节[3]。通常 packer 的配置文件名以.pkr.hcl 结尾。HCL 的语法很简单,主要是块(blocks)参数(arguments)。我对 HCL 的了解有限,一对大括号就是一个块,大括号里面的叫做属性也被叫做参数。

packer 块声明一些需要的插件。在命令行下运行 packer init template.pkr.hcl 安装需要的插件。

Each builder has its own unique set of configuration attributes.

source 块是用来配置 builder 的。source 块后面带着的 "docker" 是 build_type,"ubuntu" 是名字。source 块里面有什么属性取决于 build_type。source 就是告诉 packer 从什么地方/文件/基础镜像启动一个新的机器或者容器source 块是 builder 的配置,有什么配置属性取决于 builder plugin

builder 负责创建机器并生成镜像。当然这里的机器也可以是容器,镜像也可以就是一个虚拟机的硬盘文件。Builder 插件是用来创建机器和把机器打包成镜像的

build 块定义具体要 packer 做什么。在 sources 引用之前定义的 source 块。在终端运行 packer build 命令创建镜像。

packer build template.pkr.hcl

实际上你已经学会用 Packer 了,只不过你还需要更复杂的配置。你需要安装系统后配置系统,得到的系统镜像打包成 Vagrant Box 或者 Docker 镜像。

Provison

provision 是动词:为...提供必须品。在计算机里面就是准备环境的意思,为了部署或者开发提供必须要安装的软件和配置,就是 provision

provisioner 就是安装软件和配置的方式。provisoner 有 shell,ansible 等等。

provisioning 是 provison 的动名词,就是搭建配置 IT 基础设施的意思。provisioning 通俗讲就是搭环境,或者配环境。

HCL 变量

template.pkr.hcl 的每一个属性都是写死的,那还叫什么模板呢?

packer 里的变量其实是常量,可以理解为参数。通过配置参数,使用同一个模板(template)构建不一样的镜像

在 HCL 文件里面使用变量块声明变量[4]

variable "docker_image" {
type = string
default = "ubuntu:jammy"
}

在 HCL 文件的其他地方就可以使用这个变量。

source "docker" "ubuntu" {
- image = "ubuntu:jammy"
+ image = var.docker_image
commit = true
}

变量通常有默认值,也可以没有默认值。变量的值是可以通过命令行参数指定的,也可以从配置文件(.pkrvars.hcl)读取变量的值。正是因为属性的值是可以通过变量配置,所以 Packer 的配置文件被称为模板(packer template)。

多文件 Packer 模板

packer build 可以接收一个目录作为参数[5],目录里面以 .pkr.hcl 结尾的文件都会被 packer 分析。

以 Bento 项目为例,将模板分成 3 个文件。

pkr-variables.pkr.hcl
pkr-builder.pkr.hcl
pkr-sources.pkr.hcl

pkr-variables 里面放的全是变量的声明,pkr-sources 里面全是 source 块,pkr-builder 里面是 build 块和 packer 块。各自的文件里面使用 locals 块根据变量来决定使用哪些脚本做 provison。locals 块就是一个根据变量的值做判断和计算地地方,然后给计算得到的结果一个新的名字。

Packer 制作 Vagrant Box 踩坑记录

  • ks.cfg 文件的 EOL 必须是 LF('\n')。又多了一个不用 Windows 写代码的理由。

总结

学习 packer 制作 Vagrant Box 的过程中经历了 virtualbox 不能安装、启动不了虚拟机,provisioning 阶段失败,ks.cfg 找不到,安装过程失败。

我真的有打算要放弃了。但是还有那么一丁点成功的希望,最后折腾了三四天还是成功了,我才明白 “Failure is success in progress” 的含义。

学一个东西带来的收获往往不止是这个学会这个东西本身。在学习的过程中会增长见识,也会有一些心态上的锻炼。学习也是一种修行。与其担心 AI 在各个方面都比我强,担心未来,不如去学一些自己不会的东西,自然就会有收获。

题外话:

原本想写个制作 Vagrant Box 的教程,但是心里很乱。不知道该怎么写起,写一个点就容易越写越深,介绍了 Packer 的好处才发现光顾着介绍使用 Packer 有啥好了。想录一个视频,似乎这也没什么好录的,既然我能在网上学会,别人也能,那我录一个视频也没什么太大的用。干脆写一个学习笔记吧。packer 其实很简单,只是不会的时候觉得难。


  1. https://medium.com/@maros.kukan/automating-golden-image-builds-with-packer-3b1c6010b467

  2. Docker | Packer | HashiCorp Developer

  3. https://developer.hashicorp.com/packer/guides/hcl

  4. Input and Local Variables guide | Packer | HashiCorp Developer

  5. HCL Templates | Packer | HashiCorp Developer

packer 学习笔记的更多相关文章

  1. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  2. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  3. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  4. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

  5. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  6. seaJs学习笔记2 – seaJs组建库的使用

    原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...

  7. CSS学习笔记

    CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...

  8. HTML学习笔记

    HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...

  9. DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记

    今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...

  10. ucos实时操作系统学习笔记——任务间通信(消息)

    ucos另一种任务间通信的机制是消息(mbox),个人感觉是它是queue中只有一个信息的特殊情况,从代码中可以很清楚的看到,因为之前有关于queue的学习笔记,所以一并讲一下mbox.为什么有了qu ...

随机推荐

  1. C#/.NET/.NET Core优秀项目和框架2025年1月简报

    前言 公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的详细介绍.功能特点.使用方式以及部分功能 ...

  2. ORACLE SELECT INTO 赋值为空,抛出 NO DATA FOUND 异常

    例子: DECLARE ORDER_NUM VARCHAR2(20); BEGIN SELECT S.ORDER_NUM INTO ORDER_NUM FROM SALES_ORDER S WHERE ...

  3. python基础-元组-集合-字典

    元组 概念 元组:由一系列变量组成的不可变序列容器 序列:支持索引和切片 不可变:1.没有增删改的方法 2.所有的操作都不会直接作用于原数据 定义 <span style="font- ...

  4. ESP32-S3-WROOM-1-N16R8

    ESP32-S3-WROOM-1-N16R8 基于立创实战派S3 参考链接:实战派开发板S3介绍 | 立创开发板技术文档中心 硬件和代码,(大部分图片)基于立创文档,在此基础上进行个人的学习记录和理解 ...

  5. 使用vscode开发微信小程序

    1. 安装插件 2. 文件-打开文件夹-将新建的微信小程序导入,代码会有高亮的效果 3. 编辑内容,查看效果,如果有就说明插件引入成功.

  6. SpringBoot - [00] 注解大全

    原文链接:https://mp.weixin.qq.com/s/DgNhohtJyEq4vMGEzqrP8A @SpringBootApplication 这个注解用于标识一个SpringBoot应用 ...

  7. ragflow-ollama 知识库建立测试

    ollama查看模型 C:\Users\DK>ollama show deepseek-r1:7b Model architecture qwen2 parameters 7.6B contex ...

  8. springboot2.1.6整合activiti6.0(二)--网页流程编辑器bpmnjs

    网页流程编辑器bpmnjs 官网:https://bpmn.io/ github:https://github.com/bpmn-io/bpmn-js-examples 因为还需要做一些改造,才能使其 ...

  9. 当我老丈人都安装上DeepSeek的时候,我就知道AI元年真的来了!

    关注公众号回复1 获取一线.总监.高管<管理秘籍> 春节期间DeepSeek引爆了朋友圈,甚至连我老丈人都安装了APP,这与两年前OpenAI横空出世很不一样,DeepSeek似乎真的实现 ...

  10. MySQL 常用优化

    目录 单表优化 字段 索引 查询SQL 引擎 MyISAM InnoDB 系统调优参数 升级硬件 读写分离 缓存 表分区 分区的好处是: 分区的限制和缺点: 分区的类型: 分区适合的场景有: 垂直拆分 ...