Skip to Content
  • +31 653-919-302
Cafayate.Net
  • 0
  • 0
  • Sign in
  • Nederlands English (US) Español (AR)
  • Contact Us
  • Home
  • Blog
  • Jobs
  • Contact us
Cafayate.Net
  • 0
  • 0
    • Home
    • Blog
    • Jobs
    • Contact us
  • +31 653-919-302
  • Nederlands English (US) Español (AR)
  • Sign in
  • Contact Us

Enabling LXC on Archlinux with systemd-networkd

  • All Blogs
  • Tech Blog
  • Enabling LXC on Archlinux with systemd-networkd
  • March 5, 2021 by
    Administrator

    After playing around with docker a lot, I decided that it was time to spend some time with LXC as I tended to treat some of my docker containers like mini VMs anyway, especially when developing. I think a lot of the benefits of docker aren’t actually benefits, and I’ll be writing a follow-up post about that. To that end, I wanted to get LXC up and running.

    What’s so hard?

    I’m on a laptop with wireless, so I can’t just create a bridge and give IPs to containers from an upstream DHCP server. I needed to do NAT and essentially simulate/replicate how docker networking works. My goals were:

    • DHCP or some other auto-assignment of IPs
    • Containers can see each other by hostname
    • Containers can see the host, and other nodes on the network
    • Containers can see the internet
    • Have all of this networking transparently work and persist across reboots

    General approach

    • Create a bridge interface
    • Set up IP forwarding and masquerading
    • Set up dnsmasq as a DHCP server
    • profit?

    In practice, these things didn’t work out so well.

    Problem 1: netctl

    Netctl was the recommended choice for a while on Archlinux systems. Now that systemd is taking over, it seems like more and more support is coming over to systemd-networkd. I asked for help in chat and 3 people immediately were like “why are you still using netctl?”I ran into a bit of trouble creating a netctl profile to create a bridge on boot. While I could have made this work (and the end solution would have had me not touch netctl at all), I ended up yak shaving and switching to systemd-networkd. It was mostly painless with 1 hiccup:

    Problem 2: systemd-networkd ip forwarding defaults

    By default, systemd-networkd does not honor sys.net.ipv4.ip_forward. It instead creates a per-interface setting that defaults to no. This means that you need to explicitly set IPForward and IPMasquerade on your bridges. This includes the docker0 interface, which silently broke upon switching to systemd-networkd. It’s at least related to this bug report.

    Back to sanity

    So we are now on systemd-networkd, which more easily allows us to define bridges and we have something roughly like this:

    docker0.network

    [Match]
    Name=docker0
    
    [Network]
    IPForward=yes
    

    wired.network

    [Match]
    Name=eth0
    
    [Network]
    DHCP=ipv4
    
    [DHCP]
    RouteMetric=10
    

    wireless.network

    [Match]
    Name=wlan0
    
    [Network]
    DHCP=ipv4
    
    [DHCP]
    RouteMetric=20
    

    Now what

    We haven’t even started making LXC work yet, let’s do that now. The first approach is to create a bridge interface for just LXC, so let’s do that

    lxcbr0.netdev

    [NetDev]
    Name=lxcbr0
    Kind=bridge
    

    lxcbr0.network

    [Match]
    Name=lxcbr0
    
    [Network]
    Address=10.0.100.1
    IPForward=yes
    IPMasquerade=yes
    

    To use this, add something like the following to a config for your lxc container:

    lxc.network.type = veth
    lxc.network.flags = up
    lxc.network.link = lxcbr0
    

    This will work, but requires you to specify an IP for the container statically. Let’s add dnsmasq:

    dhcp-range=10.0.100.100,10.0.100.200,12h
    interface=lxcbr0
    

    After this, you’ll notice that it still doesn’t work. You need an iptables rule to handle some checksum mistakes

    iptables -t mangle -A POSTROUTING -o lxcbr0 -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill 
    

    So far we’ve mostly got this handled by configuration files, but this checksum mangling is a manual step with no great place to automatically handle it. After a bit of looking around, Archlinux ships with a lxc-net systemd unit, which seems to do what I need. It’s a bit tricky to setup, and needs some interaction with systemd-networkd:

    • The bridge can’t already exist, so we need to get rid of the lxcbr0.netdev file
    • The bridge still needs systemd-networkd style masquerading, so we keep the lxcbr0.network file (remove the address line)

    You also need to tell lxc-net that you want to use the bridge, so in /etc/default/lxc, change USE_LXC_BRIDGE to true. As a bonus, lxc-net handles dnsmasq for you, so you can get rid of that unit.

    Final results

    The units you should have enabled are:

    • wpa_supplicant@wlan0
    • systemd-networkd
    • systemd-resolved
    • lxc-net

    /etc/systemd/network/docker0.network

    [Match]
    Name=docker0
    
    [Network]
    IPForward=yes
    

    /etc/systemd/network/lxcbr0.network

    [Match]
    Name=lxcbr0
    
    [Network]
    IPForward=yes
    IPMasquerade=yes
    

    /etc/default/lxc

    LXC_AUTO="true"
    BOOTGROUPS="onboot,"
    SHUTDOWNDELAY=5
    OPTIONS=
    STOPOPTS="-a -A -s"
    USE_LXC_BRIDGE="true"
    [ ! -f /etc/default/lxc-net ] || . /etc/default/lxc-net
    

    On the next reboot, you should have:

    • A working docker0 interface (if you are keeping docker around)
    • An lxcbr0 interface with an IP associated with it
    • Starting LXC containers should grab a natted IP automatically via DHCP

    As a bonus, LXC containers can address each other by hostname, and docker containers and lxc containers can see each other by IP. Some more dnsmasq magic could maybe clear some of that up even further.

    The end resulting files make it seem like this is an easy problem, but the details of wireless not supporting actual bridging, netctl being flaky, systemd having unexpected ip_forwarding defaults, DHCP missing checksums, and lxc-net being a bit picky about how it gets started actually caused this exploration to take a few hours.

    in Tech Blog
    Force Redirect From HTTP to HTTPs On A Custom Port in Nginx

    Designed for companies

    We are a team of passionate people whose goal is to improve everyone's life through disruptive products. We build great products to solve your business problems. Our products are designed for small to medium size companies willing to optimize their performance.

    Get in touch

    Plantexel
    Pedernera
    Salta Capital 
    Argenina

    • +31 653-919-302
    • [email protected]
    Follow us
    Copyright © Plantexel
    Nederlands | English (US) | Español (AR)