Docker Share Resource Pattern

I have several applications that I’ve been running that use the same pattern.

Some REST, or www app with a database to support it. So the docker-compose would look something like this.

  www:
    build:
        context: .
        dockerfile: compose/app/Dockerfile
    env_file: .env
    restart: always
    ports:
      - "9000:9000"
  db:
    image: mysql:5.7.29
    restart: always
    env_file: .env
    healthcheck:
      test: ["CMD-SHELL", 'mysql --database=$$MYSQL_DATABASE --password=$$MYSQL_ROOT_PASSWORD --execute="SELECT 1 + 1" --skip-column-names -B']
      interval: 10s
      timeout: 5s
      retries: 5

This works fine for a single instance but once you have 2 or 3 mysql instances this gets a bit heavy for the server. Not to mention just straight out dumb to have 3 DB servers because i need 3 databases.

Solution:

  1. Set up a shared DB resource.
version: '3.7'
services:
  shared_mysql:
    container_name: shared_mysql
    image: mysql:5.7.29
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    env_file: .env
    networks:
       - shared_backend
    volumes:
        - ./data:/var/lib/mysql
        - ./sql:/docker-entrypoint-initdb.d
    healthcheck:
      test: ["CMD-SHELL", 'mysql --database=$$MYSQL_DATABASE --password=$$MYSQL_ROOT_PASSWORD --execute="SELECT 1 + 1" --skip-column-names -B']
      interval: 10s
      timeout: 5s
      retries: 5


networks:
    shared_backend:
        name: shared_backend
        # use a custom driver, with no options
        driver: bridge

the .env defines only the root password.

sql/site.sql

will define a new database and user with all privileges on the specific database.

Please note the network name is important as well as the container_name.

Now to update the existing app to use this, our new app will instead look like this:

version: '3.7'
services:
  www:
    build:
        context: .
        dockerfile: compose/app/Dockerfile
    volumes:
        - ./storage/app/public:/app/public/storage
    env_file: .env
    networks:
       - shared_backend
    ports:
      - "9000:9000"
    external_links:
      - shared_mysql

networks:
    shared_backend:
        name: shared_backend
        external: true

At this point we simply need to update any reference to the database host to be shared_backend.

NOTE. This is definitely starting to push what docker compose was designed for. Using kubernetes would be a better pattern but till then. This isn’t a bad compromise.

TODO: add systemd startup scripts.