Packer
- 是什么?
- 自动化多平台镜像构建工具
- 使用场景
- CD
- Dev/Prod Parity
- Appliance/Demo Creation
- 核心流程
- 启动 builder,提供一致的环境
- vm、docker
- 执行 provisioners - 服务开通
- 构建 artifact
- file provisioner 下载 artifact 到本地
- 执行 post-processor
- artifice 验证 产出物 存在
- 上传到 docker hub、oss 等其他地方
- 启动 builder,提供一致的环境
- 注意
- Builder 不支持依赖
- 自动加载变量
*.auto.pkrvars.hcl
PACKER_LOG=1
开启日志
- 参考
# macOS
brew install packer
packer version
# timestamp,target,type,data
packer -machine-readable version
packer -autocomplete-install
packer build template.json
# console
# 实验变量替换
# help exit variables
packer console my_template.json
echo {{timestamp}} | packer console
# hcl2 console - 1.6+
packer console folder/
packer console file.pkr.hcl
echo "1 + 5" | packer console --config-type=hcl2
packer console --config-type=hcl2
packer fix old.json > new.json
packer inspect template.json
packer validate my-template.json
# 使用 JQ 删除评论
jq 'walk(if type == "object" then del(._comment) else . end)' commented_template.json > uncommented_template.json
# 手动安装
# https://packer.io/downloads.html
ver=$(curl -sfL https://api.github.com/repos/hashicorp/packer/releases/latest | jq .tag_name -r)
ver=${ver##v}
curl -LOC- https://releases.hashicorp.com/packer/${ver}/packer_${ver}_linux_amd64.zip
HCL2
packer build folder
- variables.pkr.hcl
- locals.pkr.hcl
- sources.pkr.hcl
- build.pkr.hcl
- 引号和 heredoc 里使用
${
%{
- #9176 - HCL2: implementation list
# 全局定义可复用的 builder
source "docker" "base" {
image = "wener/base"
discard = true
pull = false
}
# 本地变量
locals {
# 直接引用
wee = local.baz
# 字符串中替换
baz = "Foo is '${var.foo}' but not '${local.wee}'"
}
# 变量定义
variable "foo" {
type = string
default = "the default value of the `foo` variable"
description = "description of the `foo` variable"
}
# 构建
build {
name = "test-build"
# 引用
source "docker.base" {}
# 多个
# source = [ "source.docker.first", "source.docker.second" ]
provisioner "shell" {
# 指定 source 执行
only = ["source.docker.base"]
# 等待指定时间
pause_before = "10s"
max_retries = 5
timeout = "5m"
inline = [ "echo Tesing" ]
}
post-processor "shell-local" {
inline = ["echo Down working"]
}
post-processor "checksum" {
checksum_types = [ "md5", "sha512" ]
keep_input_artifact = true
only = ["source.amazon-ebs.example"]
}
}
Template
- builders
- alicloud-ecs - 阿里云 ECS 运行
- docker - Docker 里运行
- qemu - 通过 QEMU 运行
- libvirt - 通过 libvirt 运行
- tencentcloud-cvm - 腾讯云 CVM 运行
- file - 基于文件构建 artifact 然后运行 post-processors
- null - 设置 SSH,运行 provisioners
- communicator - 通信机制
- post-processors
- alicloud-import
- artifice - 指定产出物,之后的 post-processors 能访问到
- compress
- checksum
- docker-import
- docker-push
- docker-save
- docker-tag
- manifest
- shell - 本地执行
- provisioners
- ansible-local - 本地执行
- ansible - 远程执行
- breakpoint - 等待用户确认
- file - 文件上传
- powershell
- shell
- shell-local
- variables
{{user 'aws_access_key'}}
{{env 'MY_SECRET'}}
{{ consul_key 'my_image/softs_versions/next' }}
{{ vault '/secret/data/hello' 'foo'}}
- 数组变量可使用逗号拼接的字符串
-var=name=value
-var-file=vars.json
{
"_comment": "This is a comment",
// 必须 - 定义一个或多个 builder
"builders": [{}],
"description": "",
// packer 最小版本
"min_packer_version": "",
// 后处理步骤
"post-processors": [{}],
// 安装配置和包的步骤
"provisioners": [{}],
// 错误时执行
"error-cleanup-provisioner": {
"type": "shell-local",
"inline": ["echo 'rubber ducky'> ducky.txt"]
},
// 变量定义
"variables": {
"my_secret": "{{env `MY_SECRET`}}",
"not_a_secret": "plaintext",
"foo": "bar"
},
// 定义敏感变量
"sensitive-variables": ["my_secret", "foo"]
}
模版语法
- 模板语法
{{ }}
{{timestamp}}
{{.Variable}}
func | desc |
---|---|
build_name | 构建名 |
build_type | 构建类型 |
clean_resource_name | 干净的资源名字,空格转- ,小写,截取长度(GCE 63,Azure 80) |
env | 环境变量 |
build | 构建时的状态和连接信息 |
isotime [FORMAT] | 时间 |
lower | |
packer_version | |
pwd | |
replace | ( old, new string, n int, s ) |
replace_all | 全替换 |
split | 分割字符串 |
template_dir | 模板目录 |
timestamp | UNIX 时间戳,建议设置为变量使用,否则会变 |
uuid | UUID |
upper | 大写 |
user | 用户变量 |
- build
- ID - 构建 VM 的 ID - 例如 EC2 的 instance id
- Host, Port, User, Password - 访问机器的信息,用于 Ansible 或 Inspec
- ConnType - 通信类型
- PackerRunUUID - 构建 ID
- PackerHTTPIP, PackerHTTPPort, PackerHTTPAddr - packer 提供的 http 文件服务 - vm 中的 http 目录
- SSHPublicKey, SSHPrivateKey - packer 链接的密钥
条件变量
{
"type": "shell-local",
"command": "if [ ! -z \"{{user `do_nexpose_scan`}}\" ]; then python -u trigger_nexpose_scan.py; fi"
}
HOME
{
"variables": {
"home": "{{env `HOME`}}"
},
"builders": [
{
"type": "google",
"account_file": "{{ user `home` }}/.secrets/gcp-{{ user `env` }}.json"
}
]
}
communicator
- communicator - 通信机制
- none - 不设置,不能使用 provisioners
- ssh
- ssh_host
- ssh_port
- ssh_username
- ssh_password
- ssh_keypair_name
- temporary_key_pair_name
- ssh_clear_authorized_keys
- ssh_private_key_file
- ssh_pty
- ssh_timeout
- ssh_agent_auth
- ssh_disable_agent_forwarding
- ssh_handshake_attempts
- ssh_bastion_host
- ssh_bastion_port
- ssh_bastion_agent_auth
- ssh_bastion_username
- ssh_bastion_password
- ssh_bastion_interactive
- ssh_bastion_private_key_file
- ssh_file_transfer_method
- ssh_proxy_host
- ssh_proxy_port
- ssh_proxy_username
- ssh_proxy_password
- ssh_keep_alive_interval
- ssh_read_write_timeout
- ssh_remote_tunnels
- ssh_local_tunnels
- ssh_public_key
- ssh_private_key
- winrm
- winrm_username
- winrm_password
- winrm_host
- winrm_port
- winrm_timeout
- winrm_use_ssl
- winrm_insecure
- winrm_use_ntlm
- docker
- Docker Builder
{
"communicator": "ssh",
"ssh_username": "myuser",
"pause_before_connecting": "10m"
}
docker
{
"builders": [
{
"type": "docker",
// 基础镜像
"image": "ubuntu",
// 三选一 commit, discard, export_path
// 提交
"commit": true,
// 丢弃
"discard": true,
// 导出到文件
"export_path": "image.tar"
}
],
"post-processors": [
[
{
"type": "docker-import",
"repository": "hashicorp/packer",
"tag": "0.7"
},
"docker-push"
]
]
}
qemu
- 启动参数
-cdrom /xxx/packer_cache/xxx.iso
-name packer-alpine
-vnc 127.0.0.1:92
-boot once=d
-netdev user,id=user.0,hostfwd=tcp::4287-:22
-device virtio-net,netdev=user.0
# 挂载为 /dev/vda
-drive file=output-alpine/packer-alpine,if=virtio,cache=writeback,discard=ignore,format=qcow2
-m 512M
-machine type=pc,accel=hvf