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

Configure Docker Compose#

One-time setup

Do this only once per server.

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

docker:
  user: deployer
  docker_compose:
    version: 1.29.2

This will:

  • Install the Docker Compose binary

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 run and redirect the output with 2> /dev/null, since there’s no quiet option.

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"
    scale: 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.