Деплой Python программ на Linux
⠀Для беспрерывной работы Python программы необходимо задеплоить её на сервер. На Linux это можно сделать двумя способами, описанными в данной статье.
Содержание
Windows или Linux?
⠀У обоих систем есть как плюсы, так и минусы.
Windows
- Для большинства привычная система;
- Программы могут работать с графическим интерфейсом (приложения с GUI, кликер, работа с браузером и т. п.);
- Возможность запуска программ без установки Python (при помощи EXE файла, созданного библиотекой на подобии PyInstaller).
- Высокая стоимость аренды сервера;
- Низкое соотношение цена-производительность;
- Скудный выбор хостингов с адекватными ценами;
- Нестабильность (зависит от хостинга);
- Через профиль одного пользователя можно заходить одновременно только с одного устройства.
Linux
- Возможность запуска программ без установки Python (в Docker контейнере).
- Низкая стоимость аренды сервера;
- Высокое соотношение цена-производительность;
- Большой выбор хостингов с адекватными ценами;
- Более стабильная работа (зависит от хостинга);
- Через профиль одного пользователя можно заходить одновременно с нескольких устройств.
Способы деплоя
⠀В обоих системах существует по 2 основных способа.
- Скомпилировать исполняющий EXE файл, перенести его на сервер и запускать программу (лёгкий, быстрый и предпочтительный);
- Установить Python, перенести проект на сервер, установить все зависимости и запустить исполняющий файл (более сложный, медленный и не наполненный смыслом).
- Создать Docker образ с программой и запустить в качестве контейнера (более сложный, быстрый и предпочтительный);
- Установить Python и запустить при помощи сервисного файла (лёгкий, долгий, но не предпочтительный).
⠀Способы деплоя на Linux подробно расписаны в следующем разделе.
Деплой
Подготовка
⠀У себя на ПК в виртуальном окружении проекта Python создать файл с используемыми библиотеками
pip freeze > requirements.txt
⠀При необходимости создать папку, в которую будут помещёны все программы, например
mkdir python_programs; cd python_programs
⠀Создать папку для запускаемой программы и перейти в неё
mkdir program_name; cd program_name
⠀Загрузить необходимые файлы из проекта на сервер в созданную ранее папку с виртуальным окружением.
Docker
⠀Прочитать статью про создание Docker образа.
. <(wget -qO- https://raw.githubusercontent.com/SecorD0/utils/main/installers/docker.sh)
⠀Создать у себя на ПК Dockerfile и прописать в нём инструкции создания образа, например
FROM python:3.9.7-slim WORKDIR /program COPY . . RUN pip install --upgrade pip; \ pip install -r requirements.txt ENTRYPOINT ["python3"] CMD ["main.py"]
⠀Образ python:3.9.7-slim
имеет минимальный размер, около 140 Мб. Есть вероятность, что придётся доустанавливать что-то недостающее или указать другой образ из списка.
⠀Если программа взаимодействует c БД по типу MySQL, то необходимо установить её в соседний контейнер или на сервер. Информацию о том, как это сделать с Docker, необходимо найти в интернете. Статьи про MySQL на английском: первая, вторая.
⠀Загрузить созданный Dockerfile в папку с программой на сервере.
cd $HOME/python_programs/program_name
docker build -t program_name .
docker run -dit --restart always \ -v $HOME/python_programs/program_name/:/program \ --name program_name program_name
⠀В команду добавлена опция -v
, которая сопоставляет исходный код внутри контейнера с тем, что располагается на хосте. Это позволяет обновить исходный код на хосте и при перезапуске контейнера обновить его внутри него.
⠀Удостовериться в корректном запуске программы, просмотрев лог
docker logs program_name -fn 100
⠀⠀Добавить команду для просмотра лога программы в систему в виде переменной
. <(wget -qO - https://raw.githubusercontent.com/SecorD0/utils/main/miscellaneous/insert_variable.sh) \ -n "program_name_log" -v "docker logs program_name -fn 100" -a
⠀При обновлении исходного кода программы необходимо загрузить обновлённые файлы в папку с программой на сервере и перезапустить контейнер командой
docker restart program_name
Сервисный файл
⠀Прочитать статью про параметры сервисного файла.
sudo apt update && sudo apt upgrade -y
⠀Установить необходимые пакеты
sudo apt install wget -y
⠀Запустить скрипт установки Python 3.9.7
. <(wget -qO - https://raw.githubusercontent.com/SecorD0/utils/main/installers/python.sh)
⠀При желании можно поставить другую версию (все версии), указав её через опцию -v
, например
. <(wget -qO - https://raw.githubusercontent.com/SecorD0/utils/main/installers/python.sh) \ -v "3.9.1"
⠀Дождаться окончания установки (10-20 минут)
⠀Python будет установлен в папку
/usr/local/python
python3 -m pip install --upgrade pip
⠀Установить виртуальное окружение
pip install virtualenv
⠀Добавить команду активации виртуального окружения в систему в виде переменной
. <(wget -qO - https://raw.githubusercontent.com/SecorD0/utils/main/miscellaneous/insert_variable.sh) -n "venv_py" -v ". venv/bin/activate" -a
cd $HOME/python_programs/program_name
⠀Создать виртуальное окружение
virtualenv venv
⠀Активировать виртуальное окружение
venv_py
⠀Установить необходимые зависимости
pip install -r requirements.txt
⠀Запустить программу и удостовериться, что она работает корректно
python3 main.py
⠀Остановить программу сочетанием клавиш Ctrl+C
, если она циклична, и деактивировать окружение командой
deactivate
⠀В блокноте подставить в команду свои значения и запустить её из директории с программой, тем самым создать сервисный файл
printf "[Unit] Description=Program Name After=network-online.target [Service] User=$USER EnvironmentFile=/etc/environment Environment=PYTHONUNBUFFERED=1 WorkingDirectory=`pwd` ExecStart=`pwd`/venv/bin/python3 main.py Restart=on-failure RestartSec=3 [Install] WantedBy=multi-user.target" > /etc/systemd/system/program_name.service
Description
— название программы;Environment=PYTHONUNBUFFERED=1
— для выводаprint(…)
в лог программы;WorkingDirectory
— автоматически подставляется путь до папки с программой;ExecStart
— необходимо подставить название исполняемого файла, напримерmain.py
,app.py
;
⠀Если программа работает нециклично, то можно настроить её периодический запуск, для этого нужно:
sudo systemctl daemon-reload sudo systemctl enable program_name sudo systemctl restart program_name
⠀Удостовериться в корректном запуске программы, просмотрев лог
journalctl -n 100 -f -u program_name
⠀Добавить команду для просмотра лога программы в систему в виде переменной
. <(wget -qO - https://raw.githubusercontent.com/SecorD0/utils/main/miscellaneous/insert_variable.sh) \ -n "program_name_log" -v "journalctl -n 100 -f -u program_name" -a
⠀При обновлении исходного кода программы необходимо загрузить обновлённые файлы в папку с программой на сервере и перезапустить сервисный файл командой
sudo systemctl restart program_name
MySQL (бонус)
Установка
. <(wget -qO- https://raw.githubusercontent.com/SecorD0/utils/main/installers/mysql.sh)
sudo mysql
⠀Задать пароль root пользователя
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password by 'PASSWORD';
exit
⠀Выполнить предварительную настройку, запустив команду
sudo mysql_secure_installation
⠀Ввести заданный ранее пароль и ответить на дальнейшие вопросы y
или n
:
Настройка
⠀Для подключения к MySQL можно использовать два вида пользователей:
⠀Для создания такого пользователя необходимо подключиться к MySQL
sudo mysql -u root
CREATE DATABASE DATABASE_NAME;
CREATE USER 'YOUR_USERNAME'@'localhost' IDENTIFIED BY 'YOUR_PASSWORD';
⠀Дать пользователю все права в созданной БД
GRANT ALL PRIVILEGES ON DATABASE_NAME.* TO 'YOUR_USERNAME'@'localhost'; FLUSH PRIVILEGES;
⠀При попытке подключения к MySQL через root пользователя появится ошибка
1698 (28000): Access denied for user 'root'@'localhost'
⠀Чтобы её исправить, необходимо подключиться к MySQL
sudo mysql -u root
⠀Изменить тип подключения root пользователя
USE mysql; ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'YOUR_PASSWORD'; FLUSH PRIVILEGES;
Удаление
Все БД со всеми таблицами будут удалены.
⠀Поэтому во избежании потери данных необходимо экспортировать все БД в файлы командой
sudo mysqldump -u root -p DATABASE_NAME > DATABASE_FILE_NAME.sql
⠀MySQL полностью удаляется скриптом
. <(wget -qO- https://raw.githubusercontent.com/SecorD0/utils/main/installers/mysql.sh) -u
Полезные команды
Docker
program_name_log docker logs program_name -fn 100
docker images
docker ps -a
⠀Удаление контейнера с программой
docker stop program_name docker rm program_name
⠀Перезапуск программы (например при обновлении кода)
docker restart program_name
Сервисный файл
program_name_log journalctl -n 100 -f -u program_name
sudo systemctl stop program_name
⠀Перезапуск программы (например при обновлении кода)
sudo systemctl restart program_name
MySQL
⠀Если был изменён тип подключения root пользователя, то в каждую команду необходимо добавлять опцию -p
и вводить пароль после её исполнения
sudo mysql -u root sudo mysql -u root DATABASE_NAME
Ctrl + D exit
sudo mysqldump -u root -p DATABASE_NAME > DATABASE_FILE_NAME.sql
sudo mysql -u root -p DATABASE_NAME < DATABASE_FILE_NAME.sql
⠀SQL команды (выполнять после подключения к MySQL)
/* список пользователей */ SELECT user, host FROM mysql.user; /* показать список БД */ SHOW DATABASES; /* создать БД */ CREATE DATABASE DATABASE_NAME; /* перейти в БД */ USE DATABASE_NAME; /* показать список таблиц */ SHOW TABLES; /* показать формат столбцов таблицы */ DESCRIBE TABLE_NAME; /* показать содержимое таблицы */ SELECT * FROM TABLE_NAME;
Полезные ссылки
Контейнеризация Python приложения (EN) | Python и MySQL (EN)
Подключение Python приложения к MySQL в Docker (EN)
Благодарности
Команда 1package — написание статьи