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