Aller au contenu

Des boxes Vagrant Docker avec WSL 2

logo

Pour ceux qui veulent tout de même utiliser WSL plutôt qu’une machine hyper-v, il est compliqué de faire fonctionner Vagrant. Pourtant, on peut y arriver en utilisant des boxes au format Docker. Le fonctionnement sera le même qu’avec des machines provisionnées avec libvirt sauf une seule chose : Les services ne seront pas utilisables, Docker oblige, à moins peut être de créer ses propres boxes ou systemd est opérationnel. Je l’ai déjà fait dans un job précédent, je vais fouiller dans mon historique et je vous les ajouterai au bout de ce billet.

Installation de Docker sur WSL

Ici je ne vais pas utiliser Docker Desktop, qui consomme des ressources mémoires qui parfois sont limitées sur un poste d’entreprise. Je vais donc installer Docker au sein de WSL et ajouter à mon profil le lancement de celui-ci.

Terminal window
# Installation des pre-requis
sudo apt update
sudo apt install \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release
# Ajout du repo Docker
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Ajout de la clé du repo Docker
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# Installation de Docker
sudo apt update && sudo apt install docker-ce docker-ce-cli containerd.io
# Ajout du user courant au group Docker
sudo usermod -aG docker $USER

Maintenant l’astuce pour le démarrer.

  • Sous windows 11, il faut ajouter ces lignes au fichier /etc/wsl.conf :
Terminal window
vi /etc/wsl.conf
[boot]
command = "service docker start"
Terminal window
wsl.exe --shutdown

Une fois la machine WSL redémarré vérifier que Docker est bien opérationnel :

Terminal window
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  • Sous Windows 10, il faut ajouter ces lignes à votre .profile :
Terminal window
vi ~/.profile
Terminal window
if service docker status 2>&1 | grep -q "is not running"; then
wsl.exe -d "${WSL_DISTRO_NAME}" -u root -e /usr/sbin/service docker start >/dev/null 2>&1
fi
Terminal window
wsl.exe --shutdown

Une fois la machine WSL redemarrer vérifier que Docker est bien opérationnel

Terminal window
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES

Installation de Vagrant

Il ne reste plus qu’à installer Vagrant :

Terminal window
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
sudo apt update && sudo apt install vagrant

On redémarre pour récupérer le groupe vagrant :

Terminal window
wsl.exe --shutdown

Utilisation d’une box Vagrant utilisant le provider Docker

Nous allons créer notre image Docker à base d’Ubuntu :

FROM ubuntu:jammy
ENV DEBIAN_FRONTEND noninteractive
# Install packages needed for SSH and interactive OS
RUN apt update && \
yes | unminimize && \
apt -y install \
openssh-server \
passwd \
sudo \
man-db \
curl \
wget && \
apt -qq clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Enable systemd (from Matthew Warman's mcwarman/vagrant-provider)
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*; \
rm -f /etc/systemd/system/*.wants/*; \
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*; \
rm -f /lib/systemd/system/anaconda.target.wants/*;
# Create the vagrant user
RUN useradd -m -G sudo -s /bin/bash vagrant && \
echo "vagrant:vagrant" | chpasswd && \
echo 'vagrant ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/vagrant && \
chmod 440 /etc/sudoers.d/vagrant
# Establish ssh keys for vagrant
RUN mkdir -p /home/vagrant/.ssh; \
chmod 700 /home/vagrant/.ssh
ADD https://raw.githubusercontent.com/hashicorp/vagrant/master/keys/vagrant.pub /home/vagrant/.ssh/authorized_keys
RUN chmod 600 /home/vagrant/.ssh/authorized_keys; \
chown -R vagrant:vagrant /home/vagrant/.ssh
# Enable ssh for vagrant
RUN systemctl enable ssh.service;
EXPOSE 22
# Run the init daemon
VOLUME [ "/sys/fs/cgroup" ]
CMD ["/usr/sbin/init"]

Maintenant notre Vagrantfile :

ENV['VAGRANT_DEFAULT_PROVIDER'] = 'docker'
Vagrant.configure("2") do |config|
config.vm.provider "docker" do |docker|
docker.name = "test"
docker.build_dir = "vagrant_docker"
docker.remains_running = true
docker.has_ssh = true
docker.privileged = true
docker.create_args = ['--tmpfs', '/tmp', '--tmpfs', '/run', '--tmpfs', '/run/lock', '-v', '/sys/fs/cgroup:/sys/fs/cgroup:ro', '-t']
# docker.run_args = ['--tmpfs', '/tmp', '--tmpfs', '/run', '--tmpfs', '/run/lock', '-v', '/sys/fs/cgroup:/sys/fs/cgroup:ro', '-t']
end
config.vm.synced_folder ".", "/vagrant", disabled: true
end

On lance la construction de la box :

Terminal window
vagrant up
==> default: Deleting the container...
==> default: Creating and configuring docker networks...
==> default: Building the container from a Dockerfile...
default: Sending build context to Docker daemon 5.12kB
default: Step 1/12 : FROM ubuntu:jammy
default: ---> f0b07b45d05b
default: Step 2/12 : ENV DEBIAN_FRONTEND noninteractive
default: ---> Using cache
default: ---> 8719e8bebd18
default: Step 3/12 : RUN apt update && yes | unminimize && apt -y install openssh-server passwd sudo man-db curl wget && apt -qq clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
default: ---> Using cache
default: ---> b98aead5545e
default: Step 4/12 : RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); rm -f /lib/systemd/system/multi-user.target.wants/*; rm -f /etc/systemd/system/*.wants/*; rm -f /lib/systemd/system/local-fs.target.wants/*; rm -f /lib/systemd/system/sockets.target.wants/*udev*; rm -f /lib/systemd/system/sockets.target.wants/*initctl*; rm -f /lib/systemd/system/basic.target.wants/*; rm -f /lib/systemd/system/anaconda.target.wants/*;
default: ---> Using cache
default: ---> 6446c02572c6
default: Step 5/12 : RUN useradd -m -G sudo -s /bin/bash vagrant && echo "vagrant:vagrant" | chpasswd && echo 'vagrant ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/vagrant && chmod 440 /etc/sudoers.d/vagrant
default: ---> Using cache
default: ---> 85245e51458d
default: Step 6/12 : RUN mkdir -p /home/vagrant/.ssh; chmod 700 /home/vagrant/.ssh
default: ---> Using cache
default: ---> 98f6d137e908
default: Step 7/12 : ADD https://raw.githubusercontent.com/hashicorp/vagrant/master/keys/vagrant.pub /home/vagrant/.ssh/authorized_keys
default:
default: ---> Using cache
default: ---> 99f3d4a28c38
default: Step 8/12 : RUN chmod 600 /home/vagrant/.ssh/authorized_keys; chown -R vagrant:vagrant /home/vagrant/.ssh
default: ---> Using cache
default: ---> 911ca2434ea8
default: Step 9/12 : RUN systemctl enable ssh.service;
default: ---> Using cache
default: ---> 53a988bb68c2
default: Step 10/12 : EXPOSE 22
default: ---> Using cache
default: ---> 37d6136d6e1b
default: Step 11/12 : VOLUME [ "/sys/fs/cgroup" ]
default: ---> Using cache
default: ---> 4b5c40d8c1ea
default: Step 12/12 : CMD ["/usr/sbin/init"]
default: ---> Using cache
default: ---> 3c5a7f9c664a
default: Successfully built 3c5a7f9c664a
default:
default: Image: 3c5a7f9c664a
==> default: Creating the container...
default: Name: test
default: Image: 3c5a7f9c664a
default: Port: 127.0.0.1:2222:22
default:
default: Container created: b46c9ae50f3f3cac
==> default: Enabling network interfaces...
==> default: Starting container...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 127.0.0.1:2222
default: SSH username: vagrant
default: SSH auth method: private key
default:
default: Vagrant insecure key detected. Vagrant will automatically replace
default: this with a newly generated keypair for better security.
default:
default: Inserting generated public key within guest...
default: Removing insecure key from the guest if it's present...
default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!

On vérifie que notre container tourne :

Terminal window
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b46c9ae50f3f 3c5a7f9c664a "/usr/sbin/init" 8 seconds ago Up 7 seconds 127.0.0.1:2222->22/tcp test

On se connecte :

Terminal window
vagrant ssh
Welcome to Ubuntu 22.04 LTS (GNU/Linux 5.10.102.1-microsoft-standard-WSL2 x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
vagrant@b46c9ae50f3f:~$systemctl status sshd.service
ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2022-04-21 07:36:51 UTC; 6min ago
Docs: man:sshd(8)
man:sshd_config(5)
Process: 22 ExecStartPre=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS)
Main PID: 23 (sshd)
Tasks: 6 (limit: 1157)
Memory: 23.6M
CGroup: /system.slice/ssh.service
├─ 23 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"
├─261 "sshd: vagrant [priv]"
├─271 "sshd: vagrant@pts/1" ""
├─272 -bash
├─275 systemctl status sshd

On se croirait sur un VM, non ? En plus ça se lance très vite !

Il ne reste plus qu’à créer notre provisioner ansible. On crée le fichier provision.yml avec ce contenu :

---
- hosts: all
tasks:
- debug:
msg: "Hello from Docker"

On met à jour notre Vagrantfile :

ENV['VAGRANT_DEFAULT_PROVIDER'] = 'docker'
Vagrant.configure("2") do |config|
config.vm.provider "docker" do |docker|
docker.name = "test"
docker.build_dir = "vagrant_docker"
docker.remains_running = true
docker.has_ssh = true
docker.privileged = true
docker.create_args = ['--tmpfs', '/tmp', '--tmpfs', '/run', '--tmpfs', '/run/lock', '-v', '/sys/fs/cgroup:/sys/fs/cgroup:ro', '-t']
end
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.provision "ansible" do |ansible|
ansible.playbook = "provision.yml"
end
end

On relance la box :

Terminal window
vagrant reload
==> default: Stopping container...
==> default: Deleting the container...
==> default: Creating and configuring docker networks...
==> default: Building the container from a Dockerfile...
...
==> default: Machine booted and ready!
==> default: Running provisioner: ansible...
default: Running ansible-playbook...
default: Running ansible-playbook...
____________
< PLAY [all] >
------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
________________________
< TASK [Gathering Facts] >
------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
ok: [default]
______________
< TASK [debug] >
--------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
ok: [default] => {
"msg": "Hello from Docker"
}
____________
< PLAY RECAP >
------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
default : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Et voilà le top du top !!!!