Local hostnames for Docker containers

Viewed 54899

Beginner Docker question here,

So I have a development environment in which I'm running a modular app, it is working using Docker Compose to run 3 containers: server, client, database.

The docker-compose.yml looks like this:

#############################
# Server
#############################
server:
  container_name: server
  domainname: server.dev
  hostname: server
  build: ./server
  working_dir: /app
  ports:
    - "3000:3000"
  volumes:
    - ./server:/app
  links:
    - database

#############################
# Client
#############################
client:
  container_name: client
  domainname: client.dev
  hostname: client
  image: php:5.6-apache
  ports:
     - "80:80"
  volumes:
   - ./client:/var/www/html

#############################
# Database
#############################
database:
  container_name: database
  domainname: database.dev
  hostname: database
  image: postgres:9.4
  restart: always
  environment:
    - POSTGRES_USER=postgres
    - POSTGRES_PASSWORD=root
    - POSTGRES_DB=dbdev
    - PG_TRUST_LOCALNET=true
  ports:
    - "5432:5432"
  volumes:
    - ./database/scripts:/docker-entrypoint-initdb.d # init scripts

You can see I'm assigning a .dev domainname to each one, this works fine to see one machine from another one (Docker internal network), for example here I'm pinging server.dev from client.dev's CLI:

    root@client:/var/www/html# ping server.dev
    PING server.dev (127.0.53.53): 56 data bytes
    64 bytes from 127.0.53.53: icmp_seq=0 ttl=64 time=0.036 ms

This works great internally, but not on my host OS network.

For convenience, I would like to assigns domains in MY local network, not the Docker containers network so that I can for example type: client.dev on my browsers URL and load the Docker container.

Right now, I can only access if I use the Docker IP, which is dynamic:

client: 192.168.99.100:80
server: 192.168.99.100:3000
database: 192.168.99.100:5432

Is there an automated/convenient way to do this that doesn't involve me manually adding the IP to my /etc/hosts file ?

BTW I'm on OSX if that has any relevance.

Thanks!

Edit: I found this Github issue which seems to be related: https://github.com/docker/docker/issues/2335

As far as I understood, they seem to say that it is something that is not available outside of the box and they suggest external tools like:

Is that correct? And if so, which one should I go for in my particular scenario?

5 Answers

Another solution would be to use a browser with a proxy extension sending the requests through a proxy container that will know where to resolve the domains to. If you consider using jwilder/nginx-proxy for production mode, then your issue can be easily solved with mitm-nginx-proxy-companion.

Here is an example based on your original stack:

version: '3.3'

services:

  server:
    build: ./server
    working_dir: /app
    volumes:
      - ./server:/app

  client:
    environment:
      - VIRTUAL_HOST: client.dev
    image: php:5.6-apache
    volumes:
    - ./client:/var/www/html

  database:
    image: postgres:9.4
    restart: always
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=root
      - POSTGRES_DB=dbdev
      - PG_TRUST_LOCALNET=true
    volumes:
      - ./database/scripts:/docker-entrypoint-initdb.d # init scripts

  nginx-proxy:
    image: jwilder/nginx-proxy
    labels:
      - "mitmproxy.proxyVirtualHosts=true"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro

  nginx-proxy-mitm:
    dns:
      - 127.0.0.1
    image: artemkloko/mitm-nginx-proxy-companion
    ports:
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
  • Run docker-compose up
  • Add a proxy extension to your browser, with proxy address being 127.0.0.1:8080
  • Access http://client.dev

The request will follow the route:

  • Access a local development domain in a browser
  • The proxy extension forwards that request to mitm-nginx-proxy-companion instead of the “real” internet
  • mitm-nginx-proxy-companion tries to resolve the domain name through the dns server in the same container
    • If the domain is not a “local” one, it will forward the request to the “real” internet
    • But if the domain is a “local” one, it will forward the request to the nginx-proxy
  • The nginx-proxy in its turn forwards the request to the appropriate container that includes the service we want to access

Side notes:

  • links removed as it's outdated and is replaced by Docker networks
  • you don't need to add domain names to server and database containers. client will be able to access them on server and database domains because they are all in the same network (similar to what link was doing previously)
  • you don't need to use ports on server and database containers because it only forwards ports to be used through 127.0.0.1. PHP in client container will do only "back-end" requests to other containers, and because those containers are in the same network, you already can access them with database:5432 and server:3000. The same goes for server <-> database connections.
  • I am the author of mitm-nginx-proxy-companion

My Bash script WITH ALIAS without docker-machine Based on http://cavaliercoder.com/blog/update-etc-hosts-for-docker-machine.html


#!/bin/bash

#alias
declare -A aliasArr
aliasArr[docker_name]="alias1,alias2"

# clear existing *.docker.local entries from /etc/hosts
sudo sed -i '/\.docker\.local$/d' /etc/hosts

# iterate over each machine
docker ps -a --format "{{.Names}}" \
| while read -r MACHINE; do

    MACHINE_IP="$(docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${MACHINE} 2>/dev/null)"
    
    if [[ ${aliasArr[$MACHINE]} ]]
    then
        DOMAIN_NAME=$(echo ${aliasArr[$MACHINE]} | tr "," "\n")
    else
        DOMAIN_NAME=( ${MACHINE} )
    fi

    for addr in $DOMAIN_NAME
    do
        echo "add ${MACHINE_IP} ${addr}.docker.local"
        [[ -n $MACHINE_IP ]] && sudo /bin/bash -c "echo \"${MACHINE_IP} ${addr}.docker.local\" >> /etc/hosts"
        export no_proxy=$no_proxy,$MACHINE_IP
    done
        
done

Related