packer 学习笔记
前言
网上有一个老哥用 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 官方教程。
https://developer.hashicorp.com/packer/tutorials/docker-get-started?product_intent=packer
感谢 bento 项目,一个教你如何创建 vagrant box 的项目,设置 virtualbox 和设置 vagrant key 的脚本写的很好。可以学到如何组织 packer 的 HCL 文件。
Hashicorp 在 Github 上也有一个用 packer 创建 Vagrant Box 的示例: https://github.com/hashicorp-education/ubuntu-24-04。我更推荐参考 Bento 的做法,我认为 Bento 安装 VirtualBox Guest Addition 的方式更好。
缘起
用过 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 其实很简单,只是不会的时候觉得难。
packer 学习笔记的更多相关文章
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- PHP-自定义模板-学习笔记
1. 开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2. 整体架构图 ...
- PHP-会员登录与注册例子解析-学习笔记
1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...
- 2014年暑假c#学习笔记目录
2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- seaJs学习笔记2 – seaJs组建库的使用
原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...
- CSS学习笔记
CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...
- HTML学习笔记
HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...
- DirectX Graphics Infrastructure(DXGI):最佳范例 学习笔记
今天要学习的这篇文章写的算是比较早的了,大概在DX11时代就写好了,当时龙书11版看得很潦草,并没有注意这篇文章,现在看12,觉得是跳不过去的一篇文章,地址如下: https://msdn.micro ...
- ucos实时操作系统学习笔记——任务间通信(消息)
ucos另一种任务间通信的机制是消息(mbox),个人感觉是它是queue中只有一个信息的特殊情况,从代码中可以很清楚的看到,因为之前有关于queue的学习笔记,所以一并讲一下mbox.为什么有了qu ...
随机推荐
- Iceberg 待学习链接
1.Iceberg事务特性解读 https://blog.csdn.net/naisongwen/article/details/123343566 2.FLink全链路时延-测量方式 https:/ ...
- flutter-解决长按TextField出现英文(复制粘贴)问题
第一步 引入依赖 dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter 第二步 在main.dart中添加代码 ...
- [HDU5396] Expression 题解
每次合并两个数,做过石子合并的人都能看出来是区间 dp. 设状态 \(dp_{i,j}\) 表示区间 \([i,j]\) 中合并为一个数的所有情况之和. 那么我们就可以枚举断点 \(k\): \(b_ ...
- Linux - centos6忘记root密码怎么办?
Linux的root密码修改不像Windows的密码修改找回,Windows的登录密码忘记需要介入工具进行解决.CentOS6和CentOS7的密码方法也是不一样的,具体如下 1.开机按esc 2 ...
- springboot项目发布war包
1:修改pom.xml 将"jar"改为"war" <packaging>war</packaging> 将: <dependen ...
- Selenium KPI接口 键盘操作
实现功能:百度搜索框输入selenium->复制内容->sogo搜索框粘贴内容. 首先导入Keys方法 使用格式: driver.findelementbyid("kw" ...
- selenium自动化测试入门
Selenium是一个基于浏览器的自动化测试工具,它提供了一种跨平台.跨浏览器的端到端的web自动化解决方案. Selenium是用于自动化控制浏览器做各种操作,打开网页,点击按钮,输入表单等等,可以 ...
- wordpress:nginx负载均衡+nignweb服务器+mysql数据库+nfs-lsync+rsync备份
目录 所有知识结合,注意正式环境慎用: mariadb服务器 NFS服务器配置 web服务器配置 Nginx负载均衡 backup备份服务器配置rsync NFS服务器安装lsync进行实时同步 所有 ...
- linux 上安装portainer.io
inux 上安装portainer.io 1.portainer.io是什么? 2.安装,运行镜像 3.登陆1.portainer.io是什么?Portainer是一个轻量级的Doc ...
- 代码块--java进阶day03
1.代码块 1.局部代码块 定义在方法中的一对大括号,可以提早释放内存,走完{}里的逻辑后就会被释放,在之后的编程中无法使用 2.构造代码块 位置在类中,方法外的{},在构造方法执行的时候,构造代码块 ...