Lightweight VMs With Docker

If you wanted to use Docker for very lightweight VMs for e.g. testing different Linux or BSD distributions, I will describe here one method of doing so.

First step is to install Docker, this is pretty straightforward, it is available for Linux, Windows and Mac.

Don't forget to go into the preferences and set the amount of RAM and number of CPUs you want available to your containers. If you are going to be e.g. compiling things, this is especially important.

Since the base images are very lightweight and don't run services or a GUI, you can get away with using less RAM then you would with a traditional VM.

Create the Image

Let's use Debian as an example, first pull the version you want, the format <dist>:<release>, so we are going to get Debian Jessie:

docker pull debian:jessie

Now we need to set it up, open a root shell with:

docker run --name debian-vm -h debian-vm --detach-keys="ctrl-@" -it debian:jessie bash

This runs the image in a container with the hostname set to debian-vm, and the detach key set to ctrl-shift-2, and opens an interactive session with bash as the command.

Instead of debian:jessie you can use e.g. ubuntu:trusty or just about anything, look on Docker Hub for available images.

From here you want to use adduser to create your user, install some essential packages like sudo, vim, tmux, etc., and set up your home directory, etc. When you are done exit the shell, and we are going to save the image.

docker commit debian-vm rkitover/debian:jessie
docker rm debian-vm

Here rkitover is my user name and Docker ID on Docker Hub and rkitover/debian:jessie will be the full name of the image.

Launching the Container

Now let's make a handy bash function to launch the container and automatically commit our work when done. Put something like this in your ~/.bashrc:

debian-vm() {
    docker run --name debian-vm -h debian-vm --detach-keys="ctrl-@" -it -u rkitover rkitover/debian:jessie bash -l
    docker commit debian-vm rkitover/debian:jessie
    docker rm debian-vm
}

Here the user I created in the image is rkitover and it will launch bash as that user as a login shell. When the shell exits, it will commit changes in the filesystem back to the image.

If you use ctrl-shift-2 to detach from the container, you can reattach back to your terminal session with docker attach CONTAINER_ID, and as you've seen you can get the CONTAINER ID from docker ps -a.

NOTE: the above function doesn't handle detaching and reattaching to containers, if you do that, you will need to commit it to your image manually.

If you want to make a "snapshot", just commit the name to another image name.

Configuration Notes

For the user in your container, my ~/.profile looks something like this:

cd $HOME
export SHELL=/bin/bash
. "$HOME/.bashrc"

And since the base images are bare and universal, you'll want to set your time zone and locale information at the top of ~/.bashrc, e.g.:

export LANG=en_US.UTF-8
export TZ=PST8PDT

You may need to install a locales package, edit /etc/locale.gen and run locale-gen so that the locale you want is available.

Cleanup Cron Job

It's a good idea to have something to clean up unused containers and dangling images, I have a nightly cron job the script for which looks like this:

#!/bin/sh
  

docker inspect -f '{{if not .State.Running}}{{.Id}} {{ end }}' $(docker ps -aq) | grep -Ev '^$' | \
    xargs docker rm >/dev/null 2>&1
  

docker image prune -f >/dev/null 2>&1

Last modified: 2018-4-6 (金) at 5:20 am