본문 바로가기

Dev/linux

[Linux] Shell & crontab, Google Drive api를 이용한 Mysql 데이터베이스 백업 (2)

 

 

 

이전 포스팅에서는 데이터베이스를 백업, 압축하고 과거 오래된 파일을 지워주는 스크립트를 작성했습니다.

이번 시간에는 Google Drive에 서버에서 보존하고 있는 백업 파일을 업로드하기 위해 해야 할 일들이 무엇인지 알아보겠습니다.

 

4.  Google Cloud Platform 프로젝트 생성

Google Drive api를 이용하기 위해서는 클라우드 플랫폼에 프로젝트를 생성해야 합니다.

아래의 링크로 접속해 프로젝트를 생성해줍니다.

 

https://console.cloud.google.com/

 

Google Cloud Platform

하나의 계정으로 모든 Google 서비스를 Google Cloud Platform을 사용하려면 로그인하세요.

accounts.google.com

 

프로젝트 생성

 

 

새 프로젝트

본 예시에서는 backup-drive라는 이름의 프로젝트 이름으로 생성하겠습니다.

프로젝트 이름은 자유롭게 명명해도 무방합니다.

 

프로젝트가 정상적으로 생성이 되면 잠시 후 다음과 같은 대시보드가 구성됩니다.

프로젝트 대쉬보드

 

 

5. Google Drive API 사용 설정

상단의 제품 및 리소스 검색바를 이용해 Google Drive api를 찾아 사용 설정합니다.

 

Google Drive API

 

 

이제 API를 실질적으로 사용하기 위한 남은 절차는 다음과 같습니다.

  • OAuth 동의 화면 구성
  • 사용자 인증 정보 등록 (OAuth 클라이언트 ID 생성)
  • 토큰 발급

이러한 절차를 밟은 이유는 보안과 구글 드라이브 접근 권한을 어느 정도 수준까지 정의할 것인지를 위함입니다.

 

 

OAuth 동의 화면 구성

유저 타입 중 내부는 Google Workspace를 사용할 경우에만 설정 가능합니다.

일반적으로 기업 업무 환경이라면 내부를 사용할 것입니다. 외부를 선택하고 만들기 버튼을 클릭합니다.

 

 

본 예시에서는 앱 이름을 upload로 지정하겠습니다. 이 화면에서는 사용자 지원 이메일과 개발자 이메일 주소를 필수적으로 입력해야 합니다.

지금 사용 중인 계정의 이메일을 작성하고 저장 후 계속 버튼을 눌러 진행합니다.

 

다음 단계인 범위 테스트 사용자 설정은 이 Google Drive api를 이용해 무언가 서비스를 배포할 때 서비스 이용 종류에 따라 이용자에게 요구하는 개인정보 및 이용 범위에 대한 설정입니다. 본 포스팅에서는 필요한 설정이 아니므로 넘어가겠습니다. 

 

 

OAuth 클라이언트 ID 생성

이제, 해당 api 이용 권한 부여를 위한 사용자 인증 정보를 생성합니다.

 

애플리케이션 유형은 본 예제에서는 서버의 쉘을 통해 업로드를 할 것이기 때문에 데스크톱 앱으로 합니다.

이름은 자유롭게 지정합니다.

 

만들기를 누르면 위와 같은 팝업을 출력합니다.

 

 

생성된 클라이언트 ID에서 인증 정보 파일을 다운로드합니다.

다운로드하면 파일 이름이 client_secret~.json으로 되어있는데, 절대로 이 파일은 외부에 공개해서는 안됩니다.

 

 

5. Python - Google Drive API 접근 스크립트 작성

api접근에 지원하는 언어는 Java, Node.js, Python입니다.

이 중 제일 사용이 간단한 언어인 Python을 이용해 스크립트를 작성하겠습니다.

 

아래의 스크립트는 다음의 api 문서에 따릅니다.

https://developers.google.com/drive/api/v3/quickstart/python

 

Python Quickstart  |  Google Drive API  |  Google Developers

Complete the steps described in the rest of this page to create a simple Python command-line application that makes requests to the Drive API. Prerequisites To run this quickstart, you need the following prerequisites: Python 2.6 or greater. The pip packag

developers.google.com

 

API 사용에 필요한 pip 패키지를 받습니다.

다만, 본 포스팅은 DB 백업을 자동화해야 하기 때문에 일련의 작업을 모두 sudo 권한으로 행할 것입니다.

따라서 패키지도 sudo 권한으로 설치합니다.

$ sudo pip3 install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib

 

적당한 디렉터리에 적절한 이름의 파이썬 스크립트를 생성합니다.

본 예제에서는 데이터베이스 백업을 업로드한다는 의미로 db_gd_upload.py라는 이름으로 작성했습니다.

아래의 경로에 파일을 생성하고 스크립트를 작성합니다.

 

$ sudo vim /home/db_backup/db_gd_upload.py
#-*- coding:utf-8 -*-

from __future__ import print_function
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials

# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/drive']

def main():
    """Shows basic usage of the Drive v3 API.
    Prints the names and ids of the first 10 files the user has access to.
    """
    creds = None
    # The file token.json stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.json', 'w') as token:
            token.write(creds.to_json())

    service = build('drive', 'v3', credentials=creds)

    # Call the Drive v3 API
    results = service.files().list(
        pageSize=10, fields="nextPageToken, files(id, name)").execute()
    items = results.get('files', [])

    if not items:
        print('No files found.')
    else:
        print('Files:')
        for item in items:
            print(u'{0} ({1})'.format(item['name'], item['id']))

if __name__ == '__main__':
    main()

 

여기서 중요한 부분은 SCOPE 변수입니다.

SCOPE 변수는 Google Drive 내 파일 접근 권한의 범위를 의미합니다.

드라이브 API에서 지원하는 SCOPE 범위는 아래와 같습니다.

 

https://developers.google.com/identity/protocols/oauth2/scopes

 

본 스크립트에서는 모든 권한을 부여하는 SCOPE로 지정했습니다.

 

이제, 다운로드한 client_secret~.json을 credentials.json이름으로 변경하고 작성한 스크립트와 같은 공간에 두고 스크립트를 실행합니다.

 

브라우저에 위와 같은 화면이 나타나는데, 계정을 선택하고 권한 부여를 허용해줍니다.

 

인증이 완료되면 token.json 파일이 생성됩니다.

이 파일이 있으면 다음에 연결할 때 인증과정을 거치지 않아도 됩니다.

 

이제 db_gd_upload.py에 코드를 추가해서 간단한 업로드 테스트를 진행해보겠습니다.

 

6. 업로드 테스트

기존 db_gd_upload.py에 다음과 같이 코드를 추가합니다.

 

#-*- coding:utf-8 -*-

import ...


def main():
    . . . 
    
    # 추가
    upload(service)


# 추가
def upload(service):

    file_metadata = {'name': 'test.txt'}

    media = MediaFileUpload('test.txt', resumable=True)
    file = service.files().create(body=file_metadata, media_body=media, fields='id').execute()

    print('File ID: %s' % file.get('id'))


if __name__ == '__main__':
    main()

 

같은 디렉터리에 test.txt 파일을 생성하고 실행합니다.

 

이제 Google Drive에 접속해 파일이 실제로 업로드되었는지 확인합니다.

 

https://drive.google.com/drive/my-drive

 

Google Drive - 모든 파일을 한 곳에서

하나의 계정으로 모든 Google 서비스를 Google Drive로 이동하려면 로그인하세요.

accounts.google.com

 

 

파일이 정상적으로 업로드된 것을 확인할 수 있습니다.

 

7. 특정 폴더에 업로드

드라이브 내 분류 없이 파일이 업로드되는 것도 보기가 좋지 않으므로 db_backup이라는 디렉터리를 생성하고 그 안에 test.txt 파일을 업로드해보겠습니다.

 

 

새로 만들기로 신규 폴더를 작성합니다.

 

 

생성한 db_backup 폴더로 접속하면 drive.google.com/drive/forlder/ 뒤에 위치한 해쉬값 같은 것이 폴더의 ID입니다.

Google Drive API에서는 위 폴더 ID를 통해 해당 폴더에 접근합니다. 이 ID를 복사해둡니다.

그리고 db_gd_upload.py의 코드의 upload 함수를 다음과 같이 수정합니다.

 

def upload(service):
    folder_id = '1cxW1ydMsYW3abtKlHNDmAAOf0Y_ZeQ2v'

    file_metadata = {
        'name': 'test.txt',
        'parents': [folder_id]
    }

    media = MediaFileUpload('test.txt', resumable=True)
    file = service.files().create(body=file_metadata, media_body=media, fields='id').execute()

    print('File ID: %s' % file.get('id'))

 

 

스크립트를 실행해 보면 방금 생성한 db_backup 폴더에 파일이 잘 업로드되어있는 것을 확인할 수 있습니다.

다음 포스팅은 첫 포스팅에서 생성한 쉘 스크립트와 이번 포스팅에서 작성한 파이썬 스크립트, 그리고 crontab을 결합해 실제 백업 파일을 업로드해보도록 하겠습니다.