Docker Compose

reading time 5 mins

This guide will show you two methods of using Doppler to supply app config and secrets for Docker Compose in production and local development environments.

OptionUsecase
DockerfileInstalls the Doppler CLI in the Dockerfile.
Container Env VarsSecrets injected into containers as environment variables.

Prerequisites

  • You've run applications in Docker Compose and have experience building Docker images.

Service Tokens

Accessing your secrets in production or CI/CD environments requires a Service Token to provide read-only access to a specific config. It's exposed to the CLI via the DOPPLER_TOKEN environment variable which should be provided by your CI/CD environment, e.g. GitHub Secret.

Option 1: Dockerfile

This option embeds the Doppler CLI in a Dockerfile and requires the DOPPLER_TOKEN environment variable. Save this as Dockerfile:

FROM ubuntu

# Install Doppler CLI
RUN apt-get update && apt-get install -y apt-transport-https ca-certificates curl gnupg && \
    curl -sLf --retry 3 --tlsv1.2 --proto "=https" 'https://packages.doppler.com/public/cli/gpg.DE2A7741A397C129.key' | gpg --dearmor -o /usr/share/keyrings/doppler-archive-keyring.gpg && \
    echo "deb [signed-by=/usr/share/keyrings/doppler-archive-keyring.gpg] https://packages.doppler.com/public/cli/deb/debian any-version main" | tee /etc/apt/sources.list.d/doppler-cli.list && \
    apt-get update && \
    apt-get -y install doppler
    
# Fetch and view secrets using "printenv". Testing purposes only!
# Replace "printenv" with the command used to start your app, e.g. "npm", "start"
CMD ["doppler", "run", "--", "printenv"]
FROM alpine

# Install Doppler CLI
RUN wget -q -t3 'https://packages.doppler.com/public/cli/rsa.8004D9FF50437357.key' -O /etc/apk/keys/[email protected] && \
    echo 'https://packages.doppler.com/public/cli/alpine/any-version/main' | tee -a /etc/apk/repositories && \
    apk add doppler

# Fetch and view secrets using "printenv". Testing purposes only!
# Replace "printenv" with the command used to start your app, e.g. "npm", "start"
CMD ["doppler", "run", "--", "printenv"]
FROM centos

# Install Doppler CLI
RUN rpm --import 'https://packages.doppler.com/public/cli/gpg.DE2A7741A397C129.key' && \
    curl -sLf --retry 3 --tlsv1.2 --proto "=https" 'https://packages.doppler.com/public/cli/config.rpm.txt' | tee /etc/yum.repos.d/doppler-cli.repo && \
    yum update -y && \
    yum install -y doppler

# Fetch and view secrets using "printenv". Testing purposes only!
# Replace "printenv" with the command used to start your app, e.g. "npm", "start"
CMD ["doppler", "run", "--", "printenv"]
FROM alpine

# Option 1: Standard
RUN (curl -Ls --tlsv1.2 --proto "=https" --retry 3 https://cli.doppler.com/install.sh || wget -t 3 -qO- https://cli.doppler.com/install.sh) | sh

# Option 2: Signature Verification (GnuPG package required)
RUN (curl -Ls --tlsv1.2 --proto "=https" --retry 3 https://cli.doppler.com/install.sh || wget -t 3 -qO- https://cli.doppler.com/install.sh) | sh -s -- --verify-signature

# Fetch and view secrets using "printenv". Testing purposes only!
# Replace "printenv" with the command used to start your app, e.g. "npm", "start"
CMD ["doppler", "run", "--", "printenv"]

Then save the below file as docker-compose.yml:

services:
  web:
    build: .
    image: doppler-test-alpine
    container_name: doppler-test
    init: true
    environment:
      - DOPPLER_TOKEN

Production deployments

A Doppler Service Token exposed as the DOPPLER_TOKEN environment variable provides read-only access to a specific config in production environments:

# Expects the `DOPPLER_TOKEN` environment variable
docker-compose up

Multiple Services

If you're using multiple services in your compose file and need to pass in multiple Doppler tokens, you can accomplish that by passing in multiple tokens and mapping them in your docker-compose.yml file. To do that, you would execute a command like this:

# make sure you adjust the `--max-age` value appropriately
DOPPLER_TOKEN_API="$(doppler configs tokens create --project api --config dev api-dev-token --plain --max-age 1m)" \
DOPPLER_TOKEN_WEB="$(doppler configs tokens create --project web --config dev web-dev-token --plain --max-age 1m)" \
docker-compose -f docker-compose.yml up

The above dynamically generates two Doppler tokens for two separate projects and configs with a TTL specified with the --max-age flag (make sure you adjust that how you need). You would then update your docker-compose.yml file to look something like this:

services:
  api:
    build: .
    image: doppler-test-alpine
    container_name: doppler-test-api
    init: true
    environment:
      - DOPPLER_TOKEN=${DOPPLER_TOKEN_API}
  web:
    build: .
    image: doppler-test-alpine
    container_name: doppler-test-web
    init: true
    environment:
      - DOPPLER_TOKEN=${DOPPLER_TOKEN_WEB}

Local development

For local development, an ephemeral DOPPLER_TOKEN is used:

DOPPLER_TOKEN="$(doppler configs tokens create dev --plain --max-age 1m)" \
docker-compose -f docker-compose.yml up

Option 2: Container Env Vars

Alternatively, you can use the Doppler CLI to supply environment variables to Docker Compose with each container explicitly defining which environment variables they wish to receive. The benefit of this approach is that Docker Compose is run the same in development as it is in production.

Here is a docker-compose.yml that will pass on the three standard Doppler environment variables as well as two custom variables:

πŸ“˜

Only environment variables explicitly listed in the environment: map will be passed through to the container.

Make sure you update this list any time you add a new secret to your Doppler project.

services:
  web:
    build: .
    image: alpine
    container_name: doppler-test
    init: true
    environment:
      - API_KEY
      - OTHER_SECRET

Then use the Doppler CLI to inject the environment variables:

doppler run -- docker-compose up

Dynamic Environment List

Explicitly defining the environment variables for a container is ideal, but it's also possible to auto-populate the list of environment variables at runtime.

This method allows you to create a doppler-env block containing the environment variable names from Doppler that can be injected anywhere in your docker-compose.yml file.

To use this method, rename your existing docker-compose.yml file to doppler-docker-compose.yml and replace the entire environment: block for any services you want to use this for with a reference to the extension field rendered by the Doppler CLI:

x-doppler: &doppler-env
  environment:{{range $key, $value := .}}
    - {{$key}}{{end}}

services:
  web:
    image: web
    command: npm start
    <<: *doppler-env
    ports:
      - '8080:8080'
  api:
    image: api
    command: ./app-start.sh
    <<: *doppler-env
    ports:
      - '9090:9090'
services:
  web:
    image: web
    command: npm start
    # Ignore editor syntax errors. Produces valid YAML
    environment:{{range $key, $value := .}}
      - {{$key}}{{end}}
    ports:
      - '8080:8080'    

Then inject secrets into the ephemeral docker-compose.yml file:

doppler run \
    --mount docker-compose.yml \
    --mount-template doppler-docker-compose.yml \
    --command 'doppler run -- docker-compose up'

πŸ‘

Amazing Work!

Now you know two methods for Doppler to supply app config and secrets for Docker Compose in production and local development environments.