Telegram Боты на Aiogram 3.x: Деплой бота через Docker

Приветствую, друзья! Сегодня мы разберемся, как деплоить бота с использованием Docker. Многие новички считают Docker сложным, но, прочитав эту статью, вы поймете, что это не так, и полюбите эту технологию.

Дисклеймер

Цель данного руководства — не обучение Docker, а пример использования этой технологии в контекте телеграмм ботов на aiogram 3. Я не буду сильно акцентировать внимание на таких вещах, как слои, volume, docker-compos, bridge и прочей технической информации более глубокого уровня, чем необходимо для деплоя ботов на VPS сервере.

Далее вы получите пример использования Docker и общее описание методов (команд). Если вам нужны мои обучающие публикации по Docker, сообщите мне об этом любым удобным способом.

Подготовка

Для начала вам нужно обзавестись базой данных PostgreSQL. О том, как развернуть ее на VPS сервере, я писал ТУТ. Также потребуется установить Docker. Новичкам будет удобнее поставить Docker Desktop, если с технологией уже знакомы, используйте консольный вариант.

  1. Установите Docker и запустите его.

  2. Проверьте установку командой: docker –version

Если докер установлен, то вы получите ответ с текущей установленной версией. У меня так:

Docker version 26.1.1, build 4cf5afa

Дальше я открою эту папку через Pycharm, но вы можете вводить все команды через CMD, PowerShell, терминал и так далее.

Функциональность бота мы обсуждали ТУТ, сейчас же сосредоточимся именно на Docker.

В случае если у вас есть свой проект, который вы хотели бы запустить на VPS сервере, то так же читайте далее — старался данное руководство делать универсальным.

Если вы клонировали репозиторий, то можете обнаружить в нем следующие файлы:

5f03f3ca358e7df6f6382e7dcf12c7c3.jpg

Вы видите знакомую структуру с тремя новыми файлами:

  • .dockerignore

  • DockerFile

  • Makefile

Основной файл — DockerFile. Вот его содержимое:

FROM python

WORKDIR /usr/src/app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["/bin/bash", "-c", "python aiogram_run.py"]

Объяснение строк Dockerfile:

  1. FROM python: Использует официальный образ Python.

  2. WORKDIR /usr/src/app: Устанавливает рабочую директорию.

  3. COPY requirements.txt ./: Копирует файл зависимостей.

  4. RUN pip install --no-cache-dir -r requirements.txt: Устанавливает зависимости.

  5. COPY . .: Копирует все файлы.

  6. CMD ["/bin/bash", "-c", "python aiogram_run.py"]: Запускает скрипт.

Немного кулинарной теории

Образ в контексте Docker — это своего рода шаблон или слепок, который содержит всё необходимое для запуска приложения. В образ входят:

  1. Операционная система (или её часть).

  2. Программы и библиотеки, нужные для работы приложения.

  3. Само приложение и его файлы.

Представьте образ как рецепт для приготовления блюда: он содержит все ингредиенты и инструкции, чтобы приготовить это блюдо. Когда вы запускаете контейнер, Docker использует этот образ, чтобы создать рабочую среду для вашего приложения.

На выходе сегодня мы создадим образ с ботом, а затем будем использовать его в созданном контейнере.

Контейнер — это запущенный экземпляр образа. Он работает как отдельная маленькая виртуальная машина или изолированная среда, в которой запускается ваше приложение.

Представьте контейнер как кухню, где по рецепту (образу) готовится блюдо (приложение). Контейнеры обеспечивают, чтобы приложение работало одинаково в разных средах, потому что всё необходимое уже упаковано внутри.

Надеюсь, что доступно объяснил.

.dockerignore

Данный файл работает аналогичным образом с .gitignore, с отличием в том, что тут мы настраиваем игнорирование тех файлов, которые мы не будем включать в свой  Docker-образ.

Makefile

Makefile упрощает процесс создания и запуска Docker-контейнера. Пример Makefile:

run:
	docker run -it -d --env-file .env --restart=unless-stopped --name easy_refer easy_bot_image
stop:
	docker stop easy_refer
attach:
	docker attach easy_refer
dell:
	docker rm easy_refer

Для того чтоб использовать Makefile на операционной системе на которой вы работаете должен быть установлен Make. О том как поставить Make и вообще что это такое я писал в этом посте ССЫЛКА.

Сейчас немного поговорим про команды и флаги, которые нас будут интересовать, а после вернемся к этому файлу.

Нужные команды

Сегодня нам необходимо будет:

Для создания docker-образа нам необходим Dockerfile (описали выше). Далее просто переходим в папку где расположен этот файл и вводим такую команду:

docker build -t name_image .

Пояснение:

  1. docker build:

  2. -t name_image:

    • Опция -t (или --tag) задает тег для создаваемого образа. Тег состоит из имени и, опционально, версии в формате name: tag. В данном случае образ будет называться name_image. Если версия (тег) не указана, Docker по умолчанию присваивает тег latest.

  3. . (точка):

    • Эта часть указывает контекст сборки. Точка обозначает текущую директорию, то есть Docker будет искать Dockerfile и все необходимые файлы в текущей директории для создания образа.

Пример

docker build -t easy_bot_image .

Так как мы указывали в Dockerfile FROM python — автоматически с docker hub подтянется образ python. Так как python у нас записан без тегов — будет установлена версия latest.

Для того чтоб просмотреть все установленные у вас образы воспользуйтесь командой:

docker images

Один из образов будет тот что вы создали. Далее, для взаимодействия с этим образом вам достаточно будет указывать то имя что вы передавали после -t или его IMAGE ID (достаточно первых 2–3 символов, если они уникальны). Я буду использовать имя образа.

0fd458e331d5af08c38e63476e867065.jpg

Теперь нам остается создать контейнер и запустить его.

За создание контейнера отвечает команда create, а за запуск start, но мы можем объеденить эти две команды через run (синтаксический сахар).

При выполнении команды run есть обязательный параметр — это имя или id образа, который будет лежать в основе контейнера. Так же есть дополнительные параметры, которые задаются через флаги.

Давайте рассмотрим команду:

docker run -it -d --env-file .env --restart=unless-stopped --name easy_refer easy_bot_image 

Пояснение:

  1. docker run:

  2. -it:

    • -i (interactive): Запускает контейнер в интерактивном режиме, позволяя взаимодействовать с его стандартным вводом.

    • -t (tty): Подключает терминал к контейнеру, так что у вас будет доступ к его командной строке.

  3. -d:

  4. --env-file .env:

  5. --restart=unless-stopped:

    • Автоматически перезапускает контейнер, если он завершился с ошибкой, но не перезапускает его, если он был остановлен вручную.

  6. --name easy_refer:

  7. easy_bot_image:

Что делает эта команда:

  • Запускает новый контейнер на основе образа easy_bot_image.

  • Назначает контейнеру имя easy_refer.

  • Загружает переменные окружения из файла .env.

  • Запускает контейнер в интерактивном режиме с подключением терминала, но в фоновом режиме.

  • Настраивает контейнер на автоматический перезапуск, если он завершился с ошибкой, но не перезапускает его при ручной остановке.

Перед запуском моего бота необходимо самостоятельно настроить .env файл (положите его в корень бота).

Вот параметры, которые должны быть в файле:

TOKEN=bot_token
ADMINS=список телеграмм айди админов
PG_LINK=ссылка на подключение к постгрес
ROOT_PASS=доп пароль для работы с базой данных

482181dcb7d082c4d91e0548f6850633.jpg

Видим, что бот запустился. Примечательно то, что даже если бы у вас вообще не стоял Python на операционной системе — данный метод бы отработал и бот был запущен.

Давайте посмотрим какие контейнеры у нас есть (запущенные и нет):

docker ps -a

a743ba57bee2373f2e460aebc860fde1.jpg

Видим, что контейнер запущен.

Давайте остановим контейнер, а после удалим его. Затем проверим контейнер:

docker stop easy_refer
docker rm easy_refer
docker ps -a

3afef61b53115635b87bd87a7c823731.jpg

А теперь давайте создадим новый контейнер через Make:

make run

30c62bc7370ce462235cb88547731725.jpg

Да, получили тот же результат. Согласитесь, что это удобно.

Теперь давайте зайдем в запущенный контейнер и посмотрим, что там происходит:

docker attach easy_refer

2050e11a134833e83b8f8046ff1f2047.jpg

Таким образом мы попали во внутреннюю операционную систему нашего контейнера. Внутри мы видим те же логи, что видели бы при обычном запуске. Тут же мы можем остановить контейнер комбинацией клавиш CTRL+C (если внутри контейнера не происходит ничего, то он сам останавливается) или выйти из интерактивного режима (обратно в фон вывести контейнер).

Для того нужно нажать комбинацию клавиш CTRL+p, а затем CTRL+q.

Обратите внимание. Если бы при создании контейнера мы не указали флаг -it, то возможности выйти из интерактивного режима через указанную выше комбинацию клавиш не было бы.

Давайте снова удалим наш контейнер, чтоб не занимал место, и приступим к непосредственному деплою на VPS сервер.

Отправка образа на Docker hub

  1. Выполняем авторизацию на сайте Docker hub

  2. Переименовываем свой image (образ) на имя в таком формате:

docker_username/image_name

Пример в моем случае:

docker tag easy_bot_image yakvenalexx/easy_bot_image

Авторизация:

docker login

Теперь делаем push нашего образа

docker push yakvenalexx/easy_bot_image

0c0a818362bd84adbe279d8fd6020847.jpg

Видим, что все прошло успешно. Теперь давайте зайдем в профиль на docker hub и посмотрим появиился ли у нас там репозиторий:

d58b65530ebee79f61d279e01f87c447.jpg

Репозиторий на месте, а значит что мы завершили подготовку к деплою. Теперь можно удалить ненужные образы с локального компьютера. В моем случае это:

docker rmi easy_bot_image yakvenalexx/easy_bot_image

Отлично! Теперь давайте войдем на свой VPS сервер (я буду пользоваться Ubuntu) и запустим там Docker (на примере вход по SSH с логином и паролем).

Вход по SSH:

ssh user@host
password

Обновление и установка Docker:

sudo apt update -y 
sudo apt upgrade -y
sudo apt install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install docker-ce
sudo systemctl status docker

Статус должен выглядеть примерно так:

7fdc6810ff5b3f5703332f46e8f85526.jpg

Установка Make:

sudo apt install make

Теперь можно проверить версии docker и make.

docker --version
make --verson

Если в обоих случаях видим версию — значит все установлено.

Все ок

Все ок

Отлично. Теперь давайте создадим папку с именем my_bot и закинем в него файл .env и Makefile.

cd ../home
mkdir my_bot
cd my_bot

Теперь скачаем образ. Для этого мы можем зайти в профиль на Docker hub и найти там кнопку копирования:

Жмем на нее и команду вставляем в терминал на VPS сервере

Жмем на нее и команду вставляем в терминал на VPS сервере

docker pull yakvenalexx/easy_bot_image

46e8f4927406bc7b50c6e2bcdae62796.jpg

Тут обратите внимание. Проверьте, чтоб файл Makefile содержал корректное название образа. Если это не так, то откорректируйте файл на сервере через nano или закиньте корректный файл любым удобным для себя способом.

a21f89dd9da232ac35c2f7b8ed88da63.jpg

Выполняем запуск:

make run

bdccffb2a5650486050b96923b9cb5d0.jpg

Заглянем в контейнер и убедимся, что все работает:

make attach

Сразу будет чисто. Важно чтоб после подключения attach ваша программа выдала какие-то логи.

Сразу будет чисто. Важно чтоб после подключения attach ваша программа выдала какие-то логи.

Заключение

Docker действительно упрощает создание и деплой приложений в изолированных контейнерах. С помощью этого руководства вы сможете запустить своего бота на VPS сервере, даже если раньше ничего не знали о Docker. Надеюсь, что вы теперь видите, насколько эта технология может облегчить вашу работу и сделать её более эффективной.

Если у вас возникли вопросы или нужна дополнительная информация, не стесняйтесь обращаться.

Хотели бы вы увидеть цикл моих статей на тему Docker? Подписывайтесь на обновления и ставьте лайки, чтобы не пропустить новые материалы. Ваша поддержка очень важна для меня, ведь без неё все усилия, потраченные на создание контента, теряют смысл.

© Habrahabr.ru