-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmigration.sh
More file actions
351 lines (302 loc) · 13.5 KB
/
migration.sh
File metadata and controls
351 lines (302 loc) · 13.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
#!/bin/bash
set -e
# Проверка свободного места на диске (функция)
check_disk_space() {
local min_gb=$1
local avail_gb=$(df --output=avail -BG / | tail -1 | tr -dc '0-9')
if [ "$avail_gb" -lt "$min_gb" ]; then
echo "[ERROR] Недостаточно места на диске! Требуется минимум ${min_gb}ГБ, доступно: ${avail_gb}ГБ" >&2
exit 1
fi
}
# Проверка открытых портов (функция)
check_ports() {
local ports=(80 443 8080 1337 5432)
for port in "${ports[@]}"; do
if ! ss -tuln | grep -q ":$port "; then
echo "[WARNING] Порт $port не слушает! Проверьте настройки firewall/security groups."
else
echo "[INFO] Порт $port открыт."
fi
done
}
# Функция для scp/ssh с паролем через expect
expect_scp() {
local SRC=$1
local DST=$2
local PASS=$3
expect << EOF
spawn scp -o StrictHostKeyChecking=no $SRC $DST
expect {
"*assword:" { send "$PASS\r"; exp_continue }
eof
}
EOF
}
expect_ssh() {
local HOST=$1
local PASS=$2
local CMD=$3
expect << EOF
spawn ssh -o StrictHostKeyChecking=no $HOST "$CMD"
expect {
"*assword:" { send "$PASS\r"; exp_continue }
eof
}
EOF
}
# === Ввод данных пользователя ===
read -p "Введите имя пользователя для SSH: " USER
read -p "Введите IP-адрес сервера: " HOST
read -s -p "Введите пароль для SSH: " PASSWORD
export USER
export HOST
export PASSWORD
echo
# Убедитесь, что sshpass установлен:
if ! command -v sshpass &> /dev/null; then
echo "[INFO] Устанавливаю sshpass..."
if [ -f /etc/debian_version ]; then
apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y sshpass || { echo "[ERROR] Не удалось установить sshpass!" >&2; exit 1; }
else
echo "[ERROR] Установите sshpass вручную для вашей ОС!" >&2
exit 1
fi
fi
# === 0. Определяем пользователя Postgres из .env или .env-prod ===
DB_USER=$(grep -E '^POSTGRES_USER=' $WORKDIR/GPT/.env 2>/dev/null | cut -d'=' -f2)
if [ -z "$DB_USER" ]; then
DB_USER=$(grep -E '^POSTGRES_USER=' $WORKDIR/GPT/.env-prod 2>/dev/null | cut -d'=' -f2)
fi
if [ -z "$DB_USER" ]; then
DB_USER="postgres" # fallback
fi
echo "[INFO] Используется пользователь Postgres: $DB_USER"
# === 1. Делаем дамп всех баз ===
if [ -f /tmp/all_pg_dump.sql ]; then
echo "[INFO] Дамп базы уже существует, пропускаю создание."
else
if ! docker ps | grep -q postgresql-prod; then
echo "[ERROR] Контейнер postgresql-prod не запущен!" >&2
exit 1
fi
docker exec -t postgresql-prod pg_dumpall -U "$DB_USER" > /tmp/all_pg_dump.sql
fi
# === 2. Архивируем всю рабочую директорию (root) ===
if [ -f "$ARCHIVE" ]; then
echo "[INFO] Архив уже существует, пропускаю архивацию."
else
echo "[INFO] Проверяю свободное место перед архивацией..."
check_disk_space 5 # Требуем минимум 5ГБ (пример)
cd "$WORKDIR"
if ! tar czf "$ARCHIVE" .; then
echo "[ERROR] Ошибка архивации!" >&2
exit 1
fi
echo "[INFO] Архивация завершена. Проверяю свободное место после архивации..."
check_disk_space 2
fi
# === 3. Копируем архив и дамп на новый сервер ===
sshpass -p "$PASSWORD" ssh -o StrictHostKeyChecking=no $USER@$HOST 'md5sum /tmp/project_backup.tar.gz /tmp/all_pg_dump.sql 2>/dev/null' > /tmp/remote_md5.txt || true
REMOTE_ARCHIVE_MD5=$(grep project_backup.tar.gz /tmp/remote_md5.txt | awk '{print $1}')
REMOTE_DUMP_MD5=$(grep all_pg_dump.sql /tmp/remote_md5.txt | awk '{print $1}')
LOCAL_ARCHIVE_MD5=$(md5sum "$ARCHIVE" | awk '{print $1}')
LOCAL_DUMP_MD5=$(md5sum /tmp/all_pg_dump.sql | awk '{print $1}')
if [ "$REMOTE_ARCHIVE_MD5" != "$LOCAL_ARCHIVE_MD5" ]; then
if ! expect_scp "$ARCHIVE" $USER@$HOST:/tmp/ "$PASSWORD"; then
echo "[ERROR] Ошибка копирования архива по SCP!" >&2
exit 1
fi
else
echo "[INFO] Архив уже актуален на целевом сервере, пропускаю копирование."
fi
if [ "$REMOTE_DUMP_MD5" != "$LOCAL_DUMP_MD5" ]; then
if ! expect_scp /tmp/all_pg_dump.sql $USER@$HOST:/tmp/ "$PASSWORD"; then
echo "[ERROR] Ошибка копирования дампа базы по SCP!" >&2
exit 1
fi
else
echo "[INFO] Дамп уже актуален на целевом сервере, пропускаю копирование."
fi
echo "\n[INFO] Если потребуется пароль для SSH, используйте: \n"
# === 4. Создаём скрипт для удалённого выполнения ===
cat > /tmp/remote_migrate.sh <<' '
set -e
check_disk_space() {
local min_gb=$1
local avail_gb=$(df --output=avail -BG / | tail -1 | tr -dc '0-9')
if [ "$avail_gb" -lt "$min_gb" ]; then
echo "[ERROR] Недостаточно места на диске! Требуется минимум [1m${min_gb}ГБ [0m, доступно: ${avail_gb}ГБ" >&2
exit 1
fi
}
check_ports() {
local ports=(80 443 8080 1337 5432)
for port in "${ports[@]}"; do
if ! ss -tuln | grep -q ":$port "; then
echo "[WARNING] Порт $port не слушает! Проверьте настройки firewall/security groups."
else
echo "[INFO] Порт $port открыт."
fi
done
}
NEWDIR="/root"
# === 5. Устанавливаем docker и docker-compose, если не установлены ===
if ! command -v docker &> /dev/null; then
curl -fsSL https://get.docker.com | sh
fi
if ! command -v docker-compose &> /dev/null; then
curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
fi
# === 6. Распаковываем архив ===
if [ -d "$NEWDIR/GPT" ]; then
echo "[INFO] GPT уже распакован, пропускаю распаковку."
else
echo "[INFO] Проверяю свободное место перед распаковкой..."
check_disk_space 5
if [ ! -f /tmp/project_backup.tar.gz ]; then
echo "[ERROR] Архив не найден!" >&2
exit 1
fi
if ! tar xzf /tmp/project_backup.tar.gz -C $NEWDIR; then
echo "[ERROR] Ошибка распаковки архива!" >&2
exit 1
fi
echo "[INFO] Распаковка завершена. Проверяю свободное место после распаковки..."
check_disk_space 2
fi
# === 7. Проверяем docker-compose-prod.yaml и .env ===
cd GPT
if [ ! -f docker-compose-prod.yaml ]; then
echo "[ERROR] Не найден docker-compose-prod.yaml!"; exit 1
fi
if [ ! -f .env ]; then
echo "[WARNING] Не найден .env! Проверь переменные окружения вручную."
fi
# === 8. Запускаем все сервисы ===
docker-compose -f docker-compose-prod.yaml up -d --build
# === 9. Восстанавливаем базу Postgres из дампа ===
if ! docker ps | grep -q postgresql-prod; then
echo "[ERROR] Контейнер postgresql-prod не запущен!" >&2
exit 1
fi
DB_USER=$(grep -E '^POSTGRES_USER=' /root/GPT/.env 2>/dev/null | cut -d'=' -f2)
if [ -z "$DB_USER" ]; then
DB_USER=$(grep -E '^POSTGRES_USER=' /root/GPT/.env-prod 2>/dev/null | cut -d'=' -f2)
fi
if [ -z "$DB_USER" ]; then
DB_USER="postgres"
fi
# Ожидание готовности Postgres
until docker exec postgresql-prod pg_isready -U "$DB_USER"; do
echo "[INFO] Ожидание готовности Postgres..."; sleep 2;
done
if [ -f /tmp/all_pg_dump.sql ]; then
echo "[INFO] Восстанавливаю базу Postgres под пользователем: $DB_USER"
set +e
docker exec -i postgresql-prod psql -U "$DB_USER" < /tmp/all_pg_dump.sql
set -e
else
echo "[WARNING] Дамп базы не найден, пропускаю восстановление."
fi
# === 10. Проверяем статусы контейнеров ===
docker ps
# === 11. Проверяем открытые порты ===
check_ports
# === 13. Запуск Telegram-бота ===
echo "[DEBUG] === Запуск Telegram-бота ==="
echo "[DEBUG] Текущая рабочая директория: $(pwd)"
echo "[DEBUG] Содержимое /root:"
ls -l /root
echo "[DEBUG] Содержимое /root/telegram-bot:"
ls -l /root/telegram-bot
# Переход в директорию telegram-bot
cd /root/telegram-bot || {
echo "[ERROR] Не удалось перейти в директорию /root/telegram-bot"
exit 1
}
echo "[DEBUG] Текущая директория после cd: $(pwd)"
# Проверка существования docker-compose.yml
if [ -f docker-compose.yml ]; then
echo "[INFO] Файл docker-compose.yml найден"
echo "[DEBUG] Содержимое docker-compose.yml:"
cat docker-compose.yml
# Проверка синтаксиса docker-compose файла
echo "[DEBUG] Проверка синтаксиса docker-compose файла:"
docker-compose config || {
echo "[ERROR] Ошибка в синтаксисе docker-compose.yml"
exit 1
}
# Остановка и удаление старых контейнеров (если есть)
echo "[INFO] Остановка старых контейнеров..."
docker-compose down --remove-orphans 2>/dev/null || {
echo "[WARNING] Не удалось остановить старые контейнеры, возможно их не было"
}
# Удаление потенциально конфликтующих сетей
echo "[INFO] Очистка конфликтующих сетей..."
docker network prune -f 2>/dev/null || true
# Создание переменных окружения для отладки
export COMPOSE_PROJECT_NAME="telegram-bot"
export DOCKER_BUILDKIT=1
export COMPOSE_DOCKER_CLI_BUILD=1
echo "[DEBUG] Переменные окружения:"
env | grep -E "(COMPOSE|DOCKER)" || true
# Запуск с подробным логированием
echo "[INFO] Запуск Telegram-бота с подробным логированием..."
# Попытка запуска с детальным выводом ошибок
if docker-compose up -d --build 2>&1 | tee /tmp/telegram-bot-startup.log; then
echo "[SUCCESS] Команда docker-compose up завершена успешно"
# Ожидание запуска
echo "[INFO] Ожидание 10 секунд для запуска контейнеров..."
sleep 10
# Проверка статуса контейнеров
echo "[INFO] Проверка статуса контейнеров:"
docker-compose ps -a
# Проверка логов
echo "[INFO] Логи Telegram-бота (последние 50 строк):"
docker-compose logs --tail=50 || {
echo "[WARNING] Не удалось получить логи через docker-compose"
}
# Проверка через docker ps
echo "[INFO] Проверка через docker ps:"
docker ps -a | grep telegram || {
echo "[WARNING] Контейнеры telegram не найдены в docker ps"
}
# Проверка сетей
echo "[INFO] Проверка сетей:"
docker network ls | grep telegram || {
echo "[WARNING] Сети telegram не найдены"
}
else
echo "[ERROR] Команда docker-compose up завершилась с ошибкой"
echo "[ERROR] Содержимое лога запуска:"
cat /tmp/telegram-bot-startup.log 2>/dev/null || echo "Лог не найден"
# Попытка диагностики
echo "[DEBUG] Диагностика проблемы:"
echo "[DEBUG] Статус Docker демона:"
docker info || echo "Docker info недоступен"
echo "[DEBUG] Проверка образов:"
docker images | head -10
echo "[DEBUG] Проверка процессов:"
ps aux | grep docker | head -5
exit 1
fi
else
echo "[ERROR] Файл docker-compose.yml не найден в /root/telegram-bot"
echo "[DEBUG] Содержимое директории:"
ls -la /root/telegram-bot/
exit 1
fi
echo "[DEBUG] === Завершение запуска Telegram-бота ==="
EOSCRIPT
# === 5. Копируем и запускаем remote_migrate.sh на новом сервере ===
if ! expect_scp /tmp/remote_migrate.sh $USER@$HOST:/tmp/ "$PASSWORD"; then
echo "[ERROR] Ошибка копирования remote_migrate.sh по SCP!" >&2
exit 1
fi
if ! expect_ssh $USER@$HOST "$PASSWORD" 'bash /tmp/remote_migrate.sh'; then
echo "[ERROR] Ошибка запуска remote_migrate.sh на сервере!" >&2
exit 1
fi
echo "\nПеренос и запуск завершены! Проверь логи и доступность сервисов на новом сервере (vds2783266.my-ihor.ru, 45.89.66.70)."