Lerm-IT

Blog traitant de technologies informatiques. Logiciel libre, AdminSys, DevOps et GNU/Linux !

05 Nov 2014

[Debian] Machine virtuelle headless hyper-rapide avec Vagrant et Docker

Vagrant est un outil qui permet de lancer des machines virtuelles headless. C’est à dire sans interface graphique.

Docker est un outils qui permet de gérer simplement l’isolation de processus sur un système avec un noyaux Linux.

Nous allons voir ici comment installer une machine virtuelle Vagrant basée sur les conteneurs Docker. Objectif ? Démarrage en moins de 3 secondes !

Même si les commandes présentées ici concernent Debian ceci peut être facilement adapté sur d’autres systèmes GNU/Linux (RHEL, CentOS, Gentoo, ArchLinux, …)

Installation

Vagrant

Nous allons tous d’abord installer Vagrant. Le support de Docker dans vagrant n’est disponible depuis la version 1.6 de Vagrant(1) il nous faudra donc au minimum cette version.

Téléchargeons le paquet et installons le.

$ wget https://dl.bintray.com/mitchellh/vagrant/vagrant_1.6.5_x86_64.deb
$ sudo dpkg -i vagrant_1.6.5_x86_64.deb

Vous pouvez vérifier que vagrant est correctement installé simplement en tapant la command vagrant

$ vagrant
Usage: vagrant [options] <command> [<args>]

    -v, --version                    Print the version and exit.
    -h, --help                       Print this help.

Common commands:
     box             manages boxes: installation, removal, etc.
     connect         connect to a remotely shared Vagrant environment
...

Note : Il est possible que vagrant vous demande de réaliser certaine mise à jours. Exemple :

Vagrant is upgrading some internal state for the latest version.
Please do not quit Vagrant at this time. 
...
Press any other key to continue.</blockquote>

Vagrant est maintenant installé passons à l’installation de docker.

Docker

La documentation officielle de Docker est très bien faite pour l’installation de docker(2). Nous allons donc la suivre. L’exemple ici concerne une Debian Wheezy.

Pour pouvoir fonctionner docker nécessite les fonctionnalités du noyau Linux 3.8. Il faudra donc tout d’abord installer un noyau à jour. Sous Wheezy nous sommes obligé de passer par les backports.

# echo "deb http://http.debian.net/debian wheezy-backports main" > /etc/apt/sources.list.d/backport.list 
# aptitude update
# aptitude install -t wheezy-backports linux-image-amd64

Pour utiliser ce noyau il faut redémarrer. Alors : on bookmark l’article, on sauvegarde ses documents et on reboot !

Vous re-voila ? Super ! Installons docker. Pour cela un petit script est fournit par les développeurs et fonctionne très bien. Votre mot de passe vous sera demandé pour procéder à l'élévation de privilège nécessaire à l’installation de certains composants.

$  curl -sSL https://get.docker.com/ | sh

L’installation terminée nous devons ajouter notre utilisateur courant au groupe “docker” de manière à pouvoir lancer des conteneur dans un environnement non privilégié.

$ sudo usermod -aG docker username
$ newgrp docker

Remplacer username dans la commande précédente par votre nom d’utilisateur.

Si tout est bien installé la commande suivante doit fonctionner.

$ docker ps    
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Démarrer une premier conteneur

Nous allons maintenant démarrer notre premier conteneur.

La image de base

Pour pouvoir démarrer un conteneur docker il faut avoir un image de machine de base. De nombreuse image de base sont disponible sur le “registre” docker(3). Nous allons ici télécharger l’image de base debian 8 : jessie (encore en beta aujourd’hui).

$ docker pull debian:jessie
debian:jessie: The image you are pulling has been verified
50215b109eda: Pull complete 
53f380325ee9: Pull complete 
511136ea3c5a: Already exists 
Status: Downloaded newer image for debian:jessie

Comme vous le voyez plusieurs fichiers au nom barbare sont téléchargés car docker gère ses images hirarchiquement. Chaque image dépend d’une image mère(4). Ces images intermédiaires sont appelées des “layers”.

On voit maintenant que nous avons une nouvelle image

$ docker images 
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
debian              jessie              53f380325ee9        8 days ago          120 MB

Nous allons nous pencher sur Vagrant pour voir comment exécuter celle-ci.

Un fichier Vagrantfile

Pour pouvoir lancer une machine virtuelle vagrant nous avons besoin d’un fichier de configuration nommé Vagrantfile à la racine du dossier de la machine virtuelle. Ce dossier sera d’ailleurs accessible en lecture/écriture sur la machine virtuelle dans /vagrant.

Voici un fichier Vagrantfile minimaliste.

Vagrant.configure("2") do |config|
  config.vm.provider "docker" do |d|
    d.image           = "debian:jessie"
    d.has_ssh         = false
  end
end

Ce fichier Vagrantfile va être lu au moment où on nous allons démarrer la machine virtuelle avec la commande vagrant up. Ici le paramètre le plus intéressant est ‘d.image’ qui nous permet de spécifier l’image que nous souhaitons utiliser comme base.

Go !

Allez on se lance ?!

$ vagrant up --provider=docker
Bringing machine 'default' up with 'docker' provider...
==> default: Creating the container...
    default:   Name: blog_default_1413568195
    default:  Image: debian:jessie
    default: Volume: /home/romain/project/vagrant/blog:/vagrant
    default:  
    default: Container created: 6a5fab70c2822549
==> default: Starting container...
==> default: Provisioners will not be run since container doesn't support SSH.

Quoi ?! Tout ca pour ca ?

Et oui ! Notre conteneur a bien démarré mais comme aucun processus SSH n’a été lancé à l’intérieur de celui-ci il c’est arrêté tout de suite.

Nous pouvons constater ceci à l’aide la commande suivante.

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
6a5fab70c282        debian:jessie       "/bin/bash"         9 seconds ago       Exited (0) 7 seconds ago                       blog_default_1413568195   

Nous allons voir dans la prochaine section comment palier ce petit problème.

Démarrer un conteneur et le garder en vie

Pour qu’un conteneur docker reste en vie il faut que le processus lancé à l’initialisation du conteneur reste en vie. Ainsi tant que ce processus est en vie, le conteneur l’est aussi.

Vagrant utilise activement SSH pour se connecter sur ses machines virtuelles. Nous allons donc partir du principe que notre commande initial sera le démons SSH.

init devient SSH

Une machine docker n’a aucun logiciel installé par défaut nous allons donc devoir installer OpenSSH. Ceci se passera en trois étapes :

1/ Démarrer un conteneur sur /bin/bash et se connecter dessus.

2/ Installer OpenSSH

3/ “Commiter” les modifications pour créer une nouvelle image docker utilisable par vagrant.

Pour démarrer un conteneur simple et nous connecter dessus nous allons utiliser la commande suivante :

$ docker run -i -t debian:jessie /bin/bash

Installons OpenSSH.

# apt-get update
# apt-get install openssh-server
# mkdir /var/run/sshd
# exit

Sauvegardons nos changements en les commitants. Ceci va créer une nouvelle image. Elle doit être préfixé (seul les VMs de docker peuvent ne pas être préfixée). Pour faire le commit il vous faudra l’id du conteneur que nous venons de modifier.

$ docker ps -la
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
775fb1a292af        debian:jessie      "/bin/bash"         4 minutes ago       Exited (0) 11 seconds ago                       goofy_pare

La commande suivante commite l’image.

docker commit 775fb1a292af lermit/debian-vagrant
afbcca54a4796abe6f27da6004df258f6deb7d448002df3f4280609691dd8413

Autoriser vagrant à se connecter

Nous allons maintenant modifier notre configuration Vagrant pour dire “C’est bon on a un démon SSH” !. Voici ce à quoi doit ressembler votre fichier Vagrantfile

Vagrant.configure("2") do |config|
  config.vm.provider "docker" do |d|
    d.image           = 'lermit/debian-vagrant'
    d.has_ssh         = true
    d.cmd             = [ '/usr/sbin/sshd', '-D', '-e' ]
  end
end

Pensez bien à modifier le nom de l’image par celui que vous avez créé précédemment.

Nous allons maintenant supprimer notre ancienne machine virtuel vagrant et en créer une nouvelle basée sur notre nouvelle image. Ces commandes sont à exécuter dans le dossier de votre fichier Vagrantfile.

$ vagrant destroy
    default: Are you sure you want to destroy the 'default' VM? [y/N] y
==> default: Deleting the container...
$ vagrant up --provider=docker
Bringing machine 'default' up with 'docker' provider...
==> default: Creating the container...
    default:   Name: blog_default_1415214859
    default:  Image: lermit/debian-vagrant
    default:    Cmd: /usr/sbin/sshd -D -e
    default: Volume: /home/romain/project/vagrant/blog:/vagrant
    default:   Port: 2222:22
    default:  
    default: Container created: 5f48f604248e17d9
==> default: Starting container...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 172.17.0.15:22
    default: SSH username: vagrant
    default: SSH auth method: private key
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...
    default: Warning: Authentication failure. Retrying...

Et on arrive encure sur un échec ! C’est normal car vagrant attend de pouvoir se connecter en SSH et tant qu’il n’y arrive pas … et bien il attend ! On va donc créer l’utilisateur vagrant.

Démarrons un nouveau conteneur basé sur notre image avec un shell bash et créons l’utilisateur. Nous lui attribuerons le mot de passe ‘vagrant’ et profiterons de l’occasion pour lui donner les droits d’administration via sudo.

$ docker run -i -t lermit/debian-vagrant:latest /bin/bash
root@70a37163e19c:/# useradd -m -s /bin/bash vagrant 
root@70a37163e19c:/# passwd vagrant
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully
root@70a37163e19c:/# apt-get install sudo
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  sudo
0 upgraded, 1 newly installed, 0 to remove and 29 not upgraded.
Need to get 848 kB of archives.
After this operation, 2694 kB of additional disk space will be used.
Get:1 http://http.debian.net/debian/ jessie/main sudo amd64 1.8.10p3-1 [848 kB]
Fetched 848 kB in 1s (525 kB/s)
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package sudo.
(Reading database ... 12249 files and directories currently installed.)
Preparing to unpack .../sudo_1.8.10p3-1_amd64.deb ...
Unpacking sudo (1.8.10p3-1) ...
Setting up sudo (1.8.10p3-1) ...
root@70a37163e19c:/# echo "vagrant ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
root@70a37163e19c:/# exit

Sauvegarder nos modifications

Comme pour la création de notre image nous allons devoir commiter les modifications effectué sur notre image.

On récupère l’ID et on commit sur le même nom !

$ docker ps -al
CONTAINER ID        IMAGE                          COMMAND             CREATED             STATUS                          PORTS               NAMES
70a37163e19c        lermit/debian-vagrant:latest   "/bin/bash"         3 minutes ago       Exited (0) About a minute ago                       tender_meitner      
$ docker commit 70a37163e19c lermit/debian-vagrant
e0a3bd14989af0659801937e6fc0b76e30bd0224f5ffe79a960fd237aa002b30

Avant de pouvoir relancer notre instance vagrant nous allons devoir modifier notre fichier Vagrantfile pour qu’il connaisse les identifiants avec lesquels se connecter. Voici le contenu du fichier Vagrantfile.

Vagrant.configure("2") do |config|

  config.vm.provider "docker" do |d|
    d.image           = 'lermit/debian-vagrant'
    d.has_ssh         = true
    d.cmd             = [ '/usr/sbin/sshd', '-D', '-e' ]
  end
  config.ssh.password = 'vagrant'

end

Et cette fois la connexion fonctionne !

$ vagrant up --provider=docker
Bringing machine 'default' up with 'docker' provider...
==> default: Fixed port collision for 22 => 2222. Now on port 2200.
==> default: Creating the container...
default: Name: blog_default_1415215454
default: Image: lermit/debian-vagrant
default: Cmd: /usr/sbin/sshd -D -e
default: Volume: /home/romain/project/vagrant/blog:/vagrant
default: Port: 2200:22
default:
default: Container created: d45f3a9cfaa18b0a
==> default: Starting container...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 172.17.0.18:22
default: SSH username: vagrant
default: SSH auth method: password
==> default: Inserting Vagrant public key within guest...
==> default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
$ vagrant ssh

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
vagrant@7ea874e8b88a:~$

Allez plus loin

Ca arrive …

Puppet

Librarian Puppet

Un template de base pour toutes nos machines

Références

1. https://github.com/mitchellh/vagrant/blob/master/CHANGELOG.md#160-may-6-2014

  1. https://docs.docker.com/installation/debian/

  2. https://registry.hub.docker.com/

  3. https://docs.docker.com/terms/layer/