Михаил Овчинников

Vagrant: наполнение виртуальной машины при помощи shell-скрипта

Vagrant VirtualBox DevOps Ruby

Создавать виртуалку при помощи Vagrant легко и весело, но пустая виртуалка врядли будет кому-то полезна и интересна. Раз уж мы автоматизировали создание виртуальной машины, то почему бы не автоматизировать установку необходимого программного обеспечения? В терминологии Vagrant такой процесс называется наполнением (provisioning).

В следующих статьях мы поговорим, как это делается при помощи популярного средства управления конфигурацией Chef, а сегодня я рассмотрю самый простой способ: использование shell-скрипта. Часто этот способ игнорируется, хотя для простых решений написать скрипт на 10 строчек может оказаться гораздо быстрее, чем разбираться с cookbook’ами Chef и их зависимостями.

Eсли вы читали мою первую заметку, то у вас уже должен быть минимальный Vagrantfile вида:

# -*- mode: ruby -*-
 
VAGRANTFILE_API_VERSION = "2"
 
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "precise32"
  config.vm.box_url = "http://files.vagrantup.com/precise32.box"
end

Допустим вам необходимо установить mysql. Для этого после конфигурации машины нужно написать:

config.vm.provision :shell, :inline => “sudo apt-get -q -y install mysql-server”

Здесь я указал, что в качестве «наполнителя» хочу использовать командную строку, а затем передаю команду. Это очень удобно когда вам нужно выполнить 1-2 команды, но скорее всего у вас будет более длинная последовательность, которую вы захотите вынести в отдельный файл. В этом случае команда будет выглядеть следующим образом:

config.vm.provision :shell, :path => “my_awesome_script.sh”

Если вы еще не создавали виртуалку, то достаточно запустить vagrant up, и после создания виртуалки автоматически накатится ваш скрипт. Если же виртуалка уже создана и работает, то достаточно запустить vagrant provision чтобы накатить скрипт с конфигурацией.

Vagrant: работа с несколькими машинами

Vagrant VirtualBox DevOps Ruby

Описание конфигурации в Vagrantfile не ограничивается только одной машиной. Если для вашего окружения нужно поднять несколько машин (эмуляция распределенной работы, к примеру), их конфигурации можно описать в едином файле, выделив для каждой из машин отдельный блок. Вот хороший  пример из документации:

Vagrant.configure("2") do |config|
  config.vm.provision "shell", inline: "echo Hello"

  config.vm.define "web" do |web|
    web.vm.box = "apache"
  end

  config.vm.define "db" do |db|
    db.vm.box = "mysql"
  end
end

Таким образом можно задать любое необходимое количество машин. Стоит отметить, что если продолжить задавать свойства через переменную config, они будут применены ко всем машинам. Индивидуальные же свойства следует указывать в блоке с config.vm.define. Запускать машины можно будет и по-отдельности, например: vagrant up web.

Аналогично можно поступать, если у вас несколько проектов и для каждого свой Vagrantfile. Лично мне удобно держать именно отдельный отдельный файл в папке для каждого проекта, чтобы у каждого была своя независимая конфигурация, плюс можно легко поделиться им с
человеком, который захочет со мной совместно поработать.

В любом случае, перед тем как писать конфиг машины, добавляю блок с define с названием проекта, что позволяет мне не задумываясь запускать машины. Это делать вовсе не обязательно, но получается удобно, когда ты видишь, что имя машины не «default», а соответствует названию проекта. Если вдруг у двух проектов стали просматриваться точки интеграции, то для proof-of-concept могу запросто их объединить в один простым copy-paste (речь только о Vagrantfile конечно же :) ).

Кстати, насчет имени машины. Vagrant дает им совершенно сумасшедшие имена.

Чтобы дать нормальное имя, нужно в блоке vm.provider задать параметр name равным желаемому имени.

Пример:

zc.vm.provider "virtualbox" do |vb|
  vb.name = "zencity"
end

Даст соответствующий результат.

Vagrant: автоматизация создания виртуальных машин

Vagrant VirtualBox DevOps Ruby

Vagrant  — это набор скриптов на Ruby, который предназначен для того, чтобы автоматизировать работу с виртуальными машинами на вашем компьютере. Чаще всего он используется для быстрого развертывания окружения для разработки ПО.

Зачем может понадобиться использовать виртуальную машину для разработки? Причин тому может быть много. Прежде всего, это необходимость использования разных версий библиотек и компонентов в разных проектах, а также разработка приложений под конкретную среду.

Кажется, что это не так уж и важно, но на самом деле, гораздо удобнее развернуть виртуалку с нужными вещами, чем засорять систему и ломать голову, как разрулить какие-нибудь конфликты. Думаю каждый, кто работал с крупными проектами, сталкивался с подобным вещами. Обычно развернуть и настроить среду в виртуальной машине не очень сложно, но, как правило, занимает довольно много времени. Vagrant позволяет избавиться от всей этой рутины.

Установка

Автор постарался и сделал нормальные установщики под все операционные системы [1]. На протяжении всего повествования мы будем пользоваться средством виртуализации Virtual Box [2], так как Vagrant создавался в первую очередь для него. Предпочитающие VMware, тоже могут воспользоваться Vagrant, подробности есть у них на сайте [3].

Настройка

После того, как вы установили Vagrant, потребуется создать файл файл с настройками машины, который называется Vagrantfile. Нет нужды создавать его самостоятельно, для этого есть соотвествующая команда vagrant init.

Для себя выработал такую практику: в папке каждого проекта есть папка /env, в которой лежат все файлы нужные для того, чтобы с нуля развернуть девелоперское окружение. Там создаю Vagrantfile, кладу необходимые кукбуки для Chef и т.д.

Важный момент, который нужно учитывать при работе с Vagrantfile: Vagrant использует не только тот файл, который лежит непосредственно в папке вашего проекта, но и тот, который поставляется с базовым образом машины, тот что лежит в папке с настройками (~/.vagrant.d) и т.д. Полный перечень и принцип работы подробнее можно посмотреть в документации [4].

Теперь откроем получившийся Vagrant-файл. В нем вы увидите код на Ruby и множество закомментированных строчек. Уверен, что большинству для базовой настройки будет достаточно раскомментировать нужные строчки и вписать в них необходимые значения. Далее я просто рассмотрю самые важные для нас понятия.

Если удалить все комментарии, то минимальная конфигурация, которая должна содержаться в Vagrantfile будет выглядеть следующим образом:

# -*- mode: ruby -*-
 
VAGRANTFILE_API_VERSION = "2"
 
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "precise32"
  config.vm.box_url = "http://files.vagrantup.com/precise32.box"
end

Здесь я написал, что хочу использовать 32-битную Ubuntu 12.04, и указал URL по которому её можно скачать. Этого же результата можно было добиться просто запустив команду init с соотвествующими параметрами.

vagrant init precise32 http://files.vagrantup.com/precise32.box

Уверен, вызывает вопрос расширение *.box. Никакой особенной магии тут нет: это обычный zip-архив в котором лежит vmdk-образ виртуальной машины и Vagrantfile с дефолтными настройками. У Vagrant довольно большое сообщество, и базовую сборку на любой вкус можно найти на сайте vagrantbox.es.

Скорее всего, просто с дефолтными параметрами запускать машину никому не захочется. Все что я напишу далее, можно найти и в комментариях сгенерированного вами Vagrantfile, я же просто заострю внимание на самых значимых вещах. Девелоперское окружение подразумевает хотя бы наличие расшареных папок и портов (чтобы вы работали в своем привычном окружении, а ваш софт — в своем).

config.vm.network "forwarded_port", guest: 3000, host: 3333
config.vm.synced_folder "../project_folder_host", “/project_folder_guest”

Думаю из примера очевидно: первая строчка отвечает за форвардинг портов (как можно догадаться, это порт по-умолчанию сервера в Rails) c гостевой машины на хост. Вторая строчка отвечает за создание «прозрачной» папки на гостевой машине.

Естественно, можно сконфигурировать и параметры самой виртуальной машины, например увеличим оперативную память:

config.vm.provider "virtualbox" do |vb|
  vb.customize ["modifyvm", :id, "--memory", "1024"]
end

Важный момент: по-умолчанию в Vagrant машина запускается в headless-режиме, т.е. вы не увидите окно Virtual Box с ОС внутри. Предполагается, что общение с виртуалкой будет происходить по SSH. Если по каким-либо причинам вас это не устраивает, то в этот же блок нужно добавить:

vb.gui = true

На всякий случай, приведу полный пример конфига.

# -*- mode: ruby -*-
 
VAGRANTFILE_API_VERSION = "2"
 
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "precise32"
  config.vm.box_url = "http://files.vagrantup.com/precise32.box"
  config.vm.network "forwarded_port", guest: 3000, host: 3333
  config.vm.synced_folder "../project_folder_host", “/project_folder_guest”
 
  config.vm.provider "virtualbox" do |vb|
    vb.customize ["modifyvm", :id, "--memory", "1024"]
  end
 
end

Я написал много букв, но как видите, настройка сводится к указанию небольшого количества параметров и совершенно не требует знания Ruby.

Запуск, остановка и удаление машины

Запуск машины производится командой vagrant up (из той же папки, где лежит Vagrantfile). После этого автоматически скачается базовый образ, указанный в url, создастся и запустится виртуальная машина, к которой можно будет присоединиться по SSH (словом, нужно только дождаться появления сообщения: «Machine booted and ready!»). Далее пишем vagrant ssh, откроется соединение с машиной и можно делать все, что душа пожелает.

Когда наиграетесь, появится закономерное желание выключить машину. Для этого:
vagrant suspend — сохранить состояние машины;
vagrant halt — выключить машину.

Все сломали своими экспериментами и хотите полностью удалить машину?
vagrant destroy — удаляет машину, создать заново с нуля можно будет в любой момент при помощи vagrant up!

[1] Страница загрузок Vagrant
[2] Страница загрузок VirtualBox
[3] Информация об использовании Vagrant с VMware
[4] Документация по Vagrantfile

1 of 1