Configure Docker apps

Note

This guide works with existing images. See the Software Development Handbook for how to build images from a Dockerfile using GitHub Actions.

The docker_apps state file performs common operations for apps deployed using Docker Compose. In your app’s state file, include it with:

include:
  - docker_apps

If you already have an include state, add docker_apps to its list.

This will:

  • Install the Docker service

Configure Docker

One-time setup

Do this only once per server.

In the service’s Pillar file, add, for example:

docker:
  user: deployer

This will:

  • Add a non-root user to the docker group

Add Docker Compose file

Create an {app}.yaml file in the salt/docker_apps/files directory. For example:

services:
  web:
    image: "ghcr.io/open-contracting/myrepo:latest"
    restart: unless-stopped

Validate the file, for example:

docker compose config -q salt/docker_apps/files/redash.yaml

See also

Configure Django

Stateful containers

Containers are designed to be interrupted at any time, whereas stateful services like PostgreSQL and RabbitMQ can fail in such conditions. Instead, run these on the host, where they are easier to operate with high reliability.

One-off commands

To run a one-off command, like a database migration, use docker compose run on the command line, instead of creating a one-time container. See Docker tasks for examples.

If you need to run a scheduled task in a cron job, use docker compose --progress=quiet run --rm. If needed, change the log level by adding -e LOG_LEVEL=WARNING, for example.

Confirm the meaning of a cron expression using Cronhub.

Shared configuration

To share configuration between services, you can use this pattern:

x-shared: &shared
  image: "ghcr.io/open-contracting/myrepo:latest"
  restart: unless-stopped

services:
  web:
    <<: *shared
  worker:
    <<: *shared
    command: "python -m worker"
    deploy:
      replicas: 2

Reference:

Configure Docker app

In the service’s Pillar file, add, for example:

docker_apps:
  myapp:
    target: mytarget
    env:
      MYVAR: myvalue

This will create files in the /data/deploy/mytarget directory:

  • docker-compose.yaml, containing the same as the myapp.yaml file

  • .env, containing the values under the env key

Reference:

Use host services

To connect to the host’s services, like PostgreSQL or RabbitMQ, add to the Docker Compose file:

services:
  web:
    image: "ghcr.io/open-contracting/myrepo:latest"
    restart: unless-stopped
    extra_hosts:
      - "host.docker.internal:host-gateway"

Then, under the env key in the service’s Pillar file, use host.docker.internal instead of localhost. For example:

docker_apps:
  myapp:
    target: mytarget
    env:
      DATABASE_URL: "postgresql://user:pass@host.docker.internal:5432/name"

Reference:

Map a port

If the Dockerfile exposes a port, in the service’s Pillar file, add, for example:

docker_apps:
  myapp:
    target: mytarget
    port: 8001
    env:
      MYVAR: myvalue

This makes it easier for multiple Docker Compose files to refer to the port.

Then, in the Docker Compose file, add, for example:

services:
  web:
    image: "ghcr.io/open-contracting/myrepo:latest"
    restart: unless-stopped
    ports:
      - {{ pillar.docker_apps.myapp.port }}:8000

Add a bind mount

See the last step for Bind mounts in the Software Development Handbook.

Configure Apache

Apache is used as a reverse proxy to any web servers in the Docker containers. See Configure Apache. The configuration can simply be ProxyPass directives.

Additional files

Setup

Create additional files needed to setup the service (e.g. SQL migrations) in the /data/deploy/TARGET/files directory.

Use

Create additional files needed to use the service (e.g. sudoer binaries) in the /opt or /opt/TARGET directory.