Files
han-app/deploy-steps.md
T

451 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# usefull commands
- Убрать переносы строк: sed -i 's/\r$//' name-file.sh
- find . -type f \( -name '*.sh' -o -name 'validate-env' \) -exec dos2unix {} +
- docker compose stop # мягко останавливает контейнеры (не удаляет)
- sudo shutdown -h now # выглючить ВМ
- Генерация паролей
- (со спец.символами) openssl rand -base64 32
- (без спец.символов) openssl rand -hex 16
- openssl rand -base64 16 | xclip -selection clipboard # Linux
Туннель до БД: ssh -i C:\Users\MI\.ssh\hansel -L 5433:192.168.0.211:5432 root@135.106.164.58 -N
#Обновление проекта
cd /tmp
rm han-chat-backend.tar.gz
cd /opt/han-chat/backend
rm C:\Users\MI\Documents\Assistent\han-chat-backend.tar.gz
#команда складывает архив в ту папку, из которой запускается команда
cd C:\Users\MI\Documents\Assistent\
tar -C C:\Users\MI\Documents\Assistent\HAN_chat_specification\codebase\backend -czf han-chat-backend.tar.gz .
scp -i C:\Users\MI\.ssh\hansel C:\Users\MI\Documents\Assistent\han-chat-backend.tar.gz root@135.106.164.58:/tmp/han-chat-backend.tar.gz
tar -xzf /tmp/han-chat-backend.tar.gz
find . -type f \( -name '*.sh' -o -name 'validate-env' \) -exec dos2unix {} +
chmod +x scripts/validate-env deployment/scripts/*.sh redis/scripts/*.sh nginx/scripts/*.sh
docker compose --env-file .env build frontend-static keycloak
docker compose --env-file .env up -d \
--no-deps \
--force-recreate frontend-static keycloak
# Разворачиваем инфраструктуру в Селектел ч1
## Создание сети
## Создание групп безопасности для сети и для БД
Для сети открываем порты 80, 22, 443
Для БД открываем порты 5432, 5433 но только из CIDR (192.168.0.211\24)
## Создаем ВМ, подключаем к новой сети (через порт) и перезагружаем (либо руками вводить новые сетевые настройки - надо выбрать)
# Подключение к ВМ и первичный скрипт
++ ssh -i C:\Users\MI\.ssh\hansel root@135.106.164.58
++ scp -i C:\Users\MI\.ssh\hansel -r "C:\Users\MI\Documents\Assistent\HAN_chat_specification\codebase\backend\deployment\scripts\setup-vm.sh" root@135.106.164.58:/tmp/setup-vm.sh
chmod +x /tmp/setup-vm.sh
sudo /tmp/setup-vm.sh
# Скрипт создал деплой пользователя. Нужно Перенести туда публичный ключ и дать права на файл и папку
## Вставляем публичный ключ новой строкой Далее даем права
sudo nano /home/deploy/.ssh/authorized_keys
sudo chmod 700 /home/deploy/.ssh
sudo chmod 600 /home/deploy/.ssh/authorized_keys
sudo chown -R deploy:deploy /home/deploy/.ssh
## Пароль деплою для использования sudo
sudo passwd deploy
## После этого можно подключаться под деплой пользователем
ssh -i C:\Users\MI\.ssh\han_chat_deploy deploy@135.106.164.58
## GIT не работал. Проект пришлось копировать.
tar -C HAN_chat_specification/codebase/backend -czf han-chat-backend.tar.gz .
scp -i C:\Users\MI\.ssh\han_chat_deploy C:\Users\MI\Documents\Assistent\han-chat-backend.tar.gz deploy@135.106.164.58:/tmp/
scp -i C:\Users\MI\.ssh\hansel C:\Users\MI\Documents\Assistent\han-chat-backend.tar.gz root@135.106.164.58:/tmp/
## Дальше распаковка
cd /opt/han-chat/backend
tar -xzf /tmp/han-chat-backend.tar.gz
## Правим переносы строк и даем права на исполнение
find . -type f \( -name '*.sh' -o -name 'validate-env' \) -exec dos2unix {} +
chmod +x scripts/validate-env deployment/scripts/*.sh redis/scripts/*.sh nginx/scripts/*.sh
# Разворачиваем инфраструктуру в Селектел ч2
## Создаем БД
В базе подключаем pgcrypto
Чтобы корректно работал PgBouncer выбираем session pooling
### Копируем СА сертификат
Вариант Деплоя:
mkdir -p /opt/han-chat/backend/secrets/pg
scp -i C:\Users\MI\.ssh\han_chat_deploy -r C:\Users\MI\Documents\job\HAN_new_life\HANapp\Production\sertificates\CA.pem deploy@135.106.164.58:/opt/han-chat/backend/secrets/pg/ca.pem
chmod 644 /opt/han-chat/backend/secrets/pg/ca.pem
Вариант Селектела:
mkdir -p ~/.postgresql/
wget https://storage.dbaas.selcloud.ru/CA.pem -O ~/.postgresql/root.crt
chmod 0600 ~/.postgresql/root.crt
### Правки DNS-маршрутизации (в прошлый раз, какие-то трабблы были с базовой маршрутизацией) - скрипт ниже создаст
sudo tee /etc/netplan/99-han-dns.yaml <<'EOF'
network:
version: 2
ethernets:
eth0:
nameservers:
addresses:
- 8.8.8.8
- 1.1.1.1
search:
- selcloud.ru
eth1:
dhcp4-overrides:
use-dns: false
use-domains: false
EOF
sudo chmod 600 /etc/netplan/99-han-dns.yaml
sudo netplan apply
resolvectl flush-caches
### Проверка подключения к Postgers в ВМ
nc -zv 192.168.0.211 5433
sudo apt update
sudo apt install postgresql-client
psql "host=master.ef54e3e4-ad3d-4b80-a6af-d63269e0895a.c.dbaas.selcloud.ru \
port=5432 \
dbname=han_chat \
user=dbAdmin \
sslmode=verify-ca"
(psql "host=master.ef54e3e4-ad3d-4b80-a6af-d63269e0895a.c.dbaas.selcloud.ru port=5432 dbname=han_chat user=dbAdmin sslmode=verify-ca")
### Заводим пользователей и схемы
Пользователей создаем через интерфейс селектела.
Под админом даем права на создание в БД:
GRANT CREATE ON DATABASE han_chat TO han_app;
GRANT CREATE ON DATABASE han_chat TO bitrix_local_app;
GRANT CREATE ON DATABASE han_chat TO bitrix_sync_user;
GRANT CREATE ON DATABASE han_chat TO message_safety_app;
GRANT CREATE ON DATABASE han_chat TO keycloak_user;
Схемы создаем от лица пользователей, заходя каждым из них в БД.
+ Запрещаем всем посторонним входить в схему han_app и др.
CREATE SCHEMA IF NOT EXISTS han_app;
REVOKE ALL ON SCHEMA han_app FROM PUBLIC;
ALTER ROLE CURRENT_USER IN DATABASE han_chat SET search_path TO han_app;
SHOW search_path; --чтобы заработало надо переподключиться (должно быть han_app)
CREATE SCHEMA IF NOT EXISTS bitrix_local;
REVOKE ALL ON SCHEMA bitrix_local FROM PUBLIC;
ALTER ROLE CURRENT_USER IN DATABASE han_chat SET search_path TO bitrix_local;
SHOW search_path; --чтобы заработало надо переподключиться
CREATE SCHEMA IF NOT EXISTS bitrix_sync;
REVOKE ALL ON SCHEMA bitrix_sync FROM PUBLIC;
ALTER ROLE CURRENT_USER IN DATABASE han_chat SET search_path TO bitrix_sync;
SHOW search_path; --чтобы заработало надо переподключиться
CREATE SCHEMA IF NOT EXISTS message_safety;
REVOKE ALL ON SCHEMA message_safety FROM PUBLIC;
ALTER ROLE CURRENT_USER IN DATABASE han_chat SET search_path TO message_safety;
SHOW search_path; --чтобы заработало надо переподключиться
CREATE SCHEMA IF NOT EXISTS keycloak;
REVOKE ALL ON SCHEMA keycloak FROM PUBLIC;
ALTER ROLE CURRENT_USER IN DATABASE han_chat SET search_path TO keycloak;
SHOW search_path; --чтобы заработало надо переподключиться
Проверка search_path
SELECT r.rolname, d.datname, s.setconfig
FROM pg_db_role_setting s
JOIN pg_roles r ON r.oid = s.setrole
JOIN pg_database d ON d.oid = s.setdatabase
WHERE r.rolname in ('han_app',
'bitrix_local_app',
'bitrix_sync_user',
'message_safety_app',
'keycloak_user');
После реализации bitrix_sync (проверить, вероятно не на все таблицы права нужны):
-- Даем право на чтение (SELECT) всех СУЩЕСТВУЮЩИХ таблиц в схеме
GRANT SELECT, INSERT ON ALL TABLES IN SCHEMA han_app TO bitrix_sync_user;
-- Настраиваем права по умолчанию для новых таблиц
ALTER DEFAULT PRIVILEGES IN SCHEMA han_app
GRANT SELECT ON TABLES TO bitrix_sync_user;
-- Если нужно дать право на чтение и для новых последовательностей (sequences):
ALTER DEFAULT PRIVILEGES IN SCHEMA han_app
GRANT USAGE, SELECT ON SEQUENCES TO bitrix_sync_user;
## Заводим S3 хранилища:
Создаем 2 сервисных пользователя и заводим им ключи:
- API backend SELECTEL_S3_ACCESS_KEY / SELECTEL_S3_SECRET_KEY
- Message Safety SELECTEL_S3_QUARANTINE_READ_ACCESS_KEY / SELECTEL_S3_QUARANTINE_READ_SECRET_KEY
Создаем 3 приватных бакета
- han-chat-quarantine (политика доступа API backend RW, Message Safety R)
- han-chat-attachments (политика доступа API backend RW)
- han-chat-documents (политика доступа API backend RW)
RW:
ListBucket
GetBucketLocation
PutObject
GetObject
DeleteObject
ListBucketMultipartUploads
ListMultipartUploadParts
AbortMultipartUpload
R:
ListBucket
GetBucketLocation
GetObject
ListBucketMultipartUploads
ListMultipartUploadParts
Политика CORS (бакет han-chat-quarantine, vHosted обязателен):
Allowed origin: https://chat.han0107.ru
Methods: POST, PUT, GET, HEAD
Headers: * (или явно content-type; wildcard x-amz-* в Selectel не работает)
Expose headers: ETag
# Тест инфраструктуры
mkdir -p /opt/han-chat/infratest
cd /opt/han-chat/infratest
scp -i C:\Users\MI\.ssh\hansel -r "C:\Users\MI\Documents\Assistent\HAN_chat_specification\infratest\*" root@135.106.164.58:/opt/han-chat/infratest
--настраиваю env на локальной машине и копирую на диск
scp -i C:\Users\MI\.ssh\hansel -r "C:\Users\MI\Documents\job\HAN_new_life\HANapp\Production\.env" root@135.106.164.58:/opt/han-chat/infratest/
Создаем изолированное окружение:
python3 -m venv .venv
. .venv/bin/activate
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements.txt
Если не работает, то надо DNS переправить на eth0
resolvectl dns eth0 1.1.1.1 8.8.8.8
resolvectl domain eth0 '~.'
resolvectl flush-caches
resolvectl query pypi.org
# Подготовка к запуску
Сертификат рекомендуется скопировать в папку с секретами
cp /root/.postgresql/root.crt /opt/han-chat/backend/secrets/pg/root.crt
chmod 644 /opt/han-chat/backend/secrets/pg/root.crt
В битрикс регистрируем локальное приложение:
Установка: https://chat.example.ru/bitrix/install
Обработчик: https://chat.example.ru/bitrix/handler
??? (не понадобилось) Placement: https://chat.example.ru/bitrix/placement
--настраиваю env на локальной машине и копирую на диск
scp -i C:\Users\MI\.ssh\hansel -r "C:\Users\MI\Documents\job\HAN_new_life\HANapp\Production\.env" root@135.106.164.58:/opt/han-chat/backend
--Проверка .env
cd /opt/han-chat/backend
chmod 600 .env
./scripts/validate-env .env
docker compose --env-file .env config --quiet
docker compose --env-file .env config --services
python3 -m unittest discover -s tests -v
--Проверка портов (Публиковаться должны только 80 и 443 у nginx)
docker compose --env-file .env config | grep -n 'published:'
--Собираем локальные образы:
docker compose --env-file .env build --pull
docker compose --env-file .env images
## Миграции БД и начальные настройки
cd /opt/han-chat/backend
PITR_MARKER_CONFIRMED=true deployment/scripts/migrate.sh
deployment/scripts/seed.sh
## Запуск внутренних сервисов
Сначала запустите Redis:
```sh
docker compose --env-file .env up -d redis
docker compose --env-file .env ps redis
```
Затем Keycloak и OpenTelemetry:
```sh
docker compose --env-file .env up -d keycloak otel-collector
docker compose --env-file .env ps keycloak otel-collector
```
Первый запуск Keycloak может занять несколько минут: он создаст свои таблицы и
импортирует realm `han-chat`.
После готовности Keycloak:
```sh
docker compose --env-file .env up -d message-safety
docker compose --env-file .env up -d api-backend
docker compose --env-file .env up -d bitrix-local-app bitrix-sync
docker compose --env-file .env up -d \
delivery-worker safety-recovery-worker cleanup-worker
docker compose --env-file .env ps
```
Если сервис не становится healthy:
```sh
docker compose --env-file .env logs --tail=200 <SERVICE_NAME>
docker inspect "$(docker compose --env-file .env ps -q <SERVICE_NAME>)"
```
## Первоначальный выпуск TLS-сертификата
Для ACME требуется работающий nginx по HTTP. В `.env` оставьте
`NGINX_TLS_ENABLED=true`, но первый nginx запустите с временным переопределением:
```sh
NGINX_TLS_ENABLED=false \
docker compose --env-file .env up -d frontend-static nginx
```
Проверьте HTTP:
```sh
curl -I http://chat.han0107.ru/
```
Сначала рекомендуется проверить Certbot через staging:
```sh
docker compose --env-file .env --profile certbot run --rm certbot certonly \
--staging \
--webroot -w /var/www/certbot \
-d chat.han0107.ru \
--cert-name chat.han0107.ru-staging \
--email ap@han.ru \
--agree-tos --no-eff-email --non-interactive
```
После успешного staging-теста выпустите рабочий сертификат с основным cert-name
без `--staging`:
```sh
docker compose --env-file .env --profile certbot run --rm certbot certonly \
--webroot -w /var/www/certbot \
-d chat.han0107.ru \
--cert-name chat.han0107.ru \
--email ap@han.ru \
--agree-tos --no-eff-email --non-interactive
```
Пересоздайте nginx уже с TLS:
```sh
docker compose --env-file .env up -d --force-recreate nginx
docker compose --env-file .env exec -T nginx nginx -t -c /tmp/nginx.conf
curl -I https://chat.han0107.ru/
```
Повторно запустите VM setup, чтобы он обнаружил проект и установил systemd-таймер
продления сертификата:
```sh
sudo /opt/han-chat/backend/deployment/scripts/setup-vm.sh
systemctl status han-chat-ssl-renew.timer
## Запуск всего контура
Теперь можно привести весь проект к состоянию, описанному Compose:
```sh
cd /opt/han-chat/backend
docker compose --env-file .env up -d
docker compose --env-file .env ps
```
Проверьте, что контейнеры не перезапускаются:
```sh
docker compose --env-file .env ps
docker compose --env-file .env logs --since=10m
```
## Публичная проверка
Запустите smoke-тест:
```sh
cd /opt/han-chat/backend
deployment/scripts/smoke.sh
```
Также вручную проверьте:
```sh
curl -fsS https://chat.han0107.ru/api/v1/public/app-config | jq
curl -fsS https://chat.han0107.ru/api/v1/public/content | jq
curl -fsS \
https://chat.han0107.ru/auth/realms/han-chat/.well-known/openid-configuration | jq
```
Внутренний API не должен быть опубликован:
```sh
curl -i https://chat.han0107.ru/internal/safety/v1/messages/check
```
Ожидаемый статус — `404`.
Откройте в браузере:
```text
https://chat.example.ru/
```
Для тестовой авторизации используйте значение `KEYCLOAK_OTP_MOCK_CODE` из `.env`.
Настройки keykcloack:
Для битрикса код установки приложения:
docker compose --env-file .env exec -T api-backend python - <<'PY'
import os
import urllib.request
base = os.environ["BITRIX_LOCAL_APP_BASE_URL"]
token = os.environ["BITRIX_LOCAL_APP_INTERNAL_TOKEN"]
request = urllib.request.Request(
base + "/internal/openlines/v1/setup/retry",
method="POST",
headers={"Authorization": "Bearer " + token},
)
print(urllib.request.urlopen(request).read().decode())
PY