이 페이지에서는 표준 환경용 Python 3 런타임으로 기존 번들 서비스를 설치하고 사용하는 방법을 설명합니다. 앱은 Python 3용 App Engine 서비스 SDK를 통해 번들 서비스에 액세스해야 합니다.
시작하기 전에
- Python 런타임에서 호출할 수 있는 기존 번들 서비스 API 목록을 참조하세요.
- Python 3으로 마이그레이션하는 프로젝트를 시작하기 전에 런타임 마이그레이션 개요 및 기존 번들 서비스를 사용할 때의 마이그레이션 고려사항을 참조하세요.
App Engine 서비스 SDK 설치
App Engine 서비스 SDK를 설치하려면 다음 단계를 따르세요.
requirements.txt
파일에 다음 줄을 추가하여 앱에 SDK를 포함합니다.appengine-python-standard>=1.0.0
appengine-python-standard
저장소와 PyPI에서 GitHub의 SDK를 찾을 수 있습니다.기본 Python 스크립트에 다음 코드를 추가합니다. 이 코드는 API 호출을 사용 설정하는 데 필요한 변수를 설정하는 WSGI 미들웨어를 만듭니다.
Flask
from flask import Flask from google.appengine.api import wrap_wsgi_app app = Flask(__name__) app.wsgi_app = wrap_wsgi_app(app.wsgi_app)
Django
from DJANGO_PROJECT_NAME.wsgi import application from google.appengine.api import wrap_wsgi_app app = wrap_wsgi_app(application)
피라미드
from pyramid.config import Configurator from google.appengine.api import wrap_wsgi_app config = Configurator() # make configuration settings app = config.make_wsgi_app() app = wrap_wsgi_app(app)
WSGI
import google.appengine.api def app(environ, start_response): start_response('200 OK', [('Content-Type', 'text/plain')]) yield b'Hello world!\n' app = google.appengine.api.wrap_wsgi_app(app)
앱을 배포하기 전에
app.yaml
파일에 다음 줄을 추가합니다.app_engine_apis: true
앱을 배포하려면
gcloud app deploy
명령어를 사용합니다.
마이그레이션 고려사항
앱에서 기존 번들 서비스를 사용하는 경우 Python 3 런타임으로 마이그레이션할 때 다음 사항을 고려해야 합니다.
테스트
Python 3 앱에서 기존 번들 서비스 기능을 로컬로 테스트하려면 로컬 개발 서버를 사용합니다.
dev_appserver.py
명령어를 실행할 때 Python 3 인터프리터의 경로를 포함하도록 --runtime_python_path
인수를 설정해야 합니다.
예를 들면 다음과 같습니다.
python3 CLOUD_SDK_ROOT/bin/dev_appserver.py --runtime_python_path=/usr/bin/python3
인수를 [RUNTIME_ID]=[PYTHON_INTERPRETER_PATH]
쌍의 쉼표로 구분된 목록으로 설정할 수도 있습니다. 예를 들면 다음과 같습니다.
python3 CLOUD_SDK_ROOT/bin/dev_appserver.py --runtime_python_path="python27=/user/bin/python2.7,python3=/usr/bin/python3"
Pickle 호환성
Memcache, Cloud NDB, deferred 등의 공유 서비스는 pickle 모듈을 사용하여 Python 객체를 직렬화 및 공유합니다. App Engine 환경에서 마이그레이션 중에 일반적으로 사용되는 Python 2와 Python 3을 모두 사용하는 경우, 한 버전의 Python이 작성한 공유 직렬화 객체를 다른 버전에서 재구성할 수 있는지 확인해야 합니다. 교차 버전 피클 호환성을 구현하는 방법에 관한 안내는 가이드를 참고하세요.
기본적으로 Python 3은 Python 2에서 지원되지 않는 피클링 프로토콜을 사용합니다.
이로 인해 앱이 Python 3 환경에서 작성된 Python 객체를 Python 2 환경에서 재구성하려 할 때 오류가 발생할 수 있습니다.
이 문제를 방지하려면 필요에 따라 Python 3 앱의 app.yaml
파일에서 다음 환경 변수를 설정합니다.
- NDB를 사용하는 앱 등 Memcache를 사용하는 앱의 경우
MEMCACHE_USE_CROSS_COMPATIBLE_PROTOCOL: 'True'
를 설정합니다. - NDB를 사용하여 Datastore에 연결하는 앱의 경우
NDB_USE_CROSS_COMPATIBLE_PICKLE_PROTOCOL: 'True'
를 설정합니다. - deferred를 사용하는 앱의 경우
DEFERRED_USE_CROSS_COMPATIBLE_PICKLE_PROTOCOL: 'True'
를 설정합니다.
Python 2에서 string
객체는 8비트 바이트 값의 시퀀스를 보유합니다. Python 3에서 string
객체는 일련의 유니코드 문자를 보유합니다. 기본적으로 Python 3 피클은 Python 3 string
을 ASCII로 해석하여 Python 2 string
을 유니코드로 변환합니다. 그러면 ASCII 문자 범위 0~127을 벗어나는 값에서 오류가 발생할 수 있습니다. Memcache는 이런 기본 매핑의 재정의를 지원합니다.
from google.appengine.api import memcache
import six.moves.cPickle as pickle
def _unpickle_factory(file):
return pickle.Unpickler(file, encoding='latin1')
memcache.setup_client(memcache.Client(unpickler=_unpickle_factory))
latin1
인코딩은 Python 2 string
에서 각 바이트에 대입 가능한 256개 값에 대한 매핑을 정의합니다. 이렇게 하면 디코딩 오류가 방지됩니다. 그러나 Python 2 string
이 파일에서 읽은 데이터와 같이 latin1
범위 외부에 있는 실제 유니코드 데이터를 포함하는 경우 c Pickle은 데이터를 올바르게 매핑하지 않습니다. 따라서 피클링한 객체에 대해 string
객체가 아닌 unicode
객체로 유니코드 데이터를 보관하도록 Python 2 코드를 업데이트해야 합니다. 호환성 가이드에는 필요한 업데이트에 관한 세부정보가 포함되어 있습니다.
앞서 설명한 Python 2 코드를 업데이트하여 Python 3와 호환되는 직렬화를 생성하는 방법은 Memcache에 저장된 것과 같은 단기 지속 직렬화에 해당합니다. 마이그레이션 중 Datastore에 저장된 것과 같은 장기 지속 Python 2 직렬화를 업데이트하거나 다시 작성해야 할 수 있습니다. 예를 들어 google.appengine.ext.ndb.model.PickleProperty
를 사용하여 작성된 직렬화는 업그레이드가 필요할 수 있습니다.
제한사항 및 일반적이지 않은 문제에 대한 자세한 내용은 호환성 가이드를 참조하세요.
웹 프레임워크
webapp2
는 Python 3에서 번들되거나 지원되지 않으므로 모든 WSGI 호환 프레임워크(예: Flask)를 사용하려면 애플리케이션을 다시 작성해야 합니다.
권장되는 마이그레이션 전략은 Python 2.7을 계속 사용하는 동안 Python 2.7 앱의 webapp2
를 Flask(또는 Django, Pyramid, Bottle 또는 web.py와 같은 대체 웹 프레임워크)로 바꿔 사용하는 것입니다.
그런 다음 업데이트된 앱이 안정화되면 코드를 Python 3으로 마이그레이션하고 Python 3용 App Engine을 사용하여 배포하고 테스트합니다.
webapp2
를 사용하는 Python 2.7 앱을 Flask 프레임워크를 사용하도록 변환하는 방법의 예시는 추가 리소스를 참조하세요.
핸들러 사용
Python 3 앱에는 하나의 스크립트만 연결할 수 있으므로 app.yaml
에서 여러 스크립트에 script
URL을 매핑하는 여러 개의 핸들러가 있는 경우 이러한 스크립트는 URL 라우팅을 처리하는 스크립트 하나에 결합되어야 합니다.
다음 예는 각 런타임에서 app.yaml
파일의 핸들러 차이점을 보여줍니다.
Python 2
runtime: python27 api_version: 1 threadsafe: true handlers: - url: / script: home.app - url: /index\.html script: home.app - url: /stylesheets static_dir: stylesheets - url: /(.*\.(gif|png|jpg))$ static_files: static/\1 upload: static/.*\.(gif|png|jpg)$ - url: /admin/.* script: admin.app login: admin - url: /.* script: not_found.app
Python 3
runtime: python312
app_engine_apis: true
handlers:
- url: /stylesheets
static_dir: stylesheets
- url: /(.*\.(gif|png|jpg))$
static_files: static/\1
upload: static/.*\.(gif|png|jpg)$
- url: /admin/.*
script: auto
login: admin
Python 3 앱은 URL 라우팅(예: Flask 데코레이터 사용)을 처리해야 합니다.
URL 패턴이 서로 다른 여러 script
핸들러를 사용하거나 핸들러에서 서로 다른 속성을 사용하려면 각 핸들러에서 script: auto
를 지정해야 합니다.
app.yaml
파일에서 entrypoint
필드를 지정하여 기본 시작 동작을 재정의할 수도 있습니다.
특정 핸들러를 사용하는 방법에 대한 자세한 내용은 Blobstore, Deferred, Mail 개요를 참조하세요.
스레드 안전
앱은 스레드 안전성을 갖는 것으로 간주됩니다. API 호출은 요청 스레드에서 실행해야 합니다. 앱이 시작될 때 레거시 번들 서비스 API를 사용하면 보안 오류가 발생할 수 있습니다.
자세한 내용은 Python용 기존 번들 서비스를 사용할 때 발생하는 보안 오류를 참조하세요.
URL 가져오기 사용
Python용 URL Fetch를 사용하려면 URL Fetch 라이브러리를 명시적으로 호출해야 합니다.
Python 3 앱에서 URL Fetch API를 사용하는 경우 앱이 다른 App Engine 앱에 요청을 전송하면 X-Appengine-Inbound-Appid
요청 헤더가 추가됩니다. 이렇게 하면 수신 앱이 호출 앱의 ID를 확인할 수 있습니다. 자세한 내용은 아웃바운드 요청 마이그레이션을 참조하세요.
예시(App Engine ndb
)
다음은 페이지 방문을 등록하는 기본 Python 2 앱이며, App Engine ndb
를 사용하여 Datastore에 액세스합니다. 두 번째 예시는 Python 3에 상응하는 앱입니다. 여기서 webapp2
사용량은 Flask로 대체되었고, 위에서 설명된 Python 3의 번들 서비스에 액세스하는 데 필요한 변경사항이 구현되었습니다.
Python 2(webapp2
)
Python 3(Flask)
두 앱 모두 Python App Engine 마이그레이션 콘텐츠(코드 샘플, 동영상, Codelab)에 대한 오픈소스 저장소에서 찾을 수 있으며, 구체적으로는 각각 mod0
폴더 및 mod1b
폴더에 있습니다.