TestServer DB에 DevServer DB 변경사항을 자동으로 반영하여 데이터베이스 구조 동기화
개발을 하면 보통 개발 환경, 운영 환경, 테스트 환경, 데모 환경 등 각각의 이유로 다양한 환경에서 개발하고 테스트하게 된다.
이 때 서로 다른 서버의 Database에 각각의 데이터는 유지하되 DDL과 같이 Database(table)의 구조를 변경하는 작업에 대해서는 다른 서버의 Database에 똑같이 변경해줘야 한다.
이러한 작업을 위해서는 Liquibase, Flyway 등 다양한 방법이 있지만 나 같은 경우 개발 환경, 보안, 인증, 리소스 등 다양한 조건을 생각해본 결과 서버에서 직접 Script를 작성하여 동작시키는 것이 가장 좋은 방법이라고 생각하여 Script로 개발하였다.
개발 환경 설명:
개발 서버와 Junit용 테스트 서버의 DB(postgres)를 연동해야 한다. 개발 서버에서 DB의 수정 사항은 쿼리(ddl)로 작성하여 별도의 svn서버에 올려놓고 있으며, jenkins를 붙여놔 다른 환경에서 jenkins를 통해 빌드하여 패치할 수 있다.
Jenkins는 매일 새벽에 돌며 개발 서버 DB의 변경 사항 전체를 가져와서 압축해둔다.
개발 환경은 위와 같았고, svn서버에 직접 접근한다던가 하는 방법은 보안 상의 이슈로 불가능 했기 때문에 현재 환경을 최대한 활용하여 개발해야 했다.
데이터 흐름
SNV과 Jenkins는 이미 구성되어 있기 때문에 TestServer에서 Jenkins API로 파일을 가져오면 된다.
1. 현재 패치 파일 정보 가져오기
*패치 파일명 형식 20240421-1.sql
우선 jenkins API를 사용하기 위해 jenkins에서 token을 발급받아야 한다. (아래 글 참고)
https://jenkinssuite.github.io/jenkins/jenkins-10-token/
curl -o 명령어로 jenkins서버에 API요청을 보내 현재 패치 파일의 정보를 가져올 수 있다.
(-o 옵션은 파일을 다운로드 할 때 사용)
curl -o patch.txt http://172.16.230.149:8080/view/Repository/job/REPOSITORY/lastSuccessfulBuild/api/json --user $User:$Token -v
2. 마지막 패치 파일 확인하기
jq를 사용하여 jenkins에서 가져온 패치 파일 정보를 파싱해서 이전 날짜의 패치 파일과 비교해서 패치파일 업데이트 여부를 판단한다.
= 패치 파일이 업데이트 되지 않고 어제와 같다면 작업 종료.
(jq 패키지는 Json데이터를 파싱할 때 유용)
Yesterday_patch=$(jq -r '.artifacts[0].fileName' < "${Yesterday}_patch.txt")
Today_patch=$(jq -r '.artifacts[0].fileName' < "${Today}_patch.txt")
if [ "$Yesterday_patch" == "$Today_patch" ]; then
"Already ${Today} patch file" 2>> ${Log_dir}patch_log.txt
echo "Already last patch"
exit 0
fi
3. Jenkins에서 패치 파일 다운받기
전 단계에서 확인작업을 통과했다면 새로 업데이트 된 패치파일이 있다는 것이므로 jenkins에서 패치 파일을 다운받고 현재 날짜의 폴더를 만들어 압축을 푼다.
curl -o ${Today}_patch.tar.gz ${Url}artifact/build/$Today_patch --user $User:$Token
mkdir -p ${Today}_patch
tar xvjf ${Today}_patch.tar.gz -C ${Today}_patch --strip-components=1
rm -f ${Today}_patch.tar.gz
4. DB에 Query 패치하기
이전 패치에서 저장해둔 마지막 날짜를 시작일로 지정하고, 현재를 종료일로 지정한다.
*.sql 파일의 수 만큼 반복하며 파일의 날짜를 추출하여 시작일과 종료일 사이의 날짜인지 판단하고, 맞다면 postgres에 패치한다.
START_DATE=$(tail -n 1 last_patch_date.txt)
END_DATE=$(date +%Y%m%d)
DATABASE="DB"
USER="postgres"
SQL_DIR="/root/patch/postgres/pg_patch/${Today}_patch/update_patch"
Last_file=""
for FILE in "$SQL_DIR"/*.sql; do
FILE_DATE=$(basename "$FILE" | cut -d'-' -f1)
if [[ "$FILE_DATE" > "$START_DATE" && "$FILE_DATE" < "$END_DATE" ]] || [[ "$FILE_DATE" == "$END_DATE" ]]; then
echo "Patch: $FILE"
$sql -U "$USER" -d "$DATABASE" -f "$FILE"
Last_file="$FILE_DATE"
fi
done
5. 후처리
4번에서 시작일을 확인하기 위해 사용했던 last_patch_date.txt 파일에 마지막으로 패치된 파일명을 추가한다.
if [ -n "$Last_file" ]; then
echo "$Last_file" >> ${Log_dir}last_patch_date.txt
fi
6. 스케줄 등록
마지막으로 crontab 스케줄에 shell파일을 등록하여 주면 매일 새벽 1시에 자동으로 돌며 위의 작업을 수행하여 자동으로 검사하고 패치할 수 있다.
crontab -e
0 1 * * * /path~/auto_patch.sh
auto_patch.sh
[root@0f203j control]# cat auto_patch.sh
#!/bin/bash
# Repository Auto patch..
# 매일 01시에 동작하며 패치파일을 가져와서 이전에 업데이트 되지 않았을 경우 패치함.
# Setting
Patch_dir="/root/patch/postgres/pg_patch/"
Log_dir="/root/patch/postgres/logs/"
Last_patch_dir="/root/patch/postgres/logs/repo_info/"
User="test_user"
Token="sjkafdh23jhf8239fh2f23if23fgwdg"
Today=$(date +%Y-%m-%d)
Yesterday=$(date -d "yesterday" +%Y-%m-%d)
Url="http://172.16.230.149:8080/view/Repository/job/REPOSITORY/lastSuccessfulBuild/"
# 1. Select last patch date
curl -o ${Last_patch_dir}${Today}_patch.txt ${Url}api/json --user $User:$Token -v 2> ${Log_dir}1.select_last_patch_date_log.txt
# 2. Check last patch
Yesterday_patch=$(jq -r '.artifacts[0].fileName' < "${Last_patch_dir}${Yesterday}_patch.txt")
Today_patch=$(jq -r '.artifacts[0].fileName' < "${Last_patch_dir}${Today}_patch.txt")
if [ "$Yesterday_patch" == "$Today_patch" ]; then
"Already ${Today} patch file" 2>> ${Log_dir}patch_log.txt
echo "Already last patch"
exit 0
fi
echo "Patch progress"
# 3. File down from Jenkins
curl -o ${Patch_dir}${Today}_patch.tar.gz ${Url}artifact/build/$Today_patch --user $User:$Token
mkdir -p ${Patch_dir}${Today}_patch
tar xvjf ${Patch_dir}${Today}_patch.tar.gz -C ${Patch_dir}${Today}_patch --strip-components=1
rm -f ${Patch_dir}${Today}_patch.tar.gz
# 4. Patch
START_DATE=$(tail -n 1 ${Log_dir}last_patch_date.txt)
END_DATE=$(date +%Y%m%d)
DATABASE="DB"
USER="postgres"
SQL_DIR="/root/patch/postgres/pg_patch/${Today}_patch/update_patch"
Last_file=""
for FILE in "$SQL_DIR"/*.sql; do
FILE_DATE=$(basename "$FILE" | cut -d'-' -f1)
if [[ "$FILE_DATE" > "$START_DATE" && "$FILE_DATE" < "$END_DATE" ]] || [[ "$FILE_DATE" == "$END_DATE" ]]; then
echo "Patch: $FILE"
$sql -U "$USER" -d "$DATABASE" -f "$FILE"
Last_file="$FILE_DATE"
fi
done
# 5. Post progressing
if [ -n "$Last_file" ]; then
echo "$Last_file" >> ${Log_dir}last_patch_date.txt
fi
echo "success patch"
해당 스크립트는 현재 로그 처리가 마무리 되지 않은 상태로 응용 시 로그처리 추가 작업 필요.
'🌐OS > Linux' 카테고리의 다른 글
[Linux] 노트북으로 개인 Linux 서버 만들기 (6) | 2024.10.03 |
---|---|
[Linux] 모니터링 (0) | 2023.08.27 |
[Linux] 백업 / 복구 (0) | 2023.08.27 |
[Linux] Shell 프로그램 (0) | 2023.08.27 |
[Linux] Cron 스케줄러 (0) | 2023.08.27 |