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

Docker-Componer proyectos con nombres de servicio idénticos

Utilice el nombre de servicio Docker-Compose sólo si el servicio se encuentra únicamente en la red interna del proyecto Docker-Compose.

25 agosto 2023
En Docker
post main image
https://www.pexels.com/@mikael-blomkvist

Si tenemos proyectos Docker-Compose idénticos con nombres de servicio idénticos, conectados por una red Docker , debemos asegurarnos de que accedemos al servicio adecuado. En una red Docker hay dos formas de acceder a un servicio:

  • Por nombre de servicio
  • Por nombre de contenedor

Tengo múltiples proyectos Docker-Compose que son casi idénticos, cada proyecto está en su propio directorio y tiene su propio entorno.

Supuse que un servicio dentro de un proyecto Docker-Compose utilizaría siempre otro servicio dentro del mismo proyecto Docker-Compose al utilizar el nombre del servicio (no el nombre del contenedor). Y que produciría un error, si no estaba disponible. Estaba equivocado. Lo que realmente ocurrirá es que podrás acceder al servicio con el mismo nombre en otro proyecto Docker-Compose.

Como siempre, estoy ejecutando esto en Ubuntu 22.04.

Configuración del proyecto

Tenemos dos directorios con nuestros proyectos (casi) idénticos.

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

Los dos archivos 'docker-compose.yml' son idénticos. Los archivos '.env' son diferentes, contienen sólo una variable de entorno, la 'COMPOSE_PROJECT_NAME'. Esta variable no sólo se utiliza para crear los nombres de los contenedores, también la utilizamos dentro de nuestros contenedores para identificar el proyecto Docker-Compose.

Estamos utilizando el 'nicolaka/netshoot' Docker image aquí. Tiene un montón de utilidades útiles, incluyendo un 'netcat', 'nc', que utilizamos para crear daemons.

Estos son los archivos

# my_app1/.env
COMPOSE_PROJECT_NAME=my_app1

y

# my_app2/.env
COMPOSE_PROJECT_NAME=my_app2

y

# 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

Antes de empezar, creamos la red externa Docker :

docker network create my_app_network

Ejecutando algunas comprobaciones

Abre algunos terminales e inicia ambos proyectos ejecutando este comando en cada directorio:

docker-compose up

Comprueba que se han creado y están en ejecución los siguientes contenedores:

my_app1_app_1
my_app1_web_1
my_app2_app_1
my_app2_web_1

Ahora en otra terminal ejecuta:

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

Accede a un servicio de nuestros contenedores utilizando el nombre del contenedor:

telnet my_app_1_app_1 80

La respuesta será:

Connected to my_app1_app_1
From my_app1 - app:

Esto funciona como esperábamos. Escribe algún texto. Se emitirá un eco. También puedes comprobarlo en el terminal del proyecto 'my_app1' Docker-Compose.

Generación del error

Primero entramos en el servicio 'app' del proyecto 'my_app1' :

docker exec -it my_app1_app_1 bash

Ahora accedamos al servicio 'web' del mismo proyecto Docker-Compose, utilizando el nombre del servicio:

telnet web 81

La respuesta es:

Connected to web
From my_app1 - web:

Perfecto, esto es lo que esperábamos.

Ahora vamos a hacer desaparecer (temporalmente) el servicio 'web' del proyecto 'my_app1' . Para ello, lo eliminamos.

En otro terminal, vamos al directorio 'my_app1' y tecleamos:

docker-compose stop web

Ahora accedemos de nuevo al servicio 'web' del mismo proyecto:

telnet web 81

La respuesta es:

Connected to web
From my_app2 - web:

Uh-oh. Ahora estamos accediendo al servicio 'web' en 'my_app2' mientras que queríamos acceder al servicio 'web' en 'my_app1'. Ten en cuenta que hay formas (mucho) mejores, pero también mucho más complejas, de simular esto.

Soluciones

Hay dos posibles soluciones aquí, dependiendo de su situación:

Solución 1. Si el servicio 'web' no necesita ser externo, lo eliminamos de la red externa.

Hacemos esto para ambos proyectos (recuerda que los ficheros 'docker-compose.yml' son idénticos):

  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

Bajamos los contenedores y los volvemos a subir, y volvemos a parar el servicio 'web' del proyecto 'my_app1' .

Ahora, si intentas acceder al servicio 'web' , ver arriba:

telnet web 81

la respuesta será, después de algún tiempo:

telnet: bad address 'web'

Bien. Recibimos un mensaje de error cuando el servicio no está disponible.

Solución 2. Si el servicio 'web' también debe ser externo, usamos siempre el nombre del contenedor del servicio 'web' cuando nos refiramos a él, aunque estemos en el mismo proyecto Docker-Compose

No es una buena solución, pero no queda más remedio. Si el servicio 'app' quiere acceder al servicio 'web' del mismo proyecto Docker-Compose, podemos construir el nombre del contenedor utilizando la variable 'COMPOSE_PROJECT_NAME' :

container_name = <COMPOSE_PROJECT_NAME>_<service name>_1

Para el servicio 'web' en 'my_app1':

web_container_name = my_app1_web_1

Resumen

Me encontré con esto, al pasar de un contenedor a dos contenedores. Empezaron a pasar cosas raras, y los datos se mezclaban entre los contenedores. Después de localizar el problema, lo simulé con el código de arriba. Luego lo arreglé para mi proyecto. Lección aprendida: Nunca supongas.

Enlaces / créditos

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

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

Deje un comentario

Comente de forma anónima o inicie sesión para comentar.

Comentarios

Deje una respuesta.

Responda de forma anónima o inicie sesión para responder.