Docker networking for groups of containers

Hello to everyone taking the time to read me!
I have a question about Docker containers networking!

Is it possible to expose multiple containers under a single IP address different from the Docker host’s IP on the local network?

The idea I’m looking into is being able to have a single IP on the local network that would point to a specific set of containers and also have said containers able to communicate with each other inside the group. It would also be useful for freeing up ports on the host.
The host is an unRAID server and I’m okay with using Portainer or even command line if needed.

I have attached a graphical example of what I was looking into doing in case it helps understanding what I’m looking for.

Thank you very much for taking some time to help! :blush:

Hi,

I am new to docker, so I would welcome corrections to anything that I say. With that said, I know of one way to accomplish your goal.

In order to setup services on a different IP than the host IP, I would recommend looking into docker VLANs. I setup a MACVLAN network and that has been working well for me.

After setting up this network, you will need to use docker-compose to startup your containers. Using docker-compose will allow you to connect multiple services to one IP. Below I have a docker-compose.yml file where I accomplished what you were interested in. A lot of the file is not relevant to what you’re trying to accomplish, but I’ll point out a couple key items.

  • The MACVLAN network was setup outside of this docker-compose.yml file. During the setup of the network, you can select an IP range for containers on the vlan. I called this vlan mac_vlan_8ip, but you can call it whatever you want.

  • Because the vlan is created outside of this docker-compose.yml, it is necessary to declare it as an external network underneath the networks part of the docker compose file (at the bottom of this file).

  • In the first service I define (avahi), I connect it to my vlan network called mac_vlan_8ip and set its ip address. Note that this IP address is within the IP address range of the MACVLAN network.

  • In my following service (samba), I connect the service to my other service using network_mode: "service:avahi". This allows the samba service to share an ip with the avahi service.

(I’m not sure why “verision: 3.4” cannot be grouped with the other text and set as preformatted text, but it is part of the same file.)

version: '3.4'

services:
 avahi:
   container_name: avahi
   image: solidnerd/avahi:0.7
   networks:
     mac_vlan_8ip:
       ipv4_address: 192.168.0.240
   ports:
     - "137:137/udp"
     - "138:138/udp"
     - "139:139/tcp"
     - "445:445/tcp"
   volumes:
     - ./avahi:/etc/avahi:ro
   restart: unless-stopped
 samba:
   container_name: samba
   image: dperson/samba
   environment:
     TZ: 'America/Los_Angeles'
   network_mode: "service:avahi"
   depends_on:
     - avahi
   tmpfs:
     - /tmp
   restart: unless-stopped
   stdin_open: true
   tty: true
   volumes:
     - /media/TimeMachineBackups/data:/backup:z
   command: '-s "Time Machine Backup;/backup;yes;no;no" -u "username;password"'

networks:
   mac_vlan_8ip:
     external: true
1 Like

That was very insightful and I will try it soon enough. I’m a bit busy with mid-term exams here at the moment.

Thank you very much for taking the time to help!

Is not traefik an option here?

Edit - sorry - replied before reading everything.

There’s several ways to do it, one was partially mentioned above - change the way it’s presented with the above example.

One can also utilize iptables here - depending ofc if the IP address is assigned to a nic.

I’m sorry. I did not understand well. :sweat_smile:

I know it doesnt answer your question but I would really consider using traefik. You could run something like unbound to provide local DNS and have multiple entrypoints on the traefik proxy that would handle everything that you need. If you cant use traefik for your service you can use SRV records.

How I would setup the system you would want would be to setup a docker compose file for a single stack. Run traefik, which used a traefik.toml file to use as configuration. You would want a couple of entrypoints, an HTT{ and HTTPS entrypoint, and an entrypoint for your minecraft server at port 25565. Then expose 80, 443, and 25565 from your traefik container and do not expose any ports on any of the other conainers on the stack. The file would read in a secrets file where you would set the root hostname (EX: family.local). Use labels on the minecraft, cloudbeaver, and nginx containers to attach them to the traefik proxy. Note that you dont have to expose ports in docker for the containers to network with eachother; inside the docker network there are no firewalls( at least by default). You don’t even need to hardcode Ip addresses and you can just set the hostname in the docker compose file and the docker daemon would resolve it.

1 Like

So, after trying it (and getting hit by errors that I wasn’t familiar with), I got it working! Thank you a lot, Drew!
I think the hardest was to make it work for Portainer. It only accepts docker-compose manifests using version 2. Some things are working slightly differently and/or more finicky. But now that I have a working template, I’ll be able to just replicate and adjust that.

Here’s a sample of how I got it configured (for any who’d be reading it and would like to do the same thing):

#/templates/family/docker-compose.yaml
version: '2' #!Version 2 is required for Portainer
services:
    mariadb:
        container_name: Family-MariaDB
        image: linuxserver/mariadb
        networks:
            family:
                ipv4_address: 192.168.10.16
        ports:
            - "3306:3306/tcp" #MariaDB
            - "25565:25565"   #Minecraft
            - "25575:25575"   #Minecraft RCON
        environment:
            # - TZ=America/Montreal
            # - HOST_OS=Unraid
            - PUID=99
            - PGID=100
        volumes:
            - '/mnt/user/RaccPacc/MariaDB/:/config:rw'
        restart: unless-stopped
    minecraft-server:
        container_name: Family-Minecraft
        image: 'itzg/minecraft-server:adopt15'
        network_mode: "service:mariadb"
        depends_on:
            - mariadb
        environment:
            # - TZ=America/Montreal
            # - HOST_OS=Unraid
            - EULA=TRUE
            - TYPE=PAPER
            - MEMORY=4G
            - USE_AIKAR_FLAGS=TRUE
        volumes:
            - '/mnt/user/RaccPacc/Minecraft/:/data:rw'
        restart: unless-stopped

networks:
  family:
    driver: macvlan
    driver_opts:
      parent: eth0
    ipam:
      driver: default
      config:
        - subnet: 192.168.10.0/24
          gateway: 192.168.10.1
          ip_range: 192.168.10.16/32

That’s an idea and that could be useful indeed for exposing only the ports that are needed to be exposed (if I understood right). That’s probably more inline with what I was looking for at the beginning.
But, since it’s not directly exposed on the Internet like a cloud cluster for example, I’m less concerned about it. It’s “hidden” behind an OPNsense/pfSense firewall at home. (I’m running my apps/services on my own machine of salvaged parts from the family’s old computers.) :grinning_face_with_smiling_eyes:

Although, myself knowing Terragrunt/Terraform a bit, your solution seems familiar to me. Or at least, does similar things than what we use Terraform for at work.
I didn’t go into using Terraform because it was going to be way too heavy and probably overkill for what I wanted to do.
I’ll give a shot at Traefik in lab. I’m definitely intrigued. Thanks for the suggestion!

Glad to hear that you got it working!