dockerdocker-network

Is there a way to use docker compose and setup isolate network for the defined services?


I'm trying to create an air-gapped dockerized environment where we can test restoring production backups of databases and application instances. The idea is spin up a PostgreSQL server, restore the database and then spin an instance of the application we have which is configured to connect the restored database. Then we could ensure the application is working as expected.

The problem is that there are some background tasks (and some user actions) that can trigger notifications to the actual end-user (it's a production db after all). This is I was thinking there should be a way to do network isolated tests with docker where the containers can see the services within the docker-compose.yaml, but have no access to the internet.

What would be a cross-platform way to do this? Is there a docker driver that can achieve it or would the user need to do manual interventions?


Solution

  • The way to do this is actually easy, but requires some manual steps. Here are the steps for Linux:

    1. You create a network:

      $ docker network create docker_airgap_network
      bb7645298697d420dab8eaf1fd4738fccceb8230c783aa93ebe76abec6c40f41
      
    2. Fetch the created bridge interface name:

      $ export IFACE=br-$(docker network inspect docker_airgap_network | jq -r '.[0].Id | .[:12]')
        The above will output something like: br-bb7645298697
      
    3. Verify this interface is actually there:

      $ ip -br l | grep -i "$IFACE"
      br-bb7645298697  DOWN             01:43:e3:a2:5f:9d <BROADCAST,MULTICAST,DOWN,LOWER_UP> 
      
    4. Add an iptables rule to drop traffic outside the docker subnet (this would allow communication between all containers; you might want to adjust this just to the docker_airgap_network subnet if you need to be more precise)

      $ iptables -I DOCKER-USER -i $IFACE ! -d 172.0.0.0/8 -j DROP
      $ iptables -nvL DOCKER-USER
      
       Chain DOCKER-USER (1 references)
        pkts bytes target     prot opt in     out     source               destination         
          48  4032 DROP       0    --  br-bb7645298697 *       0.0.0.0/0           !172.0.0.0/8         
         406 34104            0    --  *      *       0.0.0.0/0            0.0.0.0/0           
         430 36120 RETURN     0    --  *      *       0.0.0.0/0            0.0.0.0/0           
      
    5. Bring up your docker-compose.yml file to life with docker-compose up:

      version: '3'
      services:
        service1:
          image: alpine
          command: /bin/sh
          tty: true
          networks:
            - docker_airgap_network
      
        service2:
          image: alpine
          command: /bin/sh
          tty: true
          networks:
            - docker_airgap_network
      
      networks:
        docker_airgap_network:
          external: true
      
    6. Test

      $ docker-compose exec -it service1 ping -c 1 -W 1 google.com
      PING google.com (142.250.184.142): 56 data bytes
      --- google.com ping statistics ---
      1 packets transmitted, 0 packets received, 100% packet loss
      
      $ docker-compose exec -it service1 ping -c 1 -W 1 service2
      PING service2 (172.26.0.2): 56 data bytes
      64 bytes from 172.26.0.2: seq=0 ttl=64 time=0.077 ms
      --- service2 ping statistics ---
      1 packets transmitted, 1 packets received, 0% packet loss
      round-trip min/avg/max = 0.077/0.077/0.077 ms
      
      $ docker-compose exec -it service2 ping -c 1 -W 1 google.com
      PING google.com (142.250.184.142): 56 data bytes
      --- google.com ping statistics ---
      1 packets transmitted, 0 packets received, 100% packet loss
      
      $ docker-compose exec -it service2 ping -c 1 -W 1 service1
      PING service1 (172.26.0.3): 56 data bytes
      64 bytes from 172.26.0.3: seq=0 ttl=64 time=0.054 ms
      --- service1 ping statistics ---
      1 packets transmitted, 1 packets received, 0% packet loss
      round-trip min/avg/max = 0.054/0.054/0.054 ms