.. index:: pair: Docker ; Django (for beginners) pair: William ; Vincent pair: Tutoriaux ; William Vincent pair: Docker ; djangox .. _william_vincent: ========================================================= **Django for beginners** par William Vincent ========================================================= .. contents:: :depth: 3 Thanks to William Vincent ! ============================ .. seealso:: - https://twitter.com/wsv3000 - https://wsvincent.com/django-docker-postgresql/ - https://github.com/wsvincent/djangox - https://gitlab.com/gdevops/wsdjangoforbeginners .. figure:: william_vincent.png :align: center https://twitter.com/wsv3000 :: total 52 drwxrwxr-x. 6 pvergain pvergain 4096 28 mai 16:10 ch10-bootstrap drwxrwxr-x. 6 pvergain pvergain 4096 28 mai 16:10 ch11-password-change-reset drwxrwxr-x. 6 pvergain pvergain 4096 28 mai 16:10 ch12-email drwxrwxr-x. 7 pvergain pvergain 4096 28 mai 16:10 ch13-newspaper-app drwxrwxr-x. 7 pvergain pvergain 4096 28 mai 16:10 ch14-permissions-and-authorizations drwxrwxr-x. 7 pvergain pvergain 4096 28 mai 16:10 ch15-comments drwxrwxr-x. 4 pvergain pvergain 92 28 mai 16:10 ch2-hello-world-app drwxrwxr-x. 5 pvergain pvergain 103 28 mai 16:10 ch3-pages-app drwxrwxr-x. 5 pvergain pvergain 4096 28 mai 16:15 ch4-message-board-app drwxrwxr-x. 7 pvergain pvergain 4096 28 mai 16:10 ch5-blog-app drwxrwxr-x. 7 pvergain pvergain 4096 28 mai 16:10 ch6-blog-app-with-forms drwxrwxr-x. 7 pvergain pvergain 4096 28 mai 16:10 ch7-blog-app-with-users drwxrwxr-x. 4 pvergain pvergain 4096 28 mai 16:10 ch8-custom-user-model drwxrwxr-x. 5 pvergain pvergain 4096 28 mai 16:10 ch9-user-authentication -rw-rw-r--. 1 pvergain pvergain 689 28 mai 16:15 Readme.md tree ch4-message-board-app ============================= .. seealso:: - https://gitlab.com/gdevops/wsdjangoforbeginners :: tree ch4-message-board-app :: ch4-message-board-app/ ├── Dockerfile ├── manage.py ├── mb_project │   ├── __init__.py │   ├── settings.py │   ├── urls.py │   └── wsgi.py ├── Pipfile ├── Pipfile.lock ├── posts │   ├── admin.py │   ├── apps.py │   ├── __init__.py │   ├── migrations │   │   ├── 0001_initial.py │   │   └── __init__.py │   ├── models.py │   ├── tests.py │   ├── urls.py │   └── views.py ├── Procfile └── templates └── home.html .. _docker_django36: Installing django with pipenv and python 3.6 ============================================== .. seealso:: - https://wsvincent.com/django-docker-postgresql/ - https://gitlab.com/gdevops/wsdjangoforbeginners/blob/master/ch4-message-board-app/Dockerfile Dockerfile ----------- :: cat Dockerfile :: FROM python:3.6 ENV PYTHONUNBUFFERED 1 COPY . /code/ WORKDIR /code/ RUN pip install pipenv RUN pipenv install --system EXPOSE 8000 Pipfile -------- :: $ cat Pipfile :: [[source]] url = "https://pypi.python.org/simple" verify_ssl = true name = "pypi" [packages] gunicorn = "*" django = "*" "psycopg2" = "*" [dev-packages] [requires] python_version = "3.6" docker build --tag gdevops/django36_ch4 . ================================================== .. seealso:: - :ref:`docker_build` We can’t run a Docker container until it has an image so let’s do that by :ref:`building it `. :: docker build --tag gdevops/django36_ch4 . :: Sending build context to Docker daemon 48.82MB Step 1/7 : FROM python:3.6 3.6: Pulling from library/python cc1a78bfd46b: Pull complete 6861473222a6: Pull complete 7e0b9c3b5ae0: Pull complete 3ec98735f56f: Pull complete 9b311b87a021: Pull complete 048165938570: Pull complete 1ca3d78efb22: Pull complete 0f6c8999c3b7: Pull complete 5a85410f5000: Pull complete Digest: sha256:52a2bd143faf6430b182b56a5fdeb70f26b8ca8fbd40210c3ed8a8ee1eaba343 Status: Downloaded newer image for python:3.6 ---> 29d2f3226daf Step 2/7 : ENV PYTHONUNBUFFERED 1 ---> Running in ee1ad676c613 Removing intermediate container ee1ad676c613 ---> 8fb46520978f Step 3/7 : COPY . /code/ ---> 3a6b8395d66b Step 4/7 : WORKDIR /code/ Removing intermediate container 72885dc811e1 ---> e0c26850ab99 Step 5/7 : RUN pip install pipenv ---> Running in 19666f95212b Collecting pipenv Downloading https://files.pythonhosted.org/packages/8d/fe/4faa519acfb984015dde4e2973d89e47baf6a9cd81e9d58e2f2d3c47fb6f/pipenv-2018.5.18-py3-none-any.whl (6.4MB) Requirement already satisfied: setuptools>=36.2.1 in /usr/local/lib/python3.6/site-packages (from pipenv) (39.1.0) Collecting certifi (from pipenv) Downloading https://files.pythonhosted.org/packages/7c/e6/92ad559b7192d846975fc916b65f667c7b8c3a32bea7372340bfe9a15fa5/certifi-2018.4.16-py2.py3-none-any.whl (150kB) Collecting virtualenv (from pipenv) Downloading https://files.pythonhosted.org/packages/b6/30/96a02b2287098b23b875bc8c2f58071c35d2efe84f747b64d523721dc2b5/virtualenv-16.0.0-py2.py3-none-any.whl (1.9MB) Collecting virtualenv-clone>=0.2.5 (from pipenv) Downloading https://files.pythonhosted.org/packages/6d/c2/dccb5ccf599e0c5d1eea6acbd058af7a71384f9740179db67a9182a24798/virtualenv_clone-0.3.0-py2.py3-none-any.whl Requirement already satisfied: pip>=9.0.1 in /usr/local/lib/python3.6/site-packages (from pipenv) (10.0.1) Installing collected packages: certifi, virtualenv, virtualenv-clone, pipenv Successfully installed certifi-2018.4.16 pipenv-2018.5.18 virtualenv-16.0.0 virtualenv-clone-0.3.0 Removing intermediate container 19666f95212b ---> 2f8d9ee873ca Step 6/7 : RUN pipenv install --system ---> Running in baca593927a8 Installing dependencies from Pipfile.lock (c2c6d4)… Removing intermediate container baca593927a8 ---> 2d402a8f0e26 Step 7/7 : EXPOSE 8000 ---> Running in c3e7a4b032d8 Removing intermediate container c3e7a4b032d8 ---> b44a8c214cdf Successfully built b44a8c214cdf Successfully tagged gdevops/django36_ch4:latest docker images ========================== .. seealso:: - :ref:`docker_images` :: $ docker images --no-trunc :: REPOSITORY TAG IMAGE ID CREATED SIZE gdevops/django36_ch4 latest sha256:b44a8c214cdfc23f6f8a4481277028fd56b1adcce615f92f703ddca728e054e0 5 minutes ago 1.04GB python 3.6 sha256:29d2f3226daf297b27f0240244f4e8d614fb63eeab8cd09d816e8b7b04d1c011 3 weeks ago 911MB mb_project/settings.py ======================= .. code-block:: python # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases # https://djangoforbeginners.com/docker-postgresql/ DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'postgres', 'USER': 'postgres', 'HOST': 'db', # set in docker-compose.yml 'POST': 5432 # default postgres port } } .. _dockercompose_db_web: Launch the db and web services with docker-compose.yml ========================================================= .. code-block:: yaml version: '3' services: db: image: postgres:10.4 volumes: - postgres_data:/var/lib/postgresl/data/ web: build: . command: python /code/manage.py migrate --noinput command: python /code/manage.py runserver 0.0.0.0:8000 volumes: - .:/code ports: - "8000:8000" depends_on: - db volumes: postgres_data: On the top line we’re using the most recent version of Compose which is **3**. db --- Under **db** for the database we want the Docker image for Postgres 10.4 and use volumes to tell Compose where the container should be located in our Docker container. web ---- For **web** we’re specifying how the web service will run. First Compose needs to build an image from the current directory, automatically run migrations and hide the output, then start up the server at 0.0.0.0:8000. volumes -------- We use volumes to tell Compose to store the code in our Docker container at /code/. .. warning:: Cela nous permet d'avoir accès à notre code sur le host. ports ------ The ports config lets us map our own port 8000 to the port 8000 in the Docker container. And finally depends_on says that we should start the db first before running our web services. volumes --------- The last section volumes is because Compose has a rule that you must list named volumes in a top-level volumes key. Docker is all set! docker-compose run web python /code/manage.py migrate --noinput ================================================================= :: $ docker-compose run web python /code/manage.py migrate --noinput :: Creating network "ch4-message-board-app_default" with the default driver Creating volume "ch4-message-board-app_postgres_data" with default driver Pulling db (postgres:10.4)... 10.4: Pulling from library/postgres f2aa67a397c4: Pull complete 8218dd41bf94: Pull complete e9b7fa2e6bd8: Pull complete 7288a45ee17f: Pull complete 0d0f8a67376c: Pull complete 972b115243de: Pull complete d38528c83dd1: Pull complete 9be166d23dee: Pull complete 12015b5ceae7: Pull complete 363876c09ce9: Pull complete b810ba8b2ac0: Pull complete e1ee11d636cf: Pull complete 50d32813cba1: Pull complete 4f0109485c03: Pull complete Digest: sha256:1acf72239c685322579be2116dc54f8a25fc4523882df35171229c9fee3b3b17 Status: Downloaded newer image for postgres:10.4 Creating ch4-message-board-app_db_1 ... done Building web Step 1/7 : FROM python:3.6 ---> 29d2f3226daf Step 2/7 : ENV PYTHONUNBUFFERED 1 ---> Using cache ---> 8fb46520978f Step 3/7 : COPY . /code/ ---> 3b31f2bb6016 Step 4/7 : WORKDIR /code/ Removing intermediate container 183aa302c2d1 ---> fd032580fe90 Step 5/7 : RUN pip install pipenv ---> Running in 8f333f7716ee Collecting pipenv Downloading https://files.pythonhosted.org/packages/8d/fe/4faa519acfb984015dde4e2973d89e47baf6a9cd81e9d58e2f2d3c47fb6f/pipenv-2018.5.18-py3-none-any.whl (6.4MB) Collecting certifi (from pipenv) Downloading https://files.pythonhosted.org/packages/7c/e6/92ad559b7192d846975fc916b65f667c7b8c3a32bea7372340bfe9a15fa5/certifi-2018.4.16-py2.py3-none-any.whl (150kB) Requirement already satisfied: setuptools>=36.2.1 in /usr/local/lib/python3.6/site-packages (from pipenv) (39.1.0) Requirement already satisfied: pip>=9.0.1 in /usr/local/lib/python3.6/site-packages (from pipenv) (10.0.1) Collecting virtualenv (from pipenv) Downloading https://files.pythonhosted.org/packages/b6/30/96a02b2287098b23b875bc8c2f58071c35d2efe84f747b64d523721dc2b5/virtualenv-16.0.0-py2.py3-none-any.whl (1.9MB) Collecting virtualenv-clone>=0.2.5 (from pipenv) Downloading https://files.pythonhosted.org/packages/6d/c2/dccb5ccf599e0c5d1eea6acbd058af7a71384f9740179db67a9182a24798/virtualenv_clone-0.3.0-py2.py3-none-any.whl Installing collected packages: certifi, virtualenv, virtualenv-clone, pipenv Successfully installed certifi-2018.4.16 pipenv-2018.5.18 virtualenv-16.0.0 virtualenv-clone-0.3.0 Removing intermediate container 8f333f7716ee ---> f27a4a1e4257 Step 6/7 : RUN pipenv install --system ---> Running in 2519166487e4 Installing dependencies from Pipfile.lock (c2c6d4)… Removing intermediate container 2519166487e4 ---> 255cb3b345c2 Step 7/7 : EXPOSE 8000 ---> Running in 8cb1c964976e Removing intermediate container 8cb1c964976e ---> 376512737492 Successfully built 376512737492 Successfully tagged ch4-message-board-app_web:latest WARNING: Image for service web was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`. Operations to perform: Apply all migrations: admin, auth, contenttypes, posts, sessions Running migrations: 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 auth.0008_alter_user_username_max_length... OK Applying auth.0009_alter_user_last_name_max_length... OK Applying posts.0001_initial... OK Applying sessions.0001_initial... OK docker-compose run web python /code/manage.py createsuperuser =============================================================== :: $ docker-compose run web python /code/manage.py createsuperuser :: WARNING: The Docker Engine you're using is running in swarm mode. Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node. To deploy your application across the swarm, use `docker stack deploy`. Starting ch4messageboardapp_db_1 ... done Username (leave blank to use 'root'): Email address: patrick.vergain@id3.eu Password: Password (again): The password is too similar to the email address. This password is too short. It must contain at least 8 characters. Password: Password (again): Superuser created successfully. .. figure:: create_superuser.png :align: center docker-compose run web python /code/manage.py createsuperuser docker-compose up =================== :: Y:\projects_id3\P5N001\XLOGCA135_tutorial_docker\tutorial_docker\tutoriels\djangoforbeginners\ch4-message-board-app>docker-compose up :: WARNING: The Docker Engine you're using is running in swarm mode. Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node. To deploy your application across the swarm, use `docker stack deploy`. ch4messageboardapp_db_1 is up-to-date Creating ch4messageboardapp_web_1 ... done Attaching to ch4messageboardapp_db_1, ch4messageboardapp_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 | running bootstrap script ... ok db_1 | performing post-bootstrap initialization ... ok db_1 | syncing data to disk ... ok 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: 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 | 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....2018-01-23 08:34:30.556 UTC [39] LOG: listening on IPv4 address "127.0.0.1", port 5432 db_1 | 2018-01-23 08:34:30.557 UTC [39] LOG: could not bind IPv6 address "::1": Cannot assign requested address db_1 | 2018-01-23 08:34:30.557 UTC [39] HINT: Is another postmaster already running on port 5432? If not, wait a few seconds and retry. db_1 | 2018-01-23 08:34:30.682 UTC [39] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" db_1 | 2018-01-23 08:34:30.865 UTC [40] LOG: database system was shut down at 2018-01-23 08:34:28 UTC db_1 | 2018-01-23 08:34:30.928 UTC [39] LOG: database system is ready to accept connections db_1 | done db_1 | server started db_1 | ALTER ROLE db_1 | db_1 | db_1 | /usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/* db_1 | db_1 | 2018-01-23 08:34:31.493 UTC [39] LOG: received fast shutdown request db_1 | waiting for server to shut down....2018-01-23 08:34:31.557 UTC [39] LOG: aborting any active transactions db_1 | 2018-01-23 08:34:31.559 UTC [39] LOG: worker process: logical replication launcher (PID 46) exited with exit code 1 db_1 | 2018-01-23 08:34:31.560 UTC [41] LOG: shutting down db_1 | 2018-01-23 08:34:32.052 UTC [39] 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 | 2018-01-23 08:34:32.156 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432 db_1 | 2018-01-23 08:34:32.156 UTC [1] LOG: listening on IPv6 address "::", port 5432 db_1 | 2018-01-23 08:34:32.256 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432" db_1 | 2018-01-23 08:34:32.429 UTC [57] LOG: database system was shut down at 2018-01-23 08:34:31 UTC db_1 | 2018-01-23 08:34:32.483 UTC [1] LOG: database system is ready to accept connections web_1 | Performing system checks... web_1 | web_1 | System check identified no issues (0 silenced). web_1 | January 23, 2018 - 08:46:09 web_1 | Django version 2.0.1, using settings 'mb_project.settings' web_1 | Starting development server at http://0.0.0.0:8000/ web_1 | Quit the server with CONTROL-C. We can confirm it works by navigating to http://127.0.0.1:8000/ where you’ll see the same homepage as before. .. figure:: post_1.png :align: center http://127.0.0.1:8000/admin/posts/post/1/change/ docker-compose ps ==================== :: PS Y:\projects_id3\P5N001\XLOGCA135_tutorial_docker\tutorial_docker\tutoriels\william_vincent\ch4-message-board-app> docker-compose ps :: Name Command State Ports ------------------------------------------------------------------------------------------ ch4messageboardapp_db_1 docker-entrypoint.sh postgres Up 5432/tcp ch4messageboardapp_web_1 python /code/manage.py run ... Up 0.0.0.0:8000->8000/tcp :: docker-compose exec db bash =============================================== :: docker-compose exec db bash psql -d db -U postgres ======================= :: root@ee941cf5bc20:/# psql -U postgres :: psql (10.1) Type "help" for help. \dt ----- :: postgres=# \dt :: List of relations Schema | Name | Type | Owner --------+----------------------------+-------+---------- public | auth_group | table | postgres public | auth_group_permissions | table | postgres public | auth_permission | table | postgres public | auth_user | table | postgres public | auth_user_groups | table | postgres public | auth_user_user_permissions | table | postgres public | django_admin_log | table | postgres public | django_content_type | table | postgres public | django_migrations | table | postgres public | django_session | table | postgres public | posts_post | table | postgres (11 rows) \conninfo ---------- :: postgres=# \conninfo :: You are connected to database "postgres" as user "postgres" via socket in "/var/run/postgresql" at port "5432". :: postgres=# \l :: List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -----------+----------+----------+------------+------------+----------------------- postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + | | | | | postgres=CTc/postgres (3 rows) \dn ---- :: postgres=# \dn List of schemas Name | Owner --------+---------- public | postgres (1 row) \d posts_post --------------- :: postgres=# \d posts_post :: Table "public.posts_post" Column | Type | Collation | Nullable | Default --------+---------+-----------+----------+---------------------------------------- id | integer | | not null | nextval('posts_post_id_seq'::regclass) text | text | | not null | Indexes: "posts_post_pkey" PRIMARY KEY, btree (id)