I have been working with Django for the last two years here at Accendero. We are working on a project that will be deployed in a Docker container, so I started looking into what it takes to create one for an existing Django project. The Docker documentation explains how to build an image and create a Django project inside of it. Using this as a resource, I figured out how to build a Docker image for an existing Django project. This article shows the steps to accomplish this. The final project, including all the pieces needed for the Docker image, is available in our company Bitbucket.
We start with an existing Django project. The source code is available at the
existing-django-project tag of the git repository for this article. Clone the repository from Bitbucket and check out this tag. Then create a new file named
Dockerfile in the root directory of the project and add the following contents:
FROM python:3 ENV PYTHONUNBUFFERED 1 RUN mkdir /src WORKDIR /src COPY requirements.txt /src/ RUN pip install -r requirements.txt COPY . /src/ CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
Let’s look at each line to understand what is happening here
Start by using the base Python 3 image. At the time of this writing,
python:3 is an alias for
ENV PYTHONUNBUFFERED 1
PYTHONUNBUFFERED environment variable so that no output is buffered. This ensures that we see complete error messages in case anything goes wrong.
RUN mkdir /src
Create a directory named
src in the Docker image. This is where we will put our source code.
Set the current working directory to
/src. Later commands in the
Dockerfile can assume paths start at this directory.
COPY requirements.txt /src/
requirements.txt from the host directory to
/src/ in the image.
RUN pip install -r requirements.txt
Install all of the Python package dependencies.
COPY . /src/
Copy the entire current working directory on the host to the
/src/ directory. It is tempting to do this before running
pip install rather than just copying
requirements.txt by itself. The reason for doing it this way is that when we later run
docker image build, it will cache the results of each
COPY command. If the contents being copied haven’t changed compared to that cache, then docker will skip the
COPY. On the other hand, if there are any local changes, then docker invalidates the cached
COPY and all of the following commands. In this case, only changes to
requirements.txt will require running
pip install again. Changes to the rest of the code won’t.
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
Define the command to run when the container starts. In this case, we will run the Django development server on port
Build the Docker Image
Now run the following command to build the docker image:
docker image build -t django-docker .
-t option provides a tag which we can use to refer to this image in other commands.
Run a Docker Container
Type the following command to run a container from the built image:
docker container run --publish 8000:8000 --name django-docker django-docker
--publish option tells docker to forward requests to port
8000 on the host machine to port
8000 of the container.
Then we give the container a name with
--name django-docker. Finally we specify the image to use by referring to the tag that we gave with the
-t option to
docker image build.
With the container running, open your favorite browser and go to
127.0.0.1:8000/rest/. You should see the default Django Rest Framework interface for your app.
Now we have a Docker image that contains a complete copy of a Django project. This is great for deploying your app, but if you change the code, you will have to rebuild the image to reflect those changes. This isn’t ideal for development when you want to change a single line and see how it affects your app. Additionally, the container is not production-ready because it runs the Django development server with
./manage.py runserver. Future articles will address both of these issues.