Віртуалізація процесу розробки, частина 1: Docker
- Перш, ніж почати
- Docker
- Установка Docker і Docker-Compose
- образ Docker
- Організація роботи контейнерів
- Скрипт для повторного розгортання
- Розгортання всередині контейнера
- процес розробки
- GIT
- статичні файли
Привіт, мене звати Андрій двояко. Я фахівець з комплексної розробки веб-додатків в українському стартапі Preply.com , Це платформа для пошуку репетиторів. За останній рік наша команда виросла, і для полегшення процесу адаптації нових розробників ми вирішили організувати і стандартизувати наш процес розробки.
Ми присвятили багато часу пошуку кращих методик та обговорення з іншими командами, прагнучи з'ясувати, який шлях найбільш ефективний для організації процесу розробки і розподілу доступу, особливо коли ваш продукт розділений на кілька мікросервісов. У підсумку ми зупинилися на двох основних технологіях: Vagrant і Docker. Ви можете прочитати про всі аспекти та особливості у самих творців цих сервісів на StackOverflow .
У цьому керівництві я покажу вам, як «докерізіровать» ваше додаток, щоб ви таким чином могли зручно і просто поширити і розгорнути його на будь-якій машині, яка підтримує Docker.
Перш, ніж почати
У цьому керівництві ми будемо працювати з простим додатком Django з базою PostgerSQL і Redis в якості брокера для виконання завдань Celery . Також ми використовуємо Supervisor для запуску нашого сервера Gunicorn . Ми будемо використовувати технологію Docker Compose , Щоб організувати роботу нашого мультіконтейнерного додатки. Зверніть увагу, що Compose 1.5.1 вимагає Docker 1.8.0 або більш пізні версії.
Це допоможе нам запустити додаток Django, PostgreSQL і Redis Server і Celery Worker в окремих контейнерах і зв'язати їх між собою. Щоб реалізувати це все, нам потрібно всього лише створити кілька файлів в кореневому каталозі вашого проекту Django поруч з файлом manage .py):
- Dockerfile - для створення фінального образу і завантаження його в DockerHub;
- redeploy .sh - для розгортання в обох середовищах DEV і PROD;
- docker-compose.yml - організувати роботу декількох контейнерів;
- Vagrantfile - надати віртуальну машину для середовища розробки.
Ми використовуємо змінну RUN_ENV для визначення поточної середовища. Ви набираєте на клавіатурі export RUN_ENV = PROD на робочому сервері і export RUN_ENV = DEV на віртуальній машині Vagrant.
Docker
Як ви, можливо, вже знаєте, про Docker потрібно знати дві речі: образи та контейнери. Ми створимо образ, заснований на Ubuntu з встановленими Python, PIP і іншими інструментами, необхідними для запуску вашого застосування Django. У цьому образі буде встановлено все, що необхідно. Цей образ направимо в публічне сховище в DockerHub. Майте на увазі, що цей образ не містить жодного файлу вашого проекту.
Ми домовилися зберігати наш образ на DockerHub завжди оновленим. З цього образу ми завантажимо контейнер, пробрасивая специфічні порти і монтуючи ваш локальний каталог з проектом до якоїсь папці всередині контейнера. Це означає, що файли вашого проекту будуть доступні всередині контейнера. Ніякої необхідності копіювати файли! Це дуже зручно для процесу розробки, тому що ви можете вносити зміни в ваші файли, і вони відразу ж будуть змінені в працюючому контейнері Docker, але це неприйнятно в реальному робочому середовищі.
Як тільки ви запустили контейнер, ми запустимо Supervisor з вашим сервером Gunicorn. Як тільки ви захотіли зробити повторне розгортання, ми винесемо нові дані з GitHub, зупинимо і видалимо існуючий контейнер і запустимо абсолютно новий контейнер. Справжнє диво!
Установка Docker і Docker-Compose
Перш ніж почати, нам потрібно встановити Docker і Docker-Compose на наш локальний комп'ютер або сервер. Нижче вказано скрипт, який це робить на Ubuntu 14.04:
sudo -i echo 'debconf debconf / frontend select Noninteractive' | debconf-set-selections curl -sSL https://get.docker.com/ | sh curl -L https://github.com/docker/compose/releases/download/1.5.1/docker-compose-`uname -s`-`uname -m`> / usr / local / bin / docker-compose chmod + x / usr / local / bin / docker-compose usermod -aG docker ubuntu sudo reboot
Тут ubuntu - ваш поточний користувач.
Якщо ваша поточного середовища розробки не Ubuntu 14.04 - тоді вам буде краще використовувати Vagrant для створення цього середовища. Детальніше розповім в наступній статті.
образ Docker
По-перше, для підготовки проекту до розгортання докерів нам потрібно створити образ за допомогою тільки Python, PIP і декількох залежностей, необхідних для запуску Django.
Давайте створимо новий докер файл під назвою Dockerfile в кореневому каталозі проекту. Це буде виглядати так:
FROM ubuntu: 14.04 MAINTAINER Andrii Dvoiak RUN echo 'debconf debconf / frontend select Noninteractive' | debconf-set-selections RUN apt-get update RUN apt-get install -y python-pip python-dev python-lxml libxml2-dev libxslt1-dev libxslt-dev libpq-dev zlib1g-dev && apt-get build-dep -y python-lxml && apt-get clean # Specify your own RUN commands here (eg RUN apt-get install -y nano) ADD requirements.txt requirements.txt RUN pip install -r requirements.txt WORKDIR / project EXPOSE 80
Ви можете вказати ваші власні команди RUN, наприклад, встановити інші необхідні інструменти.
Потім вам потрібно створити образ з цього, використовуючи команду:
docker build -t username / image
Тут username - ваше ім'я користувача Dockerhub і image - назва вашого нового образу для даного проекту.
Коли вам успішно вдалося створити основний образ, краще буде вам завантажити в хмару DockerHub. Це можна зробити командою docker push username / image. І не переживайте, в цьому образі немає ніякої інформації з вашого проекту (крім файлу requiremets .txt). Якщо ви використовуєте приватне сховище DockerHub, упевніться у виконанні docker login перед завантаженням / вивантаженням образів.
Організація роботи контейнерів
Отже, на даному етапі ми можемо запустити наш контейнер з додатків Django, але нам також потрібно запустити деякі інші контейнери c Redis, базою даних PostgreSQL і Celery Worker. Щоб спростити цей процес, ми скористаємося технологією Docker Compose , Яка дозволяє нам створити простий файл YML з інструкціями про те, які контейнери запускати і як лінковані їх між собою.
Давайте створимо цей чарівний файл і назвемо його за замовчуванням docker-compose .yml:
django: image: username / image: latest command: python manage.py supervisor environment: RUN_ENV: "$ RUN_ENV" ports: - "80: 8001" volumes: -.: / project links: - redis - postgres celery_worker: image: username / image: latest command: python manage.py celery worker -l info links: - postgres - redis postgres: image: postgres: 9.1 volumes: - local_postgres: / var / lib / postgresql / data ports: - "5432: 5432" environment : POSTGRES_PASSWORD: "$ POSTGRES_PASSWORD" POSTGRES_USER: "$ POSTGRES_USER" redis: image: redis: latest command: redis-server --appendonly yes
Як ви бачите, ми запустимо чотири проекти під назвами django, celery_worker, postgres і redis. Ці назви важливі для нас.
Отже, по-перше, наш файл завантажить образ Redis з dockerhub і запустить з нього контейнер. По-друге, він завантажить образ Postgres і запустить контейнер із закріпленими даними з радела local_postgres. Про створення локальної бази даних розповім детальніше в следющие статті.
Потім, цей файл запустить контейнер з нашим додатком Django, направить 8001-й порт зсередини на 80-й зовні, зв'яже ваш поточний каталог прямо з папкою / project всередині контейнера, пролінкует його з контейнерами Redis і Postgres і запустить супервайзера. І останнє, але не менш важливе - наш контейнер з celery worker, який також пролінкован з Postgres і Redis.
Ви можете направити будь-яку кількість портів, якщо необхідно - для цього просто додайте нові записи до відповідного розділу. Також ви можете пролінковать будь-яку кількість контейнерів, наприклад, контейнер з вашою базою даних. Використовуйте тег: latest для автоматичної перевірки оновленого образу на DockerHub.
Якщо ви назвали проект Redis Server ім'ям redis в файлі YML - вам потрібно вказати redis замість localhost в вашому settings .py щоб дозволити вашому додатку Django під'єднатися до redis:
REDIS_HOST = "redis" BROKER_URL = "redis"
Те ж з базою даних Postgres - використовуйте postgres замість localhost:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'database_name', 'USER': os.getenv ( 'DATABASE_USER', ''), 'PASSWORD': os.getenv ( 'DATABASE_PASSWORD', ''), 'HOST': 'postgres', 'PORT': '5432',}}
Скрипт для повторного розгортання
Давайте створимо скрипт для повторного розгортання в один клік (давайте назвемо його redeploy .sh):
#! / Bin / sh if [-z "$ RUN_ENV"]; then echo 'Please set up RUN_ENV variable' exit 1 fi if [ "$ RUN_ENV" = "PROD"]; then git pull fi docker-compose stop docker-compose rm -f docker-compose up -d
Давайте перевіримо, що він робить:
- Він перевіряє, чи встановлена змінна RUN_ENV і здійснює вихід, якщо немає
Якщо RUN_ENV встановлена на PROD, він зробить команду 'git pull' щоб отримати нову версію вашого проекту;
- Він зупинить всі проекти, зазначені в файлі docker-compose.yml;
- Він видалить всі існуючі контейнери;
- Він запустить нові контейнери.
Отже, це виглядає досить просто: щоб зробити повторне розгортання, вам потрібно всього лише запустити ./redeploy .sh. Не забудьте дати права на виконання (chmod + x redeploy .sh) цього скрипту і всім іншим скриптам, наведеної в документації.
Щоб зробити швидке повторне розгортання, використовуйте цю команду:
docker-compose up --no-deps -d django
Розгортання всередині контейнера
Нам потрібно всього лише запустити супервайзера для того, щоб власне запустити наш сервіс всередині контейнера: python manage .py supervisor. Якщо ви не використовуєте супервайзер, ви можете просто запустити ваш сервер замість супервайзера.
Якщо ж ви користуєтеся супервайзером, давайте подивимося на файл 'supervisord.conf':
[Supervisord] environment = C_FORCE_ROOT = "1" [program: __ defaults__] redirect_stderr = true startsecs = 10 autorestart = true [program: gunicorn_server] command = gunicorn -w 4 -b 0.0.0.0:8001 YourApp.wsgi: application directory = { {PROJECT_DIR}} stdout_logfile = {{PROJECT_DIR}} / gunicorn.log
Отже, супервайзер запустить ваш сервер Gunicorn з 4 працюючими процесами і пов'язаним портом 8001.
процес розробки
Щоб зайти на ваш локальний сервер, пройдіть по 127.0.0.1:8000 .
Для повторного розгортання локальних змін зробіть:
sh redeploy .sh
Щоб переглянути всі логи в вашому проекті, виконайте:
docker-compose logs
Щоб швидко реалізувати повторне розгортання змін, використовуйте:
docker-compose restart django
Щоб під'єднатися до Django - просто під'єднувати (якщо ваш працює контейнер названий CONTAINER):
docker exec -it CONTAINER python manage .py shell
Щоб створити початкового суперкористувача:
from django.contrib.auth.models import User; User.objects.create_superuser ( 'admin', '[email protected] ',' Admin ')
Виконати міграцію:
docker exec -it CONTAINER python manage .py schemamigration blabla -auto
Або ви можете під'єднатися до bash всередині контейнера:
docker exec -it CONTAINER / bin / bash
Ви можете зберегти вашу локальну базу даних в файл .json (ви можете вказати таблицю для збереження):
docker exec -it CONTAINER python manage.py dumpdata> testdb.json
Або ви можете завантажити дані в вашу базу даних з файлу:
docker exec -it CONTAINER python manage.py loaddata testdb.json
Використовуйте цю команду для моніторингу статусу ваших працюють контейнерів:
docker stats $ (docker ps -q)
Використовуйте цю команду для видалення всіх зупинених контейнерів:
docker rm -v `docker ps -a -q -f status = exited`
Ви можете гратися з вашими контейнерами як вам захочеться. Тут - корисний Docker cheat sheet .
GIT
Коли сервер працює, він буде створювати додаткові файли, такі як .log, .pid і так далі. Вам не потрібно їх включати в репозиторій. Не забудьте створити файл .gitignore:
.idea db.sqlide3 * .pyc * .ini * .log * .pid / static .vagrant /
статичні файли
У вас можуть виявитися деякі проблеми в роботі зі статичними файлами на робочому сервері при використанні тільки gunicorn, тому не забудьте створити порожню папку / static / в вашому кореневому каталозі проекту з файлом __init__ .py для обслуговування з нього статики.
За цією схемою ваш файл settings. py повинен включати:
STATIC_URL = '/ static /' STATIC_ROOT = os.path.join (BASE_DIR, 'static')
І для обслуговування статики за допомогою gunicorn на робочому сервері додайте це в кінець файлу urls .py:
SERVER_ENVIRONMENT = os.getenv ( 'RUN_ENV', '') if SERVER_ENVIRONMENT == 'PROD': urlpatterns + = patterns ( '', (r '^ static / (? P <path>. *) $', 'Django. views.static.serve ', {' document_root ': settings.STATIC_ROOT}),)
Або ж ви можете користуватися іншими сервісами для обслуговування статичних файлів, наприклад, використовувати сервер nGinx.
PS У наступній статті я розповім, як запустити Docker практично де завгодно за допомогою Vagrant. Також розглянемо, як створювати середовище розробки на віртуальній машині, яку ви можете легко передати вашим співробітникам, не турбуючись про те, які операційні системи встановлені у них локально.