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. I'm very new to Docker myself.

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 -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.

Run this command:

docker ps -a --filter="status=exited" | head

We are interested in the first line, the output will look something like this:

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                         PORTS               NAMES
eade5e91d060        debian:jessie       "bash"              3 minutes ago       Exited (0) 17 seconds ago                          serene_booth

Note the CONTAINER ID, we will use this to save the image, like so:

docker commit eade5e91d060 rkitover/debian:jessie

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 -h debian-vm --detach-keys="ctrl-@" -it -u rkitover rkitover/debian:jessie bash -l
    docker commit $(docker ps -a --filter="status=exited" | head -2 | tail -1 | awk '{ print $1 " " $2 }')

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 CONTAINER ID 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

Setting locale is important so you don't have issues with your terminal being screwy, although I found that the terminal can still have some issues.

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:


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

docker images -qf dangling=true | xargs docker rmi >/dev/null 2>&1

exit 0

That's all I have, as I said, I'm very new to Docker myself, and this is just one way of using it that isn't even primarily what it's meant to be used for.

Last modified: 2017-1-30 (月) at 2:24 pm