Running in Docker

First, follow the Docker installation instructions to setup your Docker environment and create the project Docker containers.

We use docker-compose to run an Elasticsearch container, a PostgreSQL container, and Django in Python 2.7 and 3.6 containers. There is also a container serving the documentation.

All of these containers are configured in our docker-compose.yml file. See the Docker documentation for more about the format and use of this file.

The following URLs are mapped to your host from the containers:

To build and run the containers for the first time, run:

docker-compose up

Environment variables

Environment variables from your .env file are sourced when the Python containers start and when you access the running Python containers. Your local shell environment variables, however, are not visible to applications running in Docker. To add new environment variables, simply add them to the .env file, stop docker-compose with Ctrl+C, and start it again with docker-compose up.

Access a container's shell

  • Python 2.7: docker-compose exec python2 bash
  • Python 3.6: docker-compose exec python3 bash
  • Elasticsearch: docker-compose exec elasticsearch bash
  • PostgreSQL: docker-compose exec postgres bash

Run Django management commands

Django commands can only be run after you've opened up a shell in one of the Python containers. From there commands like cfgov/ migrate should run as expected.

The same goes for scripts like ./ and ./ — they will work as expected once you're inside the container.


Because both Python containers use the same database (in the PostgreSQL container), any management commands or scripts that operate on the database (like migrate,, and should only be run once in one of the two Python containers.

Update Python dependencies

If the Python package requirements files have changed, you will need to stop docker-compose (if it is running) and rebuild the Python containers using:

docker-compose up --build python2 python3

Work on satellite apps

See Related Projects#Using Docker.

Attach for debugging

If you have inserted a PDB breakpoint in your code and need to interact with the running Django process when the breakpoint is reached you can run docker attach:

  • Python 2.7: docker attach cfgov-refresh_python2_1
  • Python 3.6: docker attach cfgov-refresh_python3_1

When you're done, you can detach with Ctrl+P Ctrl+Q.

Useful Docker commands

For docker-compose commands, [SERVICE] is the service name that is defined in docker-compose.yml.

For docker commands, [CONTAINER] is the container name displayed with docker ps.

Production-like Docker Image

This repository includes a "production-like" Docker image, created for experimenting with how could be built and run as a Docker container in production.

This includes:

  • all relevant cfgov-refresh source code
  • all OS, Python, and JS dependencies for building and running the webapp
  • procedures for executing Django collectstatic and yarn-based frontend build process
  • an Apache HTTPD webserver with mod_wsgi, run with configs in cfgov-refresh

How do I use it?

Just Docker

If you just want to build the image:

docker build . --build-arg scl_python_version=rh-python36 -t your-desired-image-name

Note: The scl_python_version build arg specifies which Python Software Collection version you'd like to use. We've tested this against python27 and rh-python36.

Docker Compose

You can also launch the full stack locally via docker-compose. This setup is a nice way to test out new Apache config changes. It includes volumes that mount your local checkout cfgov/apache config directories into the container, allowing you to change configs locally without having to rebuild the image each time.

  1. Launch the stack.

    docker-compose -f docker-compose.yml -f up --build

    This create containers running Python 2.7 and 3.6 versions of, as well as Postgres and Elasticsearch containers, much like the development environment.

  2. Load the cfgov database (optional). If you do not already have a running cfgov database, you will need to download and load it from within the container.

    docker-compose exec python2 bash
    # Once in the container...
    export CFGOV_PROD_DB_LOCATION=<database-dump-url>
  3. Browse to your new local site.

  4. Adjust an Apache cfgov/apache config and reload Apache (optional).

    docker-compose exec python2 bash
    # Once in the container...
    httpd -d ./cfgov/apache -k restart
  5. Switch back to the development Compose setup.

    docker-compose rm -sf python3 python2
    docker-compose up --build python3 python2

How does it work?

The production image extends the development image. If you look at the Dockerfile, this is spelled out by the line:

FROM cfgov-dev as cfgov-prod

Both 'cfgov-dev' and 'cfgov-prod' are called "build stages". That line means, "create a new stage, starting from cfgov-dev, called cfgov-prod".

From there, we:

  • Install SCL-based Apache HTTPD, and the mod_wsgi version appropriate for our chosen scl_python_version.
  • Run, Django's collectstatic command, and then uninstall node and yarn.
  • Set the default command on container startup to httpd -d ./cfgov/apache -D FOREGROUND, which runs Apache using the configuration in cfgov-refresh, in the foreground (typical when running Apache in a container).