Главная

Thursday, 10 March 2022

Vagrant с Ansible.

Всем привет. 

Допустим у нас есть десяток машин. Некоторые из них одинаковы - ноды с приложением и машины со средой для разработки. В данном случае имеет смысл использовать подготовку машин. 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.

Удачи.

Слава Украине!


1 comment:

  1. chmod 600 vagrant/.vagrant/machines/node1/virtualbox/private_key

    ReplyDelete

А что вы думаете по этому поводу?