Допустим у нас есть десяток машин. Некоторые из них одинаковы - ноды с приложением и машины со средой для разработки. В данном случае имеет смысл использовать подготовку машин. Vagrant для этого позволяет использовать несколько решений:
- Puppet
- Ansible
- Salt
- Shell
- Chef
- Docker
При чём некоторые из них, например, Chef, Puppet, Salt имеют несколько вариантов использования (мастер-агент, без мастера, запуск локально).
Автоматически provision запускается только в двух случаях: vagrant up и vagrant reload. Если вы хотите запустить подготовку машин принудительно, то необхожимо это явно указать. Например:
vagrant resume --provision %machine_name%
vagrant provision %machine_name
Самый простой вариант - shell. Но сегодня мы рассмотрим вариант с Ansible.
Чтобы применить Ansible через vagrant необходимо сделать следующее:
- на хостовой машине должен быть установлен Ansible
- прописать в Vagrantfile примерно следующее:
Vagrant.configure("2") do |config|
# Run Ansible from the Vagrant Host
config.vm.provision "ansible" do |ansible|
ansible.playbook = "playbook.yml"
end
end
При этом, Playbook.yml должен находиться в одном каталоге с Vagrantfile. После того, как машина будет поднята, vagrant запустит Ansible. Так как сам по себе Ansible не требует никакого агента на целевой машине (ноде), то всё, что нужно сделать - указать верные данные в инвентори-файле. Если используется публичная сеть, то указываем ip ноды, если используется приватная сеть, то необходимо указать ip локалхоста (обычно 127.0.0.1) и порт. Для Ansible имеется достаточно много опций, узнать их можно на странице официальной документации vagrant. Помимо того, что можно запускать Ansible с хоста, его можно также запускать и в самой гостевой мащине. Называется это Ansible local. Преимущество в том, что нет необходимости устанавливать Ansible на хост. Вы можете просто загрузить роль с вашего репозитория или с Ansible galaxy и она выполнится.
Недостатки - на каждую машину необходимо устанавливать Ansible, отсутствие централизованного управления. То есть, если в дальнейшем будет необходимость управлять машинами посредством Ansible, то этот метод не для вас.
По-умолчанию, vagrant попробует сам установить Ansible на гостевую машину, для этот предусмотрено несколько опций:
install_mode - по факту, это выбор репозитория, откуда будет устанавливаться Ansible. Если оставить значение default, то будет выбран:
1.ppa:ansible/ansible - для гостя Ubuntu + family
2.EPEL - RedHat-family
3.main repo - Debian, OpenSuse, FreeBSD, Arch, etc.
Есть другое значение - pip. Тогда установка будет производиться посредтсвом pip. vagrant сначала установит pip на гостя, а затем установит Ansible. Этот вариант предпочтительней, так как это гарантирует, что версия будет свежая и одинаковая для всех нод. Часть Vagrantfile, которая отвечает за Ansible local практически ничем не отличается от обычного Ansible:
Vagrant.configure("2") do |config|
config.vm.provision "ansible_local" do |ansible|
ansible.playbook = "playbook.yml"
end
end
Подробнее о хуке, а именно о том, как использовать Ansible local для создания полноценной инфраструктуры. С помощью одного Vagrantfile можно создать ноды, которые будут разворачиваться Ansible, который установлен в виртуальной машине. Всё, что нужно сделать вам - написать Vagrantfile, роли для Ansible с inventory и немного подправить конфигурацию Ansible.
Разберём подробнее:
Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.box_check_update = false
config.vm.define "node1" do |machine|
machine.vm.network "private_network", ip: "172.17.177.21"
machine.vm.hostname = "node1"
end
config.vm.define "node2" do |machine|
machine.vm.network "private_network", ip: "172.17.177.22"
machine.vm.hostname = "node2"
end
config.vm.define 'controller' do |machine|
machine.vm.network "private_network", ip: "172.17.177.11"
machine.vm.hostname = "controller1"
machine.vm.provision “ansible_local” do |ansible|
ansible.playbook = "example.yml"
ansible.verbose = true
ansible.install = true
ansible.limit = "all"
ansible.inventory_path = "inventory"
end
end
end
Создаём две машины - node1 и node2. Это будут машины, которые мы будем конфигурировать с помощью Ansible, который установим на третью машину - controller. Vagrant сам установит на нужную машину Ansible. Что нам нужно - так это сделать нормальный инвентори файл (inventory), в котором будут указаны ip адреса наших нод:
controller ansible_connection=local
node1 ansible_ssh_host=172.17.177.21 ansible_ssh_private_key_file=/vagrant/.vagrant/machines/node1/virtualbox/private_key
node2 ansible_ssh_host=172.17.177.22 ansible_ssh_private_key_file=/vagrant/.vagrant/machines/node2/virtualbox/private_key
И этот файлик положим в директорию с Vagrantfile, в корень.
Последний штрих - нам необходимо создать свой файл Ansible.cfg. В нём мы укажем, некоторые опции для ssh-коннекта, а именно - подключаться ко всем хостам без подтверждения
[defaults]
host_key_checking = false
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes
Всё, можно делать "vagrant up" и создавать окружение. Или наблюдать как Ansible воюет с Vagrant. Первый проход Provision ansible_local говорит о том, что наш ansible.cfg ему не подходит и потому Ansible использует свой конфиг из коробки, т.е. /etc/ansible/ansible.cfg.
==> controller: Running provisioner: ansible_local...
controller: Running ansible-playbook...
cd /vagrant && PYTHONUNBUFFERED=1 ANSIBLE_NOCOLOR=true ansible-playbook --limit="all" --inventory-file=inventory.yml -v example.yml
[WARNING] Ansible is being run in a world writable directory (/vagrant), ignoring it as an ansible.cfg source. For more information see https://docs.ansible.com/ansible/devel/reference_appendices/config.html#cfg-in-world-writable-dir
Using /etc/ansible/ansible.cfg as config file
PLAY [node1] *******************************************************************
TASK [Gathering Facts] *********************************************************
fatal: [node1]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: Host key verification failed.", "unreachable": true}
PLAY RECAP *********************************************************************
node1 : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0
В принципе нет ничего сложного в том чтобы зайти на controller и внести в /etc/ansible/ansible.cfg параметры ssh:
[defaults]
host_key_checking = false
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes
Однако повторный прогон "vagrant provision controller" приводит к еще более удивительной ошибке, а именно UNPROTECTED PRIVATE KEY FILE в отношении private_key:
TASK [Gathering Facts] *********************************************************
fatal: [node1]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: WARNING: UNPROTECTED PRIVATE KEY FILE!
Permissions 0555 for '/vagrant/.vagrant/machines/node1/virtualbox/private_key' are too open.\r\n
It is required that your private key files are NOT accessible by others.\r\nThis private key will be ignored.\r\n
bad permissions: ignore key: /vagrant/.vagrant/machines/node1/virtualbox/private_key\r\nPermission denied (publickey,password).", "unreachable": true}
Я вам больше скажу - правка прав на файл с помощью "chmod 400 private_key" не дает ни ошибки, ни ожидаемого результата. Максимум что удалось мне выжать это 0555. Но этого, как вы видите, недостаточно для ansible_local. Буду писать разработчкиам ибо вариант с ansible_local это не хитрый хук, а прием который описан на официальном сайте vagrant.
Удачи.
Слава Украине!
chmod 600 vagrant/.vagrant/machines/node1/virtualbox/private_key
ReplyDelete