Docker , containers and django
Tags: docker, django, python, javascript
Published: 2021-01-15 14:19:28


You need to know Docker if you want to survive in the dev world especially that we're in 2021, so you had to do it yesterday, you know what I mean, but hey never too late.

Ok,
we will have a closer look to what Docker can do by dockerizing a Django application.

And if you've never touched docker container before, we will go through docker setup first and also the most important instructions in a dockerfile.
We'll do everything step by step, so don't worry.

What is Docker ? 
From a practical standpoint , it's just a way to package software, so it can run on any hardware.
Now, in order to understand how that process actually works, there are a 3 things you must be aware of:

1- Docker File
2- Image
3- Container

A dockerfile is a blueprint for building a docker image
A docker image is a template for running docker containers.
And a container is running process, and in our example here we have a Flask application.

We need to have a server that is running the same version of Flask and that has also installed these dependencies; it works on my computer but if someone else with a different machine tries to run it with a different version of Flask, it might crash.

The whole point of docker is to solve problems like this by reproducing environments the developer who creates the software can define the environment with a docker file 

[The environment is used to indicate to Flask what context Flask is running in. It is controlled with the FLASK_ENV environment variable and defaults to production.]

And then any developer can use the docker file to rebuild the environment which is saved as a (immutable) snapshot known as image.
Images can be uploaded to the cloud so that any developer wants to run the software can pull the image down to create a container which is a running process of that image.
In other words one image file can be set to spawn the same the process many times in different places.
In my opinion, the best approach to learn docker is to use it, and to use it we will need to install it

I highly recommend to install the docker desktop application if you're using Windows or Mac, it installs everything that you need for the command line and also gives you a GUI where you can inspect your containers, once installed you should have access to docker from the command line.

So you will have to create an account to log in, same thing you did in github to have an account and create repositories,  you will do in dockerhub to push your containers.

So, in dockerhub there is a hello-world image that you can pull 
https://hub.docker.com/_/hello-world

And to check out that your installation works correctly, go ahead and run the following command : 

>>> docker run hello-world


You can check out everything about docker by typing just docker and hit enter 
>>> docker 

You can check out your docker version

>>> docker version -v 
>>> docker info
>>> docker ps 

docker ps : gives you a list of all the running containers on your system, you will notice how every container has a unique id and also is linked to an image, and keep in mind that you can find the same information from the GUI as well.

Also, to check out if docker is well installed on your machine, login  you can open your bash or command line and you can  


The other thing you will want to install is the docker extension for vs code because this will give you language support when you write you docker files.

Now let us create a container for a django app .. 
This whole next part is extracted from docs.docker.com official documentation for Docker and how to use Docker Compose to set up and run a simple Django/PostgreSQL app. 


Define the project components
For this project, you need to create a Dockerfile, a Python dependencies file, and a docker-compose.yml file. (You can use either a .yml or .yaml extension for this file.)

Create an empty project directory.

You can name the directory something easy for you to remember. This directory is the context for your application image. The directory should only contain resources to build that image.

Create a new file called Dockerfile in your project directory.

The Dockerfile defines an application’s image content via one or more build commands that configure that image. Once built, you can run the image in a container. For more information on Dockerfile, see the Docker user guide and the Dockerfile reference.

Add the following content to the Dockerfile.

FROM python:3
ENV PYTHONUNBUFFERED=1
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/
This Dockerfile starts with a Python 3 parent image. The parent image is modified by adding a new code directory. The parent image is further modified by installing the Python requirements defined in the requirements.txt file.

Save and close the Dockerfile.

Create a requirements.txt in your project directory.

This file is used by the RUN pip install -r requirements.txt command in your Dockerfile.

Add the required software in the file.

Django>=3.0,<4.0
psycopg2-binary>=2.8
Save and close the requirements.txt file.

Create a file called docker-compose.yml in your project directory.

The docker-compose.yml file describes the services that make your app. In this example those services are a web server and database. The compose file also describes which Docker images these services use, how they link together, any volumes they might need to be mounted inside the containers. Finally, the docker-compose.yml file describes which ports these services expose. See the docker-compose.yml reference for more information on how this file works.

Add the following configuration to the file.

version: "3.9"
   
services:
  db:
    image: postgres
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    depends_on:
      - db
This file defines two services: The db service and the web service.

Note:

This uses the build in development server to run your application on port 8000. Do not use this in a production environment. For more information, see Django documentation.

Save and close the docker-compose.yml file.

Create a Django project
In this step, you create a Django starter project by building the image from the build context defined in the previous procedure.

Change to the root of your project directory.

Create the Django project by running the docker-compose run command as follows.

$ sudo docker-compose run web django-admin startproject composeexample .
This instructs Compose to run django-admin startproject composeexample in a container, using the web service’s image and configuration. Because the web image doesn’t exist yet, Compose builds it from the current directory, as specified by the build: . line in docker-compose.yml.

Once the web service image is built, Compose runs it and executes the django-admin startproject command in the container. This command instructs Django to create a set of files and directories representing a Django project.

After the docker-compose command completes, list the contents of your project.

$ ls -l

drwxr-xr-x 2 root   root   composeexample
-rw-rw-r-- 1 user   user   docker-compose.yml
-rw-rw-r-- 1 user   user   Dockerfile
-rwxr-xr-x 1 root   root   manage.py
-rw-rw-r-- 1 user   user   requirements.txt
If you are running Docker on Linux, the files django-admin created are owned by root. This happens because the container runs as the root user. Change the ownership of the new files.

$ sudo chown -R $USER:$USER .
If you are running Docker on Mac or Windows, you should already have ownership of all files, including those generated by django-admin. List the files just to verify this.

$ ls -l

total 32
-rw-r--r--  1 user  staff  145 Feb 13 23:00 Dockerfile
drwxr-xr-x  6 user  staff  204 Feb 13 23:07 composeexample
-rw-r--r--  1 user  staff  159 Feb 13 23:02 docker-compose.yml
-rwxr-xr-x  1 user  staff  257 Feb 13 23:07 manage.py
-rw-r--r--  1 user  staff   16 Feb 13 23:01 requirements.txt
Connect the database
In this section, you set up the database connection for Django.

In your project directory, edit the composeexample/settings.py file.

Replace the DATABASES = ... with the following:

# settings.py
   
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'postgres',
        'USER': 'postgres',
        'PASSWORD': 'postgres',
        'HOST': 'db',
        'PORT': 5432,
    }
}
These settings are determined by the postgres Docker image specified in docker-compose.yml.

Save and close the file.

Run the docker-compose up command from the top level directory for your project.

$ docker-compose up

djangosample_db_1 is up-to-date
Creating djangosample_web_1 ...
Creating djangosample_web_1 ... done
Attaching to djangosample_db_1, djangosample_web_1
db_1   | The files belonging to this database system will be owned by user "postgres".
db_1   | This user must also own the server process.
db_1   |
db_1   | The database cluster will be initialized with locale "en_US.utf8".
db_1   | The default database encoding has accordingly been set to "UTF8".
db_1   | The default text search configuration will be set to "english".

. . .

web_1  | July 30, 2020 - 18:35:38
web_1  | Django version 3.0.8, using settings 'composeexample.settings'
web_1  | Starting development server at http://0.0.0.0:8000/
web_1  | Quit the server with CONTROL-C.
At this point, your Django app should be running at port 8000 on your Docker host. On Docker Desktop for Mac and Docker Desktop for Windows, go to http://localhost:8000 on a web browser to see the Django welcome page.

Django example

Note:

On certain platforms (Windows 10), you might need to edit ALLOWED_HOSTS inside settings.py and add your Docker host name or IP address to the list. For demo purposes, you can set the value to:

  ALLOWED_HOSTS = ['*']
This value is not safe for production usage. Refer to the Django documentation for more information.

List running containers.

In another terminal window, list the running Docker processes with the docker container ls command.

$ docker ps

CONTAINER ID  IMAGE       COMMAND                  CREATED         STATUS        PORTS                    NAMES
def85eff5f51  django_web  "python3 manage.py..."   10 minutes ago  Up 9 minutes  0.0.0.0:8000->8000/tcp   django_web_1
678ce61c79cc  postgres    "docker-entrypoint..."   20 minutes ago  Up 9 minutes  5432/tcp                 django_db_1
Shut down services and clean up by using either of these methods:

Stop the application by typing Ctrl-C in the same shell in where you started it:

Gracefully stopping... (press Ctrl+C again to force)
Killing test_web_1 ... done
Killing test_db_1 ... done
Or, for a more elegant shutdown, switch to a different shell, and run docker-compose down from the top level of your Django sample project directory.

vmb at mymachine in ~/sandbox/django
$ docker-compose down

Stopping django_web_1 ... done
Stopping django_db_1 ... done
Removing django_web_1 ... done
Removing django_web_run_1 ... done
Removing django_db_1 ... done
Removing network django_default