Mahesh Prajapati
Posted on January 19, 2022
As starters, the term docker can be quite daunting and may seem a big cliff to overcome but it shouldn't be as such.
The vast amounts of tutorials covering a lot of information at once, doesn't help the starters, speaking from personal experience. That's why, this post is a single step towards the complete new world of docker. So, let's begin.
First thing first, you need to have a existing Django project that you are willing to Dockerize.
I have created a new Django project for this very purpose and going to use it as a starting template. Let's see files that are here inside this folder.
├── db.sqlite3
├── manage.py
├── requirements.txt
└── todo
├── asgi.py
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py
As a complete boilerplate, when run the server with python manage.py runserver
, we are presented with our starting page.
So far, so good.
Let's create a file named Dockerfile in the root directory. The files tree needs to look like
├── db.sqlite3
├── Dockerfile
├── manage.py
├── requirements.txt
└── todo
├── asgi.py
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py
Now, let's quote what Dockerfile is:
A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image.
This is where we put the commands to build our image.
FROM python:3.10
RUN mkdir /app
COPY requirements.txt /app/
WORKDIR /app
RUN pip install -r requirements.txt
COPY . /app/
EXPOSE 8000
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
Let's go through these commands one by one.
1.
FROM python:3.10-slim
We are using python:3.10-slim
as our base image from which we build our image. We can use python:3.10
but it will generate larger build file, which we should be trying to reduce. Also, we can use python:3.10-alpine
which reduces the size even further, but this will require extra care from our end. That's a topic for some other time. If you are interested in knowing further, you can go through here.
2.
RUN mkdir /app
It is pretty straight-forward. It creates a new directory called app
in root directory of the image.
3.
COPY requirements.txt /app/
It copies the requirements.txt
file from our project to the directory we just created. If you don't have this file yet, you can create one by entering the command pip freeze > requirements.txt
which gets all packages that are currently installed in our django project and writes them into the said file.
4.
WORKDIR /app
It sets the current working directory to the directory we created. In other words, we cd
ed to this directory. Any commands we enter from herein are triggered from this directory.
5.
RUN pip install -r requirements.txt
The image we used from line 1
, python:3.10-slim
as pip installed into it by default. So we can run any pip
commands in the image. This command installs all the packages that we had installed in our local system previously.
6.
COPY . /app/
Similar to line 3
, but now we copy all files and folders in the local system into the image. Now, why didn't we did this in line 3
itself? If you wondered, that's good. It's because docker
caches all the commands while building the image, so if we haven't changes requirements.txt
further down the line in future, all commands from 1-5
aren't triggered again. Else, even if there aren't any changes in packages, but have changes in our project, docker
will unnecessarily installs all the packages again.
7.
EXPOSE 8000
We are almost done. It exposes
the port 8000 to "outside world" from image. Since we are going to run Django in port 8000, this is a gateway to the server we are going to run later.
8.
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
Finally, it runs the command python manage.py runserver 0.0.0.0:8000
inside the image. That means, our server will now be up and running.
We have completed writing a very basic Dockerfile
that works. Now, head up to the terminal and enter the command:
docker build -t todo/latest .
Let's wait for some time as docker builds our image. If you are wondering what's todo/latest
, its a tag name. You can put anything as you want or even skip it to just run docker build .
, but we will have to search for our image by going to through a list of images built in the system by going through docker ps
. Let's not go out of our way for now. If you are interested, you can certain try it by yourself.
So, after waiting a couple of minutes, or seconds, depending on several factors, to complete the build, let's trigger the final command.
docker run -p 8000:8000 todo/latest
This command runs the CMD
that we have provided in the Dockerfile. As for 8000:8000
, we are binding our local port 8000
to the image's port 8000
. If you wish, you can put 80:8000
, so it binds to local port 80
to the image's port.
If everything goes well, your terminal should get a normal Django server log. For me, it's
╰─ docker run -p 8000:8000 todo/latest
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
January 19, 2022 - 11:55:15
Django version 4.0.1, using settings 'todo.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
Let's check our browser for confirmation. We should be presented again with this beautiful page.
Congratulations, you have successfully "Dockerize" your Django application.
As for the migrations warnings, you can add a line RUN python manage.py migrate
after line 6
and before line 8
, and build again.
This is a very basic Dockerfile as mentioned. I want it to be understood by a complete beginner so haven't included a number of "gotcha"s to the Dockerfile, they can be learnt as we go and code.
The complete code can be found in my GitHub. Feel free to check it out, if you are having any problems.
Posted on January 19, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.