In the earlier post, in which I described about writing a simple Dockerfile for a Django App.
We will pickup where we left off earlier. If you are completely new to Docker, I recommend checking the previous post first.
The starter code that we are using for this post is available in GitHub if you want to follow along.
Let's see how the file structure looks before we start:
├── Dockerfile
├── manage.py
├── README.md
├── requirements.txt
└── main
├── asgi.py
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py
If you are following from the previous post, you will notice I have renamed the 'main' project folder from todo to main. It's because I want to scale this tutorial series to use as a starting template for future projects. So I felt it's important to keep the folders' name as generic as they can be.
The folder structure shouldn't seem to be too confusing as they are not complicated to understand.
Let's go forward. First of all, create a directory in project root called app
and move all existing contents to the app
folder, so the folder structure now looks like:
.
├── app
│ ├── Dockerfile
│ ├── entrypoint.sh
│ ├── main
│ │ ├── asgi.py
│ │ ├── __init__.py
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── manage.py
│ └── requirements.txt
└── README.md
3 directories, 12 files
Why do this? It's because we are incorporating docker-compose
which by its nature, allows us to manage multiple tools for our project, django
being one of them. Each of those tools and their configs should go to their respective directory for clear code and readability.
Now, let's create a docker-compose.yml
file at the root directory, which now contains the app
directory and write the following lines of code.
version: "3.8"
services:
app:
build:
context: ./app
dockerfile: Dockerfile
command: python manage.py runserver 0.0.0.0:8000
volumes:
- ./app:/app
ports:
- "8000:8000"
env_file:
- ./app/.env
environment:
- DEBUG=1
Let's go through the code and see what's happening
1.
version: "3.8"
We want to use docker-compose
version 3.8. How does this versioning matter? That's a lot of complex topics for this post, but if you want to know more, you can check official docker website.
2.
services:
We want to list the 'tools
' as mentioned earlier as array items within the services.
3.
app:
Each of the 'tools
' needs their own name as recognition. app
is just a generic name for the django
container. You can put anything instead of app
like django
, server
or even labrador
.
4.
build:
context: ./app
dockerfile: Dockerfile
As we know, each 'tool
' or container
in docker languages, needs to build before we run. We learnt that in the previous post as well. docker-compose
needs to know which folder to look for to build the container app
. So, naturally, we put all the files related to the app
container into app
folder and gave the context name to ./app
, as in app
folder from where docker-compose.yml
file is located.
At the same time, it also asks for Dockerfile
location. So the name and location, relative to the folder provided in context
. We may want to have multiple Dockerfile
s later on, so it is convenient to have them in easy-to-remember place
5.
command: python manage.py runserver 0.0.0.0:8000
If you understand Django
, this is just a standard run
command which we want to do when we start the server later on.
6.
volumes:
- ./app:/app
The volumes
mapping allows us to map local folders to folders inside the container. If you look into Dockerfile
, we created a folder named app
. The folder inside the container and local system stay synchronized with this command. It also triggers hot reloading of server whenever we change something in local system, so it's very important to keep it on while debugging. Else, we will have to restart the server on every code change.
7.
ports:
- "8000:8000"
Just like the previous post, we want to map our local port 8000 to container's port 8000 to access the server.
With this, you can remove the lines 7. EXPOSE 8000
and 8. CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
Since, both of them are now managed by docker-compose
herein.
8.
env_file:
- ./app/.env
environment:
- DEBUG=1
Both env_file
and environment
can be used to set environment variables to the container. environment
s are preferred when the variables are public, whereas env_file
s which are usually git-ignored
, can be used to set private environment variables like secret-keys
, tokens
and even passwords
. We will look into how to use them later on.
For now, lets go to the terminal and hit up
docker-compose build
If everything went fine, you may now see Successfully built
in the terminal.
So, we may now fire up the server by running
docker-compose up
We should now be presented with this beautiful screen when we navigate to localhost:8000
in our browser.
That's all it takes to run our django
project with docker-compose
. As simple as it can get.
All the code is available in GitHub
Up next, we will add postgres
database and nginx
reverse proxy to the setup and find-out how docker-compose systems can be scaled up.
Top comments (1)
Concise and to the point article. Thanks. When are you planning to write next parts of this series for postgres and nginx?