Search code examples
dockerdocker-composedocker-network

how can a docker container on 2 subnets access the internet? (using docker-compose)


I have a container with 2 subnets:

  • one is the reverse proxy subnet
  • the second one is the internal subnet for the different containers of that project

The container needs to access an external SMTP server (on mailgun.com), but it looks like, with docker-compose, you can put a container on both one or more subnets and give it access to the host network at the same time.

Is there a way to allow this container to initiate connections to the outside world?

and, if no, what common workarounds are used? (for example, adding an extra IP to the container to be on the host network, etc.)

This is the docker compose file:

version: '2.3'

services:

  keycloak:
    container_name: keycloak
    image: jboss/keycloak
    restart: unless-stopped
    volumes:
      - '/appdata/keycloak:/opt/jboss/keycloak/standalone/data'
    expose:
      - 8080
    external_links:
      - auth
    networks:
      - default
      - nginx
    environment:
      KEYCLOAK_USER: XXXX
      KEYCLOAK_PASSWORD: XXXX
      PROXY_ADDRESS_FORWARDING: 'true'
      ES_JAVA_OPTS: '-Xms512m -Xmx512m'
      VIRTUAL_HOST: auth.XXXX.com
      VIRTUAL_PORT: 80
      LETSENCRYPT_HOST: auth.XXXX.com
      LETSENTRYPT_EMAIL: admin@XXXX.com


networks:
  default:
    external:
      name: app-network
  nginx:
    external:
      name: nginx-proxy

The networks are as follows:

$ dk network ls
NETWORK ID          NAME                DRIVER              SCOPE
caba49ae8b1c        bridge              bridge              local
2b311986a6f6        app-network         bridge              local
67f70f82aea2        host                host                local
9e0e2fe50385        nginx-proxy         bridge              local
dab9f171e37f        none                null                local

and nginx-proxy network info is:

$ dk network inspect nginx-proxy
[
{
    "Name": "nginx-proxy",
    "Id": "9e0e2fe503857c5bc532032afb6646598ee0a08e834f4bd89b87b35db1739dae",
    "Created": "2019-02-18T10:16:38.949628821Z",
    "Scope": "local",
    "Driver": "bridge",
    "EnableIPv6": false,
    "IPAM": {
        "Driver": "default",
        "Options": {},
        "Config": [
            {
                "Subnet": "172.18.0.0/16",
                "Gateway": "172.18.0.1"
            }
        ]
    },
    "Internal": false,
    "Attachable": false,
    "Ingress": false,
    "ConfigFrom": {
        "Network": ""
    },
    "ConfigOnly": false,
    "Containers": {
        "360b49ab066853a25cd739a4c1464a9ac25fe56132c596ce48a5f01465d07d12": {
            "Name": "keycloak",
            "EndpointID": "271ed86cac77db76f69f6e76686abddefa871b92bb60a007eb131de4e6a8cb53",
            "MacAddress": "02:42:ac:12:00:04",
            "IPv4Address": "172.18.0.4/16",
            "IPv6Address": ""
        },
        "379dfe83d6739612c82e99f3e8ad9fcdfe5ebb8cdc5d780e37a3212a3bf6c11b": {
            "Name": "nginx-proxy",
            "EndpointID": "0fcf186c6785dd585b677ccc98fa68cc9bc66c4ae02d086155afd82c7c465fef",
            "MacAddress": "02:42:ac:12:00:03",
            "IPv4Address": "172.18.0.3/16",
            "IPv6Address": ""
        },
        "4c944078bcb1cca2647be30c516b8fa70b45293203b355f5d5e00b800ad9a0d4": {
            "Name": "adminmongo",
            "EndpointID": "65f1a7a0f0bcef37ba02b98be8fa1f29a8d7868162482ac0b957f73764f73ccf",
            "MacAddress": "02:42:ac:12:00:06",
            "IPv4Address": "172.18.0.6/16",
            "IPv6Address": ""
        },
        "671cc99775e09077edc72617836fa563932675800cb938397597e17d521c53fe": {
            "Name": "portainer",
            "EndpointID": "950e4b5dcd5ba2a13acba37f50e315483123d7da673c8feac9a0f8d6f8b9eb2b",
            "MacAddress": "02:42:ac:12:00:02",
            "IPv4Address": "172.18.0.2/16",
            "IPv6Address": ""
        },
        "90a98111cbdebe76920ac2ebc50dafa5ea77eba9f42197216fcd57bad9e0516e": {
            "Name": "kibana",
            "EndpointID": "fe1768274eec9c02c28c74be0104326052b9b9a9c98d475015cd80fba82ec45d",
            "MacAddress": "02:42:ac:12:00:05",
            "IPv4Address": "172.18.0.5/16",
            "IPv6Address": ""
        }
    },
    "Options": {},
    "Labels": {}
}
]

Update:

The following test was done to test the solution proposed by lbndev:

a test network was created:

# docker network create \
       -o "com.docker.network.bridge.enable_icc"="true" \
       -o "com.docker.network.bridge.enable_ip_masquerade"="true" \
       -o "com.docker.network.bridge.host_binding_ipv4"="0.0.0.0" \
       -o"com.docker.network.driver.mtu"="1500" \
       test_network
e21057cf83eec70e9cfeed459d79521fb57e9f08477b729a8c8880ea83891ed9

we can display the contents:

# docker inspect test_network
[
{
    "Name": "test_network",
    "Id": "e21057cf83eec70e9cfeed459d79521fb57e9f08477b729a8c8880ea83891ed9",
    "Created": "2019-02-24T21:52:44.678870135+01:00",
    "Scope": "local",
    "Driver": "bridge",
    "EnableIPv6": false,
    "IPAM": {
        "Driver": "default",
        "Options": {},
        "Config": [
            {
                "Subnet": "172.22.0.0/16",
                "Gateway": "172.22.0.1"
            }
        ]
    },
    "Internal": false,
    "Attachable": false,
    "Ingress": false,
    "ConfigFrom": {
        "Network": ""
    },
    "ConfigOnly": false,
    "Containers": {},
    "Options": {
        "com.docker.network.bridge.enable_icc": "true",
        "com.docker.network.bridge.enable_ip_masquerade": "true",
        "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
        "com.docker.network.driver.mtu": "1500"
    },
    "Labels": {}
}
]

Then we can inspect the container:

I put the contents on pastebin: https://pastebin.com/5bJ7A9Yp since it's quite large and would make this post unreadable.

and testing:

# docker exec -it 5d09230158dd sh
sh-4.2$ ping 1.1.1.1
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
^C
--- 1.1.1.1 ping statistics ---
11 packets transmitted, 0 received, 100% packet loss, time 10006ms

So, we couldn't get this solution to work.


Solution

  • In the end, the problem turned out to be very simple:

    In the daemon.json file, in the docker config, there was the following line:

    {"iptables": false, "dns": ["1.1.1.1", "1.0.0.1"]}

    It comes from the setup scripts we’ve been using and we didn’t know about iptables:false

    It prevents docker from updating the host’s iptables; while the bridge networks were set up correctly, there was no communication possible with the outside.

    While simple in nature, it proved very long to find, so I’m posting it as an answer with the hope it might help someone.

    Thanks to everyone involved for trying to solve this issue!