Перейти к содержимому
Главная страница » Установка FFmpeg в Docker: Dockerfile и пример телеграм-бота

Установка FFmpeg в Docker: Dockerfile и пример телеграм-бота

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)

Идея: пользователь присылает видео; бот сохраняет файл, вызывает FFmpeg, конвертирует в 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()
Важно: лимиты Telegram на размер файлов и длительность учитывайте в продакшене; для больших роликов может понадобиться очередь и отдельное хранилище.

Сборка и запуск

В каталоге с 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

Практические советы

  1. Проверка FFmpeg в контейнере: docker run --rm tg-ffmpeg-bot ffmpeg -version
  2. Логи: при ошибках смотрите stderr FFmpeg (в примере он логируется при исключении).
  3. Безопасность: не коммитьте токен; на сервере используйте секреты (переменные окружения, Docker secrets).
  4. Производительность: тяжёлую обработку лучше выносить в очередь (Celery, RQ и т.д.), чтобы не блокировать обработку апдейтов.

Краткий итог

В Dockerfile достаточно базового Python-образа и пакета ffmpeg. Бот вызывает ffmpeg через subprocess и отправляет результат в Telegram. Так вы получаете изолированную, переносимую среду для любых сценариев: нарезка, перекодирование, склейка, работа с потоками.

Если нужно, могу адаптировать статью под Gutenberg (отдельные блоки «Код», «Заголовок») или заменить стек на Node.js + grammy/telegraf с тем же FFmpeg в Dockerfile.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *