Packer: мультисборка, пост-процессоры и пользовательские плагины
Привет, Хабр!
Packer — это open-source инструмент для создания идентичных машинных образов для множества платформ из одного исходного файла конфигурации. Т.е с пакером можно автоматизировать создание образов для Amazon EC2, VMware, Docker и т.д, используя единый процесс сборки.
Рассмотрим его возможности мультисборки, пост-процессоров и пользовательских плагинов.
Установка и конфиг. файл
Довольно интуитивная установка здесь.
Конфигурационный файл Packer в HCL2 организован в блоки, аргументы и выражения, которые вместе описывают, как должен быть создан каждый образ.
Блоки — это основные контейнеры для конфигурации в HCL2. Они имеют тип, который определяет их функцию, и тело, содержащее аргументы или даже другие блоки, есть такие блоки:
source
определяет базовый образ и настройки для создания нового образа.build
содержит настройки сборки, включая источники и провайдеры.variable
объявляет переменные для параметризации конфигураций.locals
позволяет определять локальные переменные для удобства.
Аргументы внутри блоков присваивают значения определенным свойствам. Например, в блоке source
аргумент ami_name
может использоваться для определения имени AMI.
Выражения используются для динамического вычисления значений аргументов. HCL2 поддерживает различные типы выражений, включая использование переменных, арифметические операции и вызов функций.
Пример конфигурационного файла на HCL2 для Packer:
variable "region" {
type = string
default = "us-west-2"
}
source "amazon-ebs" "example" {
ami_name = "packer-example-${var.region}"
instance_type = "t2.micro"
region = var.region
source_ami_filter {
filters = {
name = "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
owners = ["099720109477"]
most_recent = true
}
}
build {
sources = [
"source.amazon-ebs.example"
]
}
Здесь мы объявили переменную region
, источник amazon-ebs
с именем example
, который определяет параметры для создания AMI на базе Ubuntu Xenial 16.04. Затем, в блоке build
, указывается, что источником для сборки является source.amazon-ebs.example
.
Краткий обзор синтаксиса
Язык HCL основной инструмент для работы в Packer.
HCL включает базовые арифм. функции add
, subtract
, multiply
, и divide
:
variable "count" {
type = number
default = 5
}
locals {
count_plus_one = add(var.count, 1)
count_double = multiply(var.count, 2)
}
format
, join
, split
, и replace
позволяют манипулировать текстовыми данными:
locals {
formatted_string = format("This is a %s", "string")
joined_string = join(", ", ["Hello", "World"])
splitted_array = split(", ", "Hello, World")
replaced_string = replace("Hello, World", "World", "Packer")
}
Для работы с коллекциями можно использовать length
, element
, sort
, и merge
:
locals {
list_example = ["one", "two", "three"]
list_length = length(local.list_example)
second_element = element(local.list_example, 1)
sorted_list = sort(local.list_example)
}
file
и templatefile
, позволяют включать содержимое файлов непосредственно в конфигурацию:
locals {
user_data = file("${path.module}/user-data.sh")
rendered_template = templatefile("${path.module}/config.tpl", { name = "world" })
}
timestamp
возвращает текущую метку времени:
locals {
current_timestamp = timestamp()
}
md5
, sha1
, и bcrypt
позволяют исполнять криптографические операции для создания хешей строк:
locals {
md5_hash = md5("Hello, World")
}
uuid
генерирует уникальный идентификатор, а cidrsubnet
и cidrhost
используются для работы с сетевыми адресами:
locals {
unique_id = uuid()
subnet_address = cidrsubnet("10.0.0.0/16", 8, 0)
}
Мультисборка
Мультисборка осуществляется через определение нескольких источников сборки в конфиг файле Packer. Каждый источник сборки указывает на конкретную платформу и содержит необходимые параметры для создания образа для этой платформы.
В процессе сборки пакер запускает каждый источник сборки параллельно или последовательно, в зависимости от конфигурации, создавая образы для каждой целевой платформы.
Мультисборка для Amazon EC2 и Docker:
source "amazon-ebs" "amazon-linux" {
ami_name = "packer-example-{{timestamp}}"
instance_type = "t2.micro"
region = "us-west-2"
source_ami_filter {
filters = {
name = "amzn2-ami-hvm-*-x86_64-gp2"
root-device-type = "ebs"
virtualization-type = "hvm"
}
owners = ["137112412989"]
most_recent = true
}
}
source "docker" "ubuntu" {
image = "ubuntu:18.04"
commit = true
}
build {
sources = [
"source.amazon-ebs.amazon-linux",
"source.docker.ubuntu",
]
}
Оба образа создаются параллельно, используя общую конфигурацию сборки.
Мультисборка для VirtualBox и VMware:
source "virtualbox-iso" "windows-10" {
iso_url = "http://example.com/windows-10.iso"
iso_checksum = "abc123"
// доп. параметры для VirtualBox
}
source "vmware-iso" "windows-10" {
iso_url = "http://example.com/windows-10.iso"
iso_checksum = "abc123"
// доп. параметры для VMware
}
build {
sources = [
"source.virtualbox-iso.windows-10",
"source.vmware-iso.windows-10",
]
}
Используя один и тот же исходный ISO-образ, Packer создает два отдельных образа, каждый из которых оптимизирован для своей платформы виртуализации.
Пост-процессоры
Пост-процессоры в Packer конфигурируются в блоке post-processors
и могут быть заданы как одиночные задачи или как цепочки задач. Packer выполнит эти пост-процессоры в указанном порядке после успешного создания всех образов.
Загрузка образа в Amazon S3:
post-processors {
type = "amazon-s3"
only = ["amazon-ebs.ubuntu"]
bucket = "my-packer-images"
region = "us-west-2"
key = "packer/{{user `version`}}/{{.BuildName}}.ami"
acl = "private"
}
Пост-процессор amazon-s3
используется для загрузки созданного образа для Amazon EBS в заданный S3 bucket. Параметры конфигурации указывают целевой bucket, регион, путь и ключ доступа.
Создание Vagrant box:
post-processors {
type = "vagrant"
only = ["virtualbox-iso.ubuntu"]
output = "builds/ubuntu-{{user `version`}}.box"
}
Пост-процессор vagrant
преобразует образ, созданный для VirtualBox, в формат Vagrant box, сохраняя его в указанной директории.
Минификация образа Docker:
post-processors {
type = "docker-tag"
repository = "user/ubuntu"
tag = "latest"
}
post-processors {
type = "docker-push"
only = ["docker.ubuntu"]
}
Пост-процессоры docker-tag
и docker-push
юзаются для тегирования и последующей загрузки созданного Docker образа в Docker Hub.
Использование цепочек пост-процессоров:
post-processors {
sequence {
post-processors {
type = "vagrant"
}
post-processors {
type = "vagrant-cloud"
box_tag = "myusername/mybox"
access_token = "{{user `vagrant_cloud_token`}}"
}
}
}
Каждый пост-процессор имеет свой набор конфигурационных параметров:
type
: тип пост-процессора (например,vagrant
,amazon-s3
).only
: определяет, для каких сборок должен быть применен пост-процессор.except
: исключает определенные сборки из использования пост-процессора.keep_input_artifact
: указывает, следует ли сохранять исходный образ после применения пост-процессора.
Пользовательские плагины
Packer предоставляет утилиту packer-sdc
для генерации шаблона кода плагина:
packer-sdc plugin new -name=my-custom-plugin -type=[builder|provisioner|post-processor]
Разработка плагина включает реализацию определенного интерфейса в зависимости от типа плагина. Например, для создания нового провайдера вы должны реализовать интерфейс Builder
. Packer использует RPC для взаимодействия с плагинами, но большая часть этой работы абстрагирована, т.е можно сфокуситься на бизнес-logic:
package main
import (
"github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/plugin"
)
type MyCustomBuilder struct {
// интерфейс Builder
}
func (b *MyCustomBuilder) Prepare(raws ...interface{}) ([]string, []string, error) {
// логика подготовки
}
// остальная реализация
func main() {
server, err := plugin.Server()
if err != nil {
panic(err)
}
server.RegisterBuilder(new(MyCustomBuilder))
server.Serve()
}
Можно использовать стандартные инструменты Go для написания модульных тестов.
func TestMyCustomBuilder_Prepare(t *testing.T) {
// тест метода Prepare вашего плагина
}
После разработки и тестирования плагина его нужно собрать и установить в локал директорию Packer.
go build -o packer-plugin-my-custom-plugin .
mkdir -p ~/.packer.d/plugins
mv packer-plugin-my-custom-plugin ~/.packer.d/plugins/
После установки плагина можно использовать его в своих Packer шаблонах, указав его имя в конфигурации:
{
"builders": [
{
"type": "my-custom-plugin",
"some_parameter": "value"
}
]
}
my-custom-plugin
— это тип плагина, а some_parameter
— один из параметров, которые определили в его конфигурации.
Далее можно лить на гит свое сокровище или же оставить у себя на хранение.
С официальными плагинами пакер можно ознакомить здесь. А больше про инфраструктуру вы можете узнать в рамках практических онлайн-курсов от экспертов отрасли.