In Part 1
of this Unprivileged containers in Slackware article, we discussed
how to arrange the system requirements to run unprivileged containers
in Slackware.
In Part 2 we stepped through
creation of a standard privilieged container and a method to convert
it to an unprivileged container i.e. able to be started by an "ordinary"
user. In this third part, we describe a convenient method to provide
networking for an arbitrary number of containers.
At this point, it's assumed that parts 1 & 2 have been successfully digested and you're happily running an unprivileged container (although the networking method described here applies equally to normal privileged containers too). Our method is comprised of the following steps:
Step 1 - Create bridge
We will create a single bridge network interface (which we'll name lxcbr0 in this example) to the host machine's default network interface (wlan0 in this example). The new lxcbr0 interface will then be configured any other network interface (using ifconfig) and finally we use iptables to create a NAT behind the lxcbr0 interface. Any containers can then be attached to the bridge interface and access the wider internet via the host machine.
The bridge is set up by executing (as root) the following commands:
echo 1 > /proc/sys/net/ipv4/ip_forward
/sbin/brctl addbr lxcbr0
/sbin/brctl setfd lxcbr0 0
/sbin/ifconfig lxcbr0 192.168.100.1 netmask 255.255.255.0 promisc up
/usr/sbin/iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
Rather than running all these commands by hand after any reboot of the host machine, it is better to incorporate them in a script that can be run whenever needed. For that purpose, try this rc.lxc-bridge script, or something similar, which can be kept in the /etc/rc.d/ directory along with other boot scripts. Some care is needed when rebooting that the script is not executed before the wlan0 interface is active. If using NetworkManager, it is very convenient to use its dispatcher mechanism to run the script only when wlan0 (or other network interface that you choose) becomes available. See this start_lxc-bridge script as an example. It should be kept in the /etc/NetworkManager/dispatcher.d/ directory. If both scripts are executable then whenever the wlan0 interface becomes available, the script to bring up the lxcbr0 interface will be run.
Step 2 - Set up DHCP & DNS
If you prefer to set up each new container's networking
individually then this step is not needed. Otherwise we'll make use of
dnsmasq, which will already be installed on stock Slackware machines,
to provide DHCP and DNS services for the containers. We just need to
provide a suitable configuration for dnsmasq and make its
startup file, /etc/rc.d/rc.dnsmasq, executable:
chmod a+x /etc/rc.d/rc.dnsmasq
Edit the file
/etc/dnsmasq.conf file at about line 660; uncomment the line to
be conf-dir=/etc/dnsmasq.d. This enables us to leave that file
otherwise unaltered and put our particular configuration needs, modest
though they are, into a dedicated file in the
/etc/dnsmasq.d. Create that file
(I suggest /etc/dnsmasq.d/lxc-bridge.conf) with the following
content:
interface=lxcbr0
dhcp-range=192.168.100.2,192.168.100.254,2h
Of course the interface name and dhcp range values should be consistent
with those chosen for LXCBR_NAME and LXCBR0_NAT_NET in the
rc.lxc-bridge file in Step 1.
Reboot the host machine or manually run (as root):
/etc/rc.d/rc.lxc-bridge start
/etc/rc.d/rc.dnsmasq start
to start the host side services needed.
Step 3 - Set up container
First, edit the container's config file so that it
contains the following fields:
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = lxcbr0
lxc.network.name = eth0
To ensure the container will use DHCP at startup, edit its rc.inet1.conf file so that the entry USE_DHCP[0]="" becomes USE_DHCP[0]="yes". This can be done either while the container is running - edit its /etc/rc.d/rc.inet1.conf, or from the host machine's filesystem - edit ~/.local/share/lxc/test1/rootfs/etc/rc.d/rc.inet1.conf (for a container named test1).
When the container next starts, it should have normal networking available and enabled.
Extras
If you're creating lots of containers, it soon becomes tiresome having to
modify each container's config file to add the lxc.network.* fields.
Instead, these fields could be added automatically when lxc-create
is run (back in Part 2, Step 1). This is achieved by listing the fields
in LXC's /etc/lxc/default.conf file. Replace the line:
lxc.network.type = empty
with:
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = lxcbr0
lxc.network.name = eth0
For good measure, you could also add a line something like:
lxc.network.hwaddr = 00:16:3e:xx:xx:xx
which will appropriately replace each 'x' character whenever a
container is created to provide it with a unique MAC address. That unique
MAC address could later be used by dnsmasq to provide a consistent
IP address for the container.
This is achieved by adding the MAC address and desired
IP address to the dnsmasq configuration file we created back at
Step 2, /etc/dnsmasq.d/lxc-bridge.conf. Add something like:
dhcp-host=00:16:3e:41:7a:d4,192.168.100.17
depending on requirements. Add a similar line for each container which
requires a consistent IP address across reboots.
Contact
Please send any questions, comments, advice etc., to
Chris Willing <chris.willing _at_ iinet.net.au>