Files
prod/infra/ansible/playbook.yml
Andrey a1586e78b3 feat: enhance Ansible playbook with swap file management
- Update inventory to use root user with SSH options for security
- Add tasks for creating, configuring, and enabling a swap file
- Set swappiness parameter temporarily and permanently
- Ensure swap file is added to /etc/fstab for automatic mounting
- Include checks and debug information for swap status
2025-09-16 15:29:40 +03:00

563 lines
18 KiB
YAML
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.
---
- name: Полная миграция ботов на новый сервер
hosts: new_server
become: yes
vars:
# Основная директория проекта
project_root: "/home/prod"
# Пользователь и группа
deploy_user: "deploy"
uid: "1001"
gid: "1001"
# Старый сервер для копирования данных
old_server: "root@77.223.98.129"
# Опция: пересоздавать папку /home/prod (по умолчанию — нет)
recreate_project: false
# Grafana настройки
grafana_admin_user: "{{ lookup('env', 'GRAFANA_ADMIN_USER') | default('admin') }}"
grafana_admin_password: "{{ lookup('env', 'GRAFANA_ADMIN_PASSWORD') | default('admin') }}"
tasks:
- name: Обновить SSH host key для избежания ошибок при переустановке
known_hosts:
path: ~/.ssh/known_hosts
name: "{{ ansible_host }}"
key: "{{ lookup('pipe', 'ssh-keyscan -t rsa,ecdsa,ed25519 ' + ansible_host) }}"
state: present
delegate_to: localhost
run_once: true
ignore_errors: yes
- name: Обновить кэш пакетов
apt:
update_cache: yes
- name: Установить необходимые пакеты
apt:
name:
- docker.io
- docker-compose
- make
- git
- python3-pip
- curl
- sshpass
- rsync
- vim
- zsh
- ufw
- htop
- iotop
- traceroute
- ncdu
- prometheus-node-exporter
state: present
- name: Проверить существование swap-файла
stat:
path: /swapfile
register: swap_file_stat
- name: Создать swap-файл (2GB)
command: fallocate -l 2G /swapfile
when: not swap_file_stat.stat.exists
- name: Установить правильные права на swap-файл
file:
path: /swapfile
mode: '0600'
owner: root
group: root
- name: Настроить swap-файл
command: mkswap /swapfile
when: not swap_file_stat.stat.exists
- name: Включить swap-файл
command: swapon /swapfile
when: not swap_file_stat.stat.exists
- name: Настроить swappiness = 10 (временно)
sysctl:
name: vm.swappiness
value: '10'
state: present
reload: yes
- name: Настроить swappiness = 10 (постоянно)
lineinfile:
path: /etc/sysctl.conf
regexp: '^vm\.swappiness\s*='
line: 'vm.swappiness = 10'
state: present
- name: Добавить swap-файл в /etc/fstab для автоматического монтирования
lineinfile:
path: /etc/fstab
line: '/swapfile none swap sw 0 0'
state: present
create: yes
- name: Проверить статус swap
command: swapon --show
register: swap_status
changed_when: false
- name: Показать информацию о swap
debug:
var: swap_status.stdout_lines
- name: Включить и запустить prometheus-node-exporter
systemd:
name: prometheus-node-exporter
enabled: yes
state: started
- name: Проверить статус prometheus-node-exporter
command: systemctl status prometheus-node-exporter
register: node_exporter_status
changed_when: false
- name: Показать статус prometheus-node-exporter
debug:
var: node_exporter_status.stdout_lines
- name: Проверить, что node_exporter слушает на порту 9100
command: netstat -tulpn | grep 9100
register: node_exporter_port
changed_when: false
- name: Показать информацию о порте 9100
debug:
var: node_exporter_port.stdout_lines
- name: Обновить Docker Compose до последней версии
get_url:
url: "https://github.com/docker/compose/releases/latest/download/docker-compose-{{ ansible_system }}-{{ ansible_architecture }}"
dest: /usr/local/bin/docker-compose
mode: '0755'
become: yes
- name: Включить и запустить Docker
systemd:
name: docker
enabled: yes
state: started
- name: Разрешить SSH (порт 22) перед включением UFW
ufw:
rule: allow
port: "22"
proto: tcp
- name: Настроить политику UFW по умолчанию
ufw:
policy: deny
direction: incoming
- name: Включить UFW (файрвол)
ufw:
state: enabled
- name: Открыть порты для сервисов
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop:
- "8080" # Telegram Bot
- "8081" # AnonBot
- "9090" # Prometheus
- "3000" # Grafana
- "9100" # Node Exporter
- name: Проверить существование пользователя deploy
getent:
database: passwd
key: "{{ deploy_user }}"
register: user_exists
failed_when: false
- name: Создать группу deploy с GID 1001
group:
name: "{{ deploy_user }}"
gid: "{{ gid }}"
when: user_exists.ansible_facts.getent_passwd is not defined
- name: Создать пользователя deploy с UID 1001 (если не существует)
user:
name: "{{ deploy_user }}"
uid: "{{ uid }}"
group: "{{ gid }}"
shell: /bin/zsh
create_home: yes
system: no
groups: docker
append: yes
when: user_exists.ansible_facts.getent_passwd is not defined
- name: Установить zsh как оболочку по умолчанию для существующего пользователя deploy
user:
name: "{{ deploy_user }}"
shell: /bin/zsh
when: user_exists.ansible_facts.getent_passwd is defined
- name: Скопировать SSH ключ с локальной машины для пользователя deploy
authorized_key:
user: "{{ deploy_user }}"
key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
state: present
- name: Настроить безопасный SSH
lineinfile:
path: /etc/ssh/sshd_config
regexp: "^{{ item.regexp }}"
line: "{{ item.line }}"
backup: yes
loop:
- { regexp: "PermitRootLogin", line: "PermitRootLogin no" }
- { regexp: "PasswordAuthentication", line: "PasswordAuthentication no" }
- { regexp: "PubkeyAuthentication", line: "PubkeyAuthentication yes" }
notify: reload ssh
- name: Удалить /home/prod, если требуется (чистое развертывание)
file:
path: "{{ project_root }}"
state: absent
when: recreate_project | bool
- name: Создать директорию проекта /home/prod
file:
path: "{{ project_root }}"
state: directory
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0755'
- name: Настроить SSH ключи для GitHub
authorized_key:
user: "{{ deploy_user }}"
key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
state: present
- name: Скопировать приватный SSH ключ для Git
copy:
src: "~/.ssh/id_rsa"
dest: "/home/{{ deploy_user }}/.ssh/id_rsa"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0600'
remote_src: no
- name: Настроить SSH config для GitHub
lineinfile:
path: "/home/{{ deploy_user }}/.ssh/config"
line: "Host github.com\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null"
create: yes
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0600'
- name: Переключиться на пользователя deploy
meta: reset_connection
- name: Клонировать основной репозиторий prod
git:
repo: git@github.com:KerradKerridi/prod.git
dest: "{{ project_root }}"
clone: yes
update: yes
become: yes
become_user: "{{ deploy_user }}"
- name: Клонировать AnonBot
git:
repo: git@github.com:KerradKerridi/AnonBot.git
dest: "{{ project_root }}/bots/AnonBot"
clone: yes
update: yes
become: yes
become_user: "{{ deploy_user }}"
- name: Клонировать telegram-helper-bot
git:
repo: git@github.com:KerradKerridi/telegram-helper-bot.git
dest: "{{ project_root }}/bots/telegram-helper-bot"
clone: yes
update: yes
become: yes
become_user: "{{ deploy_user }}"
- name: Установить правильные права на дашборд Node Exporter Full
file:
path: "{{ project_root }}/infra/grafana/provisioning/dashboards/node-exporter-full-dashboard.json"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0644'
become: yes
become_user: "{{ deploy_user }}"
- name: Скопировать SSH ключ на старый сервер для копирования файлов
authorized_key:
user: root
key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
state: present
delegate_to: "{{ old_server }}"
- name: Копировать .env для telegram-helper-bot со старого сервера
fetch:
src: "/home/prod/bots/telegram-helper-bot/.env"
dest: "/tmp/telegram-helper-bot.env"
flat: yes
delegate_to: "{{ old_server }}"
- name: Переместить .env для telegram-helper-bot на новое место
copy:
src: "/tmp/telegram-helper-bot.env"
dest: "{{ project_root }}/bots/telegram-helper-bot/.env"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0644'
become: yes
become_user: "{{ deploy_user }}"
- name: Проверить размер БД для telegram-helper-bot
stat:
path: "/home/prod/bots/telegram-helper-bot/database/tg-bot-database.db"
delegate_to: "{{ old_server }}"
register: db_size
- name: Показать размер БД для telegram-helper-bot
debug:
msg: "Размер БД: {{ (db_size.stat.size / 1024 / 1024) | round(2) }} MB"
- name: Копировать БД для telegram-helper-bot
fetch:
src: "/home/prod/bots/telegram-helper-bot/database/tg-bot-database.db"
dest: "/tmp/tg-bot-database.db"
flat: yes
delegate_to: "{{ old_server }}"
- name: Переместить БД для telegram-helper-bot на новое место
copy:
src: "/tmp/tg-bot-database.db"
dest: "{{ project_root }}/bots/telegram-helper-bot/database/tg-bot-database.db"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0644'
become: yes
become_user: "{{ deploy_user }}"
- name: Создать папку voice_users на новом сервере
file:
path: "{{ project_root }}/bots/telegram-helper-bot/voice_users"
state: directory
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0755'
become: yes
become_user: "{{ deploy_user }}"
- name: Создать временную папку для voice_users на локальной машине
file:
path: "/tmp/voice_users_migration"
state: directory
mode: '0755'
delegate_to: localhost
become: no
- name: Копировать voice_users со старого сервера на локальную машину
command: >
rsync -avz --progress --stats --partial --verbose
root@77.223.98.129:/home/prod/bots/telegram-helper-bot/voice_users/
/tmp/voice_users_migration/
delegate_to: localhost
become: no
- name: Копировать voice_users с локальной машины на новый сервер
synchronize:
src: "/tmp/voice_users_migration/"
dest: "{{ project_root }}/bots/telegram-helper-bot/voice_users/"
mode: push
rsync_opts: "--progress --stats --partial --verbose"
become: yes
become_user: "{{ deploy_user }}"
- name: Очистить временную папку на локальной машине
file:
path: "/tmp/voice_users_migration"
state: absent
delegate_to: localhost
become: no
- name: Копировать корневой .env файл
fetch:
src: "/home/prod/.env"
dest: "/tmp/root.env"
flat: yes
delegate_to: "{{ old_server }}"
- name: Переместить корневой .env файл на новое место
copy:
src: "/tmp/root.env"
dest: "{{ project_root }}/.env"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0644'
become: yes
become_user: "{{ deploy_user }}"
- name: Копировать .env для AnonBot
fetch:
src: "/home/prod/bots/AnonBot/.env"
dest: "/tmp/anonbot.env"
flat: yes
delegate_to: "{{ old_server }}"
- name: Переместить .env для AnonBot на новое место
copy:
src: "/tmp/anonbot.env"
dest: "{{ project_root }}/bots/AnonBot/.env"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0644'
become: yes
become_user: "{{ deploy_user }}"
- name: Проверить размер БД для AnonBot
stat:
path: "/home/prod/bots/AnonBot/database/anon_qna.db"
delegate_to: "{{ old_server }}"
register: anon_db_size
- name: Показать размер БД для AnonBot
debug:
msg: "Размер БД AnonBot: {{ (anon_db_size.stat.size / 1024 / 1024) | round(2) }} MB"
- name: Копировать БД для AnonBot
fetch:
src: "/home/prod/bots/AnonBot/database/anon_qna.db"
dest: "/tmp/anon_qna.db"
flat: yes
delegate_to: "{{ old_server }}"
- name: Переместить БД для AnonBot на новое место
copy:
src: "/tmp/anon_qna.db"
dest: "{{ project_root }}/bots/AnonBot/database/anon_qna.db"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0644'
become: yes
become_user: "{{ deploy_user }}"
- name: Установить права на скопированные файлы
file:
path: "{{ item }}"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0644'
loop:
- "{{ project_root }}/bots/telegram-helper-bot/.env"
- "{{ project_root }}/bots/telegram-helper-bot/database/tg-bot-database.db"
- "{{ project_root }}/bots/AnonBot/.env"
- "{{ project_root }}/bots/AnonBot/database/anon_qna.db"
become: yes
- name: Исправить права доступа для voice_users (рекурсивно)
file:
path: "{{ project_root }}/bots/telegram-helper-bot/voice_users"
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0755'
recurse: yes
become: yes
- name: Запустить ботов через make up
command: make up
args:
chdir: "{{ project_root }}"
become: yes
become_user: "{{ deploy_user }}"
tags: ["start_bots"]
# --- НОВОЕ: Проверка портов ---
- name: Пауза на 30 секунд — дать контейнерам запуститься
pause:
seconds: 30
- name: Проверить, что порт 8080 (Telegram Bot) открыт
wait_for:
port: 8080
host: "{{ ansible_host }}"
timeout: 30
state: started
- name: Проверить, что порт 8081 (AnonBot) открыт
wait_for:
port: 8081
host: "{{ ansible_host }}"
timeout: 30
state: started
- name: Проверить, что порт 9090 (Prometheus) открыт
wait_for:
port: 9090
host: "{{ ansible_host }}"
timeout: 30
state: started
- name: Проверить, что порт 3000 (Grafana) открыт
wait_for:
port: 3000
host: "{{ ansible_host }}"
timeout: 30
state: started
- name: Проверить, что порт 9100 (Node Exporter) открыт
wait_for:
port: 9100
host: "{{ ansible_host }}"
timeout: 30
state: started
- name: Проверить доступность Grafana API
uri:
url: "http://{{ ansible_host }}:3000/api/health"
method: GET
status_code: 200
register: grafana_health
retries: 5
delay: 10
- name: Проверить, что дашборд Node Exporter загружен в Grafana
uri:
url: "http://{{ ansible_host }}:3000/api/search?query=Node%20Exporter%20Full"
method: GET
user: "{{ grafana_admin_user | default('admin') }}"
password: "{{ grafana_admin_password | default('admin') }}"
status_code: 200
register: dashboard_check
retries: 3
delay: 5
- name: Показать информацию о найденных дашбордах
debug:
var: dashboard_check.json
- name: Проверка запуска ботов завершена — всё работает 🟢
debug:
msg: "Все сервисы запущены и слушают нужные порты."
# handlers для перезагрузки сервисов
handlers:
- name: reload ssh
systemd:
name: ssh
state: reloaded
- name: restart ufw
ufw:
state: reloaded