Vagrant: запуск Ansible после загрузки всех виртуальных машин, Ansible не может подключиться ко всем хостам - PullRequest
0 голосов
/ 10 января 2020

Я пытаюсь понять, как правильно использовать Ansible с Вагрантом. По умолчанию кажется, что Vagrant изолирует выполнение Ansible для каждого блока и выполняет пьесы после каждого блока частично, как это применяется к этому отдельному блоку в l oop. Я нахожу это ОЧЕНЬ контрпродуктивным, и я пытался обмануть Vagrant, чтобы запустить playbook на всех хостах ПОСЛЕ того, как все они загрузились, но, похоже, Ansible, при запуске из Vagrant никогда не видит больше одного окна за раз.

Edit: это версия, с которой я работаю:

Vagrant: 2.2.6 Ansible: 2.5.1 Virtualbox: 6.1

Playbook (с hosts.ini ) itsef выполняется без проблем, когда я запускаю его автономно с исполняемым файлом ansible -playbook после того, как хосты подходят, поэтому проблема в моем файле Vagrant. Я просто не могу понять.

Это Vagrantfile:

# -*- mode: ruby -*-
# vi: set ft=ruby :

IMAGE_NAME = "ubuntu/bionic64"

Vagrant.configure("2") do |config|
    config.ssh.insert_key = false
    config.vm.box = IMAGE_NAME

    # Virtualbox configuration
    config.vm.provider "virtualbox" do |v|
        v.memory = 4096
        v.cpus = 2
        #v.linked_clone = true
    end

    # master and node definition
    boxes = [
        { :name => "k8s-master", :ip => "192.168.50.10" },
        { :name => "k8s-node-1", :ip => "192.168.50.11" }
    ]

    boxes.each do |opts|
        config.vm.define opts[:name] do |config|
            config.vm.hostname = opts[:name]
            config.vm.network :private_network, ip: opts[:ip]

            if opts[:name] == "k8s-node-1"
                config.vm.provision "ansible_local" do |ansible|
                    ansible.compatibility_mode = "2.0"
                    ansible.limit = "all"
                    ansible.config_file = "ansible.cfg"
                    ansible.become = true
                    ansible.playbook = "playbook.yml"
                    ansible.groups = {
                        "masters" => ["k8s-master"],
                        "nodes" => ["k8s-node-1"]
                    }
                end
            end
        end
    end
end

ansible .cfg

[defaults]
connection = smart
timeout = 60
deprecation_warnings = False
host_key_checking = False
inventory = hosts.ini

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes

hosts.ini

[masters]
k8s-master ansible_host=192.168.50.10 ansible_user=vagrant

[nodes]
k8s-node-1 ansible_host=192.168.50.11 ansible_user=vagrant

[all:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_ssh_user=vagrant
ansible_ssh_private_key_file=~/.vagrant.d/insecure_private_key

playbook.yml

- hosts: all
  become: yes
  tasks:
    - name: Update apt cache.
      apt: update_cache=yes cache_valid_time=3600
      when: ansible_os_family == 'Debian'

    - name: Ensure swap is disabled.
      mount:
        name: swap
        fstype: swap
        state: absent

    - name: Disable swap.
      command: swapoff -a
      when: ansible_swaptotal_mb > 0

    - name: create the 'mobile' user
      user: name=mobile append=yes state=present createhome=yes shell=/bin/bash

    - name: allow 'mobile' to have passwordless sudo
      lineinfile:
        dest: /etc/sudoers
        line: 'mobile ALL=(ALL) NOPASSWD: ALL'
        validate: 'visudo -cf %s'

    - name: set up authorized keys for the mobile user
      authorized_key:
        user: mobile
        key: "{{ lookup('pipe','cat ssh_keys/*.pub') }}"
        state: present
        exclusive: yes

- hosts: all
  become: yes
  tasks:
   - name: install Docker
     apt:
       name: docker.io
       state: present
       update_cache: true

   - name: install APT Transport HTTPS
     apt:
       name: apt-transport-https
       state: present

   - name: add Kubernetes apt-key
     apt_key:
       url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
       state: present

   - name: add Kubernetes' APT repository
     apt_repository:
      repo: deb http://apt.kubernetes.io/ kubernetes-xenial main
      state: present
      filename: 'kubernetes'

   - name: install kubelet
     apt:
       name: kubelet=1.17.0-00
       state: present
       update_cache: true

   - name: install kubeadm
     apt:
       name: kubeadm=1.17.0-00
       state: present

- hosts: masters
  become: yes
  tasks:
   - name: install kubectl
     apt:
       name: kubectl=1.17.0-00
       state: present
       force: yes

- hosts: k8s-master
  become: yes
  tasks:
    - name: check docker status
      systemd:
        state: started
        name: docker

    - name: initialize the cluster
      shell: kubeadm init --apiserver-advertise-address 192.168.50.10 --pod-network-cidr=10.244.0.0/16 >> cluster_initialized.txt
      args:
        chdir: $HOME
        creates: cluster_initialized.txt

    - name: create .kube directory
      become: yes
      become_user: mobile
      file:
        path: $HOME/.kube
        state: directory
        mode: 0755

    - name: copy admin.conf to user's kube config
      copy:
        src: /etc/kubernetes/admin.conf
        dest: /home/mobile/.kube/config
        remote_src: yes
        owner: mobile

    - name: install Pod network
      become: yes
      become_user: mobile
      shell: kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml >> pod_network_setup.txt
      args:
        chdir: $HOME
        creates: pod_network_setup.txt

- hosts: k8s-master
  become: yes
  gather_facts: false
  tasks:
    - name: get join command
      shell: kubeadm token create --print-join-command 2>/dev/null
      register: join_command_raw

    - name: set join command
      set_fact:
        join_command: "{{ join_command_raw.stdout_lines[0] }}"

- hosts: nodes
  become: yes
  tasks:
    - name: check docker status
      systemd:
        state: started
        name: docker

    - name: join cluster
      shell: "{{ hostvars['k8s-master'].join_command }} >> node_joined.txt"
      args:
        chdir: $HOME
        creates: node_joined.txt

В тот момент, когда playbook пытается выполнить с k8s-master, происходит сбой следующим образом:

fatal: [k8s-master]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: Could not resolve hostname k8s-master: Temporary failure in name resolution", "unreachable": true}

Хост работает. S SH работает.

Кто может помочь мне разобраться с этим?

Спасибо!

1 Ответ

1 голос
/ 11 января 2020

Мне удалось использовать Ansible внутри Vagrant.

Вот что я сделал, чтобы все заработало:

Шаги для воспроизведения:

  • Установка Vagrant, Virtualbox
  • Создайте все необходимые файлы и каталоги
    • ansible .cfg
    • playbook.yml
    • hosts
    • insecure_private_key
    • Vagrant file
  • Тест

Установка Vagrant, Virtualbox

Следуйте инструкциям по установке на соответствующих сайтах:

Создание всех необходимых файлов и каталогов

Этот пример основан на оригинальных файлах постеров .

Создание папок vagrant и ansible для хранения всех файлов конфигурации и каталогов. Структура может выглядеть так:

  • vagrant - каталог
    • Vagrantfile - файл с основной конфигурацией
  • ansible - каталог
    • ansible .cfg - файл конфигурации Ansible
    • playbook.yml - файл с шагами для Ansible для выполнения
    • hosts - файл с информацией о хостах
    • insecure_private_key - закрытый ключ созданных машин * Папка 1070 *

Ansible - это отдельный каталог, который будет скопирован в k8s-node-1.

По умолчанию Vagrant совместно использует папку vagrant с разрешениями 777. Это позволяет владельцу, группе и другим иметь полный доступ ко всему, что находится внутри него.

Вход в виртуальную машину вручную и запуск команды ansible-playbook внутри каталога vagrant выведет ошибки, связанные с разрешениями. Это сделает ansible.cfg и insecure_private_key бесполезными.

Ansible .cfg

Ansible.cfg - файл конфигурации Ansible. Пример, используемый ниже:

[defaults]
connection = smart
timeout = 60
deprecation_warnings = False
host_key_checking = False
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes

Создание ansible.cfg внутри ansible каталога.

Playbook.yml

Пример playbook.yml - это файл с шагами для Ansible выполнить. Он проверит соединения и проверит, правильно ли настроены группы:

- name: Check all connections 
  hosts: all 
  tasks:
    - name: Ping
      ping: 

- name: Check specific connection to masters 
  hosts: masters 
  tasks:
    - name: Ping
      ping: 

- name: Check specific connection to nodes 
  hosts: nodes 
  tasks:
    - name: Ping
      ping: 

Создать playbook.yml внутри ansible каталога.

Insecure_private_key

Для успешного подключения к виртуальным машинам вам понадобится insecure_private_key. Вы можете создать его, вызвав команду: $ vagrant init внутри vagrant директории. Он создаст insecure_private_key внутри вашей физической машины в HOME_DIRECTORY/.vagrant.d. Скопируйте его в папку ansible.

Хосты

Ниже hosts файл отвечает за передачу информации о хостах в Ansible:

[masters]
k8s-master ansible_host=192.168.50.10 ansible_user=vagrant

[nodes]
k8s-node-1 ansible_host=192.168.50.11 ansible_user=vagrant

[all:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_ssh_user=vagrant
ansible_ssh_private_key_file=/ansible/insecure_private_key

Создание hosts файла в каталоге ansible .

Пожалуйста, укажите c, смотрите: ansible_ssh_private_key_file=/ansible/insecure_private_key

Это объявление для Ansible для использования ранее упомянутого ключа.

Vagrant

Vagrant Файл является основным файлом конфигурации:

# -*- mode: ruby -*-
# vi: set ft=ruby :

IMAGE_NAME = "ubuntu/bionic64"

Vagrant.configure("2") do |config|
    config.ssh.insert_key = false
    config.vm.box = IMAGE_NAME

    # Virtualbox configuration
    config.vm.provider "virtualbox" do |v|
        v.memory = 4096
        v.cpus = 2
        #v.linked_clone = true
    end

    # master and node definition
    boxes = [
        { :name => "k8s-master", :ip => "192.168.50.10" },
        { :name => "k8s-node-1", :ip => "192.168.50.11" }
    ]

    boxes.each do |opts|
        config.vm.define opts[:name] do |config|
            config.vm.hostname = opts[:name]
            config.vm.network :private_network, ip: opts[:ip]

            if opts[:name] == "k8s-node-1"
                config.vm.synced_folder "../ansible", "/ansible", :mount_options => ["dmode=700", "fmode=700"]

                config.vm.provision "ansible_local" do |ansible|
                    ansible.compatibility_mode = "2.0"
                    ansible.limit = "all"
                    ansible.config_file = "/ansible/ansible.cfg"
                    ansible.become = true
                    ansible.playbook = "/ansible/playbook.yml"
                    ansible.inventory_path = "/ansible/hosts" 
                end
            end
        end
    end
end

Пожалуйста, укажите c посмотрите:

config.vm.synced_folder "../ansible", "/ansible", :mount_options => ["dmode=700", "fmode=700"]

config.vm.synced_folder скопирует каталог ansible в k8s-node-1 со всеми файлами внутри.

Устанавливает разрешения на полный доступ только для владельца (бродячего пользователя).

ansible.inventory_path =  "/ansible/hosts"

ansible.inventory_path скажет Vagrant предоставить файл hosts для Ansible.

Test

Для проверки выполните следующую команду из каталога vagrant: $ vagrant up

Часть вывода, отвечающая за Ansible, должна выглядеть следующим образом:

==> k8s-node-1: Running provisioner: ansible_local...
    k8s-node-1: Installing Ansible...
    k8s-node-1: Running ansible-playbook...

PLAY [Check all connections] ***************************************************

TASK [Gathering Facts] *********************************************************
ok: [k8s-master]
ok: [k8s-node-1]

TASK [Ping] ********************************************************************
ok: [k8s-master]
ok: [k8s-node-1]

PLAY [Check specific connection to masters] ************************************

TASK [Gathering Facts] *********************************************************
ok: [k8s-master]

TASK [Ping] ********************************************************************
ok: [k8s-master]

PLAY [Check specific connection to nodes] **************************************

TASK [Gathering Facts] *********************************************************
ok: [k8s-node-1]

TASK [Ping] ********************************************************************
ok: [k8s-node-1]

PLAY RECAP *********************************************************************
k8s-master                 : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
k8s-node-1                 : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
...