Cat

Docker 7. Разворачивание Telegram-бота в Docker на VPS

В этом посте мы разберёмся как запустить Telegram-бота на VPS сервере в Docker-контейнере, что бы бот был всегда доступен.

Все статьи

Icon Link

Реклама

Icon Link
Применение Docker proDream 29 Февраль 2024 Просмотров: 2927

Следующий шаг после (или даже в процессе) разработки какого-либо проекта – разворачивание (deploy) на сервере. Для этого будем использовать Docker.

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

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

Как установить Docker на Linux, я писал в посте "Docker 2.2 Установка Docker на Linux", но создать контейнер можно и в Windows. Как установить Docker на Windows, я описывал в постах "Docker 1. Подготовка Windows" и "Docker 2.1 Установка Docker Desktop на Windows".

Для разворачивания бота нам необходимо будет проделать следующие действия:

  1. Подготовить Telegram-бота, а именно сделать получение токена и других конфиденциальных данных из переменных окружения вместо прописывания их в коде. Как создать .env-файл описано в посте "AIOgram3 17. Подготовка к разворачиванию на сервере".
  2. Создать Dockerfile - специальный файл, необходимый для создания Docker-образа.
  3. Отправить файлы на сервер.
  4. Запустить бота.

 

Dockerfile.

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

В корневой директории создадим файл с именем Dockerfile. Именно так: без расширения, в одно слово.

В этом файле описываются инструкции, которые выполняет Docker в момент создания образа.

У нас будет шесть инструкций:

  1. Выбор базового образа.
  2. Определение рабочей директории.
  3. Копирование файла requirements.txt.
  4. Выполнение обновления pip и установки зависимостей.
  5. Копирование файлов проекта.
  6. Выполнение команды запуска проекта.

 

Что такое инструкции?

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

Инструкции пишутся следующим образом:

ИНСТРУКЦИЯ параметры_инструцкии

 

Например, инструкция FROM с названием образа:

FROM python:3.11

 

Инструкций в Dockerfile достаточно много. Прочитать подробнее можно в документации: https://docs.docker.com/reference/dockerfile/

Обратите внимание на один момент. Docker-образ создаётся из последовательно выполняемых инструкций. Каждая инструкция создаёт отдельный слой образа. Иногда выгоднее объединять инструкции одного типа вместе для уменьшения количества слоёв, а следовательно и размера образа.

 

Наши инструкции.

Первой инструкцией будет - FROM. Данная инструкция определяет используемый базовый образ. На основе него и будут выполняться дальнейшие инструкции. 
Для нашего бота будем использовать образ python:3.11-slim, где python - название образа, а 3.11-slim его "тег" в данном случае определяющий версию. Также обратите внимание на slim. Часто у готовых образов имеется "полная версия" и "упрощённые". У python есть три основные версии, это:

  • 3.11 - полная версия Python, в данном случае конкретной версии 3.11. Размер образа, примерно, 360 МБ.
  • 3.11-slim - упрощённая версия Python, без части стандартной библиотеки. Размер образа, примерно, 47 МБ.
  • 3.11-alpine - самая "лёгкая" версия основанная на alpine linux. Размер образа, примерно, 18 МБ.

Выбор версии Python остаётся за вами, но имейте в виду, что не весь код будет хорошо себя чувствовать на "облегчённых" версиях.

Второй инструкцией будет - WORKDIR. Она определяет директорию относительно корня файловой системы, в которой будет выполняться проект. В моём случае это /code. Вы можете выбрать другую. Рекомендуется использовать рабочую директорию в Docker-образе.

Третья инструкция COPY. Как понятно из названия, она копирует что-то внутрь образа. В нашем случае на этом шаге мы копируем файл requirements.txt внутрь директории /code.

Четвёртая инструкция, RUN, запускает выполнение команды внутри образа. В нашем случае, это комбинированная при помощи && команда. Сперва мы обновляем pip, а затем устанавливаем необходимые зависимости для проекта.

Пятая инструкция, как и третья - COPY. В данном случае мы копируем всё из директории с Dockerfile внутрь директории /code.

И последняя, шестая, инструкция – это CMD. Данная инструкция выполняет указанную команду при запуске контейнера, основанного на этом образе. Нам необходимо выполнить команду python ./main.py, но просто так мы её написать не можем. Команды необходимо писать в списке строк, разделяя всю команду по пробелам - [ "python", "./main.py" ].

 

Код Dockerfile:

FROM python:3.11-slim  

WORKDIR /code  

COPY requirements.txt /code  
RUN pip install --upgrade pip && pip install -r requirements.txt  

COPY . /code  

CMD [ "python", "./main.py" ]

 

Файл .dockerignore

Перед тем, как перейдём к загрузке файлов на сервер, необходимо позаботиться о том, чтобы в наш образ при копировании не попадали ненужные файлы. Для этого нужно создать .dockerignore-файл. Он по аналогии с .gitingore-файлом будет отсеивать то, что в нём прописано.

.idea  
.vscode  
.git  
**/__pycache__  
*.pyc  
.env

 

Первые две строки фильтруют директории с файлами IDE.
Третья убирает директорию git, если у вас подключена система контроля версий.
Четвёртая и пятая строчки фильтруют от файлов кэша Python.
Последняя строчка не пропускает в образ ваш .env-файл.

 

Загрузка файлов на сервер.

В посте "Разворачивание Django-проекта на PythonAnyWhere" я рассказывал о способе загрузки через git-репозиторий. Для себя я использую иной вариант - sftp.

sftp - это протокол передачи файлов по SSH. Есть различные программы, позволяющие подключиться к серверу и отправить туда файлы. Я рекомендую программу xftp, она бесплатна для частного использования.
Скачать можно на сайте: https://www.netsarang.com/ru/xftp/

Подключаемся к серверу по SSH, используя для передачи git-репозиторий или по sftp для прямой передачи файлов на сервер.

 

Создание образа.

После того как файлы залиты на сервер, настало время создать образ.

Подключаемся к серверу по SSH. Для этого можно использовать различные программы. на подобии PyTTY или xshell, но мне удобнее стандартный PowerShell, обновлённый до 7‑й версии.

Переходим в директорию с проектом, используя команду cd.

Для создания образа выполняем следующую команду:

docker build -t <имя_образа> .

 

Командой docker build мы вызываем сборку образа, далее параметром -t указываем имя образа, последняя точка означает, что Dockerfile для сборки находится в этой же директории.

После нажатия Enter начнётся скачивание базового образа и выполнение инструкций. Если проект большой, это может занять какое-то время. Во время выполнения, консоль будет заблокирована от ввода, как только сборка закончится, появится курсор.

 

Запуск контейнера.

Финишная прямая.

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

docker run --name <имя_контейнера> --env-file=./.env -d <имя_образа>

 

Команда docker run выполняет запуск контейнера из образа.

Параметр --name определяет имя контейнера для удобного ориентирования в списке. Если его не указать, оно будет сгенерировано случайно. Имя контейнера и название образа не должны совпадать.

Параметр --env-file определяет расположение .env-файла для передачи в систему образа переменных окружения. Это необходимо для безопасности, чтобы в контейнере не было файла.

Параметр -d указывает на то, что контейнер будет запущен в фоновом режиме. Если его не прописывать, то контейнер запустится и в терминале будет виден лог в "реальном времени", но в таком случае закрытие терминала вызовет остановку контейнера.

В самом конце команды указывается имя созданного ранее образа.

 

Дополнительные команды:

  • Остановка контейнера - docker stop <имя_контейнера>.
  • Запуск остановленного контейнера - docker start <имя_контейнера>.
  • Перезапуск контейнера - docker restart <имя_контейнера>.
  • Удаление контейнера (когда он остановлен) - docker rm <имя_контейнера>.
  • Удаление образа (когда удалён использующий его контейнер) - docker rmi <имя_образа>.

 

Заключение.

Это всё может показаться сложным, но на деле всё это достаточно быстро запоминается и дальше выполняется "на автомате".
В этом посте я показал запуск простого бота, не требующего дополнительных контейнеров, например, с БД.
Одним из следующих постов будет запуск нескольких контейнеров в одном docker compose сервисе.

Автор

  • 3 сентября 2024 г. 18:47

    Прикольная статья. Подсмотрел тут у Вани что можно .env не передавать в контейнер. Только запускаю по другому docker compose --env-file .env up
    --env-file=./.env - тут я думаю можно не указывать ему что мы берём из текущей директории это и так должно работать автоматом.

  • Реклама