Sharing code base between docker containers
I have two containers. One is used for holding my django application with gunicorn running and another is for the celery task queue.
Celery uses the same django application code base.
When I build Django docker container I use ADD . /usr/src/app
statement to copy source files into container. But Dockerfile for Celery lays in another folder, so there is no possibility to copy files in it as they are out of context.
So far I see two possibilities:
-
mount -o bind
seems to look hacky - keeping two copies of files can cause out-of-sync situation
- declare source code folder as a volume and start celery container with
volumes-from
.
Currently I use the third solution. Are there any better ways? Use git clone
in dockerfile? But how to auth then ...
Solution 1:
In our current docker application, we have three different images that are used for two containers.
- Base - This is what holds any common dependencies (development headers) as well as the Python source code.
-
Web - This installs the web-specific dependencies, like Gunicorn. It also sets up the
CMD
and ports. - Worker - This installs the worker-specific dependencies, mainly setting up the Celery user and locking it down.
The base image is at the root of our repository, and our base image does the equivalent of ADD . /usr/src/app
along with some other things. Both of the web and worker images extend from that base image, so they both have the source code as well.
This allows you to share the code between both containers, and doesn't require you to have another volume that holds the code.
An example setup for the three Dockerfiles would be
./Dockerfile
FROM python:3.4
ADD . /usr/src/app
RUN pip install -r /usr/src/app/requirements.txt
./web/Dockerfile
FROM app-base:latest
RUN pip install gunicorn
./worker/Dockerfile
FROM app-base:latest
RUN pip install celery
Which would then need to be built as
docker build -t app-base .
docker build -t app-web web
docker build -t app-worker worker
This will not work with docker compose because it does not support image inheritance.
Solution 2:
My original answer still serves as a valid solution to the problem, but another solution now exists as of Docker 1.6.0. You can now specify the location of the Dockerfile
, and it does not have to be in the same directory as the root of the build context.
./Dockerfile.web
FROM python:3.4
ADD . /usr/src/app
RUN pip install gunicorn
./Dockerfile.worker
FROM python:3.4
ADD . /usr/src/app
RUN pip install celery
It is recommended to keep the ADD
lines at the top of your Dockerfile
, so the addition only needs to happen once and it can be reused for building both the web and worker images.
You can build the images as
docker build -t app-web -f Dockerfile.web .
docker build -t app-worker -f Dockerfile.worker .
Or using Docker Compose, the configuration would look like
services:
web:
build:
context: .
dockerfile: Dockerfile.web
worker:
build:
context: .
dockerfile: Dockerfile.worker