ansible update /etc/hosts file with IP of all hosts across all hosts

In Ansible, SSH Communication is everything. Let it be connecting to remote servers from your controller laptop/desktop (mac/windows) or to enable connectivity between servers on the host group.

Especially this will be a huge task to accomplish when you do not have a DNS  where each remote host can easily look up the IP of another host.

We all create so many instances in the cloud or in local vagrant for our task or testing, and how we can make them talk to each other and make them be aware of each other.

Let us pretend that we are working on a local environment setup using VAGRANT  and trying to build three nodes and build SSH communication between them as well as SSH Key-based authentication.

In order to do that. We need to perform two tasks

  1. Making sure that each server is aware of the other server's IP address in the host group and could resolve the IP using the hostname
  2. Exchange the SSH public key between each other.

The First and primary step is the whole objective of this post. The second item is already covered in my another post Enable SSH Authentication between remote hosts

Let us proceed.

The Pictorial representation of what we are trying to achieve is given above. Hope it makes sense.

 

Domain Name Resolution or DNS Lookup

As mentioned earlier, if you are at industrial infrastructure with internal DNS available.

Each server you provision will have an entry in there and you should be able to resolve an IP and perform DNS lookup across the hosts you provision in your infrastructure with no further hurdles.

But in the local environmental setup like VAGRANT with NO dedicated DNS server. Or if you are not having any internal DNS system.

There is no option other than placing an entry manually into /etc/hosts file ( I presume you are aware of this file and what it does).

We call it a Local DNS lookup or First level DNS lookup. This helps me achieve the same thing that external DNS does.

So what we are trying to do here is that. I should be able to resolve the IP of all other hosts from the server I am trying without a DNS server in place

 

Practical Implementation/Example

I have three hosts newly built and named as follows

  • mwivmapp01 (192.168.16.11)
  • mwivmapp02 (192.168.16.12)
  • mwisqldb01 (192.168.16.13)

To enable communication between them and to transfer files between these remote server, I should be able to resolve the IP of all other hosts from the server I am trying.

For Instance, Frommwiapp01 If I  nslookup mwiapp02 and mwiapp03. I should get their corresponding IP address resolved  the important thing here is that we have to do it with out DNS server in place.

So we need to make an entry using in /etc/hosts of all servers with other server IP and hostnames

Let us look at the before and after snapshots of /etc/hosts file of each individual host/server for more clarity before implementing.

Before /etc/hosts file update

After /etc/hosts/ file update ( Expected Result )

ansible /etc/hosts/ file update

Here, you can see All the servers have their fellow group member's IP addresses including their own. Thanks to Jinja2 and variables of Ansible.

Playbook to make an entry of all server IPs across all the servers in the hosts file.

This Playbook given here is generic. It will work for any number of servers as long as they are in the same host group.

All you have to do is change the host group from multi to whatever you are going to use. ( in two places)

---
  - name: host file update - Local DNS setup across all the servers
    hosts: multi
    gather_facts: yes
    tasks:

    - name: Update the /etc/hosts file with node name
      tags: etchostsupdate
      become: yes
      become_user: root
      lineinfile:
        path: "/etc/hosts"
        regexp: ".*\t{{ hostvars[item]['ansible_hostname']}}\t{{ hostvars[item]['ansible_hostname']}}"
        line: "{{ hostvars[item]['ansible_env'].SSH_CONNECTION.split(' ')[2] }}\t{{ hostvars[item]['ansible_hostname']}}\t{{ hostvars[item]['ansible_hostname']}}"
        state: present
        backup: yes
      register: etchostsupdate
      when: ansible_hostname != "{{ item }}" or ansible_hostname == "{{ item }}"
      with_items: "{{groups['multi']}}"

 

 

For AWS EC2 instances - To Exchange the Private IP between hosts

The following snippet is designed to exchange the private IP address of host group members. this example is most suitable when you want to use the private IP address while updating the/etc/hosts file

- name: Update the /etc/hosts file with node name
  tags: etchostsupdate
  become: yes
  become_user: root
  lineinfile:
    dest: "/etc/hosts"
    regexp: ".*\t{{ hostvars[item]['ansible_hostname']}}\t{{ hostvars[item]['ansible_hostname']}}"
    line: "{{ hostvars[item]['ansible_default_ipv4']['address'] }}\t{{ hostvars[item]['ansible_hostname']}}\t{{ hostvars[item]['ansible_hostname']}}"
    state: present
    backup: yes
  register: etchostsupdate
  when: ansible_hostname != "{{ item }}" or ansible_hostname == "{{ item }}"
  with_items: "{{groups['launched']}}"

 

 

For AWS EC2 instances - To Exchange the Public IP between hosts

While Private IP addresses are merely for internal communication. we might sometimes need to do the same task of /etc/hosts file update amongst the host group members with public ip addresses

Let's suppose you have a few AWS EC2 instances and you are trying to connect to all of them from your local machine and you want all of these EC2 instances to talk to themselves over public IP, Then this is for you.

the EC2 instance would not be aware of its public IP so there would be no public IP related references on the Ansible Facts or variables. The only way to determine the public IP is to rely on the ansible_hosts file.

So this method would work only if you are using the Public IP to connect to the remote hosts from the control machine. In other words, Public IPs should have been used for this type to work.

- name: Update the /etc/hosts file with node name
  tags: etchostsupdate
  become: yes
  become_user: root
  lineinfile:
    dest: "/etc/hosts"
    regexp: ".*\t{{ hostvars[item]['ansible_hostname']}}\t{{ hostvars[item]['ansible_hostname']}}"
    line: "{{ inventory_hostname }}\t{{ hostvars[item]['ansible_hostname']}}\t{{ hostvars[item]['ansible_hostname']}}"
    state: present
    backup: yes
  register: etchostsupdate
  when: inventory_hostname != "{{ item }}" or inventory_hostname == "{{ item }}"
  with_items: "{{groups['launched']}}"

 

See it in Action

As said earlier, this is a First Step of enabling an SSH Key-based authentication between remote hosts.

The Next step is to exchange the key between remote servers so that Passwordless SSH Key-based authentication can be achieved.  Continue to read,  Enable SSH Authentication between remote hosts

Hope this helps.

Cheers,
Sarav AK

Follow me on Linkedin My Profile
Follow DevopsJunction onFacebook orTwitter
For more practical videos and tutorials. Subscribe to our channel

Buy Me a Coffee at ko-fi.com

Signup for Exclusive "Subscriber-only" Content

Loading