0

I've got a set of containers managed by systemd-nspawn. The containers should be (semi-)isolated from the external network, but at the same time should be able to access non-containerized services like DBMS, running on the host (see diagram). The networking is managed by systemd-networkd on both ends.

I've tried the following most common private network modes of systemd-nspawn:

Virtual Ethernet

-n, --network-veth creates a pair of connected virtual ethernet adapters per container, one on the host side, another inside the container. Seems like this is of little use, because it is not clear which address the DBMS should listen on and which address the containers should connect to.

Bridge

--network-bridge= does mostly the same, but adds virtual adapters to the specified bridge. The bridge should be already setup and assigned an IP:

# /etc/systemd/network/br0.netdev 
[NetDev]
Name=br0
Kind=bridge

 

# /etc/systemd/network/br0.network 
[Match]
Name=br0

[Network]
Address=169.254.1.1/16

This config has proven to be working, but requires additional bridge configuration and is generally problematic when it comes to external network access for the containers.

Zone

--network-zone= does the same, but manages the bridge interface automatically. Here's what we get by default for the bridge:

[root@host ~]# ip addr show vz-containers
26: vz-containers: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    inet 169.254.120.107/16 brd 169.254.255.255 scope link vz-containers
       valid_lft forever preferred_lft forever
    inet 10.0.0.1/24 brd 10.0.0.255 scope global vz-containers
       valid_lft forever preferred_lft forever
    inet 10.0.1.1/24 brd 10.0.1.255 scope global vz-containers
       valid_lft forever preferred_lft forever

Seems like it's assigned a random address from 169.254.0.0/16, and two static addresses 10.0.0.1 and 10.0.1.1. The host is reachable from the containers by these two addresses. But it's unclear where these addresses come from, and I'm not sure this won't change in the future versions of systemd. To make sure, we can assign an additional static IP to the bridge interface:

# /etc/systemd/network/80-container-vz.network - full override, systemd < 232 
[Match]
Name=vz-*
Driver=bridge

[Network]
# Default to using a /24 prefix, giving up to 253 addresses per virtual network.
Address=0.0.0.0/24
Address=169.254.1.1/24
# the rest is left as in the original /usr/lib/systemd/network/80-container-vz.network

 

# /etc/systemd/network/80-container-vz.network.d/override.conf - drop-in, systemd ≥ 232
[Network]
Address=169.254.1.1/24

This works well, doesn't pose problems with external net connectivity, but also requires additional monkeying with the bridge configuration. Additionally, both methods (bridge and zone) require configuring static /etc/hosts entry, as systemd-resolved and friends (mymachines, myhostname and resolve NSS modules) are not very helpful here:

# /etc/hosts
169.254.1.1 host

Luckily, all the containers share the same base OS image, so it's not that hard to do.

The question is, can all of the above be done in a simpler manner? Or should I wait until systemd-nspawn gets some magic option like "make the host accessible in the containers by the <foo> hostname"?

0

it's unclear where these addresses come from

If you are using systemd-networkd, then configuration files come from configuration files with a .network extension. These files are located in /etc/systemd/network or /run/systemd/network or /usr/lib/systemd/network - the later is the default if you did not modify anything in /etc. ... The documentation for systemd-networkd is here. You may have a DHCP server on your network, and depending which networking mode you use, IP addresses might get assigned from that DHCP server.

The question is, can all of the above be done in a simpler manner?

Most databases are network-based, they listen on a specific port on the host. Depending on your networking configuration, your host should have an interface with an IP address, that is on the host side, but reachable from containers. Keep in mind that firewalling and masquerade might also play a significant role. Once connectivity is established, make sure your database server is listening on the given interface as well.

make the host accessible in the containers by the hostname

Since you are in control of your host-side IP address, you can put an entry into /etc/hosts, as you did. I'm not aware of any simpler solutions, or any external solutions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.