- CI/CD 서버 스펙 변경 반영 (8vCPU/16GB) - 개발서버 DB 백업 문서화 (sam-db-backup.sh) - CI/CD 백업 경로/대상 업데이트 (/data/, codebridge 추가, root 크론) - MNG Jenkinsfile storage/logs 심링크 수정 반영 - 마이그레이션 정책 추가 (sam→API, codebridge→MNG) - MNG 배포 후 500 에러 트러블슈팅 사례 추가 - Laravel Scheduler 섹션 추가 (API+MNG, www-data) - deploy 전용 계정 전환 계획 문서 추가
8.1 KiB
8.1 KiB
6. 데이터베이스 관리
마이그레이션 정책
원칙
| 대상 DB | 마이그레이션 위치 | 실행 주체 | 비고 |
|---|---|---|---|
| sam DB | api/database/migrations/ |
API Jenkinsfile | sam DB 스키마/데이터 변경은 API에서만 |
| codebridge DB | mng/database/migrations/ |
MNG Jenkinsfile | codebridge DB 변경은 MNG에서만 |
이력 관리
- API와 MNG 모두
sam.migrations테이블에 이력 기록 (Laravel 기본 동작) - 양쪽에서
php artisan migrate --force를 실행해도 파일명이 겹치지 않으면 충돌 없음 - Laravel은 자기 폴더의 파일만 스캔하고,
sam.migrations에 이미 있으면 skip
sam.migrations 테이블:
1 (API 실행) ✓ ← API migrate 시: 이미 있으니 skip
2 (API 실행) ✓
3 (MNG 실행) ✓ ← API는 이 파일이 없으므로 모름 (무관)
4 (API 실행) ✓
5 (MNG 실행) ✓ ← MNG migrate 시: 이미 있으니 skip
주의사항
--force는 production 환경에서 확인 프롬프트를 건너뛰는 옵션 (순서 충돌과 무관)- 파일명(타임스탬프)이 겹치지 않도록 주의
- sam DB를 변경하는 마이그레이션은 반드시 API에서 작성 (MNG에서 sam DB 변경 금지)
[운영] MySQL 접속
sudo mysql # root (auth_socket)
mysql -u hskwon # 관리자 (auth_socket, sudo 불필요)
mysql -u codebridge -p sam # 앱 사용자
[CI/CD] MySQL 접속
mysql # hskwon (auth_socket)
sudo mysql # root (auth_socket)
DB 백업
[운영] 수동 백업
# sam DB
mysqldump -u hskwon --single-transaction --routines --triggers sam | gzip > /tmp/sam_$(date +%Y%m%d_%H%M%S).sql.gz
# sam_stat DB
mysqldump -u hskwon --single-transaction --routines --triggers sam_stat | gzip > /tmp/sam_stat_$(date +%Y%m%d_%H%M%S).sql.gz
# codebridge DB (Sales)
mysqldump -u hskwon --single-transaction --routines --triggers codebridge | gzip > /tmp/codebridge_$(date +%Y%m%d_%H%M%S).sql.gz
# 전체 DB
mysqldump -u hskwon --single-transaction --routines --triggers --all-databases | gzip > /tmp/all_db_$(date +%Y%m%d_%H%M%S).sql.gz
# 특정 테이블만
mysqldump -u hskwon --single-transaction sam 테이블명 > /tmp/sam_테이블명_$(date +%Y%m%d_%H%M%S).sql
[개발] 자동 백업
개발서버 /etc/crontab에서 root로 매일 04:30 실행.
| 항목 | 값 |
|---|---|
| 스크립트 | /home/webservice/api/scripts/backup/sam-db-backup.sh |
| 설정 파일 | /home/webservice/api/scripts/backup/backup.conf (chmod 600) |
| 저장소 | /data/backup/mysql/daily/YYYY-MM-DD/ |
| 대상 DB | sam, sam_stat, codebridge |
| 보존 | daily 14일, weekly 28일 (일요일 자동 복사) |
| 로그 | /data/backup/mysql/logs/backup.log |
| 상태 파일 | /data/backup/mysql/.backup_status (JSON) |
# 수동 실행
sudo /home/webservice/api/scripts/backup/sam-db-backup.sh
# 백업 확인
ls -lh /data/backup/mysql/daily/$(date +%Y-%m-%d)/
cat /data/backup/mysql/.backup_status
# 로그 확인
tail -20 /data/backup/mysql/logs/backup.log
[개발] 수동 백업
# 개별 DB (codebridge 사용자)
mysqldump -ucodebridge -p --single-transaction --routines --triggers --no-tablespaces sam | gzip > /tmp/sam_$(date +%Y%m%d_%H%M%S).sql.gz
mysqldump -ucodebridge -p --single-transaction --routines --triggers --no-tablespaces codebridge | gzip > /tmp/codebridge_$(date +%Y%m%d_%H%M%S).sql.gz
[개발] DB 복구
# 전체 DB 복구
gunzip -c /data/backup/mysql/daily/2026-03-19/sam_20260319_0430.sql.gz | mysql -ucodebridge -p sam
# sam_stat 복구
gunzip -c /data/backup/mysql/daily/2026-03-19/sam_stat_20260319_0430.sql.gz | mysql -ucodebridge -p sam_stat
# 주간 백업에서 복구 (7일 이전)
ls /data/backup/mysql/weekly/
gunzip -c /data/backup/mysql/weekly/sam_YYYYMMDD_HHMM_week.sql.gz | mysql -ucodebridge -p sam
[CI/CD] 자동 백업 (운영 DB + Gitea)
CI/CD 서버 /etc/crontab에서 root로 매일 03:00 실행. sam_backup 사용자로 운영 DB에 원격 접속.
| 항목 | 값 |
|---|---|
| 스크립트 | /data/scripts/backup-db.sh |
| 인증 파일 | /data/scripts/.sam_backup.cnf (chmod 600) |
| 저장소 | /data/backups/mysql/ |
| 실행 사용자 | root (/etc/crontab) |
| 대상 DB | gitea (로컬, auth_socket), sam + sam_stat + codebridge (운영 원격) |
| 보존 | 14일 |
| 로그 | /data/backups/mysql/backup.log |
# 수동 실행
/data/scripts/backup-db.sh
# 백업 확인
ls -lht /data/backups/mysql/ | head -10
tail -10 /data/backups/mysql/backup.log
백업 파일 외부 전송
# 운영서버 -> CI/CD 서버
scp /tmp/sam_*.sql.gz sam-cicd:/data/backups/mysql/
DB 복구
[운영]
# 전체 DB 복구
gunzip -c /path/to/sam_백업파일.sql.gz | sudo mysql sam
# 특정 테이블 복구
sudo mysql sam < /path/to/sam_테이블명_백업파일.sql
[CI/CD] Gitea DB 복구
gunzip -c /home/hskwon/backups/mysql/gitea_YYYYMMDD_HHMMSS.sql.gz | mysql gitea
[개발] MySQL Binlog 관리
sam-dev에서는 리플리케이션/PITR을 사용하지 않으므로 binlog 보관을 최소화한다.
설정 파일: /etc/mysql/mysql.conf.d/mysqld.cnf
binlog_expire_logs_seconds = 604800 # 7일 보관 (2026-03-09 설정)
max_binlog_size = 100M
# binlog 상태 확인
sudo ls -lh /var/lib/mysql/binlog.0* | wc -l # 파일 수
sudo du -shc /var/lib/mysql/binlog.0* | tail -1 # 총 크기
# 수동 퍼지 (필요 시)
mysql -u pro -p -e "PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 3 DAY);"
# binlog 완전 비활성화가 필요하면 (권장하지 않음)
# mysqld.cnf에 skip-log-bin 추가 후 MySQL 재시작
참고: 운영서버(sam-prod)의 binlog는 CI/CD 백업에 활용되므로 별도 정책 적용.
Slow Query 분석 (운영)
# 로그 직접 확인
sudo tail -100 /var/log/mysql/slow.log
# 요약 분석 (상위 10개, 횟수 기준)
sudo mysqldumpslow -s c -t 10 /var/log/mysql/slow.log
# 요약 분석 (소요 시간 기준)
sudo mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
자주 사용하는 MySQL 명령어
-- 현재 프로세스 목록
SHOW PROCESSLIST;
-- 현재 연결 수
SHOW STATUS LIKE 'Threads_connected';
-- 최대 연결 수
SHOW VARIABLES LIKE 'max_connections';
-- InnoDB 상태
SHOW ENGINE INNODB STATUS\G
-- 테이블 크기 확인 (sam DB)
SELECT table_name, ROUND(data_length/1024/1024, 2) AS data_mb,
ROUND(index_length/1024/1024, 2) AS index_mb
FROM information_schema.tables
WHERE table_schema = 'sam'
ORDER BY data_length DESC
LIMIT 20;
-- 실행 중인 쿼리 확인
SELECT id, user, host, db, command, time, state, info
FROM information_schema.processlist
WHERE command != 'Sleep'
ORDER BY time DESC;
-- 느린 쿼리 kill
KILL 프로세스_ID;
DB 사용자 관리
-- 사용자 목록
SELECT user, host, plugin FROM mysql.user;
-- 사용자 권한 확인
SHOW GRANTS FOR 'codebridge'@'localhost';
-- 비밀번호 변경
ALTER USER 'codebridge'@'localhost' IDENTIFIED BY '새_비밀번호';
FLUSH PRIVILEGES;
Redis 관리 (운영서버)
기본 명령
redis-cli info memory # 메모리 사용량
redis-cli dbsize # 키 개수
redis-cli --bigkeys # 가장 큰 키 확인
redis-cli info keyspace # 키 통계
redis-cli info commandstats | head -20 # 명령어 실행 통계
캐시 정리
# Laravel 캐시 삭제 (artisan)
cd /home/webservice/api/current
php artisan cache:clear
# 특정 접두어 키 삭제
redis-cli keys "laravel_cache:*" | xargs redis-cli del
# 전체 초기화 (세션도 삭제됨 - 주의)
redis-cli flushall
설정 임시 변경
# maxmemory 임시 증가 (재시작 불필요)
redis-cli config set maxmemory 768mb
# maxmemory 확인
redis-cli config get maxmemory
실시간 모니터링
# 실시간 명령어 모니터링 (부하 주의)
redis-cli monitor
# Ctrl+C로 중단