Search code examples
docker-composetraefik

Docker-compose isolate networks by project name


I'm trying to do a zero downtime deploying w/ docker-compose and traefik, but I'm having issues with a container cross communicating with another project.

docker-compose.yml (details omitted)

services:
   proxy:
      networks:
         - net
   app:
      networks:
         - net
   auth:
      networks:
         - net

networks:
  net:
    external:
       name: traefik_webgateway # not really important here
    

I run two different instances of my services via:

docker-compose --env-file=.env --project-name=green -f docker-compose.yml up
docker-compose --env-file=.env --project-name=blue -f docker-compose.yml up

My services in "green" work fine until I run the "blue" project. When "blue" is being brought up, some of the requests in the "green" "proxy" container is being routed to the "blue" container. Example call being made in "proxy" to talk to the "auth" service:

http://auth/session

I need the networking in "green" to stay in "green", and "blue" in "blue"... otherwise some of the requests in "green" is going to "blue" when it isn't ready it causing API failures. Once all the containers are ready, everything works but this isn't zero downtime.

It looks like everything is bound by the container name. I don't want to use container_name because I want to use the docker scale.

My workaround is creating docker-compose.blue.yml and docker-compose.green.yml and duplicates everything but suffix the container name with _blue and _green. But I'm wondering if there's a better solution.

Thanks in advance.

EDIT: The proposed solution answers the question, but by adding the internal network to my proxy, traefik loses communication with my service.


Solution

  • By default, docker-compose will setup a single, isolated network for your project. When using custom networks those, too, will be namespaced with the project name, isolating projects with different names - see the docker-compose networking docs.

    BUT: in your example all the containers are connected to an external network which is not namespaced and thus is the same even for different projects. Since the container also share the same name resolving them in that network may result in either the green or blue version.

    There are several ways to solve this. The appropriate method depends on your particular use case. The best and also the safest method would be to isolate all containers with the same project name to their own internal network and only expose the ports intended for outside connection into the external network:

    services:
       proxy:
          networks:
             - net
             - internal
       app:
          networks:
             - internal
       auth:
          networks:
             - internal
    
    networks:
      internal:
      net:
        external:
           name: traefik_webgateway # not really important here
    

    Here, all the containers are only connected to a project-scoped, internal network and are able to communicate with each other. Only the proxy service is also connected to the external net network and can be connected to from there.

    If you really need to connect all services to the same external network, you could use aliases together with variable substitution:

    services:
       proxy:
          networks:
             net:
               aliases:
                 - proxy_${COLOR}
       app:
          networks:
             net:
               aliases:
                 - app_${COLOR}
       auth:
          networks:
             net:
               aliases:
                 - auth_${COLOR}
    
    networks:
      net:
        external:
           name: traefik_webgateway # not really important here
    

    This is basically your workaround but with a single docker-compose.yml which you can use like this:

    COLOR=green docker-compose --env-file=.env --project-name=green -f docker-compose.yml up
    COLOR=blue docker-compose --env-file=.env --project-name=blue -f docker-compose.yml up