How to share single database container to multiple docker container on same host?

I currently have 3 spring-boot applications that all access the same mysql database. But all apps are standalone.

I started creating 3 individual docker containers that can connect to the real mysql database that is still running on the host.

But of course now I also want to dockerize the mysql database.

Question: how could I share the database container to the other 3 apps?

My setup is as follows:

docker-compose.yml for mysql:

services:
  mysql:
    image: mysql:8
    ports:
      - 3306:3306
    volumes:
      - ~/apps/mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=secret
      - MYSQL_PASSWORD=secret
      - MYSQL_USER=secret
      - MYSQL_DATABASE=shared-database

docker-compose.yml for application 1:

services:
    spring-boot-app-1:
        build:
            dockerfile: Dockerfile
        image: spring-boot-app1:latest
        ports:
          - 8091:8080
        extra_hosts:
          - "host.docker.internal:host-gateway"

docker-compose.yml for application 2:

services:
    spring-boot-app-2:
        build:
            dockerfile: Dockerfile
        image: spring-boot-app2:latest
        ports:
          - 8092:8080
        extra_hosts:
          - "host.docker.internal:host-gateway"

Of course I could now access the database on jdbc:mysql://host.docker.internal:3306/shared-database, but this would mean everything is routed through the default bridge network.

Can I somehow establish some kind of “direct connection” from the app container to the mysql container? Maybe be adding both to a common network? If yes, how could I tell docker the network, and let docker automatically create such a network on startup?

Actualy it’s not that hard. You just need to create a network where all containers that need to interact with each other are member of.

I would strongly suggest to create the network from the cli to detach it’s lifecylce from the docker-compose deployments.

 docker network create \
  --driver=bridge \
  --attachable \
   database

Then modify your datbase container:

services:
  mysql:
    image: mysql:8
    ports:
      - 3306:3306
    volumes:
      - ~/apps/mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=secret
      - MYSQL_PASSWORD=secret
      - MYSQL_USER=secret
      - MYSQL_DATABASE=shared-database
    networks:
      database: {}

networks:
  database:
    external: true

And modify your application services the same way:

services:
    spring-boot-app-1:
        build:
            dockerfile: Dockerfile
        image: spring-boot-app1:latest
        ports:
          - 8091:8080
    networks:
      database: {}

networks:
  database:
    external: true

This will allow spring-boot-app-1 to acess the database server of your mysql service using the service name (which is mysql in your case) and the container port (which is 3306 in your case). If the service names are not unique, you will need to use network aliases.

How would I achieve the same without having to manually create the network from CLI? I mean, let docker-compose auto generate the network?

Like I said: in those situation it IS recommended to create the network outside the compose file to de-couple it from the compose lifecycle. Appearently it is not what you want, so here we go.

Make sure to remove the existing database network, as docker networks are immutable objects - config changes to them are not applied unless deleted, then change the compose file for the database to this:

services:
  mysql:
    image: mysql:8
    ports:
      - 3306:3306
    volumes:
      - ~/apps/mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=secret
      - MYSQL_PASSWORD=secret
      - MYSQL_USER=secret
      - MYSQL_DATABASE=shared-database
    networks:
      default: {}

networks:
  default:
    name: database
    attachable: true

This will make the default network (which is created for every compose file implicitly, unless you specific it explicitly) use the name database (check docker network ls) on the docker engine level (without the projectname prefix that is normaly added to the network name). The applications still need to use the external database network like in my first response.

Note: I am not 100% sure if external: true is required or just optional for your scenario. It is a flag that allows standalone containers to be attached to the network.

2 Likes

external:true was not required, thanks for the brilliant solution!