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 a Python container.
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:
- Access consumerfinance.gov running in the Python container: http://localhost:8000/
- Access Elasticsearch: http://localhost:9200/
To build and run the containers for the first time, run:
docker network create cfgov
docker-compose up
Environment variables¶
Environment variables from your .env
file are sourced
when the Python container starts
and when you access the running Python container.
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
.
Commands that must be run from within the Python container¶
Django manage.py
commands can only be run after you've
opened up a shell in the Python container.
From there, commands like cfgov/manage.py migrate
should run as expected.
The same goes for scripts like ./refresh-data.sh
and ./initial-data.sh
—
they will work as expected once you’re inside the Python container.
Access a container’s shell¶
- Python:
docker-compose exec python sh
- Elasticsearch:
docker-compose exec elasticsearch bash
- PostgreSQL:
docker-compose exec postgres bash
Update/Change Python MAJOR.MINOR Version¶
The first line
of Dockerfile
sets the base Python Interpreter version for all cfgov
images. Our current pattern is python:MAJOR.MINOR-alpine
for the base image.
This allows us to rapidly incorporate PATCH
versions without the need
for explicit commits.
Updating PATCH
version locally¶
To update the PATCH
version on your local Docker, replace <MAJOR.MINOR>
with your target and run:
PYTHONVERSION=<MAJOR.MINOR>; \
docker pull python:${PYTHONVERSION}-alpine && \
docker-compose build --no-cache python
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 container using:
docker-compose up --build python
Work on satellite apps¶
See “Using Docker” on the Related Projects page.
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
:
docker attach consumerfinancegov_python_1
When you're done, you can detach with Ctrl+P Ctrl+Q
.
Note
docker attach
takes the specific container name or ID.
Yours may or may not be consumerfinancegov_python_1
.
To verify, use docker container ls
to get the Python container's full name or ID.
Note
docker attach
will ONLY work with the dev image, not prod (apache).
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
.
docker ps
will list all containers.docker logs [CONTAINER]
will print the logs of a container.docker top [CONTAINER]
will display the running processes in a container.docker-compose build [SERVICE]
will build any of our configured containers.
Production-like Docker Image¶
This repository includes a "production-like" Docker image, created for experimenting with how cf.gov could be built and run as a Docker container in production.
This includes:
- all relevant
consumerfinance.gov
source code - all OS, Python, and JS dependencies for building and running the cf.gov webapp
- procedures for executing Django
collectstatic
andyarn
-based frontend build process - an Apache HTTPD webserver with
mod_wsgi
, run with configs inconsumerfinance.gov
How do I use it?¶
Just Docker¶
If you just want to build the image:
docker build . -t your-desired-image-name
Docker Compose¶
You can also launch the full cf.gov 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.
- Launch the stack.
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up --build
This creates a container running cf.gov on Python, as well as Postgres and Elasticsearch containers, much like the development environment.
- Load the
cfgov
database (optional). If you do not already have a runningcfgov
database, you will need to download and load it from within the container.
docker-compose exec python sh
# Once in the container...
export CFGOV_PROD_DB_LOCATION=<database-dump-url>
./refresh-data.sh
- Browse to your new local cf.gov site.
- Adjust an Apache
cfgov/apache
config and reload Apache (optional).
docker-compose exec python sh
# Once in the container...
httpd -d /src/consumerfinance.gov/cfgov/apache -f /src/consumerfinance.gov/cfgov/apache/conf/httpd.conf -k restart
- Switch back to the development Compose setup.
docker-compose rm -sf python
docker-compose up --build python
How does it work?¶
This project heavily utilizes "multi-stage builds".
There are a few layers at work here, with the hierarchy represented by the list structure:
base
- This is the bare minimum base Python layer for building up any further layers.cfgov-python-builder
- Installs deployment Python dependencies to/build
for use incfgov-dev
andcfgov-prod
. _cfgov-dev
- Dev layer used for local development. Contains no code (requires code volume mount), and installs additional dependencies only needed for local development. _cfgov-frontend-builder
- Frontend builder layer, builds static files for Djangocfgov-mod-wsgi
- mod_wsgi compile layer for Apache2 (helps to guarantee mod_wsgi compatability with Python, Alpine, and Apache)cfgov-prod
- Final layer for Production. Installs and uses Apache2, swaps toapache
user, copies in all files from previous layers to maintain a lightweight image.
The production image extends ONLY the base layer to maintain a lightweight final image.
Everything from previous layers is copied in from those layers using COPY --from=<layer-name>
.
This dramatically improves the overall final image size.