Введение: Зачем нам это нужно?
Привет, Хабр! ?
Давайте смоделируем ситуацию, которая знакома каждому начинающему разработчику (и мне тоже).
Вы написали своего первого или десятого Telegram-бота. У вас на компьютере всё работает идеально: вы жмете зеленую кнопку Run в PyCharm или VS Code, бот оживает, отвечает на сообщения и радует глаз. Вы чувствуете себя хакером.
Но потом возникает проблема: бот работает только тогда, когда включен ваш компьютер и запущена программа. Стоит закрыть ноутбук или случайно закрыть терминал — и бот «умирает», а пользователи видят тишину.
Вы решаете пойти дальше: покупаете самый дешевый VPS-сервер за 100 рублей, чтобы бот жил там вечно. И тут начинается ад ручной настройки:
На сервере нет Python или стоит какая-то древняя версия 3.6.
Вы пытаетесь установить библиотеки, но вылезают ошибки совместимости с Linux.
Вы забыли, какие именно библиотеки устанавливали полгода назад, потому что не вели
requirements.txt.В итоге вы тратите 3 часа на настройку окружения вместо того, чтобы писать код.
А теперь представьте, что всего этого можно избежать.
Что такое Docker (простыми словами)?
Представьте, что ваш код — это домашний обед.
Чтобы пообедать в гостях (на сервере), вам обычно нужно прийти к ним на кухню, искать кастрюли, надеяться, что у них есть плита и нужные специи. Если плиты нет — вы голодаете (код падает с ошибкой).
Docker — это ваш ланчбокс (контейнер).
Вы кладете туда не только еду (ваш код), но и сразу свою вилку, любимую приправу и даже маленькую микроволновку. Теперь неважно, куда вы пришли: на пустой сервер, на компьютер друга или на мощный кластер. Вы просто открываете контейнер, и всё работает точно так же, как у вас дома.
Что мы сделаем сегодня?
Мы перестанем запускать ботов «на коленке». За 10 минут мы:
Подготовим проект по всем правилам.
Напишем простую инструкцию (
Dockerfile) для упаковки бота.Запустим его в изолированном контейнере, который будет работать стабильно и предсказуемо.
Поехали!
2. Подготовка проекта (Pre-flight check)
Прежде чем упаковывать нашего бота, давайте убедимся, что у нас есть что упаковывать, и проект выглядит опрятно. Docker любит порядок.
1. Минимальный код бота
Для примера возьмем простейшего бота на aiogram 3.x. Если у вас уже есть свой сложный проект — отлично, используйте его. Если нет — создайте файл bot.py и вставьте туда этот код:
import asyncio
import logging
import os
from aiogram import Bot, Dispatcher, types
from aiogram.filters import CommandStart
# Включаем логирование, чтобы не пропустить важные сообщения
logging.basicConfig(level=logging.INFO)
# Важный момент: мы НЕ пишем токен прямо в коде.
# Мы будем передавать его "снаружи", когда запустим контейнер.
# Это правило безопасности №1.
TOKEN = os.getenv("BOT_TOKEN")
dp = Dispatcher()
@dp.message(CommandStart())
async def cmd_start(message: types.Message):
await message.answer("Привет! Я работаю внутри Docker-контейнера! ?")
@dp.message()
async def echo_handler(message: types.Message):
await message.answer(f"Ты написал: {message.text}")
async def main():
if not TOKEN:
print("Ошибка: Токен не найден!")
return
bot = Bot(token=TOKEN)
await dp.start_polling(bot)
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
print("Бот выключен")
Обратите внимание: Мы используем
os.getenv("BOT_TOKEN"). Это значит, что бот будет искать токен в переменных окружения своей операционной системы. Позже мы передадим этот токен прямо через настройки Докера.
2. Список зависимостей (requirements.txt)
Представьте, что Docker — это абсолютно чистый лист. Там нет ни aiogram, ни других библиотек, которые вы устанавливали. Ему нужна карта покупок — список того, что нужно скачать, чтобы ваш код заработал.
В Python этот список принято хранить в файле requirements.txt.
Если вы работаете в виртуальном окружении (venv), просто выполните команду в терминале:
pip freeze > requirements.txt
Откройте созданный файл. Он должен выглядеть примерно так:
aiogram==3.x.x
aiohttp==3.x.x
...другие библиотеки...
⚠️ Совет: Если вы НЕ используете виртуальное окружение и ставите всё в системный Python (что не рекомендуется), команда pip freeze выгрузит все библиотеки с вашего компьютера, включая те, что не нужны боту. В таком случае лучше создать файл requirements.txt вручную и вписать туда только aiogram.
3. Итоговая структура
В итоге ваша папка с проектом должна выглядеть так:
my_docker_bot/
├── bot.py # Наш код
└── requirements.txt # Список библиотек
3. Пишем Dockerfile (Инструкция для сборки)
Теперь нам нужно создать файл-инструкцию. В нём мы объясним Докеру: «Возьми Python, положи туда мои файлы, скачай библиотеки и приготовься запускать».
Прямо в корне проекта создайте файл с названием Dockerfile.
⚠️ Важно: Именно так, с большой буквы и без какого-либо расширения (.txt, .py не нужны).
Давайте напишем ег�� содержимое шаг за шагом, разбирая каждую строчку.
Шаг 1. Выбираем базу (FROM)
С чистого листа писать операционную систему долго. Поэтому мы берем готовый образ, где уже установлен Linux и Python.
FROM python:3.11-slim
FROM— начало любого Dockerfile.python:3.11— версия языка.-slim— это облегченная версия образа. В ней вырезано всё лишнее, чтобы ваш контейнер весил не 1 ГБ, а 100-200 МБ. Для простых ботов — идеальный выбор.
Шаг 2. Рабочая папка (WORKDIR)
Нам нужно создать папку внутри контейнера, где будет жить наш бот.
WORKDIR /app
Это как команда
cd /appили «Создать новую папку». Теперь все следующие команды будут выполняться внутри этой папки/app. Это нужно, чтобы не разбрасывать файлы по корню системы контейнера.
Шаг 3. Копируем зависимости и устанавливаем их
Тут есть хитрость, которую отличает новичка от профи.
Мы могли бы скопировать сразу всё. Но Docker умный: он кэширует каждый шаг.
Если мы сначала скопируем requirements.txt и установим библиотеки, то при изменении кода бота (например, поправили текст сообщения) Докер не будет заново качать библиотеки, так как этот шаг не менялся. Это ускоряет сборку в разы.
COPY requirements.txt requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
COPY— берем файлrequirements.txtс вашего компьютера и кладем его в контейнер.RUN— выполняем команду в терминале контейнера.--no-cache-dir— просим pip не сохранять кэш скачанных файлов (мы же в контейнере, нам нужно экономить место).
Шаг 4. Копируем остальной код
Теперь, когда библиотеки установлены, закидываем сам код бота.
COPY . .
Первая точка
.— «всё из текущей папки на моем компьютере».Вторая точка
.— «в текущую рабочую папку контейнера (/app)».
Шаг 5. Команда запуска (CMD)
Финальный аккорд. Что сделать контейнеру, когда он запустится?
CMD ["python", "bot.py"]
Мы говорим: запусти Python и выполни файл
bot.py.Почему в квадратных скобках? Это технический нюанс (exec format), просто запомните: так надежнее, чтобы бот корректно реагировал на команду «Стоп».
Итоговый результат
Вот как выглядит ваш полный Dockerfile. Скопируйте это к себе:
# 1. Базовый образ
FROM python:3.11-slim
# 2. Рабочая директория
WORKDIR /app
# 3. Копируем зависимости и ставим их (кэширование слоев!)
COPY requirements.txt requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
# 4. Копируем сам код
COPY . .
# 5. Команда запуска
CMD ["python", "bot.py"]
4. Безопасность и .dockerignore (Правила хорошего тона)
Мы почти готовы к запуску. Но перед этим нужно обсудить одну деталь, которая отличает «тяп-ляп» сборку от профессиональной.
Помните команду COPY . . из прошлого шага? Она работает как пылесос: засасывает всё из вашей папки в контейнер. Вообще всё.
Проблема «Мусора»
Если у вас в папке проекта есть:
Папка
.git(история изменений) — она может весить сотни мегабайт. Зачем она боту на сервере? Не нужна.-
Папка
venv(ваше виртуальное окружение) — это самое страшное.Во-первых, оно весит много.
Во-вторых, если вы работаете на Windows, а Docker собирает Linux-образ, то скопированная папка
venvпросто сломает контейнер (библиотеки скомпилированы под разные ОС).
__pycache__— байт-код, который генерируется автоматически.
Решение: .dockerignore
Чтобы Docker не тащил этот мусор с собой, мы создадим файл-фильтр. Это родной брат файла .gitignore.
Создайте файл .dockerignore (с точкой в начале!) и добавьте туда:
venv/
.venv/
.git/
__pycache__/
.idea/
.vscode/
*.pyc
.env
Что мы сделали:
Исключили виртуальное окружение (
venv), потому что Docker сам установит свежие библиотеки.Убрали
.gitи настройки редакторов (.idea,.vscode), чтобы уменьшить вес образа.Добавили
.env(если он у вас есть). Почему? Читайте ниже.
Пара слов о безопасности (Токены) ?
Вы заметили, что мы добавили .env в игнор-лист? И в коде бота (bot.py) мы использовали os.getenv("BOT_TOKEN")?
Это критически важно.
Никогда, слышите, никогда не «запекайте» свои пароли и токены внутрь Docker-образа.
Если вы напишете токен прямо в коде или скопируете файл .env внутрь образа, то любой, кто получит доступ к этому образу (или вашему репозиторию), украдет вашего бота.
Правильный подход:
Код и Образ — чистые (без паролей).
Токен передается только в момент запуска контейнера.
5. Магия в терминале: Сборка и Запуск
Все файлы на месте. Пора заводить мотор! ?️
Откройте терминал (или командную строку) в папке вашего проекта.
⚠️ Важное напоминание: Убедитесь, что Docker Desktop (или Docker Engine на Linux) запущен и работает. Если кит в трее спит — разбудите его.
Этап 1. Сборка (Build)
Сейчас мы превратим наш код и Dockerfile в Образ (Image).
Образ — это тот самый запечатанный «ланчбокс», готовый к отправке.
Введите команду:
docker build -t my-telegram-bot .
(Не забудьте точку в конце! Она очень важна)
Разбор команды:
docker build: Команда «Собери».-t my-telegram-bot: Флаг Tag (имя). Мы называем наш образmy-telegram-bot, чтобы потом удобно к нему обращаться..(Точка): Говорит Докеру: «Ищи Dockerfile прямо здесь, в текущей папке».
Вы увидите, как побегут строки: скачивание Python, установка библиотек. В первый раз это займет минуту-две. Если увидели в конце что-то вроде FINISHED или exporting layers — поздравляю, сборка прошла успешно!
Этап 2. Запуск (Run)
Образ готов. Но пока он просто лежит на диске. Давайте запустим из него Контейнер (работающую программу).
Помните, мы не вшили токен в код? Сейчас мы передадим его безопасно.
Введите команду (замените ВАШ_ТОКЕН на реальный токен от BotFather):
docker run -d --name my-running-bot -e BOT_TOKEN="12345:ABC-xyz..." my-telegram-bot
Команда выглядит страшновато, но давайте разберем её по косточкам:
docker run: «Запусти контейнер».-
-d(Detached): Самый важный флаг для ботов. Он означает «Запустись в фоновом режиме».Без этого флага: Бот захватит ваш терминал, и если вы его закроете — бот умрет.
С этим флагом: Бот уйдет работать «под капот», а терминал останется свободным.
--name my-running-bot: Мы даем имя конкретно этому запущенному процессу, чтобы потом легко его найти или остановить.-e BOT_TOKEN="...": Environment (Переменная окружения). Мы «впрыскиваем» токен внутрь контейнера. В кодеos.getenvподхватит именно это значение.my-telegram-bot: Имя образа, который мы собрали на прошлом шаге.
Этап 3. Проверка
Docker выдал вам длинный набор букв и цифр (ID контейнера) и замолчал? Это хороший знак!
Давайте проверим, работает ли бот. Введите:
docker ps
Вы должны увидеть таблицу. Если в колонке STATUS написано Up ... seconds — победа! ?
Идите в Телеграм и напишите своему боту /start. Он должен ответить:
"Привет! Я работаю внутри Docker-контейнера! ?"
Если бот ответил — вы официально научились пользоваться Докером. Ваш бот теперь изолирован, упакован и работает независимо от настроек вашей системы.
6. Управление контейнером (Повседневные задачи)
Итак, ваш бот крутится где-то в фоне (в режиме -d). Вы не видите терминала с привычными принтами. Возникает вопрос: как теперь с ним общаться?
Вот 4 команды, которые вы будете использовать каждый день.
1. Смотрим логи (logs)
Если бот вдруг перестал отвечать или вы хотите увидеть те самые print(), которые написали в коде, используйте:
docker logs my-running-bot
Эта команда выведет всё, что произошло в консоли бота с момента запуска.
? Pro-tip: Если вы хотите следить за логами в реальном времени (как в PyCharm), добавьте флаг -f (follow):
docker logs -f my-running-bot
Теперь, когда вы напишете боту сообщение, вы сразу увидите лог в терминале. Чтобы выйти, нажмите Ctrl + C (это не остановит бота, только отключит просмотр логов).
2. Остановка бота (stop)
Решили выключить бота, чтобы он не тратил ресурсы или не отвечал пользователям?
docker stop my-running-bot
Docker вежливо попросит процесс завершиться. Бот уснет. В списке docker ps его больше не будет, но он не удален. Он просто выключен (как компьютер).
Чтобы включить его обратно с теми же настройками:
docker start my-running-bot
3. Удаление контейнера (rm)
Если вы хотите удалить контейнер совсем (например, вы наэкспериментировались или неправильно его назвали), сначала остановите его, а потом удалите:
docker stop my-running-bot
docker rm my-running-bot
⚠️ Важно: Удаление контейнера не удаляет ваш код или Docker-образ. Это просто удаление конкретного запущенного экземпляра.
4. Главный вопрос: «Я обновил код, как обновить бота?»
Это самая частая ошибка новичков.
Запомните: Контейнер — это запечатанная посылка. Если вы поменяли код в файле bot.py у себя на компьютере, внутри контейнера ничего не изменится.
Чтобы обновить бота, нужно пройти полный цикл перерождения:
Остановить и удалить старый контейнер (
stop+rm).Пересобрать образ заново (
docker build ...), чтобы "запечь" новый код.Запустить новый контейнер (
docker run ...).
Звучит долго? На практике это три команды, которые вводятся за 10 секунд (стрелочка вверх в терминале спасает).
7. Заключение и «Что дальше?»
Поздравляю! ? Вы только что перешли из лиги «запускаю код в редакторе» в лигу «упаковываю приложения как профи».
Что мы получили в итоге?
Изоляция: Ваш бот больше не зависит от того, что установлено на вашем компьютере. Вы можете удалить Python со своей машины, а бот в контейнере продолжит работать.
Переносимость: Вы можете передать этот Docker-образ другу, и он запустится у него с первого раза. Без установки библиотек и танцев с бубном.
Чистота: Вы не засоряете свою систему десятками библиотек для разных проектов.
Куда развиваться дальше?
Конечно, запуск одной командой docker run с кучей флагов — это удобно, но только для старта. В реальных проектах, где боту нужна база данных (PostgreSQL, Redis), всё становится интереснее.
Вот темы, которые стоит изучить следующими (или ждать моих новых статей ?):
Docker Compose: Инструмент, который позволяет описать запуск бота и базы данных в одном файле
docker-compose.yml. Больше никаких длинных команд в консоли!Volumes (Тома): Сейчас, если вы удалите контейнер, данные внутри него пропадут. Volumes позволяют сохранять данные (например, базу SQLite) на диске вашего компьютера, даже если контейнер пересоздается.
Deploy: Как за 5 минут перенести этот контейнер на арендованный VPS-сервер.
?️ Домашнее задание
Теория без практики быстро забывается. Чтобы закрепить успех, попробуйте выполнить эти задания:
Level Easy (Для уверенности):
Возьмите любой свой старый проект (калькулятор, парсер, другой бот) и напишите для негоDockerfile. Запустите и убедитесь, что он работает.-
Level Medium (Для любопытных):
Попробуйте изменить вDockerfileбазовый образ сpython:3.11-slimнаpython:3.11-alpine.Соберите образ (
docker build ...).Сравните размеры образов командой
docker images. Насколько Alpine меньше? (Спойлер: значительно, но с ним бывают нюансы при установке сложных библиотек).
-
Level Hard (Для будущих сеньоров):
Добавьте в команду запуска флаг--restart always.docker run -d --restart always ...Запустите бота, а затем... убейте процесс внутри контейнера или перезагрузите свой компьютер (если Docker в автозагрузке). Проверьте, воскреснет ли бот сам?
Анонс новых статей, полезные материалы, а так же если в процессе решения возникнут сложности, обсудить их или задать вопрос по статье можно в моём Telegram-сообществе.