Python으로 Cloud SQL 사용

Python Bookshelf 가이드의 이 부분에서는 샘플 앱에서 영구 데이터를 Google Cloud SQL에 저장하는 방법을 보여줍니다.

이 페이지는 여러 페이지로 구성된 가이드의 일부입니다. 처음부터 시작하여 설정 안내를 보려면 Python Bookshelf 앱으로 이동하세요.

Cloud SQL 인스턴스 및 데이터베이스 만들기

배포된 애플리케이션은 App Engine 환경에 기본 제공되는 Cloud SQL 프록시를 사용하여 Cloud SQL 인스턴스와 통신합니다. 하지만 애플리케이션을 로컬에서 테스트하려면 Cloud SQL 프록시의 로컬 사본을 개발 환경에 설치하여 사용해야 합니다.

Cloud SQL 프록시 자세히 알아보기

Cloud SQL 인스턴스에 대한 기본 관리 작업을 수행하려면 MySQL 클라이언트를 사용하면 됩니다.

SQL 프록시 설치

Cloud SQL 프록시를 다운로드하고 설치합니다. Cloud SQL 프록시는 로컬에서 실행할 때 Cloud SQL 인스턴스에 연결하는 데 사용합니다.

Linux 64비트

  1. 프록시를 다운로드합니다.
    wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 -O cloud_sql_proxy
    
  2. 프록시 실행 파일을 만듭니다.
    chmod +x cloud_sql_proxy
    

Linux 32비트

  1. 프록시를 다운로드합니다.
    wget https://dl.google.com/cloudsql/cloud_sql_proxy.linux.386 -O cloud_sql_proxy
    
  2. 프록시 실행 파일을 만듭니다.
    chmod +x cloud_sql_proxy
    

macOS 64비트

  1. 프록시를 다운로드합니다.
    curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.amd64
    
  2. 프록시 실행 파일을 만듭니다.
    chmod +x cloud_sql_proxy
    

macOS 32비트

  1. 프록시를 다운로드합니다.
    curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.386
    
  2. 프록시 실행 파일을 만듭니다.
    chmod +x cloud_sql_proxy
    

Windows 64비트

https://dl.google.com/cloudsql/cloud_sql_proxy_x64.exe를 마우스 오른쪽 버튼으로 클릭하고 '다른 이름으로 링크 저장...'을 선택하여 프록시 이름을 cloud_sql_proxy.exe로 바꾼 후 다운로드합니다.

Windows 32비트

https://dl.google.com/cloudsql/cloud_sql_proxy_x86.exe를 마우스 오른쪽 버튼으로 클릭하고 '다른 이름으로 링크 저장...'을 선택하여 프록시 이름을 cloud_sql_proxy.exe로 바꾼 후 다운로드합니다.
사용 중인 운영 체제가 여기에 없으면 소스에서 프록시를 컴파일할 수도 있습니다.

Cloud SQL 인스턴스 만들기

  1. MySQL 2세대용 Cloud SQL 인스턴스를 만듭니다. 인스턴스 이름을 library 또는 비슷한 이름으로 지정합니다. 인스턴스가 준비되는 데 몇 분 정도 걸릴 수 있습니다. 인스턴스가 준비되면 인스턴스 목록에 표시됩니다.
  2. 이제 명령줄에서 Cloud SDK를 사용하여 다음 명령어를 실행합니다. 다음 단계를 진행하려면 connectionName에 표시된 값을 복사합니다.
    gcloud sql instances describe [YOUR_INSTANCE_NAME]

    connectionName 값의 형식은 다음과 같습니다. [PROJECT_NAME]:[REGION_NAME]:[INSTANCE_NAME]

Cloud SQL 인스턴스 초기화

  1. 이전 단계의 connectionName을 사용하여 Cloud SQL 프록시를 시작합니다.

    Linux/macOS

    ./cloud_sql_proxy -instances="[YOUR_INSTANCE_CONNECTION_NAME]"=tcp:3306

    Windows

    cloud_sql_proxy.exe -instances="[YOUR_INSTANCE_CONNECTION_NAME]"=tcp:3306

    [YOUR_INSTANCE_CONNECTION_NAME]을 이전 단계에서 기록한 connectionName 값으로 바꿉니다.

    이 단계에서는 로컬 테스트 용도로 로컬 컴퓨터에서 Cloud SQL 인스턴스로 연결을 설정합니다. 애플리케이션을 로컬에서 테스트하는 동안 Cloud SQL 프록시를 계속 실행합니다.

  2. 그런 다음 새 Cloud SQL 사용자 및 데이터베이스를 만듭니다.

    콘솔

    1. Cloud SQL 인스턴스 library새 데이터베이스를 GCP Console을 사용하여 만듭니다. 예를 들어 bookshelf 이름을 사용할 수 있습니다.
    2. Cloud SQL 인스턴스 library새 사용자를 GCP Console을 사용하여 만듭니다.

    MYSQL 클라이언트

    1. 별도의 명령줄 탭에서 MySQL 클라이언트 또는 비슷한 프로그램을 사용하여 인스턴스에 연결합니다. 메시지가 표시되면 구성한 루트 비밀번호를 사용합니다.
      mysql --host 127.0.0.1 --user root --password
      
    2. 다음 명령을 사용하여 Cloud SQL 데이터베이스에서 필수 데이터베이스, 사용자, 액세스 권한을 만듭니다. [MYSQL_USER][MYSQL_PASSWORD]를 원하는 사용자 이름 및 비밀번호로 바꿉니다.
      CREATE DATABASE bookshelf;
      CREATE USER '[MYSQL_USER]' IDENTIFIED BY '[MYSQL_PASSWORD]';
      GRANT ALL ON . TO '[MYSQL_USER]';
      

설정 구성

이 섹션에서는 2-structured-data 디렉토리의 코드를 사용합니다. 이 디렉토리에서 파일을 수정하고 명령어를 실행하세요.

  1. 수정하기 위해 config.py를 엽니다.
  2. PROJECT_ID 값을 GCP 콘솔에 표시되는 프로젝트 ID로 설정합니다.
  3. DATA_BACKEND 값을 cloudsql로 설정합니다.
  4. CLOUDSQL_USER, CLOUDSQL_PASSWORD, CLOUDSQL_DATABASE 값을 Cloud SQL 인스턴스를 구성할 때 사용한 값으로 설정합니다. 간단하게 인스턴스를 만들 때 구성된 루트 사용자 및 루트 비밀번호를 사용할 수 있습니다.
  5. CLOUDSQL_CONNECTION_NAME 값을 Cloud SQL 인스턴스에 대한 연결 이름으로 설정합니다. 이는 Google Cloud Platform 콘솔에서 Cloud SQL 인스턴스의 세부정보에 표시되고, project:region:cloudsql-instance 형식이어야 합니다.
  6. config.py를 저장하고 닫습니다.

배포하기 전에 추가로 app.yaml에서 설정을 구성해야 합니다.

  1. 수정하기 위해 app.yaml을 엽니다.
  2. cloud_sql_instances 값을 config.py CLOUDSQL_CONNECTION_NAME에 사용한 값과 같은 값으로 설정합니다. project:region:cloudsql-instance 형식이어야 합니다. 이 전체 줄의 주석 처리를 삭제합니다.
  3. app.yaml을 저장하고 닫습니다.

종속 항목 설치

다음 명령어를 입력하여 가상 환경을 만들고 종속 항목을 설치합니다.

Linux/macOS

virtualenv -p python3 env
source env/bin/activate
pip install -r requirements.txt

Windows

virtualenv -p python3 env
env\scripts\activate
pip install -r requirements.txt

데이터베이스 테이블 만들기

애플리케이션은 Bookshelf 데이터를 저장하는 데 사용되는 데이터베이스 테이블을 만들어야 합니다. 이 명령어는 Cloud SQL 인스턴스에 연결하고 필요한 모든 테이블을 만듭니다.

Linux/macOS

python bookshelf/model_cloudsql.py

Windows

python bookshelf\model_cloudsql.py

로컬 머신에서 앱 실행:

  1. 로컬 웹 서버를 시작합니다.

    python main.py
    
  2. 웹브라우저에서 다음 주소를 입력합니다.

    http://localhost:8080

이제 앱의 웹페이지를 찾아보고 도서를 추가, 편집, 삭제할 수 있습니다.

작업자를 종료한 다음 로컬 웹 서버를 종료하려면 Control+C를 누르세요.

App Engine 가변형 환경에 앱 배포

  1. 샘플 앱을 배포합니다.

    gcloud app deploy
    
  2. 웹브라우저에서 다음 주소를 입력합니다. [YOUR_PROJECT_ID]를 프로젝트 ID로 바꿉니다.

    https://[YOUR_PROJECT_ID].appspot.com
    

앱을 업데이트하는 경우 앱을 처음 배포할 때 사용한 같은 명령어를 입력하여 업데이트된 버전을 배포할 수 있습니다. 새로 배포하면 앱의 새 버전을 만들고 기본 버전으로 승격합니다. 이전 버전의 앱은 연결된 VM 인스턴스와 마찬가지로 유지됩니다. 이러한 모든 앱 버전과 VM 인스턴스는 청구 가능한 리소스입니다.

기본 이외의 앱 버전을 삭제하여 비용을 줄일 수 있습니다.

앱 버전을 삭제하는 방법은 다음과 같습니다.

  1. GCP Console에서 App Engine 버전 페이지로 이동합니다.

    버전 페이지로 이동

  2. 삭제할 표준이 아닌 앱 버전 옆의 확인란을 클릭합니다.
  3. 페이지 상단의 삭제 버튼을 클릭하여 앱 버전을 삭제합니다.

청구 가능한 리소스 삭제에 대한 자세한 내용은 이 가이드의 마지막 단계에서 삭제를 참조하세요.

애플리케이션 구조

Bookshelf 앱 배포 프로세스 및 구조

애플리케이션은 모든 영구 데이터를 Cloud SQL에 저장합니다.

코드 이해하기

이 섹션에서는 애플리케이션 코드에 대해 단계별로 알아보고 이 코드의 작동 방식을 설명합니다.

양식으로 사용자 제출 처리

추가/수정 HTML 양식을 사용하면 앱 내에서 도서 제출을 추가하고 수정할 수 있습니다.

추가/수정 양식 이미지

HTML 양식은 Python 템플릿 엔진인 Jinja2를 사용하여 생성됩니다. 다음 Jinja2 템플릿은 양식에 제목, 저자, 게시 날짜, 설명에 대한 텍스트 입력 필드가 포함되도록 지정합니다.

{% extends "base.html" %}

{% block content %}
<h3>{{action}} book</h3>

<form method="POST" enctype="multipart/form-data">

  <div class="form-group">
    <label for="title">Title</label>
    <input type="text" name="title" id="title" value="{{book.title}}" class="form-control"/>
  </div>

  <div class="form-group">
    <label for="author">Author</label>
    <input type="text" name="author" id="author" value="{{book.author}}" class="form-control"/>
  </div>

  <div class="form-group">
    <label for="publishedDate">Date Published</label>
    <input type="text" name="publishedDate" id="publishedDate" value="{{book.publishedDate}}" class="form-control"/>
  </div>

  <div class="form-group">
    <label for="description">Description</label>
    <textarea name="description" id="description" class="form-control">{{book.description}}</textarea>
  </div>

  <button type="submit" class="btn btn-success">Save</button>
</form>

{% endblock %}

양식 제출 처리

사용자가 도서 추가를 클릭하면 crud.add 뷰에 양식이 표시됩니다. 양식을 작성하고 저장을 클릭하면 동일한 add 함수가 양식의 HTTP POST 작업을 처리하고 데이터를 model.create 함수에 전달하여 제출된 데이터를 Cloud SQL 데이터베이스에 전송하는 프로세스를 시작합니다.

@crud.route('/add', methods=['GET', 'POST'])
def add():
    if request.method == 'POST':
        data = request.form.to_dict(flat=True)

        book = get_model().create(data)

        return redirect(url_for('.view', id=book['id']))

    return render_template("form.html", action="Add", book={})

bookshelf/model_cloudsql.py 파일에는 Cloud SQL 데이터베이스에 저장된 데이터의 CRUD 기능을 수행하는 코드가 포함되어 있습니다. SQL은 SQLAlchemy라는 객체 관계형 매퍼(ORM)를 사용하여 작성됩니다. 객체 관계형 매퍼를 사용하면 데이터 모델과 Python 객체로 상호작용하고 해당 SQL을 생성할 수 있습니다. Django ORM은 작업하는 데 사용할 수 있는 또 다른 인기 ORM입니다.

Flask와의 통합을 간소화하려면 Flask 확장 프로그램인 Flask-SQLAlchemy를 사용하세요.

예를 들어 이전 코드에서 create 문은 model_cloudsql.pycreate 함수를 호출합니다. 그러면 Python 사전으로 전달된 속성을 Book 생성자의 키워드 인수로 변환하여 데이터 모델을 업데이트합니다. 그런 다음 모델을 데이터베이스 세션에 추가하고 세션을 커밋합니다. SQLAlchemy는 이를 SQL INSERT 작업으로 변환하고 새 도서 항목을 데이터베이스에 만듭니다.

def create(data):
    book = Book(**data)
    db.session.add(book)
    db.session.commit()
    return from_sql(book)

사용자가 제출된 도서 정보를 수정할 때 model_cloudsql.pyupdate 함수가 호출되어 id 필드로 기존 항목을 쿼리합니다. 그런 다음 업데이트된 필드를 반복 처리하여 기존 모델에서 수정합니다. 마지막으로 이 함수는 세션을 커밋합니다. 이 경우에 SQLAlchemy는 모델에 대한 수정 사항을 SQL UPDATE 작업으로 변환합니다.

def update(data, id):
    book = Book.query.get(id)
    for k, v in data.items():
        setattr(book, k, v)
    db.session.commit()
    return from_sql(book)

사용자가 도서를 추가한 후에 도서 링크를 클릭하면 /books 페이지로 이동하여 현재 Cloud SQL 데이터베이스에 저장된 모든 도서를 나열합니다. list 함수는 Cloud SQL 데이터베이스에서 검색한 데이터를 사용하여 도서를 모두 나열하는 작업을 수행합니다.

def list(limit=10, cursor=None):
    cursor = int(cursor) if cursor else 0
    query = (Book.query
             .order_by(Book.title)
             .limit(limit)
             .offset(cursor))
    books = builtin_list(map(from_sql, query.all()))
    next_page = cursor + limit if len(books) == limit else None
    return (books, next_page)

여기서 Python 객체 메소드를 해당 SQL로 변환하는 방법을 볼 수 있습니다. 이전 코드에서 limit 메소드는 데이터베이스에서 반환할 레코드 수를 지정하여 LIMIT 절을 쿼리에 의해 생성되는 SELECT SQL 문에 추가합니다. offset 메소드는 OFFSET 절을 SELECT 문에 추가하여 페이지 매김을 처리할 시작점을 지정하고 cursor 값을 기반으로 추가 페이지를 요청할 수 있습니다.

이 페이지가 도움이 되었나요? 평가를 부탁드립니다.

다음에 대한 의견 보내기...