DevOps#
Information is not knowledge.
—W. Edwards Deming
For us to run statecharts on different machines will require a few system administration steps. When such a process is automated, it is often called Development Operations, or DevOps.
I found the installation documentation on the RabbitMQ website to be mostly illegible to me as a new user, so I wrote this guide to save you the pain which I went through.
Once you are familiar with the miros-rabbitmq library, you can reference this full deployment procedure for setting up your distributed system.
For now, in this section, we will describe procedures for setting up RabbitMQ so that our miros-rabbitmq derived programs can talk to each other through it.
RabbitMQ On Windows and the WSL#
If you are installing RabbitMQ on (>= Windows 7), try following this video and if that doesn’t work clear your afternoon’s schedule, and work through this. Pay special attention to the section titled Synchronise Erlang Cookies.
RabbitMQ On Linux#
For Linux, I automated the installation process of RabbitMQ using a simple Ansible script. If you haven’t heard of Ansible before, it’s a Python library that allows you to automatically ssh into machines and run a series of sysadmin commands. You can use it to deploy things automatically. For this to work we will need to:
Install RabbitMQ using Ansible
Note
I tried to install RabbitMQ using my ansible scripts in windows using the WSL (Windows Subsystem for Linux). This didn’t work, but the miros-rabbitmq code will run from the WSL once you install RabbitMQ on windows using the windows procedure.
Setting up SSH so you Don’t Need a Password#
Ansible needs to be able to ssh into the computer it is trying to control. To let it do this, you will have to first, place the public ssh key of the computer running Ansible into the computer it is deploying software too.
Check to see if the machine you are going to be running Ansible from has public keys:
> ls ~/.ssh | grep pub
If nothing appears, the deployment machine doesn’t have a public key. To make a public key, do the following (only run these commands if you don’t have a public key already):
> mkdir ~/.ssh
> cd ~/.ssh
> sudo ssh-keygen
When you see an option to enter a passphrase, just hit enter.
Now, let’s see if we can ssh into our own machine without a password.
ssh $USER@localhost
If you can login without a password, great, Ansible can now deploy things to this machine, from this machine.
If you can’t SSH without a password to your localhost, we just have to put this machine’s public key into its authorized_keys file. (only run this command if you can’t ssh into your own machine without a password):
> sudo cat '~/.ssh/id_rsa.pub' >> '~/.ssh/authorized_keys'
Try to SSH into the machine again. You shouldn’t need a password anymore.
Now let’s push our public key onto a remote computer that we want to deploy software too. To do this, you will need it’s URL or IP address and the username of the account that has SSH enabled. As an example, I’ll assume that the machine you are trying to set up has the IP address of 192.168.0.169 with a username pi. Change out the username and IP address with your own for the remainder of this example.
First we test if it already has this machine’s public key:
ssh pi@192.168.0.169
If it asked for a password, it does not have our public key in its authorized_keys file. If this is true, let’s put our public key into its authorized_keys file:
> cat ~/.ssh/id_rsa.pub | ssh pi@192.168.0.169 'cat >> .ssh/authorized_keys'
Now test it:
ssh pi@192.168.0.169
The above command shouldn’t ask for a password anymore.
Repeat this procedure for every machine onto which you would like to deploy RabbitMQ.
Tell Ansible Where to Run and with What User Name#
Ansible needs to know what machines to ssh into and with what usernames. This information is kept in the /etc/ansible/hosts
file; it is called an inventory. To tell Ansible what machines you want it to run its scripts on, you first create a named configuration item, and below it place the contact information (IP/URL address and username) for each of the machines in that group. Your deployment script references this name to know what computers to log in to and run on.
Suppose I have a bunch of raspberry pi computers on my network, I might want to name their group miros-rabbitmq
in my Ansible inventory. They all have the same username, but they are on addresses, 192.168.0.71 and 192.168.0.169. So, on the Linux machine that I will run my deployment scripts from, I would edit the /etc/ansible/hosts
file like this:
sudo pico /etc/ansible/hosts
Then I would change the file to:
[miros-rabbitmq]
192.168.0.71 ansible_user=pi
192.168.0.169 ansible_user=pi
Note
The default posix username for a raspberry pi is pi
. If your usernames are different,
update the above listing with your usernames.
Have Ansible Install RabbitMQ#
Now that Ansible knows what user names and addresses to use, we need to tell it to do
something. Ansible scripts are just yml files; they are easy to read. The
only people I know, who don’t like yml files, are minecraft administrators. So,
here is the yml file that will install RabbitMq onto all of the computers in my
scotty
group, I called it rabbit_install.yml
:
---
- hosts: scotty
vars:
rabbit_name: peter
rabbit_password: rabbit
rabbit_tags:
- administrator
guest_password: energizer
tasks:
- name: Install rabbitmq-server
become: true
apt: name={{ item }} state=present update_cache=false
with_items:
- erlang
- rabbitmq-server
- name: Remove user
become: true
shell: rabbitmqctl delete_user {{rabbit_name}}
ignore_errors: True
- name: Create a user with password
become: true
shell: rabbitmqctl add_user {{rabbit_name}} {{rabbit_password}}
ignore_errors: True
- name: Assign a tag to the user
become: true
shell: "rabbitmqctl set_user_tags {{rabbit_name}} {{rabbit_tags | join(' ')}}"
ignore_errors: True
- name: Set permissions
become: true
shell: rabbitmqctl set_permissions -p / {{rabbit_name}} ".*" ".*" ".*"
ignore_errors: True
- name: Change default admin password
become: true
shell: rabbitmqctl change_password guest {{guest_password}}
ignore_errors: True
- name: Setup environment variables
become: true
template:
src: ./rabbitmq-env.conf.j2
dest: /etc/rabbitmq/rabbitmq-env.conf
mode: 644
- name: Setup configuration file
become: true
template:
src: ./rabbitmq.config.j2
dest: /etc/rabbitmq/rabbitmq.config
mode: 644
- name: Enable the management plugin
become: true
shell: rabbitmq-plugins enable rabbitmq_management
ignore_errors: True
- name: Restart the rabbitmq-server service
become: true
shell: sudo service rabbitmq-server restart
ignore_errors: True
This file references a couple of jinja2 templates, rabbitmq-env.conf.j2 and rabbitmq.config.j2. Normally an Ansible script would populate the variables in a jinja2 template, then write the resulting file to disk, but in this example it just writes out the template file without any alteration.
Here is the rabbit-env.conf.j2
file:
RABBITMQ_CONFIG_FILE=/etc/rabbitmq/rabbitmq
NODE_IP_ADDRESS=0.0.0.0
Here is the rabbitmq.config.j2
file:
[
{rabbit,
[
{loopback_users,[]}
]
}
]
.
Note
The rabbitmq.config file is actually Erlang. I lost many hours trying to get RabbitMq to install using the example rabbit.config file from RabbitMQ repo. It was broken, too many brackets or something. Not knowing anything about RabbitMQ or Erlang, it took me a while to figure out that the problem was with their code and not with my setup.
So, copy the above rabbit_install.yml
, rabbit-env.conf.j2
and the
rabbitmq.config.j2
files into your deployment directory, change the user
name and passwords to whatever you want them to be and perform a deployment:
> ansible-playbook -K rabbit_install.yml
The above command will ask you for the root password required to sudo into the machines listed in your inventory. Enter it and hit enter.
bon chance mon ami.