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
- 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
- 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, From
mwiapp01
If I nslookupmwiapp02
andmwiapp03
. 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 )
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
Signup for Exclusive "Subscriber-only" Content