Целью этой статьи я не ставил объяснять, что такое docker. Так же, как и про его установку и настройку я не буду рассказывать. Если вы этого не знаете, то вам следует сначала хотя бы поверхностно ознакоится с нею и только потом вернуться к данной статье. Жаль, что я не смог раньше прийти к данному материалу, но, надеюсь, что после его прочтения вы сможете так же легко, как и я, разворачивать проекты для разработки с помощью docker.
На самом деле, даже понимая, как работает docker, мне было достаточно сложно освоить то, как на нем без боли и страданий поднять проект и спокойно разрабатывать. В силу не только обстоятельств, но и некоторых своих предпочтений на моей рабочей лошадке стои windows, что делает немного неудобным процесс разработки web приложений на python, и приходится прибегать к магии: сначала был virtualbox, потом (дай Бог ему долгой жизни) vagrant. Но когда захотелось проникнуться темой использования docker, я как то втянулся и пока счастливо живу с ним. Надеюсь и вам понравится, хотя в начале пути всех ждут трудности и разочарование.
Дальше будет меньше слов и больше интересного кода.
Docker-Compose
Да, именно он помог мне избавиться от боли в мозгу, когда я не мог склеить два контейнера. Именно он поможет нам быстро развернуть проект и запустить. Честно признаюсь, хоть я и не сторонник запуска с docker на production, но один сайт я все таки запустил. И он не просто работает, еще и заказчик доволен ).
Что нам дает docker-compose? С его помощью мы соберем контейнеры, прицепим дисковое пространство, установим необходимые пакеты и запустим все это. Про него можете почитать здесь, а потом продолжим историю.
Для начала же давайте определимся с файловой структурой. Здесь я приведу пример того, как мне удобно работать. Я уверен, что ты сообразительный малый и, если нужно, сам сообразишь что на что поменять и как все это улучшить. Основную директорию, где мы будем создавать все файлы и откуда будем все запускать, я кратко назову DEV_PATH. Это может быть C:/work/site1/ или /home/user/site2 или где то еще. Жирным выделяю названия директорий. Курсивом - файлов.
- DEV_PATH
- docker
- nginx
- sitename.conf
- python
- Dockerfile
- nginx
- <project> (Это директория с python проектом. Название проекта, соответственно, таким, как ты назовешь его. )
- logs
- <project>
- settings.py
- wsgi.py
- gunicorn.py
- requirements.txt
- docker-compose.yml
- docker
Dockerfile
Его мы создали для контейнера python. Именно здесь больше работы приходится производить, так как нам нужно установить приложения, пакеты и примонтировать директории. Ниже содержимое файла.
FROM python:3.6 COPY ./<project> /srv/www/<project> WORKDIR /srv/www/<project> RUN pip install -r requirements.txt
Построчно:
- Указываем имя контейнера, на основе кторого будем это все собирать. Я использую официальный контейнер под python 3.6. Ты можешь выбрать свою версию.
- Указываем что и куда мотировать. Я использую директорию /srv/www/имя_проекта для лаконичности. Важно понимать, что лучше указывать путь до проекта так, как он будет выглядеть на твоем сервере. Приближаем окружение к боевой системе.
- Указываем эту же директорию как точку входя при выполнении следующих команд.
- Запускаем установку пакетов из requirements.txt. После этого твой образ сохранится уже с этими пакетами и тебе не придется каждый раз пересобирать их. главное заранее подготовить файл со всеми нужными пакетами. Каждый раз, меняя requirements.txt, придется перезапускать сборку образа и, соответственно, с нуля устанавливать эти пакеты.
sitename.conf
Обычный файл конфигурации nginx. Он нужен для того, чтобы сразу после запуска nginx "скушал" наш проект.
# portal server { listen 8080; # nginx будет слушать этот порт. server_name localhost; charset utf8; autoindex off; access_log /srv/www/<project>/logs/<project>_access.log; error_log /srv/www/<project>/logs/<project>_error.log error; set $project_home /srv/www/<project>; location / { root $project_home; try_files $uri @<project>; } location @<project> { proxy_pass http://python:8000; # gunicorn запускается в контейнере python и слушает порт 8000 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
На этом настройка nginx заканчивается, но сам образ еще будем ковырять.
gunicorn.py
Если нет желания запускать с ним, то, пожалуй, можете через manage.py runserver или иначе. Но мне gunicorn кажется весьма удачным решением. Вот конфигурационный файл.
from multiprocessing import cpu_count from os import environ def max_workers(): return cpu_count() bind = '0.0.0.0:' + environ.get('PORT', '8000') max_requests = 1000 worker_class = 'gevent' workers = max_workers() env = { 'DJANGO_SETTINGS_MODULE': '<project>.settings' } reload = True name = 'Project_name'
не забываем в requirements.txt добавить gevent и gunicorn
docker-compose.yml
Наконец то дошли к самому сладкому. Приведу пример файла, а в нем все пояснения, чтобы мы не потеряли что для чего делалось.
version: '3' # хранилища volumes: pgdata: driver: local services: nginx: # при падении будет стараться подняться restart: always # только свежий nginx image: nginx:latest # слушает порт 8080 expose: - 8080 # мапаем порт 80 на его 8080. Тогда сайт будет доступен по адресу localhost. Убедись, что порт у тебя не занят. ports: - "80:8080" # монтируем только те директории, в которых лежит статика, т.к. nginx с динамикой не будет работать. Также директорию с логами и файл настройки, который мы подготовили. volumes: - ./<project>/static:/srv/www/<project>/static - ./<project>/media:/srv/www/<project>/media - ./<project>/logs:/srv/www/<project>/logs - ./docker/nginx:/etc/nginx/conf.d # и nginx зависит от контейнера python. Т.е. python должен быть запущен первым depends_on: - python python: restart: always # указываем откуда собирать образ build: context: . dockerfile: docker/python/Dockerfile # монтируем директорию проекта volumes: - ./<project>:/srv/www/<project> expose: - 8000 ports: - 8000:8000 # запускаем gunicorn command: "gunicorn -c gunicorn.py <project>.wsgi" postgres: # Ниже даже расписывать не хочу, насколько все просто: логин, пароль, БД, порты и т.д. image: postgres:9.3.22 ports: - 5432:5432 environment: POSTGRES_USER: username POSTGRES_PASSWORD: postgresql_password POSTGRES_DB: database_name PGDATA: /var/lib/postgresql/data volumes: - pgdata:/var/lib/postgresql/data
Поехали
Ниже привожу только команды. Выполнять их нужно из директории, где лежит yml файл.
Сборка
docker-compose build
Запуск
docker-compose up -d
Остановка
docker-compose down
Не прощаясь
Надеюсь, что тебе поможет, если не понять как собирать сложные окружения, то, хотя бы как я, окружение для разработки стандартных проектов. Скоро расскажу как поднимать окружение для npm + gulp + bower с кучей сладких надстроек. Так что - возвращайся.