Packer for quick build images in Virtualbox and AWS
Packer и что нам нужно для начала
Packer — это инструмент для создания одинаковых образов ОС для различных платформ из одного описания. Packer отличная утилита для использовании в ваших ci/cd pipelines.
Что потребуется? Packer VirtualBox Vagrant
Установка packer
Osx
Установка в osx через brew
Теперь проверяем версию
packer -v 1.1.3
### Установка в любой Unix-like os
Для простоты установки Packer вы можете воспользоваться скриптом
bash #!/usr/bin/env bash cd ~
Prerequisites
if [ “$(uname)” == “Darwin” ]; then brew install jq > /dev/null 2>&1
For Linux
elif [ “$(expr substr $(uname -s) 1 5)” == “Linux” ]; then sudo apt-get update sudo apt-get install -q –assume-yes jq software-properties-common prometheus-node-exporter fi #check terraform and packer local archives
if [ -f ~/packer.zip ]; then rm -f ~/packer.zip fi
Get URLs for most recent versions
For OS-X
if [ “$(uname)” == “Darwin” ]; then terraform_url=$(curl -s https://releases.hashicorp.com/index.json | jq ‘{terraform}’ | egrep “darwin.*64” | sort -r | head -1 | awk -F[\“] ‘{print $4}’) packer_url=$(curl -s https://releases.hashicorp.com/index.json | jq ‘{packer}’ | egrep “darwin.*64” | sort -r | head -1 | awk -F[\“] ‘{print $4}’ )
For Linux
elif [ “$(expr substr $(uname -s) 1 5)” == “Linux” ]; then terraform_url=$(curl -s https://releases.hashicorp.com/index.json | jq ‘{terraform}’ | egrep “linux.*amd64” | sort -r | head -1 | awk -F[\“] ‘{print $4}’) packer_url=$(curl -s https://releases.hashicorp.com/index.json | jq ‘{packer}’ | egrep “linux.*amd64” | sort -r | head -1 | awk -F[\“] ‘{print $4}’)
fi
Create a move into directory.
cd mkdir packer > /dev/null 2>&1 mkdir -p terraform && cd $_
Download Terraform. URI: https://www.terraform.io/downloads.html
echo “Downloading $terraform_url.” curl -o terraform.zip $terraform_url > /dev/null 2>&1
Unzip and install
echo “Install terraform” unzip -o terraform.zip > /dev/null 2>&1 echo “done”
Change directory to Packer
cd ~/packer
Download Packer. URI: https://www.packer.io/downloads.html
echo “Downloading $packer_url.” curl -o packer.zip $packer_url > /dev/null 2>&1
Unzip and install
echo “Install packer” unzip -o packer.zip > /dev/null 2>&1 echo “Installed packer”
#check terraform and packer local archives if [ -f ~/terraform.zip ]; then chattr -i -a ~/terraform* > /dev/null 2>&1 chmod ugo+w ~/terraform* > /dev/null 2>&1 rm -f ~/terraform* > /dev/null 2>&1 fi if [ -f ~/terraform/terraform.zip ]; then chattr -i -a ~/terraform/terraform* > /dev/null 2>&1 chmod ugo+w ~/terraform/terraform* > /dev/null 2>&1 rm -f ~/terraform/terraform* > /dev/null 2>&1 fi if [ -f ~/packer.zip ]; then rm -f ~/packer.zip fi if [ -f ~/packer/packer.zip ]; then rm -f ~/packer/packer.zip fi
echo “Add packer and terraform to user path” if [ “$(uname)” == “Darwin” ]; then echo ‘ # Terraform & Packer Paths. export PATH=~/terraform/:~/packer/:$PATH ‘ >>~/.bash_profile
source ~/.bash_profile
For Linux
elif [ “$(expr substr $(uname -s) 1 5)” == “Linux” ]; then echo ‘ # Terraform & Packer Paths. export PATH=~/terraform/:~/packer/:$PATH ‘ >>~/.bashrc
source ~/.bashrc fi echo “All done. Local path” which packer which terraform
Как бонус этот скрипт скачивает последню версию Packer и Terrraform с официального сайта, прописывают нужные пути в переменные среды.
### Установка из исходных кодов
Чтобы установить Packer из исходных кодов, необходимо установить [Golang](https://golang.org/) и склонировать исходные коды с официально [github](https://github.com/hashicorp/packer) репозитория
$ mkdir -p $GOPATH/src/github.com/hashicorp && cd $_ $ git clone https://github.com/hashicorp/packer.git $ cd packer
После кланирования компилируем
make dev
## Ваше первый packer шаблон
После установки мы можем приступить к сборки образа, давайте смоделируем ситуацию. Есть какой-то веб сервер, на него мы хотим установить ubuntu,nginx,php
Шаг первый создаем json файл для соборки в нашем примере назовем его template.json
mkdir ubuntu-packer && cd $_ vi template.json
Далее опишем все стадии сборки будущего образа.
json
{ “provisioners”:[ { “type”:“shell”, “execute_command”:“echo ‘vagrant’|sudo -S sh ‘{{.Path}}’”, “override”:{ “virtualbox-iso”:{ “scripts”:[ “scripts/base.sh”, “scripts/vagrant.sh”, “scripts/virtualbox.sh”, “scripts/cleanup.sh”, “scripts/zerodisk.sh”, “scripts/nginx.sh” ] } } } ], “post-processors”:[ { “type”:“vagrant”, “override”:{ “virtualbox”:{ “output”:“ubuntu-14-04-x64-virtualbox.box” } } } ], “builders”:[ { “type”:“virtualbox-iso”, “boot_command”:[ “”, “”, “”, “/install/vmlinuz”, “ auto”, “ console-setup/ask_detect=false”, “ console-setup/layoutcode=us”, “ console-setup/modelcode=pc105”, “ debian-installer=en_US”, “ fb=false”, “ initrd=/install/initrd.gz”, “ kbd-chooser/method=us”, “ keyboard-configuration/layout=USA”, “ keyboard-configuration/variant=USA”, “ locale=en_US”, “ netcfg/get_hostname=ubuntu-1404”, “ netcfg/get_domain=vagrantup.com”, “ noapic”, “ preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg”, “ – “, “” ], “boot_wait”:“10s”, “disk_size”:40960, “guest_os_type”:“Ubuntu_64”, “http_directory”:“http”, “iso_checksum”:“dd54dc8cfc2a655053d19813c2f9aa9f”, “iso_checksum_type”:“md5”, “iso_url”:“http://releases.ubuntu.com/14.04/ubuntu-14.04.5-server-amd64.iso", “ssh_username”:“vagrant”, “ssh_password”:“vagrant”, “ssh_port”:22, “ssh_wait_timeout”:“10000s”, “shutdown_command”:“echo ‘shutdown -P now’ > /tmp/shutdown.sh; echo ‘vagrant’|sudo -S sh ‘/tmp/shutdown.sh’“, “vboxmanage”:[ [ “modifyvm”, “{{.Name}}”, “–memory”, “512” ], [ “modifyvm”, “{{.Name}}”, “–cpus”, “1” ] ] } ] }
Минимальный шаблон мы создали, давайте рассмотрим, что он в себе содержит:
### Builder
В качестве билдера я использую virtualbox
“builders”:[ { “type”:“virtualbox-iso”, “boot_command”:[ “”, “”, “”, “/install/vmlinuz”, “ auto”, “ console-setup/ask_detect=false”, “ console-setup/layoutcode=us”, “ console-setup/modelcode=pc105”, “ debian-installer=en_US”, “ fb=false”, “ initrd=/install/initrd.gz”, “ kbd-chooser/method=us”, “ keyboard-configuration/layout=USA”, “ keyboard-configuration/variant=USA”, “ locale=en_US”, “ netcfg/get_hostname=ubuntu-1404”, “ netcfg/get_domain=vagrantup.com”, “ noapic”, “ preseed/url=http://{{ .HTTPIP }}:{{ .HTTPPort }}/preseed.cfg”, “ – “, “” ], “boot_wait”:“10s”, “disk_size”:40960, “guest_os_type”:“Ubuntu_64”, “http_directory”:“http”, “iso_checksum”:“dd54dc8cfc2a655053d19813c2f9aa9f”, “iso_checksum_type”:“md5”, “iso_url”:“http://releases.ubuntu.com/14.04/ubuntu-14.04.5-server-amd64.iso", “ssh_username”:“vagrant”, “ssh_password”:“vagrant”, “ssh_port”:22, “ssh_wait_timeout”:“10000s”, “shutdown_command”:“echo ‘shutdown -P now’ > /tmp/shutdown.sh; echo ‘vagrant’|sudo -S sh ‘/tmp/shutdown.sh’“, “vboxmanage”:[ [ “modifyvm”, “{{.Name}}”, “–memory”, “512” ], [ “modifyvm”, “{{.Name}}”, “–cpus”, “1” ] ] } ]
В билдере у меня указаны следующие параметры:
- type -- тип билдера могут быть следующими
* Alicloud ECS
* Amazon EC2
* Azure
* CloudStack
* DigitalOcean
* Docker
* File
* Google Cloud
* Hyper-V
* LXC
* LXD
* NAVER Cloud
* Null
* 1&1
* OpenStack
* Oracle
* Parallels
* ProfitBricks
* QEMU
* Scaleway
* Triton
* VirtualBox
* VMware
Cписок постоянно изменятеся
- boot_command - команды которые выполняются, при зашрузки с cd
- boot_wait - время которое, packer будет ожидать загрузку
- disk_size - разрмер диска, в создаваемой виртальной машины
- guest_os_type - тип устанавливаемой операционной системы
- iso_checksum - чек сумма для проверки iso образа
- iso_checksum_type - тип чек-суммы, могут быть md5, sha1, sha256, или sha512
- iso_url - источник откуда мы будем выкачивать iso образ, может быть либо локальным, либо ссылка на образ или все вместе
- ssh_username, ssh_password, ssh_port, ssh_wait_timeout - параметры для работы по sshб пользователь,пароль, порт и таймаут после, которого пакер будет считать, что сервер недоступен
- shutdown_command - команда/команды для выключение
- vboxmanage - данный параметр служит для изменения параметров виртуальной машины через Virtualbox manager, вы можете изменить количество ядер, оперативной памати и тд
### Provisioners
json “provisioners”:[ { “type”:“shell”, “execute_command”:“echo ‘vagrant’|sudo -S sh ‘{{.Path}}’”, “override”:{ “virtualbox-iso”:{ “scripts”:[ “scripts/base.sh”, “scripts/vagrant.sh”, “scripts/virtualbox.sh”, “scripts/cleanup.sh”, “scripts/zerodisk.sh”, “scripts/nginx.sh” ] }
В моем примере я использую только bash скрипты, но настройка и установка ПО в процессе сборки не ограничивается скриптами, вы можете использовать любые другие ci/cd инструменты и утилиты.
Все мои скрипты раположены в отдельной папке для простоты
### Post-processors
json ], “post-processors”:[ { “type”:“vagrant”, “override”:{ “virtualbox”:{ “output”:“ubuntu-14-04-x64-virtualbox.box” } } } ],
В моем случае, после сборки я хочу получить vagrant box.
### Подготовка preseed
> Технология preseed позволяет заранее указать ответы на вопросы, задаваемые при установке, убрав таким образом необходимость отвечать на них вручную. Это позволяет создать полностью автоматические сценарии со всеми необходимыми настройками.
> Если копнуть чуть глубже, то можно выяснить, что Debian Installer использует систему debconf для управления процессом установки, а технология preseed просто заранее добавляет нужные ответы в базу данных debconf. Таким образом с помощью preseed можно настроить не только установщик, но и другие приложения, использующие debconf, хотя эта особенность вам вряд ли пригодится.
> Каждая инструкция preseed состоит обычно из четырёх частей: владельца, названия параметра, типа параметра и значения. Между частями обязательно должен быть ровно один пробел. Установщик носит имя d-i, и именно это значение будет стоять в первом поле в большинстве инструкций
Приступим, вначале создаем папку где будем хранить файл с preseed
mkdir http
Теперь создаем файл который будет использоваться для автомотизации установки ubuntu с iso образа, ``` vi http/preseed.cfg ```
Содержание достаточно простое:
debconf debconf/frontend select Noninteractive choose-mirror-bin mirror/http/proxy string d-i base-installer/kernel/override-image string linux-server d-i clock-setup/utc boolean true d-i clock-setup/utc-auto boolean true d-i finish-install/reboot_in_progress note d-i grub-installer/only_debian boolean true d-i grub-installer/with_other_os boolean true d-i partman-auto-lvm/guided_size string max d-i partman-auto/choose_recipe select atomic d-i partman-auto/method string lvm d-i partman-lvm/confirm boolean true d-i partman-lvm/confirm_nooverwrite boolean true d-i partman-lvm/device_remove_lvm boolean true d-i partman/choose_partition select finish d-i partman/confirm boolean true d-i partman/confirm_nooverwrite boolean true d-i partman/confirm_write_new_label boolean true
Default user
d-i passwd/user-fullname string vagrant d-i passwd/username string vagrant d-i passwd/user-password password vagrant d-i passwd/user-password-again password vagrant d-i passwd/username string vagrant
Minimum packages (see postinstall.sh)
d-i pkgsel/include string openssh-server d-i pkgsel/install-language-support boolean false d-i pkgsel/update-policy select none d-i pkgsel/upgrade select none
d-i time/zone string UTC d-i user-setup/allow-password-weak boolean true d-i user-setup/encrypt-home boolean false tasksel tasksel/first multiselect standard, ubuntu-server
После этого, создаем директорию со скриптами и сами скрипты
### Скрипты для Packer(ci/cd на коленки)
mkdir scripts
scripts kenny$ tree . ├── base.sh ├── cleanup.sh ├── nginx.sh ├── vagrant.sh ├── virtualbox.sh └── zerodisk.sh
Теперь можно и начинать писать скрипты, мои примеры ниже
#### base.sh
apt-get update apt-get -y upgrade apt-get -y install linux-headers-$(uname -r)
sed -i -e ‘/Defaultss+env_reset/a Defaultstexempt_group=sudo’ /etc/sudoers sed -i -e ’s/%sudo ALL=(ALL:ALL) ALL/%sudo ALL=NOPASSWD:ALL/g’ /etc/sudoers
echo “UseDNS no” >> /etc/ssh/sshd_config
#### cleanup.sh
apt-get -y autoremove apt-get -y clean
echo “cleaning up guest additions” rm -rf VBoxGuestAdditions*.iso VBoxGuestAdditions*.iso.?
echo “cleaning up dhcp leases” rm /var/lib/dhcp/*
echo “cleaning up udev rules” rm /etc/udev/rules.d/70-persistent-net.rules mkdir /etc/udev/rules.d/70-persistent-net.rules rm -rf /dev/.udev/ rm /lib/udev/rules.d/75-persistent-net-generator.rules
#### vagrant.sh
date > /etc/vagrant_box_build_time
mkdir /home/vagrant/.ssh wget –no-check-certificate ‘https://github.com/mitchellh/vagrant/raw/master/keys/vagrant.pub' -O /home/vagrant/.ssh/authorized_keys chown -R vagrant /home/vagrant/.ssh chmod -R go-rwsx /home/vagrant/.ssh
#### virtualbox.sh
apt-get -y install virtualbox-guest-utils
#### zerodisk.sh
dd if=/dev/zero of=/EMPTY bs=1M rm -f /EMPTY
#### nginx.sh
export DEBIAN_FRONTEND=noninteractive
mv /tmp/sources.list /etc/apt/sources.list wget http://www.dotdeb.org/dotdeb.gpg -O - | apt-key add -
apt-get update
apt-get -qy install nginx cp /tmp/nginx.conf /etc/nginx/sites-available/default
apt-get -qy install php5-fpm php5-cli php5-intl php5-xhprof
curl -sS https://getcomposer.org/installer | php mv composer.phar /usr/local/bin/composer apt-get -qy install mysql-client mysql-server php5-mysqlnd
### Валидация темплейта и сборка с помощью Packer
Для валидации нашего темплейта достаточно выполнить команду:
packer validate template.json
После выполнения команды мы должны увидеть следующее сообщение
Template validated successfully.
После проверки мы можем приступать к сборке:
packer build ubuntu.json
После сборки мы получим Vagrant box c именем ubuntu-14-04-x64-virtualbox.box, который уже можно использовать,
## Использование Amazon Web services(aws) для сборки Packer'ом
При использование aws в качестве билдера, шаблон упроститься и сократиться, примерный вид шаблона ниже
template_aws.json
json
{
“provisioners”: [
{
“type”: “shell”,
“execute_command”: “echo ‘vagrant’|sudo -S sh ‘{{.Path}}’”,
“override”: {
“amazon-ebs”: {
“scripts”: [
“scripts/base.sh”,
“scripts/cleanup.sh”,
“scripts/nginx.sh”
]
}
}
}
],
“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-2d39803a”,
“instance_type”: “t2.micro”,
“ssh_username”: “ubuntu”,
“ami_name”: “my-template-{{timestamp}}”,
“associate_public_ip_address”: “true”,
“force_deregister”: “true”,
“vpc_id”: “vpc-80090ae7”,
“launch_block_device_mappings”: [
{
“device_name”: “/dev/sda1”,
“volume_type”: “gp2”,
“volume_size”: “50”,
“delete_on_termination”: “true”
}]
}
]
}
Как вы можете видеть, я изменил тип билдера и добавил переменные для подключения к aws
- access_key - access ключ для aws
- secret_key - sercret ключ для aws
- region - AWS регион где будет запущен инстанс
- source_ami - исходная ami(Amazon Machine Images), которую мы будем использовать как базу
- instance_type - тип aws инстанса
- ssh_username - пользователь для подключения по ssh
- ami_name - имя будушей ami, которая будет доступна после сборки
- associate_public_ip_address - Будет ли у временного инстанса внешний ip адрес, если вы собираете со своей машины, то бесусловно нужен, если из сети aws, то можно и не использовать
- force_deregister - иногда нужно использоать чтобы не остовались не нужные инстансы
- vpc_id - в какой vpc сети мы будем запускать наш инстанс
- launch_block_device_mappings - Какого размера будет EBS(Elastic Block Storage) и каике у него будут параметры
Так же не забываем задать переменные для подключения к aws, вы можете либо добавить их в шаблон либо вводить с консоли.
### Валидация и сборка
Валидируем наш новый шаблон
packer validate template_aws.json
Если валидация прошла успешно, то начинаем сборку будущей ami
packer build template_aws.json
```
После сборки вы можете использовать новую ami для ваших будущих инстансов