Packer: введение, примеры

 

packer_logoВведение

Packer – утилита для сборки образов виртуальных машин для различных платформ из одного файла конфигурации.

Packer не является заменой таких средств как Chef или Ansible, и может использовать их для конфигрирования системы перед сборкой образа.

Образ, создаваемый Packer, включает в себя настроенную операционную систему, необходимый набор ПО, который позволяет быстро развернуть новую машину. Packer умеет создавать образы AMI для EC2, VMDK/VMX файлы для VMware, OVF для VirtualBox и т.д.

Полный список поддерживаемых платформ можно найти тут>>>.

Пример использования Packer с другими системами, входящими в Atlas:

paker_1

Установка Packer

Выбираем подходящий пакет  на странице загрузок Packer, загружаем архив:

$ wget https://releases.hashicorp.com/packer/0.10.2/packer_0.10.2_linux_amd64.zip

Устанавливаем:

$ unzip packer_0.10.2_linux_amd64.zip
$ sudo cp packer /usr/local/bin/
[sudo] password for setevoy: 
$ packer --version
0.10.2

Сборка образа

Файл конфигурации, в котором описывается создаваемый образ, в терминологии Packer называется шаблоном и представляет собой JSON-файл.

Создаём первый шаблон – ec2_example.json:

{
  "variables": {
    "aws_access_key": "",
    "aws_secret_key": ""
  },
  "builders": [{
    "type": "amazon-ebs",
    "access_key": "{{user `aws_access_key`}}",
    "secret_key": "{{user `aws_secret_key`}}",
    "region": "us-east-1",
    "source_ami": "ami-fce3c696",
    "instance_type": "t2.micro",
    "ssh_username": "ubuntu",
    "ami_name": "packer-example {{timestamp}}"
  }]
}

Variables

Во время сборки – вы передаёте значения для aws_access_key и aws_secret_key в пользовательских переменных, которые могут быть заданы в файле, в переменных окружения или переданы через командную строку.

Это позволяет убрать некоторые параметры из шаблона, такие как данные для авториазации.

Подробее о user variables – тут>>>.

Builders

Шаблон включает в себя секцию builders (“сборщики“), которая состоит из массива JSON-объектов, описывающий конкретный сборщик. builder является компонентом Packer для создания машины и затем – её образа.

В примере выше используется только один такой сборщик – amazon-ebs, который является сборщиком образов Amazon EC2 AMI. Он создаёт виртуальную машину из исходного образа, выполняет её настройку, устанавливая и настраивая необходимое ПО, а затем – создаёт из этой машины новый AMI. Описание других сборщиков для Amazon можно найти тут>>>, а больше про buildersтут>>>.

Валидация шаблона

Прежде, чем запустить сборку нового образа – выполним проверку шаблона с помощью validate:

$ packer validate --help
Usage: packer validate [options] TEMPLATE

  Checks the template is valid by parsing the template and also
  checking the configuration with the various builders, provisioners, etc.

  If it is not valid, the errors will be shown and the command will exit
  with a non-zero exit status. If it is valid, it will exit with a zero
  exit status.

Options:

  -syntax-only           Only check syntax. Do not verify config of the template.
  -except=foo,bar,baz    Validate all builds other than these
  -only=foo,bar,baz      Validate only these builds
...

Проверяем:

$ packer validate ec2_example.json 
Template validated successfully.

Сборка

Если валидация прошла успешно – выполняем сборку образа с помощью build:

$ packer build ec2_example.json 
amazon-ebs output will be in this color.

==> amazon-ebs: Prevalidating AMI Name...
==> amazon-ebs: Inspecting the source AMI...
==> amazon-ebs: Creating temporary keypair: packer 5807496d-7d0c-9ad9-f3d4-1bf0a1b7173e
==> amazon-ebs: Creating temporary security group for this instance...
==> amazon-ebs: Authorizing access to port 22 the temporary security group...
==> amazon-ebs: Launching a source AWS instance...
    amazon-ebs: Instance ID: i-8aac67ba
==> amazon-ebs: Waiting for instance (i-8aac67ba) to become ready...
==> amazon-ebs: Waiting for SSH to become available...
==> amazon-ebs: Connected to SSH!
==> amazon-ebs: Stopping the source instance...
==> amazon-ebs: Waiting for the instance to stop...
==> amazon-ebs: Creating the AMI: packer-example 1476872556
    amazon-ebs: AMI: ami-82194995
==> amazon-ebs: Waiting for AMI to become ready...
==> amazon-ebs: Terminating the source AWS instance...
==> amazon-ebs: Cleaning up any extra volumes...
==> amazon-ebs: No volumes to clean up, skipping
==> amazon-ebs: Deleting temporary security group...
==> amazon-ebs: Deleting temporary keypair...
Build 'amazon-ebs' finished.

==> Builds finished. The artifacts of successful builds are:
--> amazon-ebs: AMIs were created:

us-east-1: ami-82194995

EC2, запущенный Packer-ом для создания AMI:


aws_console_502

И собранный AMI:

$ aws --region us-east-1 ec2 describe-images --image-ids ami-82194995
{
    "Images": [
        {
            "VirtualizationType": "hvm", 
            "Name": "packer-example 1476872556", 
            "Hypervisor": "xen", 
            "SriovNetSupport": "simple", 
            "ImageId": "ami-82194995", 
            "State": "available", 
            "BlockDeviceMappings": [
                {
                    "DeviceName": "/dev/sda1", 
                    "Ebs": {
                        "DeleteOnTermination": true, 
                        "SnapshotId": "snap-148d7e0b", 
                        "VolumeSize": 8, 
                        "VolumeType": "gp2", 
                        "Encrypted": false
                    }
                }, 
                {
                    "DeviceName": "/dev/sdb", 
                    "VirtualName": "ephemeral0"
                }, 
                {
                    "DeviceName": "/dev/sdc", 
                    "VirtualName": "ephemeral1"
                }
            ], 
            "Architecture": "x86_64", 
            "ImageLocation": "264418146286/packer-example 1476872556", 
            "RootDeviceType": "ebs", 
            "OwnerId": "264418146286", 
            "RootDeviceName": "/dev/sda1", 
            "CreationDate": "2016-10-19T10:24:43.000Z", 
            "Public": false, 
            "ImageType": "machine"
        }
    ]
}

Примечание: так как данные авторизации не были указаны – то Packer использует профиль по умолчанию из файла ~/.aws/credentials. Подробнее про авторизацию Packer в AWS – см. тут>>>.

Provisioners

В предыдущем примере – мы просто перепаковали уже существующий образ, не внеся никаких изменений в систему.

Для того, что бы установить необходимые сервисы и выполнить другие настройки системы – используем provisioners.

Изменим предыдущий шаблон, и добавим установку NGINX:

{
  "variables": {
    "aws_access_key": "",
    "aws_secret_key": ""
  },
  "builders": [{
    "type": "amazon-ebs",
    "access_key": "{{user `aws_access_key`}}",
    "secret_key": "{{user `aws_secret_key`}}",
    "region": "us-east-1",
    "source_ami": "ami-fce3c696",
    "instance_type": "t2.micro",
    "ssh_username": "ubuntu",
    "ami_name": "packer-example {{timestamp}}"
  }],
  "provisioners": [{
    "type": "shell",
    "inline": [
      "sleep 30",
      "sudo apt-get update",
      "sudo apt-get install -y nginx"
    ]
  }]
}

Проверяем:

$ packer validate ec2_example.json 
Template validated successfully.

И запускаем сборку:

$ packer build ec2_example.json
amazon-ebs output will be in this color.

==> amazon-ebs: Prevalidating AMI Name...
...
==> amazon-ebs: Connected to SSH!
...
==> amazon-ebs: Provisioning with shell script: /tmp/packer-shell973438975
    amazon-ebs: Ign http://us-east-1.ec2.archive.ubuntu.com trusty InRelease
    amazon-ebs: Get:1 http://us-east-1.ec2.archive.ubuntu.com trusty-updates InRelease [65.9 kB]
    amazon-ebs: Get:2 http://us-east-1.ec2.archive.ubuntu.com trusty-backports InRelease [65.9 kB]
...
==> amazon-ebs: Deleting temporary keypair...
Build 'amazon-ebs' finished.

==> Builds finished. The artifacts of successful builds are:
--> amazon-ebs: AMIs were created:

us-east-1: ami-8d19499a

Параллельные сборки

Packer может выполнить сборку нескольких образов для нескольких платформ одновременно, из единого шаблона.

В примерах выше – мы собирали AMI для AWS EC2. Теперь добавим сборщик Docker-образа – docker builder.

В блок builders добавляем:

...
    "instance_type": "t2.micro",
    "ssh_username": "ubuntu",
    "ami_name": "packer-example {{timestamp}}"
  },{
  "type": "docker",
  "image": "ubuntu",
  "commit": true
  }],
  "provisioners": [{
...

Т.к. Docker base образ ("image": "ubuntu") не имеет sudo – немного извратимся в блоке provisioners:

...
  "provisioners": [{
    "type": "shell",
    "inline": [
      "sleep 30",
      "if which sudo; then sudo apt-get update && sudo apt-get install -y nginx; else apt-get update && apt-get install -y nginx; fi"
    ]
  }]
...

Проверяем и запускаем:

$ packer validate ec2_example.json
Template validated successfully.
$ sudo packer build ec2_example.json
[sudo] password for setevoy:
amazon-ebs output will be in this color.
docker output will be in this color.

==> amazon-ebs: Prevalidating AMI Name...
==> docker: Creating a temporary directory for sharing data...
==> docker: Pulling Docker image: ubuntu
    docker: latest: Pulling from ubuntu
    docker: 58488e45273c: Already exists
    docker: 25810b66099e: Already exists
...
==> amazon-ebs: Deleting temporary keypair...
Build 'amazon-ebs' finished.

==> Builds finished. The artifacts of successful builds are:
--> amazon-ebs: AMIs were created:

us-east-1: ami-12065605
--> docker: Imported Docker image: e64b553b8cb6ac39c2b00e27708bd9972ab91e2ec43aad52b2420ee297fa2aae

Проверяем наличие образа:

$ sudo docker images | grep e64b553b8cb
<none>                         <none>                      e64b553b8cb6        14 minutes ago      223.1 MB

Проверяем NGINX:

$ sudo docker run e64b553b8cb6 which nginx
/usr/sbin/nginx

Что бы собрать только определённый образ одним из сборщиков – используйте -only, например – сбилдить только Docker образ и не создавать AWS AMI можно так:

$ sudo packer build -only docker ec2_example.json 
docker output will be in this color.

==> docker: Creating a temporary directory for sharing data...
==> docker: Pulling Docker image: ubuntu
    docker: latest: Pulling from ubuntu
    docker: 58488e45273c: Already exists
...

Post-Processor

post-processor шаблона определяет действия, которые должны быть выполнены после сборки образа сборщиками. Например – заархивировать образ, загрузить артефакт (образ) в удалённое хранилище и т.д.

Имеется три варианта добавления post-processor в шаблон –  simple definitions, detailed definitions и sequence definitions.

simple definition – является строкой и включает в себя только имя постпроцессора, например:

{
  "post-processors": ["compress"]
}

detailed definition является JSON-объектом, и схож с builders и provisioners.

Он включает в себя поле type, в котором указывается имя постпроцессор для выполнения и может содержать дополнительные настройки для него, например:

{
  "post-processors": [
    {
      "type": "compress",
      "format": "tar.gz"
    }
  ]
}

sequence definition – является JSON-массивом, состоящем из simple- или detailed definitions, например:

{
  "post-processors": [
    [
      "compress",
      { "type": "upload", "endpoint": "http://example.com" }
    ]
  ]
}

Учтите, что постпроцессоры выполняются в том порядке, в котором они описаны в шаблоне.

Добавляем docker-tag post-processor в шаблон:

...
      "if which sudo; then sudo apt-get update && sudo apt-get install -y nginx; else apt-get update && apt-get install -y nginx; fi"
    ]
  }],
  "post-processors": [{
    "type": "docker-tag",
    "repository": "setevoy/ubuntu_nginx",
    "tag": "1.0"
  }]
}

Запускаем сборку, перенаправив STDIN и STDOUT в файл packer.log:

$ sudo packer build -only docker ec2_example.json 2>&1 | tee packer.log
docker output will be in this color.

==> docker: Creating a temporary directory for sharing data...
==> docker: Pulling Docker image: ubuntu
    docker: latest: Pulling from ubuntu
...
    docker (docker-tag): Tagging image: ba7fe714720f6457d812d76ca4a222fb8dbaea8549decd4d9a119b43ef9b8d67
    docker (docker-tag): Repository: setevoy/ubuntu_nginx:1.0
Build 'docker' finished.

==> Builds finished. The artifacts of successful builds are:
--> docker: Imported Docker image: ba7fe714720f6457d812d76ca4a222fb8dbaea8549decd4d9a119b43ef9b8d67
--> docker: Imported Docker image: setevoy/ubuntu_nginx:1.0

Готово.