Ephemeral LXC Swarm For Local Testing

So, you need to create a swarm of Linux Containers to test multiple clients but don’t want the containers to stick around when you’re finished. We can use ephemeral LXC’s that utilize OverlayFS on harddisk or temporary storage in RAM. We do need a little Bash scripting knowledge. But, when we include the use of Tmux, we gain a large increase in power, flexibility, and productivity. What we need:

  • Base LXC with software installed
  • Base-project LXC with project specific configuration files
  • Bash script to create the environment

Let’s create the Base LXC and install any software our swarm may need

$ lxc-create -t /usr/share/lxc/templates/lxc-archlinux -n base

# Edit base/config to add network connectivity
lxc.net.0.type = none

$ lxc-start -n base; lxc-attach -n base
root@base $ pacman -S <list of software>
root@base $ exit
$ lxc-stop -n base

Now, let’s create our base project LXC with various mounts and configuration files.

$ lxc-create -s -B overlayfs -n base -N base-project

# edit base-project/config to add mounts
lxc.mount.entry = /home/http home/http none bind,ro,create=dir 0 0

# Copy any project files into the container
$ rsync -a <my project files> base-project/delta0/<project files path>

Now we can write a bash script that will spawn our swarm.

# start-swarm.sh

#!/bin/bash

lxc-copy -s -e -n base-project -N one
lxc-copy -s -e -n base-project -N two
lxc-copy -s -e -n base-project -N three
lxc-copy -s -e -n base-project -N four
# Make script executable and run it
$ chmod +x start-swarm.sh
$ ./start-swarm.sh

The ephemeral LXC’s will have already been started. Once you stop each container, they will be automatically deleted. From here let’s create a Tmux session to attach to each client in the swarm.

# start-swarm.sh

#/bin/bash

# Tmux session name
sname="my-session"

# Sleep required after attaching to LXC
attach_delay=0.5

# Use variable to hold lengthy command for sending keystrokes to tmux pane
send_keys="tmux send-keys -t $sname"

# Create the LXC swarm
lxc-copy -s -e -n base-project -N one
lxc-copy -s -e -n base-project -N two
lxc-copy -s -e -n base-project -N three
lxc-copy -s -e -n base-project -N four

# Create Tmux Session
tmux start-server
TMUX= tmux new-session -d -s $sname -n $sname

# Create 3 more splits in current window
tmux split-window -t $sname:0 -v
tmux split-window -t $sname:0 -v
tmux split-window -t $sname:0 -v

# Set Tmux window 0 pane layout
tmux select-layout -t $sname:0 tiled

# First machine
$send_keys:0.0 "lxc-attach -n one" C-m
sleep $attach_delay
$send_keys:0.0 "cd /project/directory" C-m

# Second machine
$send_keys:0.1 "lxc-attach -n two" C-m
sleep $attach_delay
$send_keys:0.1 "cd /project/directory" C-m

# Third machine
$send_keys:0.2 "lxc-attach -n three" C-m
sleep $attach_delay
$send_keys:0.2 "cd /project/directory" C-m

# Fourth machine
$send_keys:0.3 "lxc-attach -n four" C-m
sleep $attach_delay
$send_keys:0.3 "cd /project/directory" C-m

tmux select-window -t $sname
tmux select-pane -t 0

if [ -z "$TMUX" ]; then
    tmux -u attach-session -t $sname
else
    tmux -u switch-client -t $sname
fi

Currently this setup assumes the swarm will use the same IP address as the host machine. Since setting up dynamic IP addresses in ephemeral containers is daunting we can just modify our script to create plain containers in a temporary directory then modify each container’s config file. First we will edit the base project configuration to use a veth network type.

# base-project/config
...
# Combine containers into group for easy shutdown
lxc.group = swarm

# Necessary to give each container a separate IP address
lxc.net.0.type = veth
lxc.net.0.name = veth0
lxc.net.0.flags = up
lxc.net.0.link = br0
lxc.net.0.ipv4.address = 10.0.0.101
lxc.net.0.ipv4.gateway = auto

Now, edit the start-swarm.sh script to create our session.

# start-swarm.sh

#!/bin/bash

# LXC directory
lxc_dir=/tmp/lxc

# Tmux session name
sname="my-session"

# Sleep required after attaching to LXC
attach_delay=0.5

# Use variable to hold lengthy command for sending keystrokes to tmux pane
send_keys="tmux send-keys -t $sname"

# Create the LXC directory
mkdir -p $lxc_dir

# Create the LXC swarm, notice they are not ephemeral
lxc-copy -P $lxc_dir -s -n base-project -N one
lxc-copy -P $lxc_dir -s -n base-project -N two
lxc-copy -P $lxc_dir -s -n base-project -N three
lxc-copy -P $lxc_dir -s -n base-project -N four

# Create a bridge device for the swarm to connect to
brctl addbr br0 > /dev/null 2>&1
ifconfig br0 10.0.0.100
ifconfig br0 up

# Edit the base-project/config that was created
# in each ephemeral LXC to give each a unique
# IP address
sed -i 's/101/101/' $lxc_dir/one/config
sed -i 's/101/102/' $lxc_dir/two/config
sed -i 's/101/103/' $lxc_dir/three/config
sed -i 's/101/104/' $lxc_dir/four/config

# Start the containers
lxc-start -P $lxc_dir -n one
lxc-start -P $lxc_dir -n two
lxc-start -P $lxc_dir -n three
lxc-start -P $lxc_dir -n four

# Create Tmux Session
tmux start-server
TMUX= tmux new-session -d -s $sname -n $sname

# Create 3 more splits in current window
tmux split-window -t $sname:0 -v
tmux split-window -t $sname:0 -v
tmux split-window -t $sname:0 -v

# Set Tmux window 0 pane layout
tmux select-layout -t $sname:0 tiled

# First container
$send_keys:0.0 "lxc-attach -P $lxc_dir -n one" C-m
sleep $attach_delay
$send_keys:0.0 "cd /project/directory" C-m

# Second container
$send_keys:0.1 "lxc-attach -P $lxc_dir -n two" C-m
sleep $attach_delay
$send_keys:0.1 "cd /project/directory" C-m

# Third container
$send_keys:0.2 "lxc-attach -P $lxc_dir -n three" C-m
sleep $attach_delay
$send_keys:0.2 "cd /project/directory" C-m

# Fourth container
$send_keys:0.3 "lxc-attach -P $lxc_dir -n four" C-m
sleep $attach_delay
$send_keys:0.3 "cd /project/directory" C-m

tmux select-window -t $sname
tmux select-pane -t 0

if [ -z "$TMUX" ]; then
    tmux -u attach-session -t $sname
else
    tmux -u switch-client -t $sname
fi

Now to cleanup our session when we’re finished testing:

$ tmux kill-session -t my-session
$ lxc-autostart -P /tmp/lxc -kAg swarm
$ rm -rf /tmp/lxc

If we want to streamline the shutdown process, we can add this after the variable declarations in our start-swarm.sh script

# start-swarm.sh

...

if [[ "$1" == "down" ]]; then
    tmux kill-session -t $sname
    lxc-autostart -P $lxc_dir -kAg swarm
    rm -rf $lxc_dir
    exit
fi

...