Проблема (бэкапы): Единственный бэкап — pg_dump, который основатель запускал вручную «когда вспоминал». Последний бэкап — неделю назад. Бэкап лежал на том же сервере, что и база.
Реальный инцидент: Во время неудачного ALTER TABLE разработчик уронил production-базу. Последний бэкап был 7-дневной давности. Потеряно 12 000 заказов, 3 400 новых пользователей, все транзакции за неделю. Восстановление заняло 48 часов. Финансовые потери — 1.2 миллиона рублей.
Решение:
#!/bin/bash
# /opt/scripts/backup_postgresql.sh
set -euo pipefail
BACKUP_DIR="/backup/postgresql"
S3_BUCKET="s3://rocketapp-backups/postgresql"
RETENTION_DAYS=30
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/rocketapp_${DATE}.sql.gz"
# Создаём дамп с сжатием
pg_dump -h localhost -U app -Fc rocketapp | gzip > "$BACKUP_FILE"
# Проверяем целостность дампа
if ! pg_restore -l "$BACKUP_FILE" > /dev/null 2>&1; then
echo "BACKUP VERIFICATION FAILED" >&2
curl -s -X POST "https://api.telegram.org/bot${TG_BOT}/sendMessage" \
-d chat_id="$TG_CHAT" \
-d text="BACKUP FAILED: verification error on $(hostname)"
exit 1
fi
# Копируем в S3 (другой дата-центр)
aws s3 cp "$BACKUP_FILE" "$S3_BUCKET/" --storage-class STANDARD_IA
# Удаляем старые локальные бэкапы
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +${RETENTION_DAYS} -delete
# Отправляем отчёт
SIZE=$(du -sh "$BACKUP_FILE" | awk '{print $1}')
curl -s -X POST "https://api.telegram.org/bot${TG_BOT}/sendMessage" \
-d chat_id="$TG_CHAT" \
-d text="Backup OK: $BACKUP_FILE ($SIZE), uploaded to S3"
# Systemd timer: каждые 6 часов
# /etc/systemd/system/backup-postgresql.timer
# [Timer]
# OnCalendar=*-*-* 00/6:00:00
# Persistent=true
Проблема (ручные деплои): Деплой = SSH на сервер, git pull, pip install -r requirements.txt, systemctl restart app. Каждый раз что-то забывали: миграцию, зависимость, перезапуск воркеров.
Решение — GitHub Actions CI/CD:
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install -r requirements.txt
- run: pytest tests/ -v --tb=short
- run: flake8 app/ --max-line-length=120
deploy:
needs: test
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Build and push Docker image
run: |
docker build -t rocketapp/api:${{ github.sha }} .
docker push rocketapp/api:${{ github.sha }}
- name: Deploy to production
run: |
ssh deploy@prod "docker pull rocketapp/api:${{ github.sha }} && \
docker-compose up -d --no-deps app && \
docker exec app python manage.py migrate --noinput"
Оставить комментарий