Docker 환경의 MySQL 및 PostgreSQL 데이터베이스 원격 자동 백업 및 복원 스크립트 구성

개요 및 아키텍처

서버 A의 Docker 컨테이너에서 실행 중인 MySQL 또는 PostgreSQL 데이터베이스를 백업하여, 서버 B의 Docker 컨테이너로 전송 및 복원하는 자동화 파이프라인을 구축하는 방법을 다룹니다. 이 구성은 mysqldumppg_dump 유틸리티와 SSH 프로토콜을 활용하여 네트워크 간 데이터 이전을 수행합니다.

사전 준비: SSH 키 기반 인증 구성

서버 A에서 서버 B로 비밀번호 없이 파일을 전송하고 원격 명령을 실행하기 위해 SSH 공개키 인증을 설정해야 합니다.

  1. 서버 A에서 RSA 키 쌍 생성: ssh-keygen -t rsa -b 4096 -C "backup-agent" -f ~/.ssh/id_rsa_backup -N ""
  2. 공개키를 서버 B로 복사: ssh-copy-id -i ~/.ssh/id_rsa_backup.pub deployer@10.0.0.50
  3. 연결 테스트: ssh -i ~/.ssh/id_rsa_backup deployer@10.0.0.50 "echo 'Connection successful'"

MySQL 데이터베이스 백업 스크립트

시나리오 1: SQL 파일 백업 및 전송만 수행 (서버 B에 DB 컨테이너가 없는 경우)

서버 A의 MySQL 컨테이너에서 덤프를 생성한 후, 서버 B의 지정된 디렉터리에 SQL 파일로 저장합니다.

#!/usr/bin/env bash
set -euo pipefail

# --- 환경 변수 설정 ---
SRC_CONTAINER="mysql_prod_01"
SRC_DBNAME="inventory_db"
SRC_DBUSER="admin_user"
SRC_DBPASS="secure_password_123"

LOCAL_DUMP_DIR="/var/lib/db_backups"
DUMP_FILENAME="mysql_dump_$(date +%F_%H%M%S).sql"
LOCAL_DUMP_PATH="${LOCAL_DUMP_DIR}/${DUMP_FILENAME}"

DEST_SSH_USER="deployer"
DEST_HOST="10.0.0.50"
DEST_SSH_KEY="/root/.ssh/id_rsa_backup"
DEST_REMOTE_DIR="/mnt/nfs/backups/mysql"

# --- 디렉터리 생성 및 덤프 수행 ---
mkdir -p "${LOCAL_DUMP_DIR}"
echo "[INFO] MySQL 덤프 시작: ${SRC_DBNAME}"
docker exec "${SRC_CONTAINER}" mysqldump \
    --single-transaction \
    --routines \
    --triggers \
    -u"${SRC_DBUSER}" -p"${SRC_DBPASS}" "${SRC_DBNAME}" > "${LOCAL_DUMP_PATH}"

if [[ ! -s "${LOCAL_DUMP_PATH}" ]]; then
    echo "[ERROR] 덤프 파일이 비어있거나 생성되지 않았습니다."
    exit 1
fi

# --- 원격 서버로 전송 ---
echo "[INFO] 백업 파일 전송 중: ${DEST_HOST}"
scp -i "${DEST_SSH_KEY}" -o StrictHostKeyChecking=no \
    "${LOCAL_DUMP_PATH}" "${DEST_SSH_USER}@${DEST_HOST}:${DEST_REMOTE_DIR}/"

echo "[SUCCESS] MySQL 백업 및 전송 완료."

시나리오 2: 백업, 전송 및 서버 B의 Docker 컨테이너에 자동 복원

백업 파일을 전송한 후, SSH를 통해 서버 B의 MySQL 컨테이너에 직접 복원 명령을 실행합니다.

#!/usr/bin/env bash
set -euo pipefail

# --- 소스 서버 설정 ---
SRC_CONTAINER="mysql_prod_01"
SRC_DBNAME="inventory_db"
SRC_DBUSER="admin_user"
SRC_DBPASS="secure_password_123"

LOCAL_DUMP_DIR="/var/lib/db_backups"
DUMP_FILENAME="mysql_full_$(date +%F_%H%M%S).sql"
LOCAL_DUMP_PATH="${LOCAL_DUMP_DIR}/${DUMP_FILENAME}"

# --- 타겟 서버 설정 ---
DEST_SSH_USER="deployer"
DEST_HOST="10.0.0.50"
DEST_SSH_KEY="/root/.ssh/id_rsa_backup"
DEST_REMOTE_DIR="/mnt/nfs/backups/mysql"

DEST_CONTAINER="mysql_staging_01"
DEST_DBNAME="inventory_db_staging"
DEST_DBUSER="staging_admin"
DEST_DBPASS="staging_password_456"

# --- 백업 및 전송 로직 ---
mkdir -p "${LOCAL_DUMP_DIR}"
docker exec "${SRC_CONTAINER}" mysqldump \
    --single-transaction -u"${SRC_DBUSER}" -p"${SRC_DBPASS}" "${SRC_DBNAME}" > "${LOCAL_DUMP_PATH}"

scp -i "${DEST_SSH_KEY}" -o StrictHostKeyChecking=no \
    "${LOCAL_DUMP_PATH}" "${DEST_SSH_USER}@${DEST_HOST}:${DEST_REMOTE_DIR}/"

# --- 원격 복원 로직 ---
echo "[INFO] 타겟 서버에서 복원 작업 시작..."
REMOTE_FILE="${DEST_REMOTE_DIR}/${DUMP_FILENAME}"

ssh -i "${DEST_SSH_KEY}" -o StrictHostKeyChecking=no "${DEST_SSH_USER}@${DEST_HOST}" << END_SSH
    cat "${REMOTE_FILE}" | docker exec -i "${DEST_CONTAINER}" mysql \
        -u"${DEST_DBUSER}" -p"${DEST_DBPASS}" "${DEST_DBNAME}"
    echo "[INFO] 원격 복원 명령 실행 완료."
END_SSH

if [[ $? -eq 0 ]]; then
    echo "[SUCCESS] MySQL 전체 파이프라인(백업-전송-복원) 성공."
else
    echo "[ERROR] 복원 단계에서 오류가 발생했습니다."
    exit 1
fi

PostgreSQL 데이터베이스 백업 스크립트

시나리오 1: SQL 파일 백업 및 전송만 수행

PostgreSQL의 pg_dump를 사용하여 덤프를 생성하고 원격 스토리지로 이동시킵니다.

#!/usr/bin/env bash
set -euo pipefail

# --- 환경 변수 설정 ---
SRC_CONTAINER="pg_prod_01"
SRC_DBNAME="analytics_db"
SRC_DBUSER="pg_admin"
SRC_DBPASS="pg_secure_pass_789"

LOCAL_DUMP_DIR="/var/lib/db_backups/pg"
DUMP_FILENAME="pg_dump_$(date +%F_%H%M%S).sql"
LOCAL_DUMP_PATH="${LOCAL_DUMP_DIR}/${DUMP_FILENAME}"

DEST_SSH_USER="deployer"
DEST_HOST="10.0.0.50"
DEST_SSH_KEY="/root/.ssh/id_rsa_backup"
DEST_REMOTE_DIR="/mnt/nfs/backups/postgres"

mkdir -p "${LOCAL_DUMP_DIR}"

echo "[INFO] PostgreSQL 덤프 시작: ${SRC_DBNAME}"
docker exec -e PGPASSWORD="${SRC_DBPASS}" "${SRC_CONTAINER}" pg_dump \
    -U "${SRC_DBUSER}" \
    -d "${SRC_DBNAME}" \
    --format=plain > "${LOCAL_DUMP_PATH}"

scp -i "${DEST_SSH_KEY}" -o StrictHostKeyChecking=no \
    "${LOCAL_DUMP_PATH}" "${DEST_SSH_USER}@${DEST_HOST}:${DEST_REMOTE_DIR}/"

echo "[SUCCESS] PostgreSQL 백업 및 전송 완료."

시나리오 2: 백업, 전송 및 서버 B의 Docker 컨테이너에 자동 복원

전송된 덤프 파일을 서버 B의 PostgreSQL 컨테이너 내부에서 psql을 통해 적재합니다.

#!/usr/bin/env bash
set -euo pipefail

# --- 소스 서버 설정 ---
SRC_CONTAINER="pg_prod_01"
SRC_DBNAME="analytics_db"
SRC_DBUSER="pg_admin"
SRC_DBPASS="pg_secure_pass_789"

LOCAL_DUMP_DIR="/var/lib/db_backups/pg"
DUMP_FILENAME="pg_full_$(date +%F_%H%M%S).sql"
LOCAL_DUMP_PATH="${LOCAL_DUMP_DIR}/${DUMP_FILENAME}"

# --- 타겟 서버 설정 ---
DEST_SSH_USER="deployer"
DEST_HOST="10.0.0.50"
DEST_SSH_KEY="/root/.ssh/id_rsa_backup"
DEST_REMOTE_DIR="/mnt/nfs/backups/postgres"

DEST_CONTAINER="pg_staging_01"
DEST_DBNAME="analytics_db_staging"
DEST_DBUSER="pg_staging_admin"
DEST_DBPASS="pg_staging_pass_012"

# --- 백업 및 전송 ---
mkdir -p "${LOCAL_DUMP_DIR}"
docker exec -e PGPASSWORD="${SRC_DBPASS}" "${SRC_CONTAINER}" pg_dump \
    -U "${SRC_DBUSER}" -d "${SRC_DBNAME}" --format=plain > "${LOCAL_DUMP_PATH}"

scp -i "${DEST_SSH_KEY}" -o StrictHostKeyChecking=no \
    "${LOCAL_DUMP_PATH}" "${DEST_SSH_USER}@${DEST_HOST}:${DEST_REMOTE_DIR}/"

# --- 원격 복원 ---
echo "[INFO] 타겟 PostgreSQL 컨테이너 복원 시작..."
REMOTE_FILE="${DEST_REMOTE_DIR}/${DUMP_FILENAME}"

ssh -i "${DEST_SSH_KEY}" -o StrictHostKeyChecking=no "${DEST_SSH_USER}@${DEST_HOST}" << END_SSH
    docker exec -e PGPASSWORD="${DEST_DBPASS}" -i "${DEST_CONTAINER}" psql \
        -U "${DEST_DBUSER}" \
        -d "${DEST_DBNAME}" < "${REMOTE_FILE}"
END_SSH

echo "[SUCCESS] PostgreSQL 전체 파이프라인(백업-전송-복원) 성공."

스크립트 실행 및 크론(Cron) 등록

작성된 스크립트에 실행 권한을 부여하고, 필요에 따라 crontab에 등록하여 자동화할 수 있습니다.

# 실행 권한 부여
chmod +x /opt/scripts/db_backup_pipeline.sh

# 수동 실행 테스트
/opt/scripts/db_backup_pipeline.sh

# Crontab 등록 예시 (매일 새벽 2시 실행)
echo "0 2 * * * /opt/scripts/db_backup_pipeline.sh >> /var/log/db_backup.log 2>&1" | crontab -

태그: docker MySQL PostgreSQL bash SSH

6월 26일 20:09에 게시됨