An opinionated LXC wrapper.
- What it does
- Example session
- Why not docker?!
- CLI Usage
LXC, aka Linux Containers. In case you don't know what they are, it's basically virtual machines without emulating the hardware. In technical details, it's chroot on steroids, because the filesystem, processes and networking are separated from the host. More information here.
This technology is getting a lot of traction since ~2 years, because it allows people to create isolated environments very quickly, very cheaply. Fedora 21, for example, will have each application run in a different container. Deploying containers on AWS lets you build multi-tier architectures for cheap, etc etc. There are many applications.
I personally use them as "VMs" for my projects (each project gets a VM). And lxc-wrapper is there to help me with that. I think this is a common usage though, so I thought it was worth sharing.
I use LXC in a very opinionated way, and has some manual maintenance to do every time I do something with LXCs. So I created this tool to automate what I do with them.
What it does
- I always forget the
--nameoption. lxc-wrapper assumes that the argument is the name of the container.
--fancywhen I want an ls should be the default. No argument needed.
- When creating a container, it assigns a static IP to it, adds an entry to the hosts file so that the container is reachable, and adds a symbolic link to the rootfs in a defined folder.
- Destroying a container cleans up behind itself.
Starting a new project "bar" based on the "foo" stack.
$ sudo lxc-wrapper --base foo create bar Created container bar as copy of foo $ sudo lxc-wrapper ls NAME STATE IPV4 IPV6 GROUPS AUTOSTART ---------------------------------------------------- bar STOPPED - - - NO foo STOPPED - - - NO $ ls ~/lxc/ foo bar $ ls ~/lxc/bar bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var $ sudo lxc-wrapper start bar $ sudo lxc-wrapper ls NAME STATE IPV4 IPV6 GROUPS AUTOSTART ---------------------------------------------------- bar STARTED 10.0.3.4 - - NO foo STOPPED - - - NO $ ssh firstname.lastname@example.org
When done with the project:
$ sudo lxc-wrapper stop bar $ sudo lxc-wrapper destroy bar $ sudo lxc-wrapper ls NAME STATE IPV4 IPV6 GROUPS AUTOSTART ---------------------------------------------------- foo STOPPED - - - NO
Why not docker?!
- Docker is based on an overlayfs system all the time. My usage is simply having long-term projects, so docker's containers don't make sense.
- Docker's networking doesn't allow me to assign a static IP to a container. It makes it inconvenient, especially for long-term containers, to connect to them via ssh.
- Docker's containers' filesystems are hidden when they're not started. I don't want to start a container just to get some random file in it.
- Docker CLI are not a very beautiful API. lxc-wrapper is supposed to be simple to use.
- Download the sources and run
make && make install. Only
- Download and install the rpm
if you're on Fedora/CentOS/Red Hat (x86
- Download and install the deb file (pgp signature) if you're on Ubuntu/Debian (amd64 only)
- Download and install the PKGBUILD if you're on ArchLinux
$ lxc-wrapper help Usage: lxc-wrapper [OPTIONS] [COMMAND] Wrapper around lxc for an opinionated workflow. Commands: help Shows this help create NAME Creates a container named NAME Options (must be BEFORE the command): --base=BASE Clones the BASE container --template=TEMPLATE Uses the TEMPLATE lxc template Overridable variables and default values (must be BEFORE the command): --lxc-default-folder=/var/lib/lxc/ --lxc-rootfs=rootfs/ --lxc-folder=~/lxc/ --lxc-host-extension=.lxc --default-dns-nameserver=188.8.131.52 --hosts-file=/etc/hosts --lxc-interfaces-file=etc/network/interfaces start NAME Starts the container named NAME stop NAME Stops the container named NAME ls Lists the containers destroy NAME Destroys the container named NAME Overridable variables and default values (must be BEFORE the command): --lxc-folder=~/lxc/ --lxc-host-extension=.lxc --hosts-file=/etc/hosts package NAME Packages the container named NAME Options (must be BEFORE the command): --archive-path=PATH the path of the archive Overridable variables and default values (must be BEFORE the command): --lxc-package-extension=.tar.gz --lxc-default-folder=/var/lib/lxc/ deploy --archive ARCHIVE NAME Deploys the ARCHIVE archive in a container named NAME Overridable variables and default values (must be BEFORE the command): --lxc-default-folder=/var/lib/lxc/ --lxc-config=config --hosts-file=/etc/hosts autostart NAME Toggles the autostart status of the container named NAME Overridable variables and default values (must be BEFORE the command): --lxc-default-folder=/var/lib/lxc/ --lxc-config=config Overridable variables and default values for all commands (must be BEFORE the c ommand): --default-shell=/bin/bash
If you just want to use the distributed package, that's all you need.
If you want to compile yourself, you need:
$ git clone https://github.com/Ralt/lxc-wrapper $ cd lxc-wrapper $ make $ make install
sudo for the
Tested on SBCL only. There is a requirement on
sb-posix to get the
The swank server or the CLI utility needs to be ran as root. (Ideally
with sudo, so that
~ matches your user folder)
- Only /24 subnetworks supported. Which means you can only make 254 containers with lxc-wrapper on one host.
- Autostart management not supported yet.
To create a CLI utility, you need:
The Makefile supports the following tasks:
all: builds the
./dist/usr/bin/lxc-wrapperbinary, along with downloading dependencies in a local quicklisp environment
clean: deletes the dependencies and the binary
install: copies the
test: runs tests; requires a functional lisp environment
(defcommand create (name args) "Creates an LXC" (destructuring-bind (&key base template) args
Creates an LXC.
If a base LXC is provided, then it makes a clone of it.
If a template is provided, then it creates a new LXC based on this template.
The opinionated part of lxc-wrapper comes here. For every new LXC:
- It gives it a static IP
- It adds the static IP to the host's /etc/hosts
- It makes a symlink to the rootfs
(defcommand destroy (name args) "Destroys an LXC and its leftovers" (declare (ignore args))
Destroys an LXC.
The opinionated part of lxc-wrapper comes here too. When an LXC is destroyed:
- It destroys the entry in the host's /etc/hosts
- It deletes the symlink to the rootfs
(defcommand start (name args) "Starts an LXC" (declare (ignore args))
Starts an LXC. The argument can be a string or a symbol.
(defcommand stop (name args) "Stops an LXC" (declare (ignore args))
Stops an LXC. The argument can be a string or a symbol.
(defcommand ls (name args) "Lists all the LXC" (declare (ignore args))
Returns the fancy output of the list of LXCs.
(defcommand package (name args) "Packages an LXC"
Packages an LXC into an shareable archive file.
(defcommand deploy (name args) "Deploys an archive created by lxc-wrapper" (destructuring-bind (&key archive) args
Deploys an archive created by
(defcommand autostart (name args) "Toggles the autostart setting of a container"
Toggles the autostart setting of a container.
Variables are used throughout the code to be able to customize them through dynamic scoping.
The folder where LXC stores its containers.
The folder where the filesystem of the container lives.
The folder where symbolic links to the containers' filesystems are made.
The TLD of the container hostname.
The gateway that the container uses.
The DNS nameserver that the container uses.
The host's hosts file.
'(10 0 3 0)
The network of the container. Only /24 supported.
The regex used to find IPs in the hosts file.
The file where interfaces are written in the container.
The shell used by the commands.
The extension to give to archives created by
The name of the configuration file of the containers.