In this Instructable I would like to share my personal work-flow for working with headless Raspberry Pi.
If you are interested in automating the setup and deployment process for one Pi or many this is the post for you.
All the code is available on github: Raspberry Pi orchestration
Please give feedback as this is my first post and first python project.
Thanks to Instructables for sending Raspery Pi 2 in quantity which allowed to create big network for testing.
Step 1: Short History
link on the cover picture to preserve copyright
I love RPi as a fast way to solve personal problems. Make a media center, maybe an internet radio, NAS or whatever.
I never tried running any desktop on RPi or connected keyboard to it. But to use it this way is not always easy. The fastest way I found was to use Google Coder project. It was so fast. Burn the image to SD card and connect ethernet cable or WiFi dongle and you are good to go. But as all Raspbian solutions it needs 4 Gb sd card. I try to re use old cards or make projects as small as possible.
What I did for myself is a Frankenstein of different projects to make it possible to find all the raspberry pi's on the network, install any distro of your choice to sd card or USB flashdrive and them provision it as you need. And if you have apps to deploy you can do it too.
Step 2: What You Need
- Raspberry pi, any model will do, this script can be changed to run on all of them. But it is much simpler if you don't use A or A+ because they don't have Ethernet port.
- Internet, and fast one if you don't want to wait long. For first runs all the files will be downloaded from external sources.
- Any computer running OS X, Linux or Windows. All steps can be reproduced on any of the platforms, some modifications to the code needed.
- Know basic python.
This tutorial is intended for people who worked with Raspberry Pi before, or is looking for any DevOps solution.
If you are only starting with Raspberry Pi try:
for guides for first start.
Step 3: Structure
This is a big project for me, so I'll have to divide it into parts.
here is the first draft of what I wanted to achieve:
- discovery module, use any way to detect ip by partial mac address
- use the ip to create ansible inventory
- test for standard login methods # integrated in rpi_ssh
- ssh with password
- ssh with key
- use detector to get list of RPi
- use templates for role definition
- generate ansible inventory based on a template
- test for default ssh login methods
- ssh with password
- if true continue to switch to key, else ssh with key
ssh with key : if policy mandates switch to key, else exit
- switch to key
- use pre-defined root key
- generate root key
- generate keys for defined users
- generate authorised_keys files
- copy to defined folders
- ssh with password
- use template to generate
- - use base image if available
- if used as stand alone app:
- run update, upgrade playbook
- run role provision playbooks
- playbook for environment verification
- playbook for deployment
- playbook for deployment verification
- monitor demon for controlling cluster status
- failure detection and re-install
Next steps will describe how I managed and sometimes failed in thees steps.
I use OS X as a development platform, but tried to test all modules on Windows and Linux. I down't have full solutions for those platforms right now, hope to get them in the future.
Step 4: OS
To do anything with Raspberry Pi you need to install minimal software.
OSs for Raspberry Pi come in different flavors, you can find some on official website or search for "raspberry pi os".
I use alternative way to get very small and custom os installed : raspbian net installer.
- very minimal install, in minimal server configuration uses ~380 Mb.
- customizable. You can define packages needed.
- Simple install, copy files to FAT partition on SD card and plug it to RPi
- Can install to USB flash drive or other media if needed
- It is possible, after first run, re-install OS without taking out SD card or touching RPi via ssh.
- Needs internet to get files from repository, if you deploy many machines it will consume lots of traffic. For this case it is recommended to have local clone of repository with necessary packages and use Ansible to add additional ones on per-machine basis.
- Takes time. If used over Internet speed of install will depend on downlink.
You can run this once and create preferable base installation, create an image of it and use that next time.
NB ! When you create image don forget to clean up. Delete package manager cache and other unnecessary files.
Also, I spent an hour with eth0 unavailable until I figured out that I need to delete /etc/udev/rules.d/70-persistent-net.rules before creating image as it stores MAC address for the Ethernet module.
Yes, it is possible to use base image to deploy os over network.(Will add if there is interest)
To define installer parameters and install additional packages use installer-config.txt. Put it on /boot partition of SD card you plug to your RPi.
Step 5: Detector
By now you should have a raspberry pi running, with os of your choice and connected to your network.
There are options how to find Raspberry Pi on the network.
- nmap - great multi platform tool for network discovery and security auditing. You can scan your network for all connected devices and get ip addresses for RPi. Downside is that you need to install it on OS X and Windows and not all Linux distros have it pre-installed. I use it all the time for different applications and if you like it – use this option for the discovery part.
- login to your router if possible and look up the ip that was assigned to RPi. Not very scriptable process.
- if RPi has avahi-daemon running than use Apple zeroconfig, Bonjour in Windows, or avahi-browse in Linux to get ip addresses.
- Pi Finder.app - Simple Apple script app for discovery.
- many more
I needed small and fast solution that needs no additional apps, libs for python – "arp". Arp is networking tool available on almost all platforms, definitely on OS X, Windows and Linux. It produces basically same output and readily available through python.
You can see I found 4 RPi's on my network.
There is a caveat with this code. By default arp table is empty and you have to fill it. My monitor server fills it for it constantly in contact with all machines.
- use nmap instead, or use it as a solution to fill the arp table .
- add ping loop for the subnet scan
I use arp because nmap needs additional library in python to function properly and parsing nmap output as is not as simple as arp for me.
From her you can pipe it to next stage.
Step 6: Inventory
So we got ip addresses.
We can use them to connect to RPi's using ssh and configure them as we want.
I use Ansible because:
- Server only. Doesn't need client software installed
- Python based
- Very simple YAML configuration files
Main concept is to run scripts with tasks you want to perform(Playbooks) against list of machines you have (Inventory). Read more in documentation.
To install ansible on your main machine use your method of choice:
- pip install ansible
- brew install ansible
- apt-get install ansible
This step explains how to make inventory file from list of IPs we got before.
I use dynamic inventory strategy in combination with rpi_detector module to create list of hosts I will run my Playbooks on.
This gives flexibility to the process so you don't have to think if all machines were added.
Current version of the solution can be found on github: inventory.py
It is base on this great tutorial : Ansible and Dynamic Inventory
It is necessary to provide host list with needed parameters, such as port, username, ssh password or key for this to work. Fill in ANSIBLE_INV with this data. At the moment of making this Instructable this dictionary is created with rpi_detector module.
Step 7: Ansible Playbooks
This part is just an example of what is possible with ansible playbooks.
I will use my testing project to deploy raspberry pi temperature monitor with web interface. It uses :
python script to:
get temperature from ds18b20 1-wire sensors, store it in sqlite database;
view a web ui with temperature plot
apache server to serve web page and run cgi script to generate temperature plot.
File structure of my project
- pyrun.py # used to run playbook programmatically.
- main.yml # is the main file that I run to do all tasks, it includes update/upgrade features, provisioning and deployment tasks. As it is simple project there no roles and decision making.
- files/ # is a folder to store all files you need to copy to raspberry pi, for example public ssh keys
- playbooks/ # is a folder for ansible playbooks, if you want to have separate set of tasks for different scenarios like update/upgrade as you don't want to run it every time.
- vars/ # stores files with different variables you might need like paths and permissions, user lists etc.
- templates/ # stores jinja2 template files to generate different things on the machines. I use it to create apache configuration, but it's not necessary for simple setup
To test that inventory works you should run test module 'ping', which will return 'pong' if all is OK. Do it in two ways:
- ansible -i inventory.py all -m ping
- python pyrun.py with "run modules" block uncommented and "run playbooks" commented
They produce similar output. Python option gives more flexibility for monitoring and ability to react to errors in code.
If all goes well try running main playbook:
- ansible-playbook -i inventory.py all main.yml
- python pyrun.py with "run playbooks" block uncommented and "run modules" commented
This process will take some time, depending on how fast your downlink is and how many Rpi's you have.
In the end you should be able to use link of the form "rpi_ip_adress/cgi-bin/webgui.py" and see a webpage with Temperature Chart.
Notes if it doesn't work
- there are differences in apache2.config for different OS, even for Debian 'wheezy' vs 'jessie' I had to change activation for cgi module in apache for all to run. Any ideas why is it so?
- you might be missing correct permissions in the system.
- check if ansible finished without any errors or missed something.
Step 8: More...
I will add to this Instructable as soon as I finish other modules I have in mind, or if there would be any requests for detailed explanation.
Thank you for reading this. Good luck with orchestration.