Перевод по методу Ильи Франка. Сначала часть текста с вставками-переводами, потом без перевода.

Django development (разработка) environment (окружение/среда) (среда разработки) with Docker — A step by step (шаг за шагом) guide (руководство) (пошаговое руководство).

Django development environment with Docker — A step by step guide

About Docker

Docker is the software development and devops ("development и operations" - девопс) tool (инструмент) everyone wants to use for their (своих) projects. It’s a platform that allows (позволит) you to easily create isolated (изолированное) environments (aka Containers - так называемые Контейнеры) that can run specific pieces (определенные части) of software. In other words (другими словами), it provides (предоставит) a lightweight (легкий) mechanism to “virtualize” environments in a host computer (хост).

Docker is the software development and devops tool everyone wants to use for their projects. It’s a platform that allows you to easily create isolated environments (aka Containers) that can run specific pieces of software. In other words, it provides a lightweight mechanism to “virtualize” environments in a host computer.


This is a very powerful (мощный) tool for development since (поскольку) it simplifies (упрощает) the process of configuring (конфигурирования) and setting up (создания) environments or switching (переключения) between completely (полностью/совершенно) different projects in the same (в одном и том же) development box (боксе(?) разработки). But, most importantly (самое главное), it allows developers (разработчикам) to consistently (последовательно) reproduce (воспроизводить) production (производственные) environments and avoid (избегать) problems due to (due - в связи, due to - из-за) configuration differences (различий в конфигурации).

This is a very powerful tool for development since it simplifies the process of configuring and setting up environments or switching between completely different projects in the same development box. But, most importantly, it allows developers to consistently reproduce production environments and avoid problems due to configuration differences.


Particularly (в частности) in Django there are (есть/существуют) some (некоторые) common (общие/распространенные) errors that can arise (возникать) with (при) the default settings configuration (настройках по умолчанию) and their differences with a typical (типичный) production deployment (деплой/развертывание ПО). When using (когда используется/при использовании) SQLite as a development database (в качестве БД разработки), which lacks (не хватает/отсутствует) DDL constraints (ограничения), you can encounter (столкнуться) some (некоторыми) migrations failing (проавалами/неудачными миграции) in production (продакшн: стадия использования продукта клиентом) even if you were able (в состоянии) to run (запустить) them perfectly (прекрасно) on your local environment. Another (другой) common source (источник) of problems can be the difference between serving (обслуживание/предоставление) static files using the runserver command and the existence (наличие) of a Web server with a reverse proxy (обратный прокси-сервер) in production. Also (кроме того), if you use Memcached in production you might not be able to reproduce (воспроизвести) invalidation errors (недействительные(?) ошибки), and so on (и т.д.).

Particularly in Django there are some common errors that can arise with the default settings configuration and their differences with a typical production deployment. When using SQLite as a development database, which lacks DDL constraints, you can encounter some migrations failing in production even if you were able to run them perfectly on your local environment. Another common source of problems can be the difference between serving static files using the runserver command and the existence of a Web server with a reverse proxy in production. Also, if you use Memcached in production you might not be able to reproduce invalidation errors, and so on.


The advisable (желательно) thing to do would be to configure your development box exactly as (exactly as - точно так же как) the production environment, but switching between projects wouldn’t be (было бы не) that easy and you don’t want to have all the services running while doing other tasks. That’s where (именно здесь) virtualization becomes (становится) handy (удобной).

The advisable thing to do would be to configure your development box exactly as the production environment, but switching between projects wouldn’t be that easy and you don’t want to have all the services running while doing other tasks. That’s where virtualization becomes handy.


Using Docker for development
As an example (для примера) we are going (собираемся) to go through (через) the process of creating a Django application (приложения) from scratch (from scratch - с нуля) as setting up (создание) two of the most (наиболее) common (распространенных) external (внешних) services you would use in production; MySQL and NGINX.

As an example we are going to go through the process of creating a Django application from scratch as setting up two of the most common external services you would use in production; MySQL and NGINX.

Create a Django project
First (сначала) we create an empty virtual environment (виртуальное окружение) and initialize (инициализируем/создадим) our Django project.

First we create an empty virtual environment and initialize our Django project.

$ mkvirtualenv djangodocker
$ pip install django
$ django-admin startproject djangodocker

MySQL
In order to (чтобы) use MySQL instead (вместо) of SQLite we are going to edit the default settings.

In order to use MySQL instead of SQLite we are going to edit the default settings.

$ vim djangodocker/settings.py
# replace your default DATABASES section for this one
DATABASES = {
  'default': {
  'ENGINE': 'django.db.backends.mysql',
  'NAME': 'djangodocker_db',
  'USER': 'root',
  'PASSWORD': 'root',
  'HOST': '127.0.0.1', # Or an IP Address that your DB is hosted on
  'PORT': '3306',
  }
}

Add (добавим) the Python driver and attempt (попытаемся) to run migrations.

Add the Python driver and attempt to run migrations.

$ pip install MySQL-python
$ python manage.py migrate
django.db.utils.OperationalError: (2002, "Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)")

Naturally (натурально/естественно), the connection to MySQL fails (не удалось) since (поскольку) we aren’t running (не запустили) any (какой-либо) server locally. Instead of installing it in your OS as you normally would (как вы обычно делаете) we are going to run a Container with a MySQL installation inside it (с установленным MySQL внутри). Luckily (к счастью) Docker has a public hub which hosts (размещается) lots (множество) of Container images (образов) with the most (самыми) popular services. The one that (один из которых) includes a MySQL installation is called (называется) mysql and we are going to start it with the command docker run. We are also passing (передаем) the -p parameter to expose (выставить/открыть) the Port 3306 outside (вне) the container, and also (также) a database name with a root password.

Naturally, the connection to MySQL fails since we aren’t running any server locally. Instead of installing it in your OS as you normally would we are going to run a Container with a MySQL installation inside it. Luckily Docker has a public hub which hosts lots of Container images with the most popular services. The one that includes a MySQL installation is called mysql and we are going to start it with the command docker run. We are also passing the -p parameter to expose the Port 3306 outside the container, and also a database name with a root password.

$ docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=djangodocker_db mysql
$ mysql -h127.0.0.1 -proot -uroot
mysql> show DATABASES;
$ python manage.py migrate

You can now check (проверить) that your migrations run and your database is correctly initialized. But what happens if you run the Container again (снова)?

You can now check that your migrations run and your database is correctly initialized. But what happens if you run the Container again?

$ docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=djangodocker_db mysql
$ python manage.py migrate

You’ll see that migrations are lost (потеряны) and you need (нужно) to execute (запустить) them again. This is because (это потому что/это связано с тем, что) run command creates and starts a Container in the same action (в одном действии), so (поэтому) every time (каждый раз) you use run you are actually (фактически) creating a new Container from scratch (с нуля). In order to (In order to - чтобы) reuse (повторно использовать) the same (тот же) image (образ) with persisted (сохраненными) data (данными), first you need to find out (find out - узнать) the image name and then you can use the start command.

You’ll see that migrations are lost and you need to execute them again. This is because run command creates and starts a Container in the same action, so every time you use run you are actually creating a new Container from scratch. In order to reuse the same image with persisted data, first you need to find out the image name and then you can use the start command.

$ docker container ls --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
61f76cdccfd3 mysql "docker-entrypoint..." 7 minutes ago Exited (0) 4 seconds ago 0.0.0.0:3306->3306/tcp flamboyant_wozniak
$ docker start flamboyant_wozniak

NGINX
Similarly (аналогично), we are going to follow (следовать) the same process to launch a Container with an NGINX server running. The image we will be using is called nginx and you are encouraged (поощряетесь/рекомендуется) to check the documentation in the Hub page.

Similarly, we are going to follow the same process to launch a Container with an NGINX server running. The image we will be using is called nginx and you are encouraged to check the documentation in the Hub page.

The configuration file we are going to use for our basic application will look like this.

The configuration file we are going to use for our basic (основного) application will look (выглядеть) like this (как-то так/следующим образом).

upstream django_server {
 server 127.0.0.1:8001 fail_timeout=0;
}
server {
 listen 80;
 client_max_body_size 4G;
 server_name localhost;
 keepalive_timeout 5;
 location /static/ {
  root /usr/share/nginx/djangodocker/;
  expires 30d;
 }
 location / {
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header Host $http_host;
  proxy_redirect off;
  if (!-f $request_filename) {
  proxy_pass http://django_server;
  break;
  }
 }
}

In order to use this file from the container we are going to create it on our project directory and map (отобразить) it as a Data Volume. Data Volumes are a way (способ) to share (обмена) files between the host and the Container context. That way (таким образом) you can destroy and create new Containers that use those files while keeping (сохраняя) them intact (неповрежденными).

In order to use this file from the container we are going to create it on our project directory and map it as a Data Volume. Data Volumes are a way to share files between the host and the Container context. That way you can destroy and create new Containers that use those files while keeping them intact.

$ vim nginx.conf
$ docker run -v /home/fernando/djangodocker/nginx.conf:/etc/nginx/nginx.conf:ro -d nginx

You can now run your Django application locally making sure (making sure - убедившись) you expose (показываете/открыли) the development server to external (внешним) requests (запросам) and on the port 8001.

You can now run your Django application locally making sure you expose the development server to external requests and on the port 8001.

$ python manage.py runserver 0.0.0.0:8001

But when you browse (перейдете) to http://localhost/ you’ll see a Bad Request response (ответ), something (что-то) in the reverse proxy (в обратном прокси сервере) configuration is failing (не удалось). That’s because (связано с тем) the Docker Container localhost IP refers (относится) to the Container itself (самому Контейнеру) and not to the outside host (а не к внешнему хосту) which is running the Python process. In order to make the configuration work we’ll need to find the IP address of our host from inside (изнутри) the network of the container. To do that we are going to run an interactive shell (интерактивную оболочку/командную строку) on the NGINX Container and use the route command to get (получить) the host IP.

But when you browse to http://localhost/ you’ll see a Bad Request response, something in the reverse proxy configuration is failing. That’s because the Docker Container localhost IP refers to the Container itself and not to the outside host which is running the Python process. In order to make the configuration work we’ll need to find the IP address of our host from inside the network of the container. To do that we are going to run an interactive shell on the NGINX Container and use the route command to get the host IP.

$ docker container exec -it distracted_kare /bin/bash
# apt update
# apt install net-tools
# route | awk ‘/^default/ { print $2 }’

Now update (обновим) the nginx.conf file to use that IP address in the upstream_server section instead (вместо) of the 127.0.0.1, restart the container and it should (должен) be working.

There’s one more thing (Есть еще одна вещь) to complete (завершить) the configuration (настройку). If you browse to the /admin section you’ll see that static files (статические файлы/статика) are not working. That’s because NGINX is expecting (ожидает) to serve (обслуживания) them from an inexistent (несуществующего) location (места) in the Container. We need to map (сопоставить) it also with a Data Volume.

Now update the nginx.conf file to use that IP address in the upstream_server section instead of the 127.0.0.1, restart the container and it should be working.

There’s one more thing to complete the configuration. If you browse to the /admin section you’ll see that static files are not working. That’s because NGINX is expecting to serve them from an inexistent location in the Container. We need to map it also with a Data Volume.

$ python manage.py collectstatic
$ docker run -v /home/fernando/djangodocker/nginx.conf:/etc/nginx/conf.d/default.conf:ro -v /home/fernando/djangodocker/static/:/usr/share/nginx/djangodocker/static/ -p 80:80 nginx

Docker Compose

There’s (Есть) an easier (более простой) way to run both containers every time we are working on the project (над проектом) and that’s with (с помощью) the Docker Compose tool.
To use it we just (только/просто) need  to create a docker-compose.yml file on our project directory with all the parameter we’ve been using to run our Containers. The file should look like this.

There’s an easier way to run both containers every time we are working on the project and that’s with the Docker Compose tool.
To use it we just need to create a docker-compose.yml file on our project directory with all the parameter we’ve been using to run our Containers. The file should look like this.

version: '2'
services:
 db:
  image: mysql
  environment:
  MYSQL_DATABASE: djangodocker_db
  MYSQL_ROOT_PASSWORD: root
  ports:
  — "3306:3306"
 nginx:
  image: nginx
  volumes:
  — ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
  — ./static:/usr/share/nginx/djangodocker/static
  ports:
  — "80:80"

You can now launch everything with the following command.

$ docker-compose up

Note (замечание): since this will be creating new Images you will have to run an interactive shell on the NGINX instance (экземпляре) and check for the host IP to fix (фиксировал) the nginx.conf file the first time you run the Container.

Note: since this will be creating new Images you will have to run an interactive shell on the NGINX instance and check for the host IP to fix the nginx.conf file the first time you run the Container.

Next steps

You might (возможно) have noticed (заметили) by now (уже) that launching new images is very easy, and that the Hub already has lots of useful (полезных) configurations to use on your projects. I encourage (призываю) you to start playing with them and creating your own compose configurations; as you familiarize (знакомиться) yourself with it you can start looking into (начать изучать) the deployment possibilities (возможности развертывания).

You might have noticed by now that launching new images is very easy, and that the Hub already has lots of useful configurations to use on your projects. I encourage you to start playing with them and creating your own compose configurations; as you familiarize yourself with it you can start looking into the deployment possibilities.

0 комментариев:

Отправить комментарий