Часть девятая. Деплой проекта

Мы у финиша
Цель: Выгрузить сайт в интернет
Задачи:
  • Указать три способа выгрузки сайта
  • Осуществить первый способ
  • Осуществить второй способ
  • Осуществить третий способ

Какие бывают способы деплоя?

Существует 3 способа выгрузить проект в интернет. Выгрузка проекта называется деплоем.

Способ первый. WGET.

Этот способ самый дешёвый, но при это совершенно не правильный, хоть и простой. При использовании этого способа, сайт будет отображаться страница целиком, но никакие механизмы в нём работать не будут.
  • Шаг 0 (для Windows). Скачать на компьютер wget. Это бесплатная утилита для скачивания сайтов целиком. В UNIX-образных системах она установлена.
  • Шаг 1. Запускаем сервер.
  • Шаг 2. Переходим в терминал/командную строку и пишем команду:
    wget -r -k -l 7 -p -E -nc <http://127.0.0.1:8080/>
  • Шаг 3. Заходим в папку загрузки (по умолчанию – это папка пользователя) и находим папку с проектом.
  • Шаг 4. Выгружаем папку целиком на публичный хостинг.

Способ №2. Деплой при помощи PythonAnywhere

Плюсы данного способа – полноценный деплой и простота настройки. Главный минус – использование стороннего ПО.
Есть много компаний, предоставляющих сервера в интернете. Мы воспользуемся услугами одной из них, с довольно простым процессом публикации: PythonAnywhere (https://www.pythonanywhere.com). PythonAnywhere бесплатен для маленьких приложений с небольшим числом посетителей, и этого будет для нас более чем достаточно.
Другим внешним сервисом, которым мы воспользуемся, будет GitHub (https://github.com) — сервис хостинга кода. Существуют и другие похожие сервисы, но практически у каждого программиста есть GitHub аккаунт.
В итоге код будет в трёх местах. На локальном компьютере мы будем заниматься разработкой и тестированием. Когда результат полностью устроит, мы загрузим свою программу на GitHub. А сайт будет на PythonAnywhere, и мы сможем обновлять его, просто загружая новую версию кода с GitHub.

Git

Git — это «система управления версиями», используемая множеством программистов. Эта программа отслеживает изменения, происходящие с файлами, чтобы впоследствии можно было восстановить состояние кода на нужный момент времени. Это немного похоже на функцию отслеживания изменений в Microsoft Word, но куда мощнее.

Установка Git

Windows

Вы можете загрузить Git с официального сайта git-scm.com. Можно нажимать "дальше, дальше, дальше" на всех этапах установки за исключением одного: на пятом шаге, который называется "Adjusting your PATH environment" (Настройка системной переменной Path), выберите "Use Git and optional Unix tools from the Windows Command Prompt" (Запуск Git и соответствующих Unix утилит через командную строку Windows, нижняя опция). Все остальные настройки можно оставить по умолчанию. Также неплохо будет выбрать опцию "Checkout Windows-style, commit Unix-style line endings".
После окончания установки не забудьте перезапустить командную строку или powershell.

OS X

Загрузи Git с официального сайта git-scm.com и просто следуй инструкциям по установке.

Debian и Ubuntu

command-line
$ sudo apt install git

Fedora

command-line
$ sudo dnf install git

openSUSE

command-line
$ sudo zypper install git

Создаём Git-репозиторий

Git отслеживает изменения определенного набора файлов, который называется репозиторием. Давайте создадим такой для нашего проекта. Откройте консоль и запустите эти команды в папке saitMiigaika:
command-line
$ git init
Initialized empty Git repository in ~/saitMiigaika/.git/
$ git config --global user.name "Your Name"
$ git config --global user.email [email protected]
Инициализировать git-репозиторий придется только один раз за проект.
Git будет отслеживать изменения всех файлов и каталогов в заданной директории, однако некоторые из них мы предпочли бы игнорировать. Для этого нам нужно создать файл .gitignore в корневом каталоге репозитория. Откройте редактор и создай новый файл со следующим содержанием:
.gitignore
*.pyc
*~
__pycache__
myvenv
db.sqlite3
/static
.DS_Store
И сохраните его как .gitignore в корневом каталоге "saitMiigaika".
Используйте команду git status перед git add или в любой другой момент, когда вы не уверены, что изменения — хорошая идея. Это убережёт сайт от таких неприятных сюрпризов, как добавление неправильных файлов. Команда git status возвращает информацию обо всех ранее неотслеживаемых/изменённых/добавленных в git файлах, а также статус ветки и многое другое. Результат должен быть похож на:
command-line
$ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
.gitignore
blog/
manage.py
mysite/
nothing added to commit but untracked files present (use "git add" to track)
И, наконец, мы сохраним наши изменения. Переключаемся на консоль и набираем:
command-line
$ git add --all .
$ git commit -m "My Django MIIGAiK app, first commit"
[...]
13 files changed, 200 insertions(+)
create mode 100644 .gitignore
[...]
create mode 100644 mysite/wsgi.py
Загружаем код в репозиторий GitHub
Зайдите на GitHub.com и создайте новую бесплатную учётную запись.
Затем создайте новый репозиторий и назови его "my-first-blog" (к примеру). Не выбирайте опцию "initialise with a README", не создавайте файл .gitignore (мы сделаем это локально сами) и оставьте лицензию None.
На следующем экране мы видим URL для клонирования репозитория. Выберите вариант "HTTPS" и скопируй ссылку:
Теперь нужно связать локальный репозиторий с репозиторием на GitHub.
Напечатайте у себя в консоли следующую команду (замените \ на имя, указанное при создании аккаунта на GitHub, но без угловых скобок):
command-line
$ git remote add origin https://github.com/<github-username>/my-first-blog.git
$ git push -u origin master
Введите свое имя пользователя и пароль от аккаунта GitHub; мы должны увидеть примерно следующее:
command-line
Username for 'https://github.com': Username
Password for 'https://hjwp\@github.com':
Counting objects: 6, done.
Writing objects: 100% (6/6), 200 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/hjwp/my-first-blog.git
* [new branch] master -> master
Branch master set up to track remote branch master from origin.
Наш код теперь на GitHub. Зайдите на сайт и проверьте.

Настройка блога на PythonAnywhere

Регистрация на PythonAnywhere

PythonAnywhere — это сервис по запуску кода на Python в облаке. Мы будем использовать его, чтобы разместить наш сайт «вживую» в интернете.
Создайте аккаунт уровня "Beginner" на PythonAnywhere. Он бесплатный.

Создание API токена для PythonAnywhere

Это нужно будет сделать только один раз. Когда вы зарегистрируетесь на PythonAnywhere, откроется панель управления (dashboard). На ней в правом верхнем углу будет ссылка на страницу «Account»:
Там выберите вкладку «API token» и нажмите кнопку, на которой написано «Create new API token» (создать новый API token).

Настройка сайта на PythonAnywhere

Вернитесь на главную страницу PythonAnywhere, кликнув логотип. Затем запустите Bash-консоль. Нажав на кнопку bash мы запускаем командную строку, которая находится на серверах PythonAnywhere. Эта командная строка аналогична тому, что есть на компьютере.
Чтобы опубликовать сайт на PythonAnywhere, нужно загрузить на PythonAnywhere код с Github и затем настроить PythonAnywhere так, чтобы он распознал код и запустил веб-приложение. Существуют способы сделать это «вручную», но для PythonAnywhere есть программа-помощник, которая сделает это за нас. Давайте её установим.
PythonAnywhere command-line
$ pip3.6 install --user pythonanywhere
Когда мы это запустим, в консоли будет печататься лог установки. Он начнётся с чего-то вроде Collecting pythonanywhere, а последней будет строчка Successfully installed (...) pythonanywhere- (...).
Теперь запустим эту вспомогательную утилиту, которую только что установили. Она настроит приложение, скачав его код с GitHub. Напечатайте следующее в консоли PythonAnywhere:
PythonAnywhere command-line
$ pa_autoconfigure_django.py https://github.com/<github-username>/my-first-blog.git
Утилита будет печатать в консоль, что она делает:
  • Скачивает код с GitHub
  • Создаёт виртуальное окружение на PythonAnywhere, такое же, как на компьютере
  • Обновляет файл настроек с настройками деплоя
  • Создаёт базу данных на PythonAnywhere, используя команду manage.py migrate
  • Разбирается со статическими файлами
  • Настраивает PythonAnywhere так, чтобы приложение было доступно в интернете
Все эти шаги автоматизированы на PythonAnywhere, но они совершенно такие же, какие надо было бы совершить с любым другим хостинговым сервисом.
Главное, на что нужно обратить внимание сейчас, — это то, что база данных на PythonAnywhere никак не связана с базой данных на компьютере. Поэтому там будут разные посты и разные аккаунты администраторов. Как следствие, для базы на PythonAnywhere необходимо создать аккаунт администратора так же, как мы это дели локально с помощью команды createsuperuser. На PythonAnywhere заранее активировано виртуальное окружение, так что всё, что нужно сделать — это запустить в консоли PythonAnhywhere команду:
PythonAnywhere command-line
(ola.pythonanywhere.com) $ python manage.py createsuperuser
Введите параметры для своего пользователя-админа. Лучше всего использовать те же самые данные, что и на локальном компьютере, чтобы избежать путаницы.
Сейчас, если хотите, посмотрите на файлы на PythonAnywhere с помощью команды ls:
PythonAnywhere command-line
(ola.pythonanywhere.com) $ ls
blog db.sqlite3 manage.py mysite requirements.txt static
(ola.pythonanywhere.com) $ ls blog/
__init__.py __pycache__ admin.py apps.py migrations models.py tests.py views.py

Вариант 3. Без автоматизации PythonAnywhere (не рекомендуется новичку)

Самый сложный, но при этом самый правильный метод настройки, так как нам не потребуется использовать стороннее ПО для деплоя, а это уменьшает число уязвимостей.
Необходимо купить выделенный VDS или VPS сервер. VDS выделяет место на сервере физически, VPS – программным методом.
Предположим, у Вас куплена свежая машина, мы первый раз к ней подключаемся. Используем мы Ubuntu.
Далее буду вводить команды списком, чтобы не запутаться в шагах.
  • Если у вас уже прописан ключ к вашей машине, но он не совпадает, очищаете его
rm .ssh/known_hosts
  • Подключаетесь и вводите пароль от сервера.
ssh root\@5.45.120.175
  • Обновляете пароль рута, если он вас не устраивает
passwd root
  • Обновляем списки репозиториев.
apt-get update
  • Апгредим.
apt-get upgrade
  • Если присутствуют проблемы локали, исправляем их сразу.
perl -v
  • Смотрим, если ругается и есть предупреждения генерируем локаль.
locale-gen en_US en_US.UTF-8 ru_RU.UTF-8
  • Затем реконфигурируем локаль машины.
dpkg-reconfigure locales
  • Вновь проверяем на наличие ошибок
perl -v
  • Ура их нет! Двигаемся дальше. Устанавливаем Nginx.
apt-get install nginx
  • После установки запускаем nginx.
service nginx start
  • Смотрим статус:
service nginx status
  • Если все ок, и он запущен можете открыть страничку вашего сайта и вы увидите
    стартовую страницу nginx. Если же сервер не запустился, проверте, не запущен ли
    у вас apache
service apache2 status
  • Если он запущен стопайте его. Его необходимо полностью удалить.
service apache2 stop
  • Деинсталируем апач и все его конфиги такой вот не хитрой командой:
apt-get purge apache2 apache2-utils apache2.2-bin apache2-common
  • Если какие то пакеты, которые собираемся удалить отсутствуют, просто уберите
    их из команды. Далее:
apt-get autoremove
  • Наконец, надо проверить наличие конфигурационных файлов или мануалов,
    связанных с Apache2, но до сих пор не удаленных.
whereis apache2
  • Удаляете все эти директории вручную. Например, вот так:
rm -rf /etc/apache2
  • Если все удалено, аллилуя. Запускаем nginx. И смотрим статус:
service nginx start
service nginx status
  • Если все ок, заходите на вашу страничку и вы увидете стартовую страницу
    nginx. Идем дальше. Cоздайте пользователя для старта django-приложения. Создайте
    из-под него виртуальное окружение.
apt-get install python3-dev python3-setuptools
easy_install-3.4 virtualenv
adduser django
login django
cd /home/django
virtualenv venv
  • Теперь, переносим проект в эту папку.Устанавливаем git, nano если они не
    установлены.
apt-get install git nano
  • Создаем ключ ssh. Все поля оставляем пустыми.
ssh-keygen -t rsa -C "your_mail\@mail.com"
  • Переходим в директорию ключа, открываем необходимый нам публичный ключ.
    Советую с помощью утилиты sshfs подключиться к вашей машине через gui интерфейс.
    Вам будет необходимо указать адрес машины и папку, в которую поместите файлы
    машины. Например вот так.
sshfs [email protected]:/ /home/user/Develop/sites/my_site/
  • Затем копируете ключ.
/root/.ssh/id_rsa.pub
  • Копируем его в настройки пользователя git репозитория
  • После того, как вы это сделаете, вы сможете спокойно клонировать по ssh репозиторий. Заходите под рутом.
su - root
cd /home/django/
git clone [email protected]:user/my_site.git
  • Симлинк /etc/nginx/sites-enabled/default можно удалить
  • Логинимся под юзером django.
login django
  • Активируем виртуальное окружение.
source venv/bin/activate
  • Устанавливаем Django в наше виртуальное окружене:
pip install Django
  • Переходим в корневую папку проекта.
cd my_site
  • Один из хороших способов установить uWSGI:
pip install uwsgi
  • Проверка. Создаем файл test.py:
nano test.py
  • С таким содержимым:(Если не создается, создайте от рута)
def application(env, start_response):
start_response('200 OK', [('Content-Type','text/html')])
return [b"Hello World"]
  • Запускаем uWSGI:
uwsgi --http :8000 --wsgi-file test.py
  • Если все работает, нажимаем ctrl-c, завершая процесс и продолжаем дальше.
  • Теперь конфигурируем наш сайт. Устанавливаем postgresql. Из под рута.
apt-get install libpq-dev postgresql postgresql-contrib
su - postgres
createdb my_site
createuser -P django
psql
postgres=# GRANT ALL PRIVILEGES ON DATABASE my_site TO django;
su - root
login django
source /home/django/venv/bin/activate
pip install psycopg2
  • Если необходимо перенести БД со старой на новую делается это так:
  • Шаг 1. Выполняется со старыми настройками DATABASES в settings.py python manage.py dumpdata > datadump.json
  • Шаг 2. Выполняется с новыми настройками DATABASES в settings.py python manage.py loaddata datadump.json
  • После этого устанавливаем все библиотеки что есть в requirements.txt. Для этого заходим в папку my_site проектом и вводим следующую команду. Разумеется с помощью виртуального окружения.
pip install -r requirements.txt
  • Если не установилась какая-нибудь библиотека X устанавливайте более позднюю
    версию:
pip install X==2.9.0
  • В файле …/my_site/settings.py обязательно нужно указать настройки базы
    данных:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'my_site',
'USER': 'django',
'PASSWORD': '1234567890',
'HOST': 'localhost',
'PORT': '',
}
}
  • В файле settings.py должен быть такой путь:
MEDIA_ROOT = "/home/django/my_site/media"
  • Делаем миграцию, если это необходимо:
python manage.py migrate
  • Создаем супер пользователя.
python manage.py createsuperuser
  • Запускаем сервер
python manage.py runserver 0.0.0.0:8080
  • Если ошибок не возникло, заходим и настраиваем сайт через панель администратора (если у вас новая свежая база данных без данных).
  • После того, как вы сконфигурировали проект идем дальше. Собираем всю статику (Скорее всего это сработает только из под рута):
python manage.py collectstatic
  • Теперь, вы можете запустить my_site через uwsgi, и если это не сработало, значит вы где то совершили ошибку. Вполне вероятно, о ней сообщат логи uwsgi.
uwsgi --http :8000 --module my_site.wsgi
  • Теперь нам необходимо сконфигурировать nginx. Для начала, создайте файл в корне проекта my_site с названием uwsgi_params, с таким содержанием:
uwsgi_param QUERY_STRING $query_string;
uwsgi_param REQUEST_METHOD $request_method;
uwsgi_param CONTENT_TYPE $content_type;
uwsgi_param CONTENT_LENGTH $content_length;
uwsgi_param REQUEST_URI $request_uri;
uwsgi_param PATH_INFO $document_uri;
uwsgi_param DOCUMENT_ROOT $document_root;
uwsgi_param SERVER_PROTOCOL $server_protocol;
uwsgi_param REQUEST_SCHEME $scheme;
uwsgi_param HTTPS $https if_not_empty;
uwsgi_param REMOTE_ADDR $remote_addr;
uwsgi_param REMOTE_PORT $remote_port;
uwsgi_param SERVER_PORT $server_port;
uwsgi_param SERVER_NAME $server_name;
  • Вообще, лучше поместите этот файл в корень проекта, в папку с названием deployment, чтобы файлы проекта различались с файлами деплоя.
  • Теперь в той же папке создайте файл my_site_nginx.conf
  • Наполните его таким содержимым:
# the upstream component nginx needs to connect to
upstream django {
server unix:///home/django/my_site/uwsgi_nginx.sock; # for a file socket
# server 127.0.0.1:8001; # for a web port socket (we'll use this first)
}
# configuration of the server
server {
# the port your site will be served on
listen 8000;
# the domain name it will serve for
server_name my_site.ru; # substitute your machine's IP address or FQDN
charset utf-8;
# max upload size
client_max_body_size 75M; # adjust to taste
# Django media
location /media {
alias /home/django/my_site/media; # your Django project's media files - amend as required
}
location /static {
alias /home/django/my_site/static; # your Django project's static files - amend as required
}
# Finally, send all non-media requests to the Django server.
location / {
uwsgi_pass django;
include /home/django/my_site/deployment/uwsgi_params; # the uwsgi_params file you installed
}
}
  • В папке /etc/nginx/sites-enabled создаем ссылку на файл mysite_nginx.conf, чтобы nginx увидел его.
sudo ln -s /home/django/rss_news/deployment/rss_news_nginx.conf /etc/nginx/sites-enabled
  • Перезапускаем nginx:
/etc/init.d/nginx restart
  • Помещаем файл с именем, например, media.png в папку /home/django/my_site/media.
  • В браузере переходим по адресу yourserver.com:8000/media/media.png и, если видим наш файл, значит мы все сделали правильно.
  • Пробуем запустить через сокет:
uwsgi --socket uwsgi_nginx.sock --wsgi-file test.py —-chmod-socket=666
  • nginx + uWSGI + Django. Запускаем: В браузере переходим на yourserver.com:8000/ и видим стартовую страницу Django.
uwsgi --socket uwsgi_nginx.sock --module my_site.wsgi --chmod-socket=666
  • Мы собрали всю цепочку, но настройка еще не закончена, идем дальше.
  • Очень удобно все опции, с которыми мы запускаем uWSGI, указать в ini файле, а при запуске передавать только путь к этому файлу. Создаем файл my_site_uwsgi.ini в нашей папке deployment. Указываем в нем следующее содержимое:
#mysite_uwsgi.ini
[uwsgi]
# Настройки, связанные с Django
# Корневая папка проекта (полный путь)
chdir = /home/django/my_site
# Django wsgi файл
module = my_site.wsgi
# полный путь к виртуальному окружению
home = /home/django/venv
# общие настройки
# master
master = true
# максимальное количество процессов
processes = 10
# полный путь к файлу сокета
socket = /home/django/my_site/uwsgi_nginx.sock
# права доступа к файлу сокета
chmod-socket = 666
# очищать окружение от служебных файлов uwsgi по завершению
vacuum = true
env = DEBUG_MODE=False
daemonize=/var/log/uwsgi/my_site.log
  • Запускаем этот файл:
uwsgi --ini my_site_uwsgi.ini
  • Проверяем. Все работает? Дальше. До сих пор uWSGI был установлен в виртуальном окружении. Чтобы была возможность автоматически запускать uWSGI при старте операционной системы, мы установим его глобально. Деактивируем виртуальное окружение:
deactivate
  • Устанавливаем pip и pip3 глобально.
apt-get install python-pip python3-pip
  • Затем, устанавливаем uwsgi глобально.
pip3 install uwsgi
  • Проверяем запуск:
uwsgi --ini my_site_uwsgi.ini
  • Если сервер обслуживает несколько проектов, каждый из которых использует uWSGI, то нужно использовать режим Emperor. В этом режиме uWSGI просматривает папку с конфигурационными файлами и для каждого файла запускает отдельный процесс (вассал).
    Если один из конфигурационных файлов будет изменен, uWSGI перезапустит соответствующего вассала.
    Создаем папку для конфигурационных файлов:
sudo mkdir /etc/uwsgi
sudo mkdir /etc/uwsgi/vassals
  • Создаем в ней ссылку на my_site_uwsgi.ini:
sudo ln -s /home/django/my_site/deployment/my_site_uwsgi.ini /etc/uwsgi/vassals/
  • Запускаем uWSGI в режиме Emperor, потом отключаем если все работает (Возможно вам придется перезапустить вашу БД такой командой sudo service postgresql restart):
uwsgi --emperor "/home/django/my_site/deployment/my_site_uwsgi.ini"
  • Устанавливаем супервизор
apt-get install supervisor
  • Создаем файл конфигурации в папке etc/supervisor/conf.d/my_site.conf:
echo_supervisord_conf > /etc/supervisord.conf
  • В Этом файле указываем следующий текст:
[program:my_site]
command=uwsgi --emperor "/home/django/my_site/deployment/my_site_uwsgi.ini"
stdout_logfile=/home/django/my_site/deployment/uwsgi.log
stderr_logfile=/home/django/my_site/deployment/uwsgi_err.log
autostart=true
autorestart=true
  • Индексируем этот файл: (Если появляются какие то ошибки, перезапускаем supervisor (service supervisor restart)) Так же, смотрим логи.
supervisorctl reread
supervisorctl update
  • Все должно работать. Управлять supervisor можно как сервисом:
service supervisor start|stop|status ...
  • Если происходят какие то изменения в коде, выполняем эту команду в папке deployment:
service supervisor stop
touch my_site_uwsgi.ini
service supervisor start
  • Команда supervisorctl покажет запущенные приложения императором.
  • Если необходимо запустить проект в режиме дебага, меняем значение DEBUG_MODE=False на DEBUG_MODE=True в файле конфигурации uwsgi.
  • Готово!