모듈 2: App Engine ndb에서 Cloud NDB로 마이그레이션

이 Codelab 시리즈(사용자 주도형, 실무 가이드)는 Google App Engine(표준) 개발자가 일련의 마이그레이션을 통해 자신의 앱을 현대화할 수 있도록 돕기 위한 것입니다. 가장 중요한 단계는 차세대 런타임이 더 유연하고 다양한 서비스 옵션을 제공하기 때문에 원래의 런타임 번들 서비스로부터 벗어나는 것입니다. 새로운 세대의 런타임으로 이동하면 Google Cloud 제품과 보다 쉽게 통합하고, 지원되는 다양한 서비스를 사용하고, 최신 출시 버전을 지원할 수 있습니다.

이 가이드에서는 App Engine의 기본 제공되는 ndb(Next Database) 클라이언트 라이브러리에서 Cloud NDB 클라이언트 라이브러리로 마이그레이션하는 방법을 알려줍니다.

학습 목표

  • App Engine ndb 라이브러리 사용(익숙하지 않은 경우)
  • ndb에서 Cloud NDB로 마이그레이션
  • 추가로 앱을 Python 3로 마이그레이션

필요한 사항

설문조사

이 Codelab을 어떻게 사용할 예정인가요?

읽기만 할 계획입니다. 읽은 다음 연습 활동을 완료할 계획입니다.

모듈 1에서는 App Engine의 기본 제공되는 webapp2에서 Flask로 웹 프레임워크를 마이그레이션했습니다. 이 Codelab에서는 App Engine의 ndb 라이브러리를 Google Cloud NDB로 전환하여 App Engine의 기본 제공 서비스에서 계속 벗어납니다.

이 마이그레이션을 완료하면 다음을 수행할 수 있습니다.

  1. Python 3 및 차세대 App Engine 런타임으로 마이그레이션
  2. Cloud Datastore로 마이그레이션(비App Engine 앱용 클라이언트 라이브러리)
  3. Python 2(또는 3) 앱 컨테이너화Cloud Run으로 마이그레이션
  4. App Engine(푸시) 태스크 큐 사용 추가 이후 Cloud Tasks로 마이그레이션

하지만 아직 이 단계에는 도달하지 않았습니다. 다음 단계를 고려하기 전 이 Codelab을 완료하세요. 이 가이드의 마이그레이션 기능에는 다음과 같은 기본 단계가 사용됩니다.

  1. 설정/사전 작업
  2. Cloud NDB 라이브러리 추가
  3. 애플리케이션 파일 업데이트

이 가이드의 주요 부분을 진행하기 전에 프로젝트를 설정하고, 코드를 가져온 후 기본 앱을 배포하여 작동하는 코드로 시작할 수 있도록 준비합니다.

1. 프로젝트 설정

모듈 1 Codelab을 완료했으면 동일 프로젝트(및 코드)를 다시 사용하는 것이 좋습니다. 또는 완전히 새로운 프로젝트를 만들거나 다른 기존 프로젝트를 다시 사용할 수도 있습니다. 프로젝트에 활성 결제 계정이 있고 App Engine이 사용 설정되었는지 확인하세요.

2. 기준 샘플 앱 가져오기

기본 요건 중 하나는 작동하는 모듈 1 샘플 앱을 준비하는 것입니다. 해당 가이드를 완료한 경우 해당 솔루션을 사용합니다. 지금 완료할 수도 있고(위 링크), 건너뛰려는 경우 모듈 1 저장소를 복사할 수도 있습니다(아래 링크).

무엇을 사용하든 모듈 1 코드에서부터 시작해야 합니다. 이 모듈 2 Codelab은 각 단계를 진행합니다. 완료되었을 때는 완료 지점의 코드와 비슷해야 합니다(Python 2~3의 선택적인 '보너스' 포트 포함).

시작 모듈 1 코드 폴더의 내용은 다음과 같습니다.

$ ls
README.md               appengine_config.py     requirements.txt
app.yaml                main.py                 templates

모듈 1 가이드를 완료했으면 Flask 및 해당 종속 항목이 포함된 lib 폴더가 있을 것입니다. lib 폴더가 없으면 다음 단계에서 이 기준 앱을 배포할 수 있도록 pip install -t lib -r requirements.txt 명령어로 만듭니다. Python 2 및 3가 모두 설치된 경우 Python 3와 충돌을 방지하기 위해 pip 대신 pip2를 사용하는 것이 좋습니다.

3. 모듈 1 앱 (재)배포

이제 남은 사전 작업 실행 단계는 다음과 같습니다.

  1. gcloud 명령줄 도구 사용 방법을 다시 숙지합니다(필요한 경우).
  2. 모듈 1 코드를 App Engine에 (재)배포합니다(필요한 경우).

이러한 단계를 성공적으로 실행하고, 작동하는지 확인한 후에는 이 가이드로 이동하여, 구성 파일 작업을 시작합니다.

많은 원본 App Engine 기본 제공 서비스가 각각의 제품에 사용되었고 Datastore도 이들 중 하나입니다. 현재는 비App Engine 앱Cloud Datastore를 사용할 수 있습니다. 오랫동안 ndb 사용자를 위해 Google Cloud 팀은 Cloud Datastore를 지원하기 위해 Cloud NDB 클라이언트 라이브러리를 만들었습니다. 이 라이브러리는 Python 2 및 3 모두에 사용할 수 있습니다.

구성 파일을 업데이트하여 App Engine ndb를 Cloud NDB로 바꾸고 애플리케이션을 수정하세요.

1. requirements.txt 업데이트

모듈 1에서 앱의 유일한 외부 종속 항목은 Flask였습니다. 이제 여기에 Cloud NDB를 추가합니다. 모듈 1이 종료되었을 때 requirements.txt 파일의 모습은 다음과 같습니다.

  • 이전:
Flask==1.1.2

App Engine ndb에서 마이그레이션하려면 Cloud NDB 라이브러리(google-cloud-ndb)가 필요하므로, 해당 패키지를 requirements.txt에 추가합니다.

  • 이후:
Flask==1.1.2
google-cloud-ndb==1.7.1

이 Codelab이 작성되었을 때 최신 권장 버전은 1.7.1이지만 저장소의 requirements.txt에는 이보다 새로운 버전이 포함될 수 있습니다. 각 라이브러리에 대해 최신 버전이 권장되지만, 작동하지 않을 경우에는 이전 출시 버전으로 롤백할 수 있습니다.

갖고 있고 위에서 만들지 않았으면 lib 폴더를 삭제합니다. 이제 필요에 따라 pip 대신 pip2를 사용하여 pip install -t lib -r requirements.txt 명령어로 업데이트된 라이브러리를 (재)설치합니다.

2. app.yaml 업데이트

google-cloud-ndb와 같은 Google Cloud 클라이언트 라이브러리를 추가하는 데에는 '기본 제공' 라이브러리의 포함, Google 서버에서 이미 사용 가능한 타사 패키지를 중심으로 몇 가지 요구 사항이 포함됩니다. 이를 requirements.txt에 나열하거나 pip install로 복사하지는 않습니다. 유일한 요구사항은 다음과 같습니다.

  1. app.yaml에서 기본 제공되는 라이브러리 지정
  2. 사용될 수 있는 복사된 타사 라이브러리에 연결(lib)

모듈 1의 시작 app.yaml은 다음과 같습니다.

  • 이전:
runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

이제 다음 줄을 app.yaml에 추가하여 타사 번들 패키지 쌍(새로운 libraries 섹션의 grpciosetuptools)을 참조합니다.

libraries:
- name: grpcio
  version: 1.0.0
- name: setuptools
  version: 36.6.0

이러한 기본 제공 라이브러리는 왜 사용할까요? gRPCgoogle-cloud-ndb를 포함하여 모든 Google Cloud 클라이언트 라이브러리에서 사용되는 개방형 RPC 프레임워크입니다. grpcio 라이브러리는 Python gRPC 어댑터이므로 필요합니다. setuptools를 포함해야 하는 이유는 다음과 같습니다.

  • 이후:

위의 변경사항에 따라 업데이트된 app.yaml은 이제 다음과 같이 표시됩니다.

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

libraries:
- name: grpcio
  version: 1.0.0
- name: setuptools
  version: 36.6.0

3. appengine_config.py 업데이트

setuptools 라이브러리에 포함되는 pkg_resources 도구는 기본 제공 타사 라이브러리가 번들 항목에 액세스하도록 허용하기 위해 사용됩니다. pkg_resources를 사용하여 lib의 번들 라이브러리에 연결할 수 있도록 appengine_config.py를 업데이트하세요. 이 변경을 완료했으면 전체 파일이 다음과 같이 표시됩니다.

import pkg_resources
from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
# Add libraries to pkg_resources working set to find the distribution.
pkg_resources.working_set.add_entry(PATH)

중간에서 벗어난 구성 파일 형식에 따라 이제 ndb에서 Cloud NDB로 마이그레이션할 수 있습니다. 마이그레이션을 완료하려면 가져온 라이브러리를 업데이트하고 main.py에서 컨텍스트 관리 사용을 추가합니다.

1. 가져오기

main.py에서 다음과 같이 가져오기 스왑을 수행합니다.

  • 이전
from google.appengine.ext import ndb
  • 이후:
from google.cloud import ndb

App Engine 라이브러리에서 Google Cloud 라이브러리로의 변경은 이 경우에서와 같이 알아채기 힘든 경우가 종종 있습니다. 전체 Google Cloud 제품으로 된 기본 제공 서비스의 경우 google.appengine 대신 google.cloud에서 특성을 가져옵니다.

2. Datastore 액세스

Cloud NDB 라이브러리를 사용할 수 있으려면 앱이 Python 컨텍스트 관리자를 사용해야 합니다. 이것들의 목적은 반드시 획득한 이후에만 사용할 수 있도록 리소스에 대한 액세스를 '제어'하는 것입니다. 컨텍스트 관리자는 Resource Allocation Is Initialization(RAII)으로 알려진 컴퓨터 공학 제어 기술을 기반으로 합니다. 컨텍스트 관리자는 Python 파일에 사용되며(액세스하려면 먼저 열어야 함), '중요 섹션'의 코드를 실행하려면 먼저 '스핀 잠금' 동시성을 획득해야 합니다.

마찬가지로 Cloud NDB에서는 Datastore 명령어를 실행하기 전 Datastore와 통신하기 위해 먼저 클라이언트의 컨텍스트를 획득해야 합니다. 먼저 Flask 초기화 바로 직후, main.py에서 ds_client = ndb.Client()를 추가하여 클라이언트(ndb.Client())를 만듭니다.

app = Flask(__name__)
ds_client = ndb.Client()

Python with 명령어는 객체 컨텍스트를 얻기 위해서만 사용됩니다. with 문으로 Datastore에 액세스하는 모든 코드 블록을 래핑합니다.

다음은 새 항목을 Datastore에 기록하고 최근에 추가된 항목을 표시하도록 읽기 위해 사용된 모듈 1의 동일 함수입니다.

  • 이전:

다음은 컨텍스트 관리가 없는 원본 코드입니다.

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    return (v.to_dict() for v in Visit.query().order(
            -Visit.timestamp).fetch(limit))
  • 이후:

이제 with ds_client.context():를 추가하고 Datastore 액세스 코드를 with 블록으로 이동합니다.

def store_visit(remote_addr, user_agent):
    'create new Visit entity in Datastore'
    with ds_client.context():
        Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()

def fetch_visits(limit):
    'get most recent visits'
    with ds_client.context():
        return (v.to_dict() for v in Visit.query().order(
                -Visit.timestamp).fetch(limit))

ndb(또는 Cloud NDB) 코드가 없기 때문에 기본 드라이버 애플리케이션은 모듈 1에 사용된 것과 동일하게 유지됩니다.

@app.route('/')
def root():
    'main application (GET) handler'
    store_visit(request.remote_addr, request.user_agent)
    visits = fetch_visits(10)
    return render_template('index.html', visits=visits)

권장사항은 애플리케이션 코드와 데이터 액세스 사이를 명확하게 구분하는 것입니다. 이렇게 하면 이 마이그레이션을 수행할 때 기본 데이터 스토리지 메커니즘이 변경되더라도 기본 애플리케이션 코드가 변경되지 않습니다.

애플리케이션 배포

gcloud app deploy로 앱을 다시 배포하고 앱이 작동하는지 확인합니다. 이제 사용자의 코드가 모듈 2 저장소에 있는 것과 일치합니다.

앞의 Codelab을 수행하지 않고 이 시리즈를 바로 시작한 경우에는 앱 자체가 변경되지 않습니다. 모든 방문을 기본 웹페이지(/)에 등록하고 사이트를 충분히 방문한 후 다음과 같이 표시됩니다.

visitme 앱

이 모듈 2 Codelab 완료를 축하합니다. Datastore에 관한 한 이 시리즈에서 강력히 권장되는 마이그레이션의 마지막 단계인 모듈 2 Codelab의 마지막 결승선을 이제 막 통과했습니다.

선택사항: 삭제

다음 마이그레이션 Codelab으로 이동할 준비가 될 때까지 비용이 결제되지 않도록 하려면 삭제를 수행해야 합니다. 기존 개발자라면 App Engine 가격 책정 정보를 이미 잘 알고 계실 것입니다.

선택사항: 앱 사용 중지

다음 가이드로 이동할 준비가 되지 않았으면 비용 발생을 방지하기 위해 앱을 사용 중지하세요. 다음 Codelab으로 이동할 준비가 되었으면 이를 다시 사용 설정하면 됩니다. 앱이 사용 중지되면 비용을 일으키는 트래픽이 수행되지 않습니다. 하지만 무료 할당량을 초과할 경우 해당 Datastore 사용량에 대한 비용이 결제될 수 있습니다. 따라서 제한에 걸리지 않도록 충분히 삭제해야 합니다.

반면에 마이그레이션을 계속하지 않고 모든 것을 완전히 삭제하려면 프로젝트를 종료하면 됩니다.

다음 단계

이제부터는 다음 단계로 진행하는 데 많은 유연성이 존재합니다. 다음 옵션 중에서 선택할 수 있습니다.

  • 모듈 2 보너스: 이 가이드의 보너스 부분을 계속하여 Python 3로의 포팅 및 차세대 App Engine 런타임에 대해 알아봅니다.
  • 모듈 7: App Engine 푸시 태스크 큐([푸시] 태스크 큐를 사용하는 경우 필요)
    • App Engine taskqueue 푸시 태스크를 모듈 1 앱에 추가합니다.
    • 모듈 8에서 Cloud Tasks로 마이그레이션하기 위해 사용자를 준비합니다.
  • 모듈 4: Docker를 사용하여 Cloud Run으로 마이그레이션합니다.
    • Docker를 사용하여 Cloud Run에서 실행하기 위해 앱을 컨테이너화합니다.
    • Python 2로 계속 유지합니다.
  • 모듈 5: Cloud 빌드팩을 사용하여 Cloud Run으로 마이그레이션
    • Cloud 빌드팩을 사용하여 Cloud Run으로 실행할 앱을 컨테이너화합니다.
    • Docker, 컨테이너, Dockerfile에 대해 알 필요가 없습니다.
    • 앱이 이미 Python 3로 마이그레이션되어 있어야 합니다.
  • 모듈 3:
    • Cloud NDB에서 Cloud Datastore로 Datastore 액세스 현대화
    • Python 3 App Engine 앱 및 비App Engine 앱에 사용되는 라이브러리입니다.

최신 App Engine 런타임 및 기능에 액세스하기 위해서는 Python 3로 마이그레이션하는 것이 좋습니다. 샘플 앱에서 Datastore는 사용된 유일한 기본 제공 서비스였습니다. ndb에서 Cloud NDB로 마이그레이션했기 때문에 이제는 App Engine의 Python 3 런타임으로 포팅할 수 있습니다.

개요

Python 3로 포팅이 Google Cloud 가이드의 범위를 벗어나지만, 이 Codelab 부분을 통해 개발자는 Python 3 App Engine 런타임의 차이점을 이해할 수 있습니다. 차세대 런타임에서 한 가지 뛰어난 기능은 타사 패키지에 대한 간소화된 액세스입니다. app.yaml에서 기본 제공 패키지를 지정할 필요도 없고 기본제공 라이브러리를 복사하거나 업로드할 필요도 없습니다. 이것들은 requirements.txt에 나열된 대로 암시적으로 설치됩니다.

샘플이 매우 간단하고 그리고 Cloud NDB가 Python 2-3과 호환되기 때문에 애플리케이션 코드를 3.x로 명시적으로 포팅할 필요가 없습니다. 앱은 수정하지 않은 상태로 2.x 및 3.x에서 실행됩니다. 즉, 이 경우 구성만 변경하면 됩니다.

  1. Python 3를 참조하고 타사 라이브러리를 삭제하도록 app.yaml을 단순화합니다.
  2. 더 이상 필수가 아니므로 appengine_config.pylib 폴더를 삭제합니다.

main.py 외에도 requirements.txttemplates/index.html 파일이 변경되지 않은 상태로 유지됩니다.

app.yaml 단순화

이전:

이 샘플 앱의 유일한 실제 변경은 app.yaml을 상당히 단축시키는 것입니다. 다시 말하지만 모듈 2의 결론에서 app.yaml에 포함되는 내용은 다음과 같습니다.

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

libraries:
- name: grpcio
  version: 1.0.0
- name: setuptools
  version: 36.6.0

이후:

Python 3에서 threadsafe, api_version, libraries 지시문은 모두 지원 중단되었으며 모든 앱이 스레드에 안전한 것으로 가정됩니다. api_version은 Python 3에서 사용되지 않습니다. App Engine 서비스에 사전 설치된 기본 제공 타사 패키지가 더 이상 없으므로 libraries도 지원 중단됩니다. 이러한 변경사항에 대한 자세한 내용은 app.yaml 변경사항에 대한 문서를 참조하세요. 따라서 app.yaml의 3개 항목을 모두 삭제하고 지원되는 Python 3 버전(아래 참조)으로 업데이트해야 합니다.

handlers 지시문 사용

또한 App Engine 애플리케이션에서 트래픽을 전달하는 handlers 지시문도 지원 중단되었습니다. 차세대 런타임에서는 웹 프레임워크가 앱 라우팅을 관리하므로, 모든 '핸들러 스크립트'를 'auto'로 변경해야 합니다. 위 변경사항을 조합하면 다음 app.yaml에 도달합니다.

runtime: python38

handlers:
- url: /.*
  script: auto

해당 문서 페이지에서 script: auto에 대해 자세히 알아보세요.

handlers 지시문 삭제

handlers가 지원 중단되었기 때문에 전체 섹션을 삭제하고 한 줄 app.yaml만 남겨둘 수 있습니다.

runtime: python38

기본적으로 이렇게 하면 모든 애플리케이션에 사용할 수 있는 Gunicorn WSGI 웹 서버가 시작됩니다. gunicorn에 익숙할 경우 이것은 기본적으로 베어본 app.yaml로 시작될 때 실행되는 명령어입니다.

gunicorn main:app --workers 2 -c /config/gunicorn.py

선택사항: entrypoint 지시문 사용

하지만 애플리케이션에 특정 시작 명령어가 필요하면 app.yaml이 다음과 같이 표시되는 entrypoint 지시문으로 지정할 수 있습니다.

runtime: python38
entrypoint: python main.py

이 예시는 특히 gunicorn 대신 Flask 개발 서버를 사용하도록 요청합니다. 이 작은 섹션을 main.py 하단에 추가하여 포트 8080으로 0.0.0.0 인터페이스에서 시작하도록 개발 서버를 시작하는 코드도 앱에 추가해야 합니다.

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080, debug=True)

해당 문서 페이지에서 entrypoint에 대해 자세히 알아보세요. 더 많은 예시와 권장사항은 App Engine 표준 시작 문서App Engine 가변형 시작 문서에서 찾아볼 수 있습니다.

appengine_config.pylib 삭제

appengine_config.py 파일 및 lib 폴더를 삭제합니다. Python 3로 마이그레이션하는 경우 App Engine이 requirements.txt에 나열된 패키지를 획득하고 설치합니다.

직접 복사했거나 App Engine 서버에서 이미 제공되는 항목(기본 제공)을 사용하는지 여부에 관계없이 appengine_config.py 구성 파일은 타사 라이브러리/패키지를 인식하는 데 사용됩니다. Python 3로 이동할 때 중요한 변경사항에 대한 요약은 다음과 같습니다.

  1. 복사된 타사 라이브러리를 번들로 묶지 않음(requirements.txt에 나열됨)
  2. lib 폴더로 pip install을 수행하지 않음, lib 폴더 기간 없음
  3. app.yaml에 기본 제공 타사 라이브러리 목록 없음
  4. 타사 라이브러리에 앱 참조 필요 없음, 따라서 appengine_config.py 파일 없음

requirements.txt에서 모든 필수 타사 라이브러리만 나열하면 됩니다.

애플리케이션 배포

앱이 작동하는지 확인하기 위해 앱을 다시 배포합니다. 또한 솔루션이 모듈 2 샘플 Python 3 코드에 얼마나 가까운지도 확인할 수 있습니다. Python 2와의 차이를 시각화하려면 코드를 해당 Python 2 버전과 비교합니다.

모듈 2의 보너스 단계를 완료하신 것을 축하합니다! Python 3 런타임을 위한 구성 파일 준비 문서를 참조하세요. 마지막으로 다음 단계 및 삭제를 위해 위에 표시된 '요약/삭제' 단계로 돌아가세요.

개발자의 애플리케이션 준비

개발자의 애플리케이션을 마이그레이션할 시간이 되었으면 main.py 및 기타 애플리케이션 파일을 3.x로 포팅해야 합니다. 따라서 권장사항은 2.x 애플리케이션을 가능한 한 '이후 버전과 호환'되도록 만들기 위해 최선을 다하는 것입니다.

이를 위해 정말 많은 온라인 리소스가 존재하지만, 이들 중 몇 가지 중요한 팁은 다음과 같습니다.

  1. 모든 애플리케이션 종속 항목이 3.x와 완전히 호환되도록 합니다.
  2. 애플리케이션이 최소 2.6(2.7 추천) 이상으로 실행되도록 합니다.
  3. 애플리케이션이 전체 테스트 모음을 통과하도록 합니다(최소 80% 지원).
  4. six, Future 또는 Modernize와 같은 호환성 라이브러리를 사용합니다.
  5. 이전 버전과 호환되는 주요 2.x와 3.x 사이의 차이점을 확인합니다.
  6. 모든 I/O는 유니코드 및 바이트 문자열 간의 비호환성으로 이어질 수 있습니다.

이 샘플 앱은 이 모든 것을 염두에 두고 설계되었습니다. 따라서 차세대 플랫폼을 사용하기 위해 변경해야 하는 것들을 집중적으로 보여줄 수 있도록 앱이 2.x 및 3.x에서 바로 실행됩니다.

App Engine 마이그레이션 모듈 Codelab 문제/피드백

이 Codelab에 문제가 발견된 경우 문제를 기록하기 전에 먼저 비슷한 기록이 있는지 검색해보세요. 검색 및 새 문제 만들기 링크:

마이그레이션 리소스

모듈 1(시작) 및 모듈 2(완료)의 저장소 폴더 링크는 아래 표에서 찾을 수 있습니다. 또한 클론 또는 ZIP 파일로 다운로드할 수 있는 모든 App Engine Codelab 마이그레이션 저장소에서 액세스할 수도 있습니다.

Codelab

Python 2

Python 3

모듈 1

코드

(해당 없음)

모듈 2

코드

코드

App Engine 리소스

다음은 이 특정 마이그레이션과 관련된 추가적인 리소스입니다.