Seize the day

POST : Backend study

mongodb 매일 1회 백업하여, firebase에 업로드

https://docs.nestjs.com/techniques/task-scheduling  참고
https://dev.to/yasseryka/how-to-backup-mongodb-every-night-in-nodejs-257o 참고2
이것을 참고할 만 하나 mongo를 도커로 돌리고 있기때문에 Nestjs에서 db를 백업하는게 좀 애매하다.  cron으로 db를 백업하고 별도 스크립트로 firebase에 업로드하는 식으로 구현해봤다. 

 

Cron으로 매일 특정 시간에 mongodb를 백업하고 , 클라우드에 업로드하는 스크립트를 실행한다.


https://jainsaket-1994.medium.com/installing-crontab-on-amazon-linux-2023-ec2-98cf2708b171  참고 Amazon linux2023에 기본으로 crond가 동작하지 않는 것 같으니 일단 서비스 설정을 해주고

cat /etc/crontab

[ec2-user@ip-172-31-28-80 docker]$ cat /etc/crontab
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name  command to be executed
0 21 * * * ec2-user /home/ec2-user/docker/backup_upload.sh

ec2-user로 스크립트를 실행해도 상관없을 듯 하다. root권한이 필요한 것은 docker exec 쪽에 몰아두거나 sudo로 실행하면 되니.  시간설정시 서버는 UTC시간이므로 적당히 리전에 따라 조정한다.  편집후에는 서버 재시작

[ec2-user@ip-172-31-28-80 docker]$ sudo systemctl enable crond.service
[ec2-user@ip-172-31-28-80 docker]$
[ec2-user@ip-172-31-28-80 docker]$
[ec2-user@ip-172-31-28-80 docker]$ sudo systemctl start crond.service
[ec2-user@ip-172-31-28-80 docker]$ sudo systemctl status crond | grep Active
     Active: active (running) since Tue 2024-05-21 14:22:17 UTC; 36s ago

 

backup_upload.sh

mongodb를 백업하는 backup.sh를 호출하고 , db압축파일을 업로드하는 mongo_upload.ts를 호출한다. 

#!/bin/bash

today=$(date +"%Y%m%d")
old_date=`date -d '7 days ago' +%Y%m%d`
echo "today=$today, old_date=$old_date"

cd /home/ec2-user/docker

#backup mongodb to backup/$today.tar
sudo docker exec docker-mongo-1 sh -c "cd /app/backup; sh backup.sh $today"

zip -P mypassword1 ./backup/$today.zip  ./backup/$today.tar

#upload to firebase storage
/home/ec2-user/.bun/bin/bun run /home/ec2-user/nest_server/src/mongo_upload.ts /home/ec2-user/docker/backup/$today.zip $old_date.zip

# delete files
sudo rm ./backup/$today.tar
old_file="./backup/$old_date.zip"
if [ -e $old_file ]
then
    rm $old_file
fi
# /etc/crontab
# 0 6 * * * ec2-user /home/ec2-user/docker/backup_upload.sh

날짜별로 db를  tar로 묶은 파일을 zip으로 암호를 걸어서 압축한다. 이후 firebase로 업로드하고, zip 파일은 그대로 두고, tar파일과 오래된 zip파일은 삭제하는 코드다. 

backup.sh

도커로 돌아가는 컨테이너에서 실행되는 backup 스크립트이다.  $today 파라미터를 받아서 dump폴더를 날짜.tar로 압축한다.

#!/bin/bash

today=$1
echo "[docker]today=$today"

# mongo db backup
echo "backup db to ${today}/"
mongodump --username=user1 --password=password2 --db=db3 --out=$today

today_file=${today}.tar
# if exist $today_file delete it
if [ -e $today_file ]
then
    rm $today_file
fi

echo "make $today_file"
tar cvf $today_file $today

# delete directory
rm -rf $today

 

mongo_upload.ts

frebase의 firestorage에 업로드하는 스크립트이다. 기본적으로 사용자 서비스에는 클라우드 스토리지는 사용하지 않으모로 필히 엑세스 권한을 read / write 모두 false로 해 두어야 한다. 

import { App, initializeApp } from "firebase-admin/app";
import { getStorage } from "firebase-admin/storage";
var admin = require("firebase-admin");
const fs = require("fs");
const path = require("path");

var serviceAccount = require("../firebse-adminsdk.json");

const app:App = initializeApp({
    credential: admin.credential.cert(serviceAccount),
    storageBucket: "gs://yourappId.appspot.com"
});

// bun run ~/projects/leetzsche_backend/nest_server/src/mongo_upload.ts target_path old_filename
//console.log(process.argv[0]) // bun
//console.log(process.argv[1]) // .../mongo_upload.ts
//console.log(process.argv[2]) // target_path

const target = process.argv[2];
if (fs.existsSync(target)) {
    console.log(`Upload ${target} to firebase`);
    
    const filename = path.basename(target);

    const storage = getStorage(app)
    const metadata = {
        destination: filename,
        contentType: 'application/zip'
    };

    try {
        await storage.bucket().upload(target, metadata);
        console.log(`${filename} upload done`);
    } catch(err) {
        console.log(err);
    }

    //delete old file
    const old_filename = process.argv[3];
    if (old_filename != undefined) {
        console.log(`try to delete old ${old_filename}`);
        try {
            await storage.bucket().file(old_filename).delete();
            console.log(`${old_filename} delete done`);
        } catch(err) {
            if (err.code != "404") {
                console.log(err);
            }
        }
    }

} else {
    console.log(`not found: ${target}`);
}

 

top

posted at

2024. 5. 21. 23:43


CONTENTS

Seize the day
BLOG main image
김대정의 앱 개발 노트와 사는 이야기
RSS 2.0Tattertools
공지
아카이브
최근 글 최근 댓글
카테고리 태그 구름사이트 링크