Raspberry Pi 2 cluster with NAT routing

Introduction

In this post I will describe how to build a 12-node cluster of Raspberry Pi 2, how to set it up and configure it with a NAT-routing, DHCP-serving head node, and some simple ways to manage the slaves. In order to minimise typing/copy-and-pasting, and to make everything as simple and automated as possible, all of the commands, scripts and config files associated with this post are available in an associated github repo, which the reader is encouraged to browse in conjunction with reading this post. All of the scripts are very short and simple (just a few lines), and could easily be entered directly at the command line. There is no hidden magic here.

Hardware

To give an idea of what I’m talking about, a picture of my finished cluster is given below. Click on it to view additional detail.

A 12-node Pi 2 cluster
A 12-node Pi 2 cluster

In the foreground are 12 Pis in off-the-shelf cases, stacked in 3 columns of 4. They are connected to a 16-port switch in the background via the regular Pi ethernet ports. They are powered by three 4-port USB chargers (one per column), which are resting on top of the switch. The head node has a USB ethernet dongle, which is in turn connected to an upstream switch, providing internet connectivity. In the picture, the head node is also connected to a display via an HDMI cable (and to a wireless keyboard), though once up and running, the display and keyboard are optional.

For this cluster you need: 12 x Raspberry Pi 2, 12 x (stackable) Pi 2 case, 12 x uSD card (64GB, Class 10), 12 x short patch cable, 12 x short USB to uUSB cable, 3 x 4-port, high power USB charger, 1 x 16 port switch (12 port would do), 1 x USB ethernet dongle, 1 x HDMI display and cable, 1 x USB keyboard, 1 x long patch cable for internet uplink, 1 x 6-way mains power adaptor/extension.

Software

I am using vanilla Raspbian as the base OS. Using an Ubuntu laptop, I flashed the 12 uSD cards one at a time with

sudo dd bs=32M if=2015-05-05-raspbian-wheezy.img of=/dev/mmcblk0
sync

It takes between 3 and 4 minutes per card. Before assembling the cluster, I booted up each card in turn in a Pi 2 to do some very basic initial config. On first boot “raspi-config” will run. I made 4 changes to the default settings. From the main settings I selected “Expand filesystem” and set “Overclock” to “Pi2”. From the advanced settings I changed the RAM split to “16” and enabled SSH. I then finished and rebooted to re-size the card, before logging back in (pi/raspberry) and doing a “shutdown -h now” and then powering down. Again, this took between 3 and 4 minutes per card.

After assembling the cluster, put the cards in all of the Pis, but don’t power up any of the Pis. Pick a head node and attach the ethernet dongle, the internet uplink, a keyboard and display, and then boot up just this head node. Assuming that your internet uplink will respond to DHCP requests made by the dongle, the Pi should auto-detect the fact that there is internet via the dongle (eth1) and not via the internal NIC (eth0), and configure itself appropriately. Check you have connectivity by logging in and doing a ping http://www.google.com or some such. Also change the password on this node to something secure (using passwd). Make sure you have internet connectivity on the head node before proceeding (ifconfig provides useful info).

Grab my code from github and install a few required packages with

wget https://github.com/darrenjw/blog/archive/master.zip
unzip master.zip
cd blog-master/pi-cluster
sudo sh install-packages

This could take around half an hour, and the node will reboot when it is finished. Log back in and return to the script directory to continue. Configure the network with

sudo sh setup-network

This will first configure the two network interfaces correctly, then set up a DHCP server to manage the network settings of the nodes on the internal network, and finally will set up iptables correctly for NAT routing of internal traffic from the worker nodes to the internet and back, ensuring that the LAN-side nodes can all connect to the internet properly. Again, this script will reboot when it is finished (it only takes a few seconds to run).

Once the head node comes back up, log back in, check you still have internet connectivity, and then return to the script directory.

Now boot up all of the other nodes. When they boot, they will send out DHCP requests which the head node should respond to, correctly configuring all of the nodes for internet connectivity. Wait at least 2-3 minutes for all of the nodes to have a chance to boot up properly.

Now on the head node run

sh setup-cluster

Note that this does not need to run as root. This will first generate SSH keys on the head node (for passwordless SSH). Just hit return (3 times) to prompts. Once it has generated the keys, it will scan the internal network to find the other nodes. It will store a list of workers in the file "workers.txt", which will be stored in both the script directory and the home directory. It will then copy the keys to each worker node in turn. For this, you will have to accept the connection and type in the password (raspberry) for each node in turn. This should be the last time you need to enter a password for the worker nodes. Finally, it will upgrade Raspbian on the workers and the workers will all reboot when they have finished upgrading. This last stage will take a long time (up to half an hour, depending on your internet connection). Once this command has completed, wait 2-3 minutes for the workers to reboot before continuing.

Note that the script setup-cluster calls three other scripts to do its work, and these scripts can be useful on their own. The script map-network scans the network to see what nodes are available, and stores them in the file workers.txt. You should re-run this whenever nodes are added or removed from the cluster. The script copy-keys copies the SSH keys to all of the workers. You should re-run this after adding new nodes to the cluster (after running map-network). Finally, the script upgrade-workers upgrades Raspbian on all of the worker nodes and then reboots them.

Finally, there is one more script, shutdown-workers which shuts down all of the workers in anticipation of the head node being shut down and the cluster being powered down.

You may be tempted to customise the worker nodes by logging in to them individually and giving them host names, etc. It’s best to resist this temptation. The Zen of cloud computing is to treat nodes like sheep and not like ponies! Don’t name them, don’t pick favourites, don’t treat them individually, and don’t care if the odd one occasionally goes missing. You might imagine that this can make it difficult to track down hardware problems with individual nodes, but it’s usually possible to track these down quite quickly by looking at indicator lights on the nodes and the network switch when the system is under load.

That’s it – you now have your own private cloud.

Use case: a standalone Spark cluster

There are lots of things that one can do with a cluster like this, but for illustration, I will now show how to use the cluster as a standalone Apache Spark cluster. In previous posts I have described how to install Spark on a Pi 2 and how to create a small Spark cluster. It may be worth quickly reviewing those posts before proceeding. On the head node run

cd
wget http://www.eu.apache.org/dist//spark/spark-1.4.1/spark-1.4.1-bin-hadoop2.6.tgz
tar xvfz spark-1.4.1-bin-hadoop2.6.tgz
cd spark-1.4.1-bin-hadoop2.6

to get and unpack a recent version of Spark. Then configure Spark appropriately with:

cp ~/workers.txt conf/slaves
echo '#!/usr/bin/env bash' > conf/spark-env.sh
echo "" >> conf/spark-env.sh
echo "SPARK_MASTER_IP=192.168.0.1" >> conf/spark-env.sh
echo "SPARK_WORKER_MEMORY=512m" >> conf/spark-env.sh

Having configured Spark on the head node (which will also act as the Spark Master), we can copy it to the workers with

parallel-scp -h ~/workers.txt -r -p 100 -t 0 /home/pi/spark-1.4.1-bin-hadoop2.6 /home/pi/spark-1.4.1-bin-hadoop2.6

Note that if you subsequently change the config, you don’t need to re-copy the entire Spark distribution. Just re-copy the conf directory with

parallel-scp -h ~/workers.txt -r -p 100 -t 0 /home/pi/spark-1.4.1-bin-hadoop2.6/conf /home/pi/spark-1.4.1-bin-hadoop2.6/conf

A simple Spark session can then be run with

sbin/start-all.sh
bin/spark-shell --master spark://192.168.0.1:7077

When Spark eventually starts up, you can enter the following into the Spark shell

sc.textFile("README.md").count

After exiting the Spark shell (Ctrl-D), you can shut everything down with

sbin/stop-all.sh

See my other posts for additional pointers and further reading.

Some useful links/references

The main relevant link for this post is that of the associated code on GitHub:

https://github.com/darrenjw/blog/tree/master/pi-cluster

If you are a Git person you might want to clone or fork this repo. The main other post I found useful for setting up the Pi as a NAT router was:

http://qcktech.blogspot.co.uk/2012/08/raspberry-pi-as-router.html

There was also an article on turning your Pi into a Wifi access point in Issue 11 of MagPi that I found somewhat useful.

Advertisements

Docker on Snappy Ubuntu Core on a Raspberry Pi 2

In a previous post I gave a quick introduction to Snappy Ubuntu Core on the Raspberry Pi 2. This was based on the very early version of Ubuntu Snappy Core that was released around the time of the Rasberry Pi 2. There were various problems with that early release that have since been fixed, so in this post I want to give a quick update on the status of Snappy on the Pi, especially in relation to Docker.

If you have an early version of Snappy for the Pi 2, you should manually download a new image and re-flash your SD card. I did not have any luck in using the Snappy upgrade mechanism (which is somewhat ironic). You can download a new image here. I used ubuntu-15.04-snappy-armhf-rpi2.img for this post.

You can check if you have an old or new version of Snappy by running snappy list. That gave an error with the old version, but should work fine with the new version. The new version also sets the system clock using the internet, so date should return the correct time for any system that is connected to the internet. As before, Snappy runs an SSH server from first boot (ubuntu/ubuntu), so can be happily run completely headless.

Once logged in the snappy guides should more-or-less work. Commonly used Snappy commands are indicated below.

snappy
snappy --help
snappy list --help
snappy info
snappy list
snappy list -a
snappy list -u
snappy search docker
sudo snappy update ubuntu-core
sudo reboot
sudo snappy install docker

There is now a Snappy framework for Docker which can be easily installed, as indicated above. If you are a Docker person, this is essentially the only Snappy framework/app you need, as you can do everything else with Docker images.

The main issue with Docker on the Pi 2 (and on ARM more generally), is that the vast majority of images on DockerHub are for x86, and therefore will not work on ARM. For the Pi, the best bet is to search for images containing the text rpi or armhf. Again, some indicative Docker commands are given below.

docker search rpi
docker info
docker images
docker pull hypriot/rpi-java
docker pull resin/rpi-raspbian
docker images
docker run -i -t hypriot/rpi-java /bin/bash
docker ps
docker ps -a

Some useful base images include resin/rpi-raspbian which is a minimal Raspbian base, and hypriot/rpi-java, which includes OpenJDK7. With these (or other) base images, it is easy to layer on top with your own Dockerfile to create your own custom images. As discussed previously on this blog, OpenJDK is very slow relative to Oracle’s JVM on ARM. I’ve not yet found a public image containing Oracle’s JVM (perhaps due to licensing issues), but it’s easy enough to roll-your-own from a minimal base image. You can follow the standard Docker User Guides for information on how to build your own images.

Setting up a Minecraft server on a Raspberry Pi

I’ve recently set up a Minecraft server on a Raspberry Pi. There’s lots of information on line describing how to do this, but I still had some problems, in part due to a lot of information on-line being out-of-date, in part due to the fact that running a Minecraft server is right on the limit of what a Pi is capable of, and in part due to the fact that I don’t really know much about Minecraft…

Just to be clear, this is about running a Minecraft SERVER, not the game client. The game client doesn’t work well on the Pi, as it doesn’t have enough memory. There is a special game client for the Pi, the Minecraft Raspberry Pi Edition, which is free, and programmable, but is creative mode only, and has no monsters. That is not what this post is about. You can run a server on the Pi (for free) which you can use from a standard game client (which is not free). That is what this post is about.

Useful on-line information I found useful includes the Gamepedia tutorial, this Forum thread, and this how-to-geek article. It is worth having a quick read through these before continuing.

It is important to understand that there are lots of different Minecraft servers out there, most of which are Java based, but not all. There are potential advantages to not using the standard vanilla Mojang reference server, as some servers are lighter weight, and hence could potentially run better on the Pi. However, lots of servers “out there” are not compatible with the latest (1.7.x) versions of the game client, so it’s probably best to get the vanilla server up and running first, before exploring other possibilities. Note that I’m assuming a Revision 2 Model B Pi with 512MB RAM. I don’t imagine that you will have a good experience with 256MB RAM. You should use raspi-config to allocate as little RAM as possible to the GPU, and you should overclock the Pi as much as you dare.

The Mojang server is a Java server, so you need a fast JVM installed on the Pi. The OpenJDK JVM is too slow – you need the Oracle JVM. Lot’s of info on the web refers to Oracle’s developer preview of Java 8, but that isn’t necessary now, as Oracle’s Java 7 is now a standard part of Raspbian. So just install that:

sudo apt-get update
sudo apt-get install oracle-java7-jdk

Use java -version to make sure it has worked. Then just pull the server jar, stick it into an appropriately named directory, and run the server from that directory with a command like:

java -Xms256M -Xmx384M -jar minecraft_server.1.7.2.jar nogui

The first time you run this it will take an age (possibly up to half an hour). Subsequent starts will be much quicker (15 seconds). Once it is up and running, try connecting to the address/name of the Pi from the machine you usually use for running the Minecraft game client. If the connection fails due to a protocol error, this usually means that the server is too old to cope with the latest version of the game client, so you need to find a new server. If it fails due to a timeout, then it means that your Pi isn’t running fast enough. Tweak settings. Overclock more, etc. There are various settings in the “server-properties” file that you can tweak to improve the speed at which the server runs. Disabling “nether” and dropping the view distance down (to, say, 5) seem to be particularly effective. Again, you can find out more about this by googling around. My current server-properties looks like this:

#Minecraft server properties
#Sat Nov 30 14:23:39 UTC 2013
generator-settings=
op-permission-level=4
allow-nether=false
level-name=world
enable-query=false
allow-flight=false
announce-player-achievements=true
server-port=25565
level-type=DEFAULT
enable-rcon=false
force-gamemode=false
level-seed=
server-ip=
max-build-height=256
spawn-npcs=true
white-list=true
spawn-animals=true
hardcore=false
snooper-enabled=true
texture-pack=
online-mode=true
resource-pack=
pvp=true
difficulty=1
enable-command-block=false
player-idle-timeout=0
gamemode=0
max-players=10
spawn-monsters=true
generate-structures=true
view-distance=5
spawn-protection=16
motd=Pi server

If you’ve never set up a server before and are having trouble, it may be easier to set things up on another machine and then copy things across to the Pi when you get it working. I actually got mine up and running on a fast Ubuntu laptop first, which saved a lot of time.

I’m still running the Mojang server. It’s generally fine, but gives lots of warnings about “Not keeping up”, and riding horses doesn’t really work very well. If anyone has suggestions for another server that will work as a swap-in replacement and run better on the Pi, please do leave a comment. I’d be interested in something that runs a bit faster, and copes better with riding horses, smashing blocks, etc. But my kids will not be pleased if they have to re-build their world…