This article builds on what was covered in the article about microservices with docker where flask and redis were used; in this case it will be with postgresql and Django.
Below is the list of docker articles covered on the blog:
- Installing Docker on Debian Jessie (broken link)
- Using Docker on Debian Jessie (part 1)
- Using Docker on Debian Jessie (part 2)
- Creating a Docker image from a Dockerfile (broken link)
- Starting Django using Docker (broken link)
- Installing Gitlab through Docker (broken link)
- Running microservices with docker using docker-compose (broken link)
- Docker in Docker (DinD) (broken link)
The article is based on an English article about docker-compose and django.
The idea is to have two containers, one running postgresql and the other Django.
In a directory, create the Dockerfile file with the following contents:
FROM python:2.7
ENV PYTHONUNBUFFERED 1
RUN mkdir /codigo
WORKDIR /codigo
ADD requerimientos.txt /codigo/
RUN pip install --upgrade pip
RUN pip install -r requermientos.txt
ADD . /codigo/
The requerimientos.txt file will contain the installation of Django and of the psycopg2 library to connect to postgresql from django:
Django
psycopg2
The last file to create is the one that docker-compose will use, named docker-compose.yml, and its contents will start the postgresql database and then Django:
bd:
image: postgres
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/codigo
ports:
- "8000:8000"
links:
- bd
There will be two containers, one called bd and the other web. The command to start DJango is the usual one, and it uses port 8000, which will be visible publicly.
Next, the Django project is created with the following command:
docker-compose run web django-admin.py startproject djangoapp .
Building web
Step 1 : FROM python:2.7
---> 19ab33b86bc6
Step 2 : ENV PYTHONUNBUFFERED 1
---> Running in eb54e8bab43f
---> a4206823aac3
Removing intermediate container eb54e8bab43f
Step 3 : RUN mkdir /app
---> Running in bf221dbca163
---> 44eb31969545
Removing intermediate container bf221dbca163
Step 4 : WORKDIR /app
---> Running in 6209e18e7e87
---> 6f7d50fc9b12
Removing intermediate container 6209e18e7e87
Step 5 : ADD requerimientos.txt /app/
---> 293c5424f664
Removing intermediate container c072ad8ca2ae
Step 6 : RUN pip install --upgrade pip
---> Running in 48f862804290
Collecting pip
Downloading pip-8.0.2-py2.py3-none-any.whl (1.2MB)
Installing collected packages: pip
Found existing installation: pip 7.1.2
Uninstalling pip-7.1.2:
Successfully uninstalled pip-7.1.2
Successfully installed pip-8.0.2
---> 6126a41cd55b
Removing intermediate container 48f862804290
Step 7 : RUN pip install -r requerimientos.txt
---> Running in 7e6c9ff9fefa
Collecting Django (from -r requerimientos.txt (line 1))
Downloading Django-1.9.2-py2.py3-none-any.whl (6.6MB)
Collecting psycopg2 (from -r requerimientos.txt (line 2))
Downloading psycopg2-2.6.1.tar.gz (371kB)
Building wheels for collected packages: psycopg2
Running setup.py bdist_wheel for psycopg2: started
Running setup.py bdist_wheel for psycopg2: finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/e2/9a/5e/7b620848bbc7cfb9084aafea077be11618c2b5067bd532f329
Successfully built psycopg2
Installing collected packages: Django, psycopg2
Successfully installed Django-1.9.2 psycopg2-2.6.1
---> 971bcfbe34ec
Removing intermediate container 7e6c9ff9fefa
Step 8 : ADD . /app/
---> 7a7faf87cf21
Removing intermediate container 6c246df080b3
Successfully built 7a7faf87cf21
This will generate a directory and some files, as shown below:
ls -l
total 20
drwxr-xr-x 2 root root 4096 feb 10 21:35 djangoapp
-rw-r--r-- 1 ernesto ernesto 174 feb 10 21:14 docker-compose.yml
-rw-r--r-- 1 ernesto ernesto 177 feb 10 21:14 Dockerfile
-rwxr-xr-x 1 root root 252 feb 10 21:35 manage.py
-rw-r--r-- 1 ernesto ernesto 17 feb 10 20:10 requerimientos.txt
You need to change the owner of the djangoapp directory and manage.py.
sudo chown -R $USER:$USER .
Check the images that were created:
docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
docker5_web latest 7a7faf87cf21 4 minutes ago 715.2 MB
postgres latest 54fa18d9f3b6 2 weeks ago 263.8 MB
Modify the djangoapp/settings.py file to support the connection to the postgresql container:
Modify the database section with the following contents:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'postgres',
'USER': 'postgres',
'HOST': 'db',
'PORT': 5432,
}
}
The user and password are the ones predefined by the docker image for postgresql.
Run migrate from manage.py to create the tables:
docker-compose run web python manage.py migrate
Operations to perform:
Apply all migrations: admin, contenttypes, auth, sessions
Running migrations:
Rendering model states... DONE
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying sessions.0001_initial... OK
Create the django administrator account:
docker-compose run web python manage.py createsuperuser
Username (leave blank to use 'root'): admin
Email address:
Password:
Password (again):
Superuser created successfully.
To bring up django's web server, start docker-compose:
$docker-compose up
docker5_db_1 is up-to-date
Creating docker5_web_1
Attaching to docker5_db_1, docker5_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".
db_1 |
db_1 | Data page checksums are disabled.
db_1 |
db_1 | fixing permissions on existing directory /var/lib/postgresql/data ... ok
db_1 | creating subdirectories ... ok
db_1 | selecting default max_connections ... 100
db_1 | selecting default shared_buffers ... 128MB
db_1 | selecting dynamic shared memory implementation ... posix
db_1 | creating configuration files ... ok
db_1 | creating template1 database in /var/lib/postgresql/data/base/1 ... ok
db_1 | initializing pg_authid ... ok
db_1 | initializing dependencies ... ok
db_1 | creating system views ... ok
db_1 | loading system objects' descriptions ... ok
db_1 | creating collations ... ok
db_1 | creating conversions ... ok
db_1 | creating dictionaries ... ok
db_1 | setting privileges on built-in objects ... ok
db_1 | creating information schema ... ok
db_1 | loading PL/pgSQL server-side language ... ok
db_1 | vacuuming database template1 ... ok
db_1 | copying template1 to template0 ... ok
db_1 | copying template1 to postgres ... ok
db_1 | syncing data to disk ... ok
db_1 |
db_1 | WARNING: enabling "trust" authentication for local connections
db_1 | You can change this by editing pg_hba.conf or using the option -A, or
db_1 | --auth-local and --auth-host, the next time you run initdb.
db_1 |
db_1 | Success. You can now start the database server using:
db_1 |
db_1 | pg_ctl -D /var/lib/postgresql/data -l logfile start
db_1 |
db_1 | ****************************************************
db_1 | WARNING: No password has been set for the database.
db_1 | This will allow anyone with access to the
db_1 | Postgres port to access your database. In
db_1 | Docker's default configuration, this is
db_1 | effectively any other container on the same
db_1 | system.
db_1 |
db_1 | Use "-e POSTGRES_PASSWORD=password" to set
db_1 | it in "docker run".
db_1 | ****************************************************
db_1 | waiting for server to start....LOG: database system was shut down at 2016-02-11 04:34:33 UTC
db_1 | LOG: MultiXact member wraparound protections are now enabled
db_1 | LOG: database system is ready to accept connections
db_1 | LOG: autovacuum launcher started
db_1 | done
db_1 | server started
db_1 | ALTER ROLE
db_1 |
db_1 |
db_1 | /docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*
db_1 |
db_1 | LOG: received fast shutdown request
db_1 | LOG: aborting any active transactions
db_1 | waiting for server to shut down...LOG: autovacuum launcher shutting down
db_1 | .LOG: shutting down
db_1 | LOG: database system is shut down
db_1 | done
db_1 | server stopped
db_1 |
db_1 | PostgreSQL init process complete; ready for start up.
db_1 |
db_1 | LOG: database system was shut down at 2016-02-11 04:34:38 UTC
db_1 | LOG: MultiXact member wraparound protections are now enabled
db_1 | LOG: database system is ready to accept connections
db_1 | LOG: autovacuum launcher started
db_1 | LOG: database system was interrupted; last known up at 2016-02-11 04:34:39 UTC
db_1 | LOG: database system was not properly shut down; automatic recovery in progress
db_1 | LOG: invalid record length at 0/1707848
db_1 | LOG: redo is not required
db_1 | LOG: MultiXact member wraparound protections are now enabled
db_1 | LOG: database system is ready to accept connections
db_1 | LOG: autovacuum launcher started
db_1 | ERROR: relation "auth_user" does not exist at character 280
db_1 | STATEMENT: SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login", "auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user" WHERE "auth_user"."username" = 'root'
web_1 | Performing system checks...
web_1 |
web_1 | System check identified no issues (0 silenced).
web_1 | February 11, 2016 - 12:38:56
web_1 | Django version 1.9.2, using settings 'djangoapp.settings'
web_1 | Starting development server at http://0.0.0.0:8000/
web_1 | Quit the server with CONTROL-C.
All that is left is to open the browser at the following URL http://127.0.0.1:8000/admin.
Below is the image of the Django admin session:
And the figure with the logs of the Django execution:
As seen in the article, you can run the manage.py commands from outside the container, and those commands will be executed in the container.
With this, you can make more complex configurations such as adding redis or rabbitMQ (with Django Celery, explained in a previous article), and the best part is that the configuration is simply adapting what exists to the specific needs of the project.
References:
- Quickstart: Compose and Django.
- Packaging Django applications into Docker container images.
- Deploying Django on Docker.
- Docker Explained: How to Create Docker Containers Running Memcached.
- Docker in running integration tests in NodeJS.
Make a donation! If you liked the article you can make a donation in Bitcoin (BTC) using the digital wallet of your choice to the following address: 17MtNybhdkA9GV3UNS6BTwPcuhjXoPrSzV
Or by scanning the QR code from your wallet:
