Introduction
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.
Dockerfile
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"]
Analysis
Let’s look at each line to understand what is happening here
FROM python:3
Start by using the base Python 3 image. At the time of this writing, python:3
is an alias for python:3.8.0
.
ENV PYTHONUNBUFFERED 1
Set the 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.
WORKDIR /src
Set the current working directory to /src
. Later commands in the Dockerfile
can assume paths start at this directory.
COPY requirements.txt /src/
Copy 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 8000
.
Build the Docker Image
Now run the following command to build the docker image:
docker image build -t django-docker .
The -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
The --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
.
Result
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.
Conclusion
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.