Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assign outgoing IP for docker container via docker-compose

I have a server with 2 IPs that I need to run 3 docker containers on.

One container is an nginx reverse proxy that takes incoming connections on the first IP.

The second containers uses the same IP to connect externally, I have this portion working.

What I need to do now, is setup a network to let the last container to access external services via the second IP, but still allow the nginx container to access it's ports.

Is there a way to do this in docker-compose? I'd rather not go down the kubernetes / swarm path if I didn't have to.

version: '2'
services:
  nginx:
    image: jwilder/nginx-proxy
    environment:
      - VIRTUAL_PORT=8000
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
    ports:
      - "80:80"


  python:
    depends_on:   
      - nginx
    image: python:2.7-slim
    restart: always
    working_dir: /usr/src/app/
      - VIRTUAL_HOST=python.mydomain.com
    expose:
    - "8000"
    volumes:
    - "./:/usr/src/app/"
    command: bash -c "~/do_some_stuff.sh"

I've already tried to add a bridge network, but I couldn't get it working as it seemed to use my main IP still. Then I tried assigning the IP statically in the container, which didn't work either as the routing didn't function.

It seems like this should be possible, I'm just not sure if I'm searching for the wrong things or don't understand the documentation properly.

like image 443
Michael Robinson Avatar asked Sep 20 '17 11:09

Michael Robinson


1 Answers

I managed to get this working, but it needs an iptables command afterwards. Though it is easily wrapped in a script for full automation by providing just the outgoing IP.

I added a custom network and assigned that to the container:

    version: '2'
    services:
      nginx:
        image: fedora:latest
        command: /bin/bash -c "curl -s ifconfig.co" # Check our external IP
        networks:
          - secondaryIP


    networks:
      secondaryIP:
        driver: bridge
        ipam:
          config:
            - subnet: 103.11.0.0/16

First you should use get the network name you can find that out with:

    docker inspect --format '{{ .HostConfig.NetworkMode }}' <ContainerID>

Once you have that you can get the IP of the container with:

    docker inspect --format '{{ .NetworkSettings.Networks.iptest_secondaryIP.IPAddress }}' <ContainerID>

Where iptest_secondaryIP is the name of your network. This gives the address of the container. Which should be used in the following iptables command:

    sudo iptables -t nat -I POSTROUTING -s $IPADDR -j SNAT --to $SourceIP
  • Note : You can substitute the IP address here with the mask of the network, in this example 103.11.0.0/16, which would mean all containers started with that network would use the same IP

So to wrap it all up in a script:

    #!/bin/bash
    SourceIP=103.11.1.2 # Outgoing IP to use

    # Gets IP of last launched docker container
    CID=$(docker ps -q | head -1)
    # Gets custom network of docker container
    NETMAP=$(docker inspect --format '{{ .HostConfig.NetworkMode }}' $CID)
    # Gets ip address of container
    IPADDR=$(docker inspect --format "{{ .NetworkSettings.Networks.$NETMAP.IPAddress }}" $CID)
    # Sets up SNAT iptables rule for docker container to use SourceIP for outgoing traffic
    sudo iptables -t nat -I POSTROUTING -s $IPADDR -j SNAT --to $SourceIP
like image 56
Michael Robinson Avatar answered Sep 25 '22 03:09

Michael Robinson