Migrating apps from Kubernetes to "native" Docker on TrueNAS Scale forced me to move my containers.
However, I have several VLANs in which the containers should be accessible via an IP address I define. Using the typical Docker network via NAT and then passing the workload through is a bit awkward.
To connect a container on TrueNAS Scale to an "external" network, we use the "macvlan" network type and need the following prerequisites on the system:
- A network interface to which we want to bind the network
- A unique IP address range (IP address, subnet mask, and gateway, IPv4 and/or IPv6)
- A Docker image (Librespeed is an example here)
- A configured app service on TrueNAS Scale
Unfortunately, TrueNAS Scale itself doesn't (yet) offer a convenient way to create Docker networks directly in the GUI. Therefore, we need to create our desired network in the console. To do so, run the following command with root privileges:
docker network create -d macvlan --subnet=<Netzadresse IPv4>/<Prefix> --gateway=<Gateway IPv4> --ipv6 --subnet=<Netzadresse IPv6>/<Prefix IPv6> --gateway=<Gateway IPv6> -o parent=<Interface> <Name des Netzes>
Example:
docker network create -d macvlan --subnet=10.25.0.0/16 --gateway=10.25.0.1 --ipv6 --subnet=fdf8:f53b:83e4::/64 --gateway=fdf8:f53b:83e4::53 -o parent=br0000 NET_MANAGEMENT
The network has now been created and can now be referenced in a Docker Compose YAML.
Creating the network only needs to be done once; the Docker service stores the network persistently, meaning it will be automatically recreated even if the system is restarted.
Now we can create a new custom Compose file and give the app a name via "Apps" > "Discover Apps" > "..." > "Install via YAML."
I'm using Librespeed in this example because the container is relatively easy to describe:
networks:
<Network name>:
external: True
services:
librespeed01:
container_name: librespeed01
environment:
- TZ=Europe/Berlin
- PUID=1000
- PGID=1000
- PASSWORD=PASSWORD
hostname: librespeed01
image: lscr.io/linuxserver/librespeed:latest
networks:
<Network name>:
ipv4_address: <IP-Address>
restart: unless-stopped
Example:
networks:
NET_MANAGEMENT:
external: True
services:
librespeed01:
container_name: librespeed01
environment:
- TZ=Europe/Berlin
- PUID=1000
- PGID=1000
- PASSWORD=PASSWORD
hostname: librespeed01
image: lscr.io/linuxserver/librespeed:latest
networks:
NET_MANAGEMENT:
ipv4_address: 10.25.1.4
restart: unless-stopped
Once the container is started, all of the container's ports are available at the defined IP address.
Note: If individual ports should not be accessible on the network, this must be resolved using a firewall between different networks or VLANs. The firewall can be operated either physically or virtualized on the host system.
The following also applies here:
- Never make workloads directly accessible over the internet without a reverse proxy.
- Always run containers with a restricted user, never root!
- Set resource limits (CPU/RAM) for a container so that a faulty container cannot bring down the entire host system.
- Store persistent data in volumes using the host path.