Cloud/GCP

[GCP] Cloud SQL Backup을 Cloud Run(Function), Cloud Scheduler을 통해 정기적으로 백업 받기

달빛궁전- 2025. 5. 25. 19:26

Cloud SQL은 GCP에서 제공하는 관리형 DBMS로 사용자는 DB를 잘 사용하는것에 집중하고, 관리는 GCP가 해주는 부분입니다.
백업도 알아서 시간대만 지정해 주면, 하루에 한번 해당 시간대에 백업을 해줍니다.
그 외에는 사용자가 콘솔(GUI)에서 직접 수동 백업을 실행하거나, gcloud 명령어로 수동 백업을 받을 수 있습니다.

하지만 운영을 하다보면 여러 작업과 사정이 있고, 예를 들어 6시간 간격으로 백업이 필요한 경우도 있을 수 있을 것입니다. 
이러한 상황을 가정하고, 파이썬 코드+Cloud Run(Function)+Cloud Scheduler 을 통해 일회성 백업과 지정된 시간에 백업을 하는 방안에 대해 작성하였습니다.

 
  • 구성도

필요권한 : Cloud SQL 백업을 트리거하려면 최소 cloudsql.backupRuns.create 권한이 필요합니다.
일반적으로 Cloud SQL Admin(roles/cloudsql.admin) 역할에 포함되어 있으며, 커스텀 역할로 최소 권한만 부여할 수도 있습니다.

 

https://cloud.google.com/sql/docs/mysql/iam-roles?hl=ko

 

  1. Cloud Run (기존 Cloud Function) 에서 함수 작성을 선택합니다.
    본 문서 최하단에 있는 코드를 Cloud Run main.py 소스코드에 입력합니다.
    함수 진입점은 “backup_sql_instance” 으로 설정하며

    필요한 라이브러리를 작성하는 “requirements.txt”에는 아래의 라이브러리를 입력합니다.

    google-api-python-client: Google API 호출을 위한 클라이언트 라이브러리
    google-auth: Google 인증을 위한 공식 라이브러리⁠

  2. 코드에 직접 프로젝트, CloudSQL명을 넣지 않고 환경변수로 실행하기에 아래의 방법으로 진행합니다.
    변수 및 보안 비밀에서 환경 변수 탭 이동
    변수 2개를 설정합니다.
    “PROJECT_ID” 백업할 Cloud SQL 이 있는 Project ID
    “INSTANCE_ID” 백업할 Cloud SQL 인스턴스 이름



  3. 모든 설정이 완료 된 후 상단 URL을 확인합니다.



    해당 URL을 웹에서 호출하면 아래와 같이 'Backup successfully' 메시지를 확인할 수 있습니다.
    다만 본문서에서는 Cloud Run(Function)을 통해 진행하는 방안에 대해 중점을 두고 작성하였습니다.
    해당 함수 실행시 보안 부분( "서비스 계정 권한 최소화", "HTTP 엔드포인트 인증" )에 대해서는 차 후 다른 문서에 작성하도록 하겠습니다.




Cloud Run(Function)작업은 마무리 되었으므로, 지정된 시간에 실행될 수 있도록 Cloud Scheduler설정을 진행해보겠습니다.


실행할 리전을 지정하고, 빈도를 설정합니다.
Unix, Linux의 Crontab과 동일합니다. 
분   시   일   월   요일  

필드 의미 범위
Minute 0-59
Hour 0-23
Day of month 1-31
Month 1-12
요일 Day of week 0-7


예시로는 아래와 같습니다.
0 2 * * *
→ 매일 새벽 2시 0분에 실행

15 14 * * 1
→ 매주 월요일 오후 2시 15분에 실행

0 */6 * * *
→ 매 6시간마다(0시, 6시, 12시, 18시) 실행

0 9 * * 1-5
→ 매주 월~금 오전 9시에 실행

본 문서에서는 25분마다 실행하기로 했기에
25 * * * * 으로 설정하였습니다.




실행 구성부분은 다음과 같이 설정합니다.
대상 유형 : HTTP
URL : Cloud Run(Function)에서 생성된 URL
HTTP 메소드 : POST

그외는 빈란으로 진행되어도 무방합니다.

 
모든 설정이 완료되면 내용을 확인하고 강제 실행으로 성공 되는지 확인합니다.


최종적으로 Cloud Scheduler로 인해 25분마다 실행되며
Cloud SQL 콘솔 -> 작업에서 위의 캡쳐화면 처럼 백업이 정상적으로 완료됨을 알 수 있습니다. 


Cloud SQL Backup Python코드 
import os
import googleapiclient.discovery
from google.auth import compute_engine

def backup_sql_instance(request):
    # 환경 변수에서 프로젝트 및 인스턴스 ID를 읽어옴
    PROJECT_ID = os.environ.get("PROJECT_ID")
    INSTANCE_ID = os.environ.get("INSTANCE_ID")

    if not PROJECT_ID:
        print("Error: Environment variable 'PROJECT_ID' is not set or is empty.")
        return "Configuration error: PROJECT_ID not set.", 500

    if not INSTANCE_ID:
        print("Error: Environment variable 'INSTANCE_ID' is not set or is empty.")
        return "Configuration error: INSTANCE_ID not set.", 500

    try:
        # Compute Engine 기본 인증 사용
        credentials = compute_engine.Credentials()
        sql_admin_service = googleapiclient.discovery.build(
            "sqladmin", "v1beta4", credentials=credentials, cache_discovery=False
        )

        # 백업 요청 바디 작성
        backup_request_body = {
            "description": f"Automated backup for {INSTANCE_ID} triggered by HTTP call."
        }

        # 백업 실행 요청
        api_request = sql_admin_service.backupRuns().insert(
            project=PROJECT_ID,
            instance=INSTANCE_ID,
            body=backup_request_body
        )
        response = api_request.execute()

        print(f"Backup operation successfully initiated for instance {INSTANCE_ID}.")
        print(f"Operation details: {response}")
        return f"Backup initiated successfully for {INSTANCE_ID}.", 200

    except googleapiclient.errors.HttpError as e:
        # Google API 호출 시 발생하는 HTTP 에러 처리 (인증, 권한, 파라미터 등)
        error_message = (
            f"Google API HTTP Error triggering backup for instance {INSTANCE_ID}: {e}"
        )
        print(error_message)
        return error_message, 500

    except AttributeError as e:
        # API 클라이언트 객체 사용 오류 (오타, 잘못된 메서드/속성 접근 등)
        error_message = (
            f"AttributeError (likely an issue with API client usage) for instance {INSTANCE_ID}: {e}"
        )
        print(error_message)
        return error_message, 500

    except Exception as e:
        # 기타 모든 예외 처리
        error_message = (
            f"An unexpected error occurred while triggering backup for instance {INSTANCE_ID}: {e}"
        )
        print(error_message)
        return error_message, 500