I plan to run a bunch of services on my home network. Right now, my plan is to host most of the services on a small RaspberryPi cluster in a C4 Labs Cloudlet Case. All of these Pi's run Raspbian and each one will run a few services that I like having hosted on my home network.
Although 3 RPis isn't exactly impossible to configure manually; why would I want to do that? Plus, the Cloudlet Case accepts up to 8 RPis which would be a lot to manage manually.
The Plan
For now, I'm going to configure all the following things with Ansible:
-
.bashrc
- This enables me to use the same bash aliases across all nodes - Changing the default password of every pi
- Installing Vim
-
.vimrc
- Configures Vim settings like the color scheme and line numbers across all nodes - MOTD - Just for fun, I'm going to install the
fortune | cowsay
packages and broadcast funny cow sayings on log in - Prometheus Exporters - Eventually we will deploy some Prometheus exporters to remotely view each node's status
- Mounting a network share on boot
In the future I'll also be deploying some Docker containers via Ansible but first we need to configure Ansible itself.
Installing Ansible on the Master Node
Since Raspbian is a Debian derivative, we will need to add the Ansible PPA to the /etc/apt/sources
file.
cd /etc/apt
sudo vim sources
The Ubuntu PPA works fine for Raspbian, at the top of the file add:
deb http://ppa.launchpad.net/ansible/ansible/ubuntu trusty main
Update apt and then install with:
sudo apt update
sudo apt install ansible
Alright, let's define the hosts on the network. Right now, there are three. One will function as a master node that runs Ansible and the others will be slaves that Ansible controls via SSH.
[master]
pi@192.168.0.101
[slave]
pi@192.168.0.102
pi@192.168.0.103
I could have used Ansible's built-in expansion syntax and written the slaves as 192.168.0.[102:103] but I like the readability of listing them explicitly.
You need SSH keys configured for Ansible to work without password prompts. I already have SSH setup on all these nodes but I'll be writing a post on setting up headless ssh on a RPi in the future.
Let's check if Ansible can talk to our nodes:
ansible all -m ping
192.168.0.101 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.0.103 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.0.102 | SUCCESS => {
"changed": false,
"ping": "pong"
}
Great! We can talk to everything on to writing playbooks.
Writing a playbook
Okay, first let's add a very basic Ansible playbook to install Vim to all three nodes. First, move to the Ansible directory and create a folder for playbooks and the playbook itself:
cd /etc/ansible
mkdir playbooks
touch install_vim.yml
Inside the playbook, define a task that installs the latest version of Vim on all the hosts. I'll also add configuration to use sudo to install Vim.
- hosts: all
remote_user: pi
tasks:
- name: Install Vim
become: true
become_method: sudo
apt:
name: vim
state: latest
install_recommends: true
Save the file and run the following command:
ansible-playbook install_vim.yml
Your output should be all ok.
PLAY [all] **************************************************************************
TASK [Gathering Facts] **************************************************************
ok: [pi@192.168.0.101]
ok: [pi@192.168.0.103]
ok: [pi@192.168.0.102]
TASK [Install Vim] ******************************************************************
ok: [pi@192.168.0.101]
ok: [pi@192.168.0.103]
ok: [pi@192.168.0.102]
PLAY RECAP **************************************************************************
pi@192.168.0.101 : ok=2 changed=0 unreachable=0 failed=0
pi@192.168.0.102 : ok=2 changed=0 unreachable=0 failed=0
pi@192.168.0.103 : ok=2 changed=0 unreachable=0 failed=0
Great, now that Vim is installed let's advertise some Vim settings (I like the desert color scheme and line numbers) to all 3 machines.
Let's make a new folder to hold files we want to advertise to other nodes and then create the .vimrc
file:
cd ..
mkdir repo
cd repo
touch .vimrc
Inside the .vimrc
file add the following lines to enable a desert color scheme and line numbers:
color desert
set number
Now let's define a new task in the Ansible recipe:
- name: Advertise .vimrc
become: true
become_method: sudo
copy:
src: ../repo/.vimrc
dest: /etc/vim/vimrc.local
Alright, re-run the ansible-playbook install_vim.yml
command and you should see all the same output plus a few new lines:
[Advertise .vimrc] *************************************************************
changed: [pi@192.168.0.101]
changed: [pi@192.168.0.103]
changed: [pi@192.168.0.102]
PLAY RECAP **************************************************************************
pi@192.168.0.101 : ok=3 changed=1 unreachable=0 failed=0
pi@192.168.0.102 : ok=3 changed=1 unreachable=0 failed=0
pi@192.168.0.103 : ok=3 changed=1 unreachable=0 failed=0
Vim is now installed on every node and my personal .vimrc
file is also being used. The beauty of this system is adding new nodes is as simple as adding it to the Ansible inventory file and then will have all these new settings pushed to them immediately.
/etc/profile
What better way to use our new Ansible system than syncing some bash aliases to all three nodes. I really like using bash aliases but if they aren't perfectly synced across every system they can quickly become a pain. Let's make a new Ansible playbook for this task.
cd /etc/ansible/playbooks
touch etc_profile.yml
vim etc_profile.yml
Now let's define two tasks. One that adds the aliases to the /etc/profile
file and one that sources the file so the aliases become available to us in the bash shell.
- hosts: all
remote_user: pi
tasks:
- name: Add aliases to global profile
become: true
become_method: sudo
blockinfile:
path: /etc/profile
insertafter: EOF
block: |
alias 'll=ls -al'
alias '..=cd ..'
alias '...=cd .. && cd..'
alias 'mvansible=cd /etc/ansible'
- name: Source profile
become: true
become_method: sudo
shell: . /etc/profile
args:
executable: /bin/bash
This playbook will allow us to add bash aliases via the master node and sync them to all other nodes in the network with a single Ansible command!
Let's try it:
ansible-playbook etc_profile.yml
PLAY [all] ********************************************************* ************
TASK [Gathering Facts] ********************************************* ************
ok: [pi@192.168.0.101]
ok: [pi@192.168.0.103]
ok: [pi@192.168.0.102]
TASK [Add aliases to global profile] ******************************* ************
ok: [pi@192.168.0.101]
ok: [pi@192.168.0.103]
ok: [pi@192.168.0.102]
TASK [Source profile] ********************************************** ************
changed: [pi@192.168.0.101]
changed: [pi@192.168.0.103]
changed: [pi@192.168.0.102]
PLAY RECAP ********************************************************* ************
pi@192.168.0.101 : ok=3 changed=1 unreachable=0 f ailed=0
pi@192.168.0.102 : ok=3 changed=1 unreachable=0 f ailed=0
pi@192.168.0.103 : ok=3 changed=1 unreachable=0 f ailed=0
Awesome! It looks like everything worked. Just for fun lets try it on a slave node:
pi@raspberrypi3BP-1:~ $ ll
total 56K
drwxr-xr-x 7 pi 4.0K Oct 12 00:21 .
drwxr-xr-x 3 root 4.0K Sep 15 23:54 ..
drwx------ 3 pi 4.0K Oct 11 21:38 .ansible
-rw------- 1 pi 6.5K Oct 11 23:10 .bash_history
-rw-r--r-- 1 pi 220 Jul 10 01:07 .bash_logout
-rw-r--r-- 1 pi 3.5K Sep 15 23:27 .bashrc
drwx------ 3 pi 4.0K Sep 7 19:12 .config
drwx------ 3 pi 4.0K Jul 10 01:30 .gnupg
drwxr-xr-x 3 pi 4.0K Sep 7 18:24 .local
-rw-r--r-- 1 pi 807 Jul 10 01:07 .profile
drwxr-xr-x 2 pi 4.0K Sep 7 20:02 .ssh
-rw------- 1 pi 1.6K Oct 12 00:21 .viminfo
-rw-r--r-- 1 pi 165 Sep 7 18:53 .wget-hsts
Looks like our aliases were correctly synced.
Ansible is now configured. We have a huge amount of potential for installing other applications and advertising configurations. Expect to see some more Ansible posts in the future!
Top comments (0)