Skip to content

HOWTO dev docker_compose

steveoro edited this page Feb 2, 2021 · 2 revisions

HOW-TO: Docker-compose: running multiple containers at once

References (updated, 2020):

Using multiple containers as one: docker-compose

Docker Compose (or just Compose for short) is a tool for managing an application that needs several different containers to work together.

Compose is declarative: you describe each part of your application -known as a service - and Compose handles the grunt work of ensuring the right containers are run when and how you need. It also manages creating and destroying the resources needed for the app.

The docker-compose.yml file orchestrates how all the services for the app are tied together.


Goggles API docker-compose.yml example

Each container that has to be run is identified as a "service".

The composition file starts always with the syntax version:

version: '3.7'

services:
  goggles-db:
    image: mariadb:latest
    container_name: goggles-db.dev
    ports:
      - '33060:3306'
    env_file:
      - .env
    restart: always
    volumes:
      - type: volume
        source: db_data
        target: /var/lib/mysql
        volume:
          nocopy: true

  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    image: steveoro/goggles-api:dev-0.1.6
    depends_on:
      - goggles-db
    container_name: goggles-api.dev
    restart: always
    ports:
      - '8080:8080'
    env_file:
      - .env

volumes:
  db_data:
  gem_cache:
  node_modules:

The example yaml is by itself pretty self-explanatory.

Here we define 2 services:

  • goggles-db, running inside the goggles-db.dev container;
  • app, running inside the goggles-api.dev container; it'll be created and mounted on the same bridged network.

Any container will then be able to refer to another one by its service name, which will act as a published name on the docker local network.

goggles-db service

The resulting container goggles-db.dev relies on the standard mariadb:latest image for creation. Uses an external mounted data volume, db_data, which handles the serialization of the database and is declared at the end.

The data volume points to the /var/lib/mysql folder, which is the data folder for MySQL.

Not much else is needed for the definition of the container context, except for the environment file .end, which stores any ENV variable customization such as MySQL's root password, for instance.

To avoid clashing with existing MariaDb/MySQL localhost installations, the container publishes its internal 3306 port to localhost's 33060. In this way localhost installations can coexist with the container with no port clashing.

app service

The app service needs a bespoke Dockerfile to define its container context, it while can use the same .env file shared with the DB container.

The resulting container will be named goggles-api.dev, will be based on the public image URL steveoro/goggles-api:dev-0.1.6, while its custom Dockerfile used for the container layers definition is Dockerfile.dev:

FROM ruby:2.6.3-alpine
LABEL AUTHOR=steve.alloro@gmail.com version="0.1.6"

ENV BUNDLER_VERSION=2.1.4 \
    INSTALL_PATH=/app \
    RAILS_ENV=development \
    DATABASE_NAME=goggles_development \
    DATABASE_HOST=goggles-db \
    DATABASE_PORT=3306 \
    DATABASE_USER=root

RUN mkdir -p $INSTALL_PATH
RUN apk add --update --no-cache binutils-gold build-base curl file g++ gcc git less libstdc++ libffi-dev libc-dev linux-headers libxml2-dev libxslt-dev libgcrypt-dev make mariadb-client mariadb-dev netcat-openbsd nodejs openssl pkgconfig python tzdata yarn

# App image:
RUN gem install bundler -v $BUNDLER_VERSION
WORKDIR $INSTALL_PATH
COPY . ./
RUN bundle config build.nokogiri --use-system-libraries
COPY ./config/database.docker.yml ./config/database.yml

RUN bundle check || bundle install
RUN yarn install --check-files

ENTRYPOINT ["./entrypoints/docker.dev.sh"]

Each command in the Dockerfile corresponds to an individual cached layer for the resulting container.

The resulting service will be published on localhost's 8080 port.

Useful command examples

The composed service definitions inside the custom docker-compose.yml will take care of binding together the containers (as said above).

A simple docker-compose -f <DOCKER_COMPOSE_FILE_NAME> up will run the "orchestrated" result, automatically building or pulling everything that is missing.

Most of the docker-compose sub-commands are a mirror copy of their Docker counter part, such as build, logs, stop, exec, ps, images and many more.

At a glance:

  • docker-compose up to start (and automatically build, if not existing) the composed service
  • docker-compose up --build to force rebuilding the service
  • docker-compose ps to display the running (composed) containers
  • docker-compose logs -f to follow the logs of the running service (CTRL-C to exit)
  • docker-compose stop to just stop the containers
  • docker-compose down to stop and also remove the containers
Clone this wiki locally