현재 사내에서 상용 DB는 AWS RDS를 이용하고 있으며, 주기적으로 백업을 진행하고 있다.
다만, 개발 환경의 DB는 온프레미스(구 개발) 서버에서 직접 설치하여 실행 중이며, 백업을 하고 있지 않음.
따라서, 이를 온프레미스(신 개발) 서버로 이전하는 작업을 진행해야 할 필요도 있었습니다.
이 글은 mysqldump
를 이용해 데이터를 백업하고, 생성된 백업본으로 새로운 환경에 DB를 구축하는 마이그레이션 과정을 담았습니다.
목표는 구 개발서버의 MySQL5.7을 신 개발 서버로 옮기는 것이다
이때, 신 개발 서버에서는 Docker로 MySQL 5.7을 구동한다.
추후 신 개발서버의 MySQL 5.7이 안정화가 되면, MySQL 8.0으로 마이그레이션을 진행할 예정
→ AWS RDS의 백업 정책 부터 알아보자.
→ mysqldump 이용해보자.
mysqldump [--옵션] --all-databases
mysqldump [--옵션] --databases db_name
mysqldump [--옵션] --databases db_name --tables table_name
# 전체 데이타 베이스 백업
mysqldump -u <username> -p<PASSWORD> -F --single-transaction --all-databases > alldatabase.sql
# 특정 데이타 베이스(testdb) 백업
mysqldump -u <username> -p<PASSWORD> -F --single-transaction --databases testdb > testdb.sql
# 특정 테이블(t1) 백업
mysqldump -u <username> -p<PASSWORD> --databases db_name --tables t1 > t1.sql
# 특정 테이블(t1)의 **구조만** 백업
mysqldump -u <username> -p<PASSWORD> --no-data <데이터베이스명> > <백업파일명>.sql
# 데이타베이스 복구
mysql -u root -p PASSWORD < testdb.sql
덤프 백업 후 생성된 바이너리 로그 파일 확인 (ls -l 로 확인) 후에
덤프 후 생성된 바이너리 파일 2개 이상일 경우에 각각 바이너리 로그 파일마다 mysqlbinlog를 해줘야 한다.
# 현재 바이너리로그 파일 확인
mysql> show master status ;
+--------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+--------------------+----------+--------------+------------------+-------------------+
| testsvr-bin.000031 | 7443 | | | |
+--------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
# 장애 발생시
mysql> drop database testdb ;
# 바이너리 로그 파일 변환
shell> mysqlbinlog testsvr-bin.000031 > binlog.sql
# 데이터베이스 복구
shell> mysql -u root -pPASSWORD < testdb.sql
# 바이너리 로그 파일 복원
shell> mysql -u root -pPASSWORD < binlog.sql
실제 구 개발 서버의 경우는 MySQL을 직접 설치하여 사용 중
$ ssh ~~~~~~~~~~ # 접속 내용
> password : {password}
#20240519_TestDB.sql 파일 생성
$ mysqldump -u diabuser -p --single-transaction --databases TestDB > /etc/mysql/backup/$(date +%Y%m%d)_TestDB.sql
> password : {password}
$ mysqldump -u diabuser -p --single-transaction --all-databases > /etc/mysql/backup/$(date +%Y%m%d)_AllDevDB.sql
> password : {password}
$ cd /etc/mysql/backup
$ ls -al
-rw-rw-r-- 1 mars mars 190M 5월 21 17:31 20240521_AllDevDB.sql
-rw-rw-r-- 1 mars mars 163M 5월 21 17:19 20240521_TestDB.sql
scp 명령어 혹은 FTP 등을 이용하여 각자 편한 방식을 이용.
보안상 이 내용은 기재하지 않음.
디렉토리 생성
# 신개발 서버 접속 후
$ mkdir /test/docker/mysql57 # mysql 관련 설정/데이터 파일들이 위치하도록
$ mkdir /test/docker/mysql57/backup # 백업 sql 파일들이 위치하도록
/test/docker/mysql57/docker-compose.yml
작성
version: '3'
services:
mysql:
image: mysql:5.7
container_name: mysql-container
restart: always
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD={password} # root 계정의 password
- TZ=Asia/Seoul
command:
- --character-set-server=utf8mb4
volumes:
- ./db/mysql/data:/var/lib/mysql
- ./db/conf.d:/test/docker/mysql57/conf.d
- ./:/test/docker/mysql57
docker 실행
# docker-compose.yml을 작성한 장소(/test/docker/mysql57)에서 실행
$ sudo docker compose up -d # -d: 백그라운드 실행 옵션
# 실행 확인
$ sudo docker ps
아래 내용은 기존 구 개발 서버에 위치하던 사용자 권한/정보와 동일하게 구성합니다.
# docker(mysql-container)의 bash 접속
$ sudo docker exec -it mysql-container bash
# 첫 실행 시, 루트 계정만 존재
# 암호는 docker-compose.yml에서 작성했던 내용
bash> mysql -u root -p
> password : {password}
# 사용자 생성 (localhost -> 내부 접근을 허용)
mysql> CREATE USER '{NEW_USER}'@'localhost' identified by '{NEW_PASSWORD}';
# 모든 권한 추가 예시. (권장하지 않음.)
mysql> GRANT ALL ON *.* to {NEW_USER}@localhost;
# docker(mysql-container) bash 접속
$ sudo docker exec -it mysql-container bash
# 특정 DB만 백업하고 싶을 경우
bash> mysql -u {NEW_USER} -p DiabDB < /test/docker/mysql57/backup/20240521_testDB.sql
# 전체 DB 백업하고 싶을 경우
bash> mysql -u {NEW_USER} -p < /test/docker/mysql57/backup/20240521_AllDevDB.sql
password : {NEW_PASSWORD}
이후, DB에 접속하여 최근 데이터까지 제대로 복원이 되었는지 확인 필요.
백업 파일을 주기적으로 생성하고, 오래된(30일이 지난) 파일들을 지우는 스크립트 작성
#!/bin/bash
# MySQL 사용자 이름 및 비밀번호
USER="{NEW_USER}"
PASSWORD="{NEW_PASSWORd}"
# 백업 저장 경로
BACKUP_DIR="/test/docker/mysql57/backup"
# 각 DB별로 백업 파일 이름
TEST_BACKUP_FILE="$BACKUP_DIR/$(date +%Y%m%d)_TestDB.sql"
# 각 DB별로 백업 명령 실행
mysqldump -u $USER -p$PASSWORD --single-transaction --databases TestDB > $TEST_BACKUP_FILE
# DB 전체를 한번에 백업할 경우
# ALLDEVDB_BACKUP_FILE="$BACKUP_DIR/$(date +%Y%m%d)_AllDevDB.sql"
# mysqldump -u $USER -p$PASSWORD --single-transaction --all-databases > $ALLDEVDB_BACKUP_FILE
# mysqldump 명령어가 오래 걸릴 수 있으니, 바로 실행되지 않게 10초 대기
sleep 10
# 각 DB 파일별로 최근 3개 버전만 남기고 나머지를 삭제
ls -t $BACKUP_DIR/*TestDB.sql | tail -n +4 | xargs rm -f
$ chmod +x /test/docker/mysql57/mysql57backup.sh
run_db_backup.sh
현재 신개발 서버에서 사용하는 계정은 루트 계정이 아니라, docker 명령어를 사용하기 위해 sudo를 사용해야 한다.
크론 탭에 sudo를 사용한 명령어를 입력하는 것은 좋지 못하니, sudo로 mysql57backup.sh
를 호출하는 스크립트를 작성하자.
#!/bin/bash
###
# NEW_USER 계정은 docker 명령어에 대한 권한이 없기 때문에, root로 호출해야 함.
# crontab에 작업 등록시 root로 등록하여야 함.
###
docker exec -i mysql-container sh /test/docker/mysql57/mysql57backup.sh
$ crontab -e
# 1주 간격으로 실행
# 0시 0분 7일간격 * *
# -> 첫 실행 : 크론이 등록된 후 7일 뒤
0 0 */7 * * /test/docker/mysql57/run_db_backup.sh
등록된 크론탭 확인
$ crontab -l
크론 정보 수정시 반드시 재시작해주어야함
$ sudo service cron restart
# 이외 cron 명령어들
$ sudo service cron status
$ sudo service cron start
$ sudo service cron stop
아래이 경우 슬랙 알림이 오도록 추가했다.
run_db_backup.sh
#!/bin/bash
# Slack 알림 함수
send_slack_notification() {
local message="$1"
curl -X POST -d "text=$1" -d "channel={슬랙 채널명}" \
-H "Authorization: Bearer {슬랙 API 토큰}" \
https://slack.com/api/chat.postMessage
}
# 파일 존재 및 크기 확인 함수
validate_mysql_backup_file() {
local file=$1
if [ ! -e "$file" ]; then
send_slack_notification "dev::: MySQL backup fail - file does not created!"
return 1
elif [ ! -s "$file" ]; then
send_slack_notification "dev::: MySQL backup fail - file is empty!"
return 1
else
return 0
fi
}
# 신 개발서버 백업 저장 경로
# BACKUP_DIR="/test/docker/mysql57/backup"
# 백업 파일 이름
TEST_BACKUP_FILE="$BACKUP_DIR/$(date +%Y%m%d)_TestDB.sql"
# 신 개발서버 백업 실행 명령
# docker exec -i mysql-container sh /test/docker/mysql57/mysql57backup.sh
sleep 15
# 백업 파일이 제대로 생성 되었을 때만 각 DB 파일별로 최근 3개 버전만 남기고 나머지를 삭제
if validate_mysql_backup_file "$TEST_BACKUP_FILE" &&
validate_mysql_backup_file "${이외 다른 DB 백업1}"; then
ls -t $BACKUP_DIR/*TestDB.sql | tail -n +4 | xargs rm -f
ls -t $BACKUP_DIR/*{다른}DB.sql | tail -n +4 | xargs rm -f
send_slack_notification "dev::: MySQL backup success"
fi