angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

Docker-Compose projects with identical service names

Use the Docker-Compose service name only if the service is only on the Docker-Compose project internal network.

25 August 2023 Updated 25 August 2023
In Docker
post main image
https://www.pexels.com/@mikael-blomkvist

If we have identical Docker-Compose projects with identical service names, connected by a Docker network, we must make sure that we access the proper service. Over a Docker network there are two ways we can access a service:

  • By service name
  • By container name

I have multiple Docker-Compose projects that are almost identical, each project is in its own directory and has its own environment.

I assumed that a service inside a Docker-Compose project would always use another service inside the same Docker-Compose project when using the service name (not the container name). And that it would produce an error, if it was not available. I was wrong. What actually will happen is that you may access the service with the same name in another Docker-Compose project.

As always, I am running this on Ubuntu 22.04.

Project setup

We have two directories with our (almost) identical projects.

├── my_app1
│   ├── docker-compose.yml
│   └── .env
├── my_app2
│   ├── docker-compose.yml
│   └── .env

The two 'docker-compose.yml' files are identical. The '.env' files are different, they contain only one environment variable, the 'COMPOSE_PROJECT_NAME'. This variable not only is used to create the container names, we also use it inside our containers to identify the Docker-Compose project.

We are using the 'nicolaka/netshoot' Docker image here. It has a lot of useful utilities, including a proper working 'netcat', 'nc', which we use to create listener daemons.

Here are the files:

# my_app1/.env
COMPOSE_PROJECT_NAME=my_app1

and

# my_app2/.env
COMPOSE_PROJECT_NAME=my_app2

and

# docker-compose.yml

version: '3.7' 

x-service_defaults: &service_defaults
  env_file:
    - ./.env
  restart: always

services:
  app:
    << : *service_defaults
    image: nicolaka/netshoot
    command: bash -c "echo \"From ${COMPOSE_PROJECT_NAME} - app:\" | /usr/bin/nc -l 80"
    
    networks: 
      - internal_network
      - app_network

  web:
    << : *service_defaults
    image: nicolaka/netshoot
    command: bash -c "echo \"From ${COMPOSE_PROJECT_NAME} - web:\" | /usr/bin/nc -l 81"

    networks: 
      - internal_network
      - app_network

networks:
  internal_network:
  app_network:
    external:
      name: my_app_network

Before starting, we create the external Docker network:

docker network create my_app_network

Running some checks

Open some terminals and start both projects by running this command in each directory:

docker-compose up

Check that the following containers have been created and are running:

my_app1_app_1
my_app1_web_1
my_app2_app_1
my_app2_web_1

Now in another terminal run:

docker run -it --network=my_app_network --rm busybox

Access a service in our containers using the container name:

telnet my_app_1_app_1 80

The response will be:

Connected to my_app1_app_1
From my_app1 - app:

This is working as expected. Type some text. This will be echo-ed. You can also check this in the terminal of the 'my_app1' Docker-Compose project.

Generating the error

First we enter the 'app' service of the 'my_app1' project:

docker exec -it my_app1_app_1 bash

Now let's access the 'web' service in the same Docker-Compose project, using the service name:

telnet web 81

The response is:

Connected to web
From my_app1 - web:

Perfect, this is what we expected.

Now let's make the 'web' service in the 'my_app1' project (temporarily) disappear. We do this by taking it down.

In another terminal, we go to the 'my_app1' directory and type:

docker-compose stop web

Now we access the 'web' service in the same project again:

telnet web 81

The response is:

Connected to web
From my_app2 - web:

Uh-oh. Now we are accessing 'web' service in 'my_app2' while we wanted to access the 'web' service in 'my_app1'. Note that there are (much) better, but also much more complex, ways to simulate this.

Solutions

There are two possible solutions here, depending on your situation:

Solution 1. If the 'web' service does not need to be external, we remove it from the external network

We do this for both projects (remember that the 'docker-compose.yml' files are identical):

  web:
    << : *service_defaults
    image: nicolaka/netshoot
    command: bash -c "echo \"From ${COMPOSE_PROJECT_NAME} - web:\" | /usr/bin/nc -l 81"

    networks: 
      - internal_network
      #- app_network

Take the containers down and then up again, and stop the 'web' service of the 'my_app1' project again.

Now, if you try to access the 'web' service, see above:

telnet web 81

the response will be, after some time:

telnet: bad address 'web'

Good. We get an error message when the service is not available.

Solution 2. If the 'web' service also must be external, we always use the container name of the 'web' service when referring to it, even if we are in the same Docker-Compose project

This is not really a nice solution but there is no other way. If the 'app' service wants to access the 'web' service in the same Docker-Compose project, we can construct the container name using the 'COMPOSE_PROJECT_NAME' variable:

container_name = <COMPOSE_PROJECT_NAME>_<service name>_1

For the 'web' service in 'my_app1':

web_container_name = my_app1_web_1

Summary

I bounced into this, when going from one container to two containers. Strange things started happening, and data got mixed up between the containers. After locating the problem, I simulated it with the code above. Then I fixed it for my project. Lesson learned: Never assume.

Links / credits

Docker - Change pre-defined environment variables in Docker Compose
https://docs.docker.com/compose/environment-variables/envvars

nicolaka / netshoot
https://github.com/nicolaka/netshoot

Leave a comment

Comment anonymously or log in to comment.

Comments

Leave a reply

Reply anonymously or log in to reply.