loading...

Using Docker as provider for Vagrant

mattdark profile image Mario García ・5 min read

According to the documentation, Vagrant has support for VirtualBox, VMWare, Hyper-V and Docker as providers.

Through this blog post you will learn how to configure Docker and Vagrant.

Docker

For installing Docker on Linux follow the instructions in the documentation. Go directly to the instructions of your distribution from the following list:

If you use Arch Linux or any Arch-based distribution, install it using pacman and initialize the daemon:

$ sudo pacman -S docker
$ sudo systemctl start docker

For running Docker commands you will need root permissions. As Vagrant will run it on your behalf, you have to configure it for running without sudo. You can follow the instructions in the Post-installation steps for Linux section as described below.

First create the docker group:

$ sudo groupadd docker

Add your user to the docker group:

$ sudo usermod -aG docker $USER

You will have to log out and log back in for the changes to take effect.

If you want to activate the changes to groups in your current session, run:

$ newgrp docker

To check if you can run docker commands without sudo:

$ docker run hello-world

This command will download the test container hello-world and run it.

Vagrant

For installing Vagrant go to the download page and get the right package for your distribution. You can also install it from the repositories of some Linux distributions.

Debian-based:

$ sudo apt install vagrant

Fedora:

$ sudo dnf install vagrant

CentOS

$ sudo dnf install -y https://releases.hashicorp.com/vagrant/2.2.9/vagrant_2.2.9_x86_64.rpm

Arch Linux:

$ sudo pacman -S vagrant

Vagrant + Docker

There are two ways you can use Docker as provider. Using an image from the Docker registry:

Vagrant.configure("2") do |config|
  config.vm.provider "docker" do |d|
    d.image = "foo/bar"
  end
end

Or a Dockerfile:

Vagrant.configure("2") do |config|
  config.vm.provider "docker" do |d|
    d.build_dir = "."
  end
end

Using a Dockerfile

First you have to create a directory to store the configuration files for your environment and change to this directory.

$ mkdir docker-test
$ cd docker-test

Create a Dockerfile:

$ touch Dockerfile

And add the following content:

FROM ubuntu:20.04

RUN apt-get update && apt-get install -y openssh-server sudo
RUN mkdir /var/run/sshd
RUN adduser --disabled-password --gecos '' vagrant
RUN adduser vagrant sudo
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
RUN chown -R vagrant /home/vagrant
RUN echo 'vagrant:vagrant' | chpasswd
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# SSH login fix. Otherwise user is kicked off after login
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd

ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile

EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]

The official Docker image of Ubuntu 20.04 will be used as specified in FROM ubuntu:20.04.

Vagrant requires an SSH connection to access the container and Docker images come only with the root user and you have to configure another user with root permissions. That's why the openssh-server and sudo packages are required.

In the following lines the vagrant user is created, without a password and without asking for one when running any command with sudo The user is also added to the sudo group.

RUN adduser --disabled-password --gecos '' vagrant
RUN adduser vagrant sudo
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

The ownership of the /home/vagrant directory is assigned to the vagrant user.

RUN chown -R vagrant /home/vagrant

The password of the vagrant user is changed as it is required for the configuration of the Vagrantfile. Use another password as you wish.

RUN echo 'vagrant:vagrant' | chpasswd

You can log in with the root user but the password wasn't assigned. You can change the password adding a similar line but changing vagrant:vagrant to root:THEPASSWORDYOUCHOOSE or after log in.

This Dockerfile is partially based on the available in the documentation.

Vagrantfile

Now create a Vagrantfile:

$ touch Vagrantfile

And add the following content:

Vagrant.configure("2") do |config|
  config.ssh.insert_key = true
  config.vm.hostname = "ubuntu"
  config.ssh.username = "vagrant"
  config.ssh.password = "vagrant"
  config.vm.provider :docker do |d|
     d.build_dir = "."
     d.remains_running = true
     d.has_ssh = true
  end
  config.vm.provision :shell, path: "install.sh", privileged: false
end

The config.ssh.insert_key set to true will tell Vagrant to generate and replace automatically the keypair for accessing through SSH.

The hostname of the virtual environment is set at config.vm.hostname.

Here you set the username and password for logging in:

config.ssh.username = "vagrant"
config.ssh.password = "vagrant"

Here you tell Vagrant to build the Docker image from the Dockerfile and the container can be accessed through SSH and must be always running.

d.build_dir = "."
d.remains_running = true
d.has_ssh = true

For installing software you can use a shell script or any provisioning tool supported by Vagrant:

config.vm.provision :shell, path: "install.sh", privileged: false

The privileged option is set to false as you will not require to run this commands with the root user.

Provisioning

For installing software inside the container you can use a shell script, Ansible, Chef or Puppet as provisioners. This time you will create a shell script to configure a dev environment for Python.

In the same directory create a shell script:

$ touch install.sh

With the following content:

#!/usr/bin/env bash

sudo apt-get update
sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \
libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \
xz-utils tk-dev libffi-dev liblzma-dev python-openssl git

curl https://pyenv.run | bash

echo 'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.bashrc && \
echo 'eval "$(pyenv init -)"' >> ~/.bashrc && \
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc

curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python

The script will install pyenv and Poetry to manage the Python version and dependencies of the project.

Up and running

When running vagrant up Vagrant will build the Docker image based on the Dockerfile and run the container. After that it will execute the install.sh script.

When finished you can log in to the virtual environment running vagrant ssh.

If you want to stop the environment, run vagrant halt For destroying the virtual environment run vagrant destroy.

Posted on by:

mattdark profile

Mario García

@mattdark

FOSS Enthusiast | Speaker | Mozillian | Python & Rust Developer | GitLab Hero | GitKraken Ambassador

Discussion

markdown guide