aiogram + Docker + Local Server
Пытаюсь поднять локальный веб-сервер от Telegram и связать его с ботом написанным на Python + aiogram.
Создаю контейнеры с помощью docker-compose up -d
Затем пытаюсь установить вебхук для бота командой
pipenv run python -m app webhook
То получаю ошибку:
OSError: [Errno 48] error while attempting to bind on address ('::', 8084, 0, 0): address already in use
Шаблон бота взял отсюда: https://github.com/aiogram/bot
Так же прикрепляю код напрямую сюда:
Dockerfile
FROM python:3.9 as production
LABEL maintainer="Alex Root Junior <[email protected]>" \
description="Telegram Bot"
ENV PYTHONPATH "${PYTHONPATH}:/app"
ENV PATH "/app/scripts:${PATH}"
EXPOSE 80
WORKDIR /app
COPY Pipfile* /app/
RUN pip install pipenv && \
pipenv install --system --deploy
ADD . /app/
RUN chmod +x scripts/* && \
pybabel compile -d locales -D bot
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["run-webhook"]
docker-compose.yml
version: '3.7'
services:
bot:
container_name: bot
build:
context: .
env_file:
- .env
restart: on-failure
stop_signal: SIGINT
depends_on:
- redis
- postgres
- api
- nginx
environment:
BOT_PUBLIC_PORT: 80
TELEGRAM_TOKEN:
DOMAIN:
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_DB_FSM:
REDIS_DB_JOBSTORE:
POSTGRES_HOST: postgres
POSTGRES_PORT: 5432
POSTGRES_PASSWORD:
POSTGRES_USER:
POSTGRES_DB:
TELEGRAM_API_ID:
TELEGRAM_API_HASH:
TELEGRAM_STAT:
TELEGRAM_LOCAL:
api:
image: aiogram/telegram-bot-api:latest
container_name: bot-api
restart: always
environment:
TELEGRAM_API_ID:
TELEGRAM_API_HASH:
TELEGRAM_STAT:
TELEGRAM_LOCAL: 1
volumes:
- telegram-bot-api-data:/var/lib/telegram-bot-api
nginx:
container_name: bot-nginx
image: nginx:1.19-alpine
restart: always
depends_on:
- api
volumes:
- telegram-bot-api-data:/var/lib/telegram-bot-api
- ./nginx:/etc/nginx/conf.d/
ports:
- 8084:80
redis:
container_name: bot-redis
image: redis:5-alpine
restart: on-failure
volumes:
- redis-data:/data
postgres:
container_name: bot-postgres
image: postgres:12-alpine
restart: on-failure
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD:
POSTGRES_USER:
POSTGRES_DB:
volumes:
redis-data:
postgres-data:
telegram-bot-api-data:
Устанавливаю настройки бота: /app/config.py
import datetime
import secrets
from envparse import env
...
TELEGRAM_TOKEN = env.str("TELEGRAM_TOKEN")
BOT_PUBLIC_PORT = env.int("BOT_PUBLIC_PORT", default=8080)
DOMAIN = env.str("DOMAIN", default="example.com")
SECRET_KEY = secrets.token_urlsafe(48)
WEBHOOK_BASE_PATH = env.str("WEBHOOK_BASE_PATH", default="/webhook")
WEBHOOK_PATH = f"{WEBHOOK_BASE_PATH}/{SECRET_KEY}"
WEBHOOK_URL = f"https://{DOMAIN}{WEBHOOK_PATH}"
/app/main.py
from app.utils.cli import cli
if __name__ == "__main__":
cli()
/app/utils/cli.py
import functools
import click
from aiogram.__main__ import SysInfo
from loguru import logger
try:
import aiohttp_autoreload
except ImportError:
aiohttp_autoreload = None
@click.group()
def cli():
from app.utils import logging
from app import misc
logging.setup()
misc.setup()
def auto_reload_mixin(func):
@click.option(
"--autoreload", is_flag=True, default=False, help="Reload application on file changes"
)
@functools.wraps(func)
def wrapper(autoreload: bool, *args, **kwargs):
if autoreload and aiohttp_autoreload:
logger.warning(
"Application started in live-reload mode. Please disable it in production!"
)
aiohttp_autoreload.start()
elif autoreload and not aiohttp_autoreload:
click.echo("`aiohttp_autoreload` is not installed.", err=True)
return func(*args, **kwargs)
return wrapper
@cli.command()
def version():
"""
Get application version
"""
click.echo(SysInfo())
@cli.command()
@click.option("--skip-updates", is_flag=True, default=False, help="Skip pending updates")
@auto_reload_mixin
def polling(skip_updates: bool):
"""
Start application in polling mode
"""
from app.utils.executor import runner
runner.skip_updates = skip_updates
runner.start_polling(reset_webhook=True)
@cli.command()
@auto_reload_mixin
def webhook():
"""
Run application in webhook mode
"""
from app.utils.executor import runner
from app import config
runner.start_webhook(webhook_path=config.WEBHOOK_PATH, port=config.BOT_PUBLIC_PORT)
/app/misc.py
...
from app import config
local_server = TelegramAPIServer.from_base('http://localhost:8084')
bot = Bot(config.TELEGRAM_TOKEN, parse_mode=types.ParseMode.HTML, server=local_server)
dp = Dispatcher(bot, storage=storage)
...
def setup():
from app import filters
from app import middlewares
from app.utils import executor
middlewares.setup(dp)
filters.setup(dp)
executor.setup()
logger.info("Configure handlers...")
# noinspection PyUnresolvedReferences
import app.handlers