
FFmpeg часто нужен ботам и сервисам: конвертация голосовых сообщений, сжатие видео, извлечение аудио из роликов. Установка на хосте бывает неудобной из‑за версий библиотек и зависимостей. Docker даёт воспроизводимую среду: один раз описали образ — одинаково работает локально и на сервере.
В статье разберём минимальный Dockerfile с FFmpeg и простой Telegram-бот на Python, который принимает видео и отвечает аудиодорожкой в формате OGG (как голосовое).
Зачем FFmpeg в контейнере
- Одинаковые версии утилит на всех машинах
- Не засоряем систему пакетами
- Удобно деплоить вместе с ботом одним образом
Минимальный Dockerfile с FFmpeg
Базовый образ с официальным FFmpeg — jrottenberg/ffmpeg (или можно поставить ffmpeg из репозиториев Debian/Ubuntu). Для бота на Python удобнее взять образ с Python и доустановить FFmpeg:
FROM python:3.12-slim-bookworm
RUN apt-get update && apt-get install -y --no-install-recommends \
ffmpeg \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY bot.py .
CMD ["python", "-u", "bot.py"]
Пояснения:
python:3.12-slim-bookworm— небольшой образ на Debian.ffmpegставится из репозитория дистрибутива; для редких кодеков иногда нужны другие пакеты или готовый образ FFmpeg.-uу Python снимает буферизацию вывода в логах Docker.
Зависимости бота
Файл requirements.txt:
python-telegram-bot==21.7
(Версию при желании обновите по документации.)
Пример бота: видео → аудио (OGG)
Файл bot.py (подставьте свой токен через переменную окружения, не храните токен в коде):
import asyncio
import logging
import os
import subprocess
import tempfile
from pathlib import Path
from telegram import Update
from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters
logging.basicConfig(
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
level=logging.INFO,
)
logger = logging.getLogger(__name__)
TOKEN = os.environ.get("TELEGRAM_BOT_TOKEN", "")
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
await update.message.reply_text(
"Пришлите видео — верну аудиодорожку голосовым сообщением (OGG Opus)."
)
def video_to_voice_ogg(input_path: Path, output_path: Path) -> None:
cmd = [
"ffmpeg",
"-y",
"-i",
str(input_path),
"-vn",
"-acodec",
"libopus",
"-b:a",
"64k",
str(output_path),
]
subprocess.run(cmd, check=True, capture_output=True, text=True)
async def on_video(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
if not update.message or not update.message.video:
return
msg = await update.message.reply_text("Конвертирую…")
with tempfile.TemporaryDirectory() as tmp:
tmpdir = Path(tmp)
in_file = tmpdir / "input.mp4"
out_file = tmpdir / "voice.ogg"
file = await context.bot.get_file(update.message.video.file_id)
await file.download_to_drive(custom_path=str(in_file))
try:
video_to_voice_ogg(in_file, out_file)
except subprocess.CalledProcessError as e:
logger.exception("ffmpeg failed: %s", e.stderr)
await msg.edit_text("Ошибка конвертации. Проверьте формат файла.")
return
await update.message.reply_voice(voice=out_file.open("rb"))
await msg.delete()
def main() -> None:
if not TOKEN:
raise SystemExit("Задайте TELEGRAM_BOT_TOKEN")
app = Application.builder().token(TOKEN).build()
app.add_handler(CommandHandler("start", start))
app.add_handler(MessageHandler(filters.VIDEO, on_video))
app.run_polling(allowed_updates=Update.ALL_TYPES)
if __name__ == "__main__":
main()
Сборка и запуск
В каталоге с Dockerfile, requirements.txt и bot.py:
docker build -t tg-ffmpeg-bot .
docker run —rm -e TELEGRAM_BOT_TOKEN=»ВАШ_ТОКЕН» tg-ffmpeg-bot
Токен берётся у @BotFather.
docker-compose (по желанию)
docker-compose.yml:
services:
bot:
build: .
restart: unless-stopped
environment:
TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN}
Запуск:
docker compose up -d —build
Практические советы
- Проверка FFmpeg в контейнере:
docker run --rm tg-ffmpeg-bot ffmpeg -version - Логи: при ошибках смотрите
stderrFFmpeg (в примере он логируется при исключении). - Безопасность: не коммитьте токен; на сервере используйте секреты (переменные окружения, Docker secrets).
- Производительность: тяжёлую обработку лучше выносить в очередь (Celery, RQ и т.д.), чтобы не блокировать обработку апдейтов.
Краткий итог
В Dockerfile достаточно базового Python-образа и пакета ffmpeg. Бот вызывает ffmpeg через subprocess и отправляет результат в Telegram. Так вы получаете изолированную, переносимую среду для любых сценариев: нарезка, перекодирование, склейка, работа с потоками.
Если нужно, могу адаптировать статью под Gutenberg (отдельные блоки «Код», «Заголовок») или заменить стек на Node.js + grammy/telegraf с тем же FFmpeg в Dockerfile.