Monday, September 5, 2016

SOLVED: docker-compose. Error starting userland proxy: listen tcp 0.0.0.0:80: bind: address already in use

I configured new set of containers (via docker-compose),  and tried them to run

>docker-compose up -d
...
Error starting userland proxy: listen tcp 0.0.0.0:80: bind: address already in use 


googling returns me pretty inconvenient solutions:
  • just stop local web/mysql server or use different port for container. 
  • don't publish ports at all, i.e. remove '-ports'/'-p'  
  • use reverse-proxy before containers for web servers 
But I needed something less troublesome, I needed different/independent sets of containers running, i.e. different projects with different needs, with easy way to setup/remove, so I ended with next solution:
  • tie each set of containers (from single docker-compose.yml ) to docker custom networks i.e. all containers from set are bound to some unique IP range
  • use /etc/hosts to bind IPs to names  and always have regular ports 80, 443, 3306 etc accessible from local host
  • use of environment file (.env) for local config (so team can use the same config, while each member can customize important values) 

so, this is how it looks:
>cat .env
GATEWAY_IP=172.16.240.1
SUBNET=172.16.240.0/24
COMPOSE_PROJECT_NAME=myproject1

>cat docker-compose.yml
version: '2'

services:
  nginx:
    image: nginx:latest
    ports:
      - "${GATEWAY_IP}:80:80"
    networks:
      - export

networks:
  export:
    driver: bridge
    ipam:
      driver: default
      config:
      - subnet: "${SUBNET}"
        gateway: "${GATEWAY_IP}"

and docker merges both files and has config as:
>docker-compose config                  
networks:
  export:
    driver: bridge
    ipam:
      config:
      - gateway: 172.16.240.1
        subnet: 172.16.240.0/24
      driver: default
services:
  nginx:
    image: nginx:latest
    networks:
      export: null
    ports:
    - 172.16.240.1:80:80
version: '2.0'
volumes: {}


>docker-compose up -d                   
Creating network "myproject1_export" with driver "bridge"
Creating myproject1_nginx_1


>docker-compose ps                    
       Name                Command          State                Ports              
------------------------------------------------------------------------------------
myproject1_nginx_1   nginx -g daemon off;   Up      443/tcp, 172.16.240.1:80->80/tcp



Now, just add into your /etc/hosts file some like
172.16.240.1 myprojecthost

and go to http://myprojecthost to check if it works (MySQL will be on myprojecthost:3306 etc)

Some additional notes:
  • you will need to link every service in docker-compose.yml  to same network, i.e.

        networks:
          - export


    Otherwise, docker-compose will create two networks - default and custom one, and if services don't share common network, they won't communicate.
    Of course, you can use default network too for services you want to publish:

        networks:
          - export
         
          - default

    then there no need to update every service
     
  • do not add .env in git , just create .env.sample , so every developer can copy it to .env and use customized config 
  • docker-compose names containers based on directory name, this is inconvenient if you work with different project with similar directory structure, because docker tools checks only name of container (i.e. down/restart etc will catch containers from other directories).
    To make things manageable COMPOSE_PROJECT_NAME environment variable is used. Still, it should be unique per docker host/machine, or docker tools will work incorrectly 

No comments:

Post a Comment