Installing Cabot on Debian

Let’s say we want to install Cabot on a server, but not on AWS, nor on DigitalOcean. And because we like challenges, let’s just use Debian Wheezy 7.5 instead of the recommended Ubuntu 12.04 LTS. Ready?

We will try to follow Cabot quickstart to perform the installation.
But first, we must set up a few things. I’ve discovered that during installation, Cabot locks the password of the root account using passwd -l root. So be aware that you won’t be able to log with root and ssh if you haven’t set an authentication process using SSH keys. As The Hitchhiker’s Guide to the Galaxy would say: « Don’t Panic », you can reverse the process if you want using passwd -u root. As a security, you could always create another user with adduser mynewuser and give him an admin status by adding it to the suddoers file with visudo.

So let’s create our keys and configure ssh.
Generate the key:

ssh-keygen -t rsa

Now that we have a key named id_rsa.pub in our .ssh directory, we should do the following steps:

  1. Generate the key-file.
  2. Somehow get the key-file over to the right user-id on the right host.
  3. If that user doesn’t already have an « .ssh » directory, create one AND set its permissions to « 700. » (« rwx——« )
  4. If that user doesn’t already have an « .ssh/authorized_keys » file, create one AND set its permissions to « 600. » (« rw——-« )
  5. Append … don’t overwrite(!) … the new key to that file.

Or we can use ssh-copy-id:

 ssh-copy-id -i ~/.ssh/id_rsa.pub root@hostname.org

You should now be able to log in without having to type in a password.

Before going further, we need to install Fabric as it is used to provision the server and deploy Cabot.

pip install fabric

Fabric also requires some dependencies which are described on Fabric installation page.

Next step, clone the repository. I am using the deploy branch of lincolnloop fork which include awesome python packaging.

 git clone https://github.com/lincolnloop/cabot.git
 git checkout deploy
 cd cabot

Modify configuration: (might need to use development.env with the fork here)

 cp conf/production.env.example conf/production.env
 vim conf/production.env

Before doing anything, make sure you can or can’t install nodejs: aptitude search node. If nodejs can’t be found, you’ll need to install it manually.
A few changes before provisioning our server. Edit file bin/setup_dependencies.sh
and remove line 57 and 58:   ‘nodejs‘ and ‘npm’
Install nodejs manually, npm should come it.

fab provision -H root@your.server.hostname

Once it’s done, we can deploy cabot:

 fab deploy -H ubuntu@your.server.hostname

You should get an error because cabot is trying to use upstart but can’t find it.
To run Cabot, log in to your server under the user ubuntu.

 cd 2014-06-19-e662635

(Your directory will have a different name following a similar pattern year-month-day-wathever)

 foreman start

Congratulations, Cabot should now be running!

Cabot

Things to do

I will certainly add a simple init.d script to my Cabot fork so that we can run it easily. I will maybe change one or more things as the ubuntu username.

Understanding how to install and run Cabot took me a few hours. I got disturbed by the quickstart speaking of AWS or DigitalOcean server. I also tried to install it manually but didn’t manage to get it work, although I was close to it (I think. Or at least I hope ^^). Installing it on Debian added some difficulties, but nothing insurmountable. As a conclusion, I must say that Cabot is worth the effort. It provides a great way to monitor your service with Http checks and the possibility to alert based on Graphite metrics is just priceless.

Déterminer l’emplacement des sources de Django

Voici comment déterminer l’emplacement des sources de Django :

$ python
>>>import django
>>> django
<module 'django' from '/usr/lib/python2.7/dist-packages/django/__init__.pyc'>

Le chemin vers Django est donc

/usr/lib/python2.7/dist-packages/django/

Autre possibilité plus rapide :

python -c "
import sys
sys.path = sys.path[1:]
import django
print(django.__path__)"

Qui nous donne

['/usr/lib/python2.7/dist-packages/django']

Graphite: Vérifier la réception de données

Une commande bien utile pour vérifier ce qui transite sur une interface réseau pour un port donné. Par exemple, pour vérifier l’envoi de paquet depuis Riemann vers Graphite en local (interface lo et port 2003):

ngrep port 2003 -d lo

Qui nous donne le résultat suivant:

interface: lo (127.0.0.0/255.0.0.0)
filter: (ip or ip6) and ( port 2003 )
#
T 127.0.0.1:33936 -> 127.0.0.1:2003 [AP]
 test 1.4 1401805746. 
##
T 127.0.0.1:33935 -> 127.0.0.1:2003 [AP]
 test 1.0 1401805747.

Les messages arrivent jusqu’à Graphite et utilisent le bon format, donc pas de problème du côté de l’envoi.

Limiter la RAM disponible pour Mongo

Pour des besoins de test, et notamment dans le but de mesurer les performances et d’analyser le comportement de Mongo avec différentes quantités de mémoire vive, je me suis penché sur la façon de restreindre les ressources pour un processus donné sous GNU/Linux.

Je me suis d’abord tourné vers ulimit qui semblait permettre de restreindre explicitement la ram, avec en particulier la commande suivante:

ulimit -Hm 30000

Pour la mémoire virtuel, on remplace le m par un v, par exemple:

ulimit -Sv 200000

Cette façon de faire n’était malheureusement pas satisfaisante. En surveillant mon mongo avec mongostat, je constate que celui-ci dépasse largement les limites imposées. Je me tourne donc vers une autre solution: les cgroups.

Reprenons la définition de Wikipédia, les cgroups sont une fonctionnalité du noyau Linux permettant de « limiter, compter et isoler l’utilisation des ressources ». Ça tombe bien, c’est exactement ce que je cherche à faire. En bonus, les cgroups sont utilisés par les LinuX Containers (LXC), procédé de « virtualisation légère », une raison de plus de s’y intéresser.

Revenons à notre problématique de limitation de la ram de mongo. Dans un premier temps, il est nécessaire de préparer l’environnement:

aptitude install libcgroup1

Si le paquet n’est pas disponible sous ce nom là, une simple recherche de cgroup devrait permettre de le trouver. Nous allons tout d’abord créer un nouveau cgroup qui nous permettra d’appliquer les limitations:

sudo cgcreate -t <user> -a <user> -g memory,cpu:<groupname>

Ici, notre cgroup pourra imposer des limites sur la mémoire (memory) et le processeur (cpu).  Nous pouvons maintenant définir les paramètres de notre groupe, en terme de mémoire notamment:

echo 33000000 > /sys/fs/cgroup/memory/<groupname>/memory.limit_in_bytes

Ici, nous limitons la mémoire vive à 33 Mo pour notre cgroup. Des raccourcis existent pour l’écriture des quantités d’octets, on pourrait par exemple remplacer 33000000 par 33M. Il ne nous reste plus qu’à démarrer notre processus mongo avec ces restrictions:

cgexec -g memory:<groupname> mongod

En surveillant notre mongo avec mongostat, nous pouvons ainsi constater une augmentation du nombre de « page faults » lorsque nous réduisons la mémoire disponible de manière significative et constater que mongo prend bien en compte la limite.

Voilà donc un court exemple qui permet d’éviter de saturer sa ram en totalité avant de pouvoir commencer des tests sur mongo, notamment en ce qui concerne l’étude du nombre de « page faults » en fonction du working set et de la ram disponible. Ce procédé peut bien sûr être appliquer à d’autres processus pour éviter qu’ils ne consomment toutes les ressources de la machine. Pour de plus amples d’informations sur le sujet, on se tournera vers le wiki Arch Linux ou encore ce guide Red Hat.