Свой приватный Интернет-клуб (на платформе Vas3k.Club) #2
ЧАСТЬ 2: Запускаем клуб локально
Первая часть доступна тут: https://teletype.in/@toptuk/pmiclub1
Покодить локально (Запускаем Клуб локально)
Моя инструкция здесь: https://github.com/TopTuK/pmi.moscow.club/blob/master/docs/setup.md
Установка pipenv (Python)
Нужно локально установить pipenv. Для этого в директории, куда склонирован форк нужно выполнить команды:
pip3 install --user pipenv pipenv install --dev
После успешной установки pipenv нужно проверить, что он работает без ошибок. Для этого выполнить:
pipenv shell # На этом шаге должна запуститься консоль Пайтона. # Чтобы выйти из нее нужно выполнить команду: exit()
Редактируем docker-compose.yml
Вот пример работающего файла конфигурации
version: "3.7" services: club_app: &app build: dockerfile: Dockerfile context: . command: make docker-run-dev container_name: club_app environment: - MODE=dev - DEBUG=true - PYTHONUNBUFFERED=1 - POSTGRES_DB=pmi_club - POSTGRES_USER=pmiclub - POSTGRES_PASSWORD=pmiclub - POSTGRES_HOST=postgres - REDIS_DB=0 - REDIS_HOST=redis restart: always volumes: - .:/app:delegated # enable hot code reload in debug mode depends_on: - postgres - redis - queue - webpack ports: - "8000:8000" queue: build: dockerfile: Dockerfile context: . command: make docker-run-queue environment: - MODE=dev - DEBUG=true - PYTHONUNBUFFERED=1 - POSTGRES_DB=pmi_club - POSTGRES_USER=pmiclub - POSTGRES_PASSWORD=pmiclub - POSTGRES_HOST=postgres - REDIS_DB=0 - REDIS_HOST=redis restart: always volumes: - .:/app:delegated depends_on: - postgres - redis # bot: # build: # dockerfile: Dockerfile # context: . # command: make docker-run-bot # environment: # - MODE=dev # - DEBUG=true # - PYTHONUNBUFFERED=1 # - POSTGRES_DB=pmi_club # - POSTGRES_USER=pmiclub # - POSTGRES_PASSWORD=pmiclub # - POSTGRES_HOST=postgres # - REDIS_DB=0 # - REDIS_HOST=redis # restart: always # volumes: # - .:/app:delegated # depends_on: # - club_app # - postgres # - redis postgres: image: postgres:11 container_name: club_postgres environment: - POSTGRES_USER=pmiclub - POSTGRES_PASSWORD=pmiclub - POSTGRES_DB=pmi_club ports: - "5432:5432" redis: image: redis:alpine environment: - ALLOW_EMPTY_PASSWORD=yes ports: - "6379:6379" webpack: image: node:14-slim command: npm run watch restart: always volumes: - .:/app:delegated working_dir: /app/frontend networks: default: name: pmi_network
Тут сделаны несколько изменений по сравнению с оригинальным docker-compose.yml файлом Вастрика:
- Изменены значения параметров POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB
- Добавлена секция "networks". Все запускаемые сервисы будут подключены к сети с названием "pmi_network". Это понадобится в будущем для настройки обратного прокси.
- Закомментировала секция для сервиса Bot.
Создаем файл конфигурации ".env"
Первое, что нужно сделать, чтобы иметь возможность что-то локально покодировать необходимо подготовить конфигурационный файл окружения .env. В нем будут содержать ключевые параметры, необходимые для работы Клуба.
Эти параметры не должны попасть в публичный репозитарий, поэтому, первое, что необходимо сделать - это обновить в корне проекта Клуба файл “.gitignore”. Требуется убедиться в наличии следующих строк (если их нет, то добавить):
club/.env club/.env.example .env
В директории "club" вы обнаружите файл ".env.example". Его нужно скопировать в файл с названием ".env" также в директории "club" (Прим.: Вастрик при деплое кладет его в корень, что по моему мнению несколько усложняет отладку).
cd club cp .env.example .env
Изучаем и изменяем файл settings.py
Открываем и изучаем файл settings.py в директории club.
После секции импорта необходимых модулей можно заметить вызов функции:
load_dotenv()
Эта функция - не что иное, как загрузка параметров окружения из конфигурационного файла .env. Значения параметров получаются путем вызова функций: “os.getenv()”.
В файле settings.py есть некоторые настройки, которые не задаются в .env файле. Необходимо их указать вручную:
- ALLOWED_HOSTS - вписать в список возможные домены клуба. У меня так:
ALLOWED_HOSTS = ["*", "127.0.0.1", "localhost", "0.0.0.0", "pmi.moscow"] - ADMINS - в параметр ADMINS нужно указать email адреса Администраторов. Судя по коду, это влияет только на отправку тестовых ежедневных и еженедельных дайджестов. Список может быть пустой.
- Словарь DATABASES - нужно задать “свои” параметры по умолчанию (кроме PASSWORD. Его в паблике светить не стоит, чтобы GitHub не ругался). Понадобится в дальнейшем для удобства локальной разработки. Можно и не делать, но хуже не будет точно.
У меня так:
DATABASES = { "default": { "ENGINE": "django.db.backends.postgresql_psycopg2", "NAME": os.getenv("POSTGRES_DB") or "pmi_club", "USER": os.getenv("POSTGRES_USER") or "pmiclub", "PASSWORD": os.getenv("POSTGRES_PASSWORD") or "", "HOST": os.getenv("POSTGRES_HOST") or "localhost", "PORT": os.getenv("POSTGRES_PORT") or 5432, } }
- Задать параметры в секции “# Email”. Требуется указать:
- Задать параметры в секции “# App”:
- Задать значение для параметра “MEDIA_UPLOAD_URL”. Это ссылка на ваше сервис Pepic, формируется как <% Домен Pepic %> + “upload/multipart/“.
Пример: MEDIA_UPLOAD_URL = "https://media.pmi.moscow/upload/multipart/" - Задать параметры для сервиса OGIMGD. Нужно изменить домен для сервиса OgImgd:
- Ссылку OG_IMAGE_GENERATOR_URL.
- Ссылку OG_IMAGE_DEFAULT.
- Ссылку OG_MACHINE_AUTHOR_LOGO.
- В словаре OG_IMAGE_GENERATOR_DEFAULTS задать ссылку для параметра logo.
- Задать некоторые параметры для Telegram бота и чатов:
- TELEGRAM_BOT_WEBHOOK_URL - заменить доменную часть в ссылке на домен своего Клуба
- TELEGRAM_BOT_URL - это ссылка на вашего TG бота. До сих пор мы пока не делали чатов и TG бота. Пока оставим “как есть”, но в будущем поменяем. Вообще, я не нашел мест, где бы использовался этот параметр по умолчанию.
- Задаем аватар по умолчанию:
- Нужно задать свою ссылку на картинку в параметре DEFAULT_AVATAR.
- Для удобства, ничего не мешает вам загрузить свою картинку в ваш сервис Pepic, а после использовать полученную ссылку. Потренироваться сделать такое можно следующим способом:
- Зайти по URL адресу своего сервиса Pepic.
- Ввести код для аутентификации в сервисе.
- Загрузить релевантную картинку для аватара по умолчанию.
- Скопировать полученную ссылку на файл в буфер обмена.
- Пример: DEFAULT_AVATAR = "https://media.pmi.moscow/30095075d17a92786cfea143a73d68f5f1b3e71173e3f4ecf16f90d25834e45e.png"
Что еще потребуется сделать в будущем:
- Задать ссылку на TELEGRAM_BOT_URL.
- Задать ключи (приватный и публичный) для JWT токена.
- После того, как поднимем свой Клуб, то указать ссылки для следующих параметров: POSTING_GUIDE_URL, CHATS_GUIDE_URL, PEOPLE_GUIDE_URL, PARLIAMENT_GUIDE_URL.
Создаем JWT-токены
- Гайд как создавать ключи для JWT токена тут: https://gist.github.com/ygotthilf/baa58da5c3dd1f69fae9
- Пошаговый алгоритм для создания ключей:
# Создаем приватный ключ. # После выполнения будет запрошен пароль. Его нужно оставить пустым. ssh-keygen -t rsa -b 4096 -m PEM -f club_private.key # Создаем открытый ключ openssl rsa -in club_private.key -pubout -outform PEM -out club_public.key.pub
- После выполнения команд в новой директории будут созданы файлы “club_public.key.pub” и “club_private.key”.
- После создания файлов необходимо указать параметр JWT_PUBLIC_KEY в файле settings.py. Требуется скопировать содержимое файла “club_public.key.pub” (копировать “как есть”) и вставить в settings.py. Должно получится что-то типа:
JWT_PUBLIC_KEY = """-----BEGIN PUBLIC KEY---— MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA03rHsNGQ3HUfHIqSYXCh … -----END PUBLIC KEY-----"""
- В файле club_private.key содержится приватный ключ, который мы будем использовать в конфигурационном файле .env
Редактируем конфигурационный файл .env
Сейчас в этом файле нам нужно задать ключевые параметры, без которых невозможна локальная разработка клуба. По мере дальнейшей кастомизации платформы Vas3k’а мы будем еще добавлять новые параметры. Приступим!
- SECRET_KEY - это какой-то настолько секретный ключ, что поиск по коду не дает результатов, где же он используется в реальности. Однако, пускай будет. Задаем в кавычках “свой” код.
- Указываем параметры POSTGRES_DB, POSTGRES_USER и POSTGRES_PASSWORD - такие же, как в docker-compose.yml файле. Нет ничего страшного, что в продакшен среде у вас будут простые пароли от сервиса Postgress, ведь все равно он будет доступен только “локально на сервере”.
- Задаем параметр MEDIA_UPLOAD_URL - это <% Домен сервиса Pepic %> + “/upload/“. Пример: MEDIA_UPLOAD_URL="https://media.pmi.moscow/upload/“. (Почему тут путь отличается от значения по умолчанию в settings.py - загадка. Но, “работает - не трожь”).
- Задаем параметр MEDIA_UPLOAD_CODE - из названия понятно, что это секретный код для сервиса Pepic
- Задаем параметры для отправки писем (у вас должна быть отдельная учетная запись для Клуба. От имени этой учетной записи Клуб будет отправлять различные письма, в т.ч. - приветственные):
- EMAIL_HOST - хост почтового сервиса. Задается без протокола, т.е. без “https://“. В моем случае: EMAIL_HOST="mail.pmi.moscow"
- EMAIL_HOST_USER - почтовый адрес пользователя от имени которого Клуб будет отправлять письма.
- EMAIL_HOST_PASSWORD - пароль для аутентификации и авторизации пользователя выше в почтовом сервисе.
- Задаем JWT_PRIVATE_KEY - копируем содержимое файла club_private.key из раздела выше. Копируем “как есть” по подобию JWT_PUBLIC_KEY.
Следующие параметры стоит сразу указать в .env файле и оставить пустыми: STRIPE_API_KEY, STRIPE_PUBLIC_KEY, STRIPE_WEBHOOK_SECRET, PATREON_CLIENT_ID, PATREON_CLIENT_SECRET и WEBHOOK_SECRETS. Должно быть что-то типа:
STRIPE_API_KEY="" STRIPE_PUBLIC_KEY="" STRIPE_WEBHOOK_SECRET="" PATREON_CLIENT_ID="" PATREON_CLIENT_SECRET=""
Какие параметры нам осталось задать в конфигурационном файле .env:
Создание учетной записи в сервисе Sentry.io
Сервис Sentry.io - один из самый известный сервисов, который позволяет в режиме реального времени отслеживать ошибки в работе Клуба, мониторить его состояния и получать различные статистические данные. Для маленьких проектов данный сервис является бесплатным, так что цель данного этапа - создать учетную запись Sentry, создать новый проект для Клуба, получить токен для доступа в Sentry и прописать этот токен в конфигурационном файле .env.
- Переходим на сайт Sentry https://sentry.io/welcome/
- Регистрируем новую учетную запись, если другой никакой нет.
- Создаем новую организацию и новый проект.
После создания проекта и копирования DSN прописываем его в конфигурационный файл .env в параметр SENTRY_DSN. Должно быть что-то вида:
SENTRY_DSN="https://<xxxyyyyzzz>@123456.ingest.sentry.io/98765432"
Создание телегам бота (ака “бездушная машина”), базовых чатов и каналов
На данном шаге мы выполним минимально необходимый набор шагов для интеграции Клуба с Телеграммное, а именно:
- Создадим бота, получим для него токен и URL, добавим бота в релевантные чаты и каналы.
- Создадим главный чат Клуба и чат Модераторов. Получим необходимые параметры для этих чатов.
- Создадим TG-каналы для выборочного постинга новостей и канал для “Прямого эфира”.
В Телеграмме находим бота для создания ботов @BotFather
- Создаем нового бота через команду /newbot
- Задаем имя для Бота.
- Задаем username для Бота. В конце должно быть Bot или _bot, чтобы пользователи знали, с кем имеют дело.
- После создания бота копируем токен в формате <userid>:<token> и коробку ссылку на бота.
- В конфигурационный файл .env в следующие параметры задаем токен и ссылку на бота:
Создаем чаты для Модераторов и общий чат для всех
Для Клуба нужно минимально создать 2 чата в Телеграмм:
- Чат Модераторов, где будут аппрувиться посты, новые участники и все в таком духе.
- Общий чат членов Клуба.
После создания нужно скопировать ссылки на чаты и получить их идентификаторы.
Если с получением ссылок не возникает много вопросов (ссылки есть в настройках чатов), то с получением идентификаторов придется повозиться:
- Нужно добавить в чаты бота @RawDataBot.
- Написать сообщение.
- Бот в чате отобразит дамп,
- Среди дампа бота нужно из секции "chat" скопировать значение атрибута "id" вместе со знаком "-". Пример:
"chat": { "id": -1001234567890, "title": "PMI Club Russia Admin", "type": "supergroup" },
Полученные параметры нужно записать в конфигурационный файл .env.
TELEGRAM_ADMIN_CHAT_ID="<Идентификатор чата Модераторов>" TELEGRAM_CLUB_CHAT_URL="<Ссылка на общий чат Клуба>" TELEGRAM_CLUB_CHAT_ID="<Идентификатор общего чата Клуба>"
Создаем каналы для прямого эфира и выборочного постинга новостей
Для запуска Клуба нужно в Телеграмм создать 2 канала:
После создания каналов потребуется получить ссылку на созданные каналы, а также идентификаторы этих каналов.
Ссылку на каналы можно получить в настройках каналов. С идентификаторами сложнее, нужно форварднуть сообщения из каналов боту @getidsbot.
В ответ получите следующее сообщение:
Нужно скопировать id каналов в конфигурационный файл .env. Копировать вместе со знаком "-". Заполнить нужно следующие параметры:
TELEGRAM_CLUB_CHANNEL_URL="<Ссылка на канал для выборочного постинга новостей>" TELEGRAM_CLUB_CHANNEL_ID="<Идентификатор канала для выборочного постинга новостей>" TELEGRAM_ONLINE_CHANNEL_URL="<Ссылка на канал для прямого эфира>" TELEGRAM_ONLINE_CHANNEL_ID="<Идентификатор канала для прямого эфира>"
Запускаем клуб локально
Ну штош, коллеги, вы большие молодцы! Настало время научится локально поднимать Клуб с заданными параметрами. Проверим, что Клуб работает, и что мы можем локально что-то покодировать!
В первой части мы запускали клуб через поднятие docker сервисов:
docker-compose up -d
Этот способ работает до сих пор. Однако, сейчас мы запустим Клуб вручную, чтобы была простая возможность покодировать.
Для локального запуска Клуба я рекомендую запустить несколько консолей в VSCode для удобной дальнейшей отладки и остановки.
На данный момент локально у нас уже должен быть установлен python, pipenv, Docker. Значения одноименных или “схожих” параметров всегда должны быть синхронизированы между *.yml файлами и конфигурационным файлом .env.
Запускаем сервис Postgres
Для запуска сервиса Postgress достаточно выполнить в консоли команду:
docker-compose -f docker-compose.yml up -d postgres
Все вот так просто, а сложнее см пример тут: setup.md
Запускаем Front
В консоли переходим в директорию “frontend”. В этой директории выполняем команду “npm run watch”, которая неявно выполнит команду “npm ci”. В результате запуска и ожидания в консоли вы должны увидеть что-то типа:
То ли у меня руки кривые, то ли у Vas3k’а какие-то проблемы с зависимостями, но команда “npm run watch” стабильно возвращала ошибку вида:
Чтобы обойти эту ошибку нужно использовать в команде параметр “--legacy-peer-deps”. Итого команда должна быть следующая:
npm run watch --legacy-peer-deps
- В директории frontend выполняем команду либо “npm run watch”, либо “npm run watch --legacy-peer-deps” (если первая завершилась с ошибкой)
- ДОЛГО ждем запуска Front’а, пока в консоли не появится сообщение:
Запускаем “все остальное”
В директории club у нас есть сконфигурированный файл .env. В корневой директории проекта есть файл docker-compose.yml, где мы в первой части задали свои параметры. После запуска Postgres и Front’а нужно выполнить следующую последовательность команд:
# Запускаем сервис Redis в Detach режиме. Если нужен консольный вывод, то уберите флаг “-d” (в этом случае запускать в отдельной консоли) docker-compose -f docker-compose.yml up -d redis # В отдельной консоли запускаем сервис задач pipenv run python manage.py qcluster # В “общей” консоли запускаем создание необходимых таблиц баз данных pipenv run python manage.py migrate # Запускаем обновление тегов для профилей пользователей (Без этой команды теги по умолчанию будут пустыми) pipenv run python manage.py update_tags # В отдельной консоли запускаем локальный веб-сервер pipenv run python manage.py runserver 0.0.0.0:8000
Во время запуска смотрите, нет ли каких-то ошибок! Если есть, добро пожаловать в комментарии.
Процесс запуска занимает некоторое время! Дождитесь, пока все запуститься. В консоли локального веб-сервера должно отображаться что-то типа:
Для проверки работы Клуба надо в браузере перейти на сайт http://localhost:8000.
- Для логина в качестве Администратора перейти на страницу: http://localhost:8000/godmode/dev_login/
- Для логина в качестве обычного пользователя перейти на страницу: http://localhost:8000/godmode/random_login/
- Пересборка бэкенда и фронтеда осуществляется автоматически при каждом изменении кода.
Останавливаем Клуб
Чтобы оставить сервисы, которые запущены локально нужно выполнить следующие шаги:
- Во всех "отдельных" консолях, где пишутся какие-то логи нужно нажать комбинацию клавиш Ctrl+C (Mac: Cmd+C)
- После остановки сервисов в отдельных консолях где-то выполнить команду: “docker-compose down -v”.
- После остановки Docker сервисов все лишние консоли можно закрывать.
Последовательность команд для локального запуска Клуба
Итого, последовательность команд для локального запуска Клуба должна получаться следующая:
# В общей консоли: docker-compose -f docker-compose.yml up -d postgres # В общей консоли: docker-compose -f docker-compose.yml up -d redis # В новой отдельной консоли: cd frontend npm run watch --legacy-peer-deps # В новой отдельной консоли: pipenv run python manage.py qcluster # В “общей” консоли pipenv run python manage.py migrate # В “общей” консоли pipenv run python manage.py update_tags # В отдельной консоли pipenv run python manage.py runserver 0.0.0.0:8000
Заключение
В этой статье мы разобрались как подготовить конфигурационные файлы и запустить Клуб локального. Все готово для начала кодирования, о котором мы поговорим в следующей статье: