INTEGRATE

Docker Compose

You can use Phase Run to inject secrets to your application process during runtime. There's no need for you to change any code or add a dependency.

Prerequisites

  • Have signed up for the Phase Console and created an application.
  • PHASE_SERVICE_TOKEN (Ideally for each of your services).

Using Phase Run

This method uses the Phase CLI to inject secrets into your docker compose services without requiring any change in your docker file.

  1. Reference the required environment variables directly in your docker-compose.yml:
services:
  web:
    build: .
    image: example-service-1
    # 👇 Explicitly mention each secret that you want to supply to each service
    environment:
      - SECRET_VAR
      - REDIS_HOST
      - REDIS_PASSWORD
    depends_on:
      - redis

  api:
    build: .
    image: example-service-2
    environment:
      # 👇 Explicitly mention each secret that you want to supply to each service
      - ANOTHER_SECRET
      - PG_HOST
      - PG_USER
      - PG_PASSWORD
      - PG_DB_NAME
    depends_on:
      - pgql

  pgql:
    image: postgres:latest
    environment:
      # 👇 Explicitly mention each secret that you want to supply to each service
      - POSTGRES_USER
      - POSTGRES_PASSWORD
      - POSTGRES_DB
    ports:
      - '5432:5432'
    volumes:
      - pgdata:/var/lib/postgresql/data

  redis:
    image: redis:latest
    environment:
      # 👇 Explicitly mention each secret that you want to supply to each service
      - REDIS_PASSWORD
      - '6379:6379'

volumes:
  pgdata:
  1. Inject secrets into docker compose:
phase run --app "my application name" docker compose up -d

Using Docker Compose secrets with Phase Run

This method combines Phase Run's secret injection with Docker Compose's native secrets feature, without writing any secrets on disk for enhanced security. Environment variables are often available to all processes; it can be difficult to track access. They can also be printed in logs when debugging errors without your knowledge. Using secrets mitigates these risks. Instead of passing sensitive data as environment variables, secrets are mounted as files inside the container. More information over at Docker Compose docs.

  1. Reference the required secrets directly in your docker-compose.yml using the top-level secrets element along with the services which require access to each secret using the secrets attribute:
services:
  api:
    build: .
    image: example-service
    environment:
      # Non-sensitive configuration
      - API_PORT=3000
    secrets:
      # 👇 Secrets will be mounted under /run/secrets/*
      - api_key
      - db_password
    command: ["./wait-for-secrets.sh", "node", "server.js"]

  db:
    image: postgres:latest
    environment:
      # 👇 So postgresql knows where to find the password file
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password
    volumes:
      - pgdata:/var/lib/postgresql/data

secrets:
  api_key:
    # 👇 This key must be the same as your secret in Phase
    environment: 'API_KEY'
  db_password:
    # 👇 This key must be the same as your secret in Phase
    environment: 'POSTGRES_PASSWORD'

volumes:
  pgdata:
  1. Inject secrets into docker compose:
phase run --app "my application name" docker compose up -d

Using Docker CMD

This method uses the Phase CLI running inside each of your Docker containers to inject secrets to your application at runtime. You will need to install the Phase CLI inside each of your Containers and adjust your CMD to add the phase run command as prefix.

  1. Installing the Phase CLI in Your Docker Container

To maintain deterministic Docker builds and prevent accidentally breaking things, it's recommended to specify the --version flag. You can find the latest versions of the CLI at the GitHub releases. If no version flag is provided then the latest version of the CLI will be installed.

ENV VERSION=<X.XX.XX>
RUN apk add --no-cache curl && curl -fsSL https://pkg.phase.dev/install.sh | sh -s -- --version $VERSION
  1. Defining Your Container's Start Command

Use CMD to specify the default command to run when starting your container, offering flexibility to override it easily. For initializing the Phase CLI with or without a .phase.json, including the --app and --env flags as context.

For a Single Command:

FROM your-base-image

# ... (other Docker commands, e.g., installing dependencies, copying source code, etc.)

# Use CMD to define the default command. Include --app, --env, and optionally --version flags to specify context.
CMD ["sh", "-c", "phase run --app \"my application name\" --env \"production\" yarn start"]

For Multiple Commands:

FROM your-base-image

# ... (other Docker commands, e.g., installing dependencies, etc.)

# Use CMD to define a series of commands with correct format and escaping, including Phase CLI version specification if needed.
CMD ["sh", "-c", "phase run \"python manage.py migrate && python manage.py runserver payments-api:8000\""]
  1. Set PHASE_SERVICE_TOKEN as an environment variable.
export PHASE_SERVICE_TOKEN_FOR_WEB=<YOUR_PHASE_SERVICE_TOKEN_FOR_WEB>
export PHASE_SERVICE_TOKEN_FOR_API=<YOUR_PHASE_SERVICE_TOKEN_FOR_API>
  1. Create or edit your docker-compose.yml:
services:
  web:
    build: .
    image: example-service-1
    environment:
      - PHASE_SERVICE_TOKEN=${PHASE_SERVICE_TOKEN_FOR_WEB}

  api:
    build: .
    image: example-service-2
    environment:
      - PHASE_SERVICE_TOKEN=${PHASE_SERVICE_TOKEN_FOR_API}

Using eval

This method lets you export all secrets stored in Phase as environment variable on the host system which can be used by docker compose.

  1. Export secrets as environment variables in your shell.
eval $(phase secrets export --app "my application name" --env development)
  1. Reference these environment variables directly in your docker-compose.yml:
services:
  web:
    build: .
    image: example-service-1
    # 👇 Explicitly mention each secret that you want to supply to each service
    environment:
      - SECRET_VAR
      - REDIS_HOST
      - REDIS_PASSWORD
    depends_on:
      - redis

  api:
    build: .
    image: example-service-2
    environment:
      # 👇 Explicitly mention each secret that you want to supply to each service
      - ANOTHER_SECRET
      - PG_HOST
      - PG_USER
      - PG_PASSWORD
      - PG_DB_NAME
    depends_on:
      - pgql

  pgql:
    image: postgres:latest
    environment:
      # 👇 Explicitly mention each secret that you want to supply to each service
      - POSTGRES_USER
      - POSTGRES_PASSWORD
      - POSTGRES_DB
    ports:
      - '5432:5432'
    volumes:
      - pgdata:/var/lib/postgresql/data

  redis:
    image: redis:latest
    environment:
      # 👇 Explicitly mention each secret that you want to supply to each service
      - REDIS_PASSWORD
      - '6379:6379'

volumes:
  pgdata:

Using Phase Export

This method lets you export all secrets stored in Phase to a file on disk and supply them to docker compose via env_file:.

  1. Export secrets as environment variables in your shell.
phase secrets export --app "my application name" --env development > secrets.env
  1. Reference these environment variables directly in your docker-compose.yml:
services:
  web:
    build: .
    image: example-service-1
    # 👇 Path to the file where you exported secrets to
    env_file:
      - secrets.env
    depends_on:
      - redis

  api:
    build: .
    image: example-service-2
    # 👇 Path to the file where you exported secrets to
    env_file:
      - secrets.env
    depends_on:
      - pgql

  pgql:
    image: postgres:latest
    # 👇 Path to the file where you exported secrets to
    env_file:
      - secrets.env
    ports:
      - '5432:5432'
    volumes:
      - pgdata:/var/lib/postgresql/data

  redis:
    image: redis:latest
    # 👇 Path to the file where you exported secrets to
    env_file:
      - secrets.env

volumes:
  pgdata: