1. 개요
서버리스 마이그레이션 스테이션 Codelab 시리즈 (사용자 주도형 실습 튜토리얼) 및 관련 동영상은 Google Cloud 서버리스 개발자가 주로 기존 서비스에서 벗어나 하나 이상의 마이그레이션을 통해 애플리케이션을 현대화하도록 돕는 것을 목표로 합니다. 이렇게 하면 앱의 이식성이 향상되고 더 많은 옵션과 유연성이 제공되므로 다양한 Cloud 제품과 통합하고 액세스하고 최신 언어 버전으로 보다 쉽게 업그레이드할 수 있습니다. 이 시리즈는 처음에는 초기 Cloud 사용자, 특히 App Engine (표준 환경) 개발자에 중점을 두고 있지만 Cloud Functions 및 Cloud Run과 같은 다른 서버리스 플랫폼이나 해당하는 경우 다른 플랫폼을 포함할 만큼 광범위합니다.
이 Codelab에서는 App Engine blobstore에서 Cloud Storage로 이전하는 방법을 설명합니다. 다음 위치에서 암시적 마이그레이션도 가능합니다.
webapp2
웹 프레임워크에서 Flask로 (모듈 1에서 다룸)- Datastore 액세스를 위해 App Engine NBS에서 CloudNDB로 변경 (모듈 2에서 처리)
- Python 2~3 (마이그레이션된 앱이 Python 2 및 3과 모두 호환됨)
자세한 단계별 정보는 관련 이전 모듈을 참조하세요.
다음 실습에서는
- App Engine blobstore API/라이브러리 사용 추가
- blobstore 서비스에 사용자 업로드 저장
- Cloud Storage로 마이그레이션을 위한 다음 단계 준비
필요한 항목
- 활성 GCP 결제 계정이 있는 Google Cloud Platform 프로젝트
- 기본 Python 기술
- 일반적인 Linux 명령어에 대한 실무 지식
- App Engine 앱 개발 및 배포에 관한 기본 지식
- 작동하는 모듈 15 App Engine 앱: 모듈 15 Codelab (권장) 완료 또는 저장소에서 모듈 15 앱 복사
설문조사
이 튜토리얼을 어떻게 사용하실 계획인가요?
귀하의 Python 사용 경험이 어떤지 평가해 주세요.
귀하의 Google Cloud 서비스 사용 경험을 평가해 주세요.
<ph type="x-smartling-placeholder">2. 배경
이 Codelab은 모듈 15의 샘플 앱으로 시작하여 Blobstore (및 NBS)에서 Cloud Storage (및 Cloud NBS)로 마이그레이션하는 방법을 보여줍니다. 마이그레이션 프로세스에는 App Engine의 기존 번들 서비스의 종속 항목을 교체하는 과정이 포함됩니다. 이를 통해 원하는 경우 앱을 다른 Cloud 서버리스 플랫폼이나 다른 호스팅 플랫폼으로 옮길 수 있습니다.
이 마이그레이션에는 이 시리즈의 다른 마이그레이션에 비해 좀 더 많은 노력이 필요합니다. Blob 저장소는 원래의 웹 앱 프레임워크에 종속되므로 샘플 앱에서는 Flask 대신 webapp2 프레임워크를 사용합니다. 이 가이드에서는 Cloud Storage, Cloud NBS, Flask, Python 3로의 마이그레이션에 대해 설명합니다.
앱에서 여전히 최종 사용자 '방문'을 등록함 최신 버전 10개를 표시했지만 이전 (모듈 15) Codelab에서는 blobstore 사용을 수용하는 새로운 기능을 추가했습니다. 앱은 최종 사용자에게 '방문'에 해당하는 아티팩트 (파일)를 업로드하라는 메시지를 표시합니다. 사용자가 건너뛰거나 '건너뛰기'를 선택할 수 있습니다. 선택 해제할 수 있습니다. 사용자의 결정과 관계없이 다음 페이지에서는 이 앱의 이전 구현과 동일한 출력을 렌더링하여 최근 방문 내역을 표시합니다. 한 가지 추가적인 반전은 관련 아티팩트가 있는 방문에 '조회'가 표시된다는 점입니다. 방문의 아티팩트를 표시하기 위한 링크입니다. 이 Codelab에서는 앞서 언급한 이전을 구현하면서 설명한 기능을 유지합니다.
3. 설정/사전 작업
튜토리얼의 주요 부분으로 이동하기 전에 프로젝트를 설정하고 코드를 가져온 다음 기준 앱을 배포하여 작업 코드부터 시작하겠습니다.
1. 프로젝트 설정
모듈 15 앱을 이미 배포했다면 동일한 프로젝트 및 코드를 재사용하는 것이 좋습니다. 또는 새 프로젝트를 만들거나 다른 기존 프로젝트를 재사용할 수 있습니다. 프로젝트에 활성 결제 계정이 있고 App Engine이 사용 설정되어 있는지 확인하세요.
2. 기준 샘플 앱 가져오기
이 Codelab의 기본 요건 중 하나는 모듈 15 샘플 앱이 작동하는 것입니다. 없는 경우 모듈 15 '시작'에서 가져올 수 있습니다. 폴더 (아래 링크)를 클릭합니다. 이 Codelab에서는 각 단계를 살펴보고 모듈 16 'FINISH'의 내용과 유사한 코드로 마무리합니다. 있습니다.
모듈 15 시작 파일의 디렉터리는 다음과 같습니다.
$ ls README.md app.yaml main-gcs.py main.py templates
main-gcs.py
파일은 모듈 15의 main.py
대체 버전으로, 프로젝트 ID PROJECT_ID
.appspot.com
에 따라 앱에 할당된 URL의 기본값과 다른 Cloud Storage 버킷을 선택할 수 있습니다. 이 파일은 원하는 경우 유사한 이전 기법을 해당 파일에 적용할 수 있다는 것 외에는 이 Codelab (모듈 16)에서 아무 역할도 하지 않습니다.
3. 기준 앱 (재)배포
이제 남은 사전 작업 실행 단계는 다음과 같습니다.
gcloud
명령줄 도구 다시 숙지gcloud app deploy
를 사용하여 샘플 앱 재배포- 앱이 문제 없이 App Engine에서 실행되는지 확인합니다.
이러한 단계를 성공적으로 실행하고 모듈 15 앱이 작동하는지 확인했으면 초기 페이지에는 '건너뛰기' 옵션과 함께 업로드할 방문 아티팩트 파일을 요청하는 양식이 사용자에게 표시됩니다. 버튼을 클릭하여 선택 해제하려면 다음 단계를 따르세요.
사용자가 파일을 업로드하거나 건너뛰면 앱에서 익숙한 '최근 방문 내역'을 렌더링합니다. 페이지:
아티팩트가 있는 방문에는 '보기'가 표시됩니다. 링크를 사용하여 아티팩트를 표시 (또는 다운로드)할 수 있습니다. 앱의 기능을 확인하고 나면 App Engine 기존 서비스 (webapp2, NBS, blobstore)에서 최신 대안 (Flask, Cloud NBS, Cloud Storage)으로 마이그레이션할 수 있습니다.
4. 구성 파일 업데이트
업데이트된 앱 버전에서는 세 가지 구성 파일이 작동합니다. 필수 작업은 다음과 같습니다.
app.yaml
에 내장된 서드 파티 라이브러리를 업데이트하고 Python 3 이전을 시작하세요.- 기본 제공되지 않는 모든 필수 라이브러리를 지정하는
requirements.txt
를 추가합니다. - 앱이 내장 및 내장되지 않은 서드 파티 라이브러리를 모두 지원하도록
appengine_config.py
를 추가합니다.
app.yaml
libraries
섹션을 업데이트하여 app.yaml
파일을 수정합니다. jinja2
를 삭제하고 grpcio
, setuptools
, ssl
를 추가합니다. 세 라이브러리 모두에서 사용 가능한 최신 버전을 선택합니다. 또한 Python 3 runtime
지시문을 추가하지만 주석 처리되었습니다. 완료되면 다음과 같이 표시됩니다 (Python 3.9를 선택한 경우).
이전:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: jinja2
version: latest
변경 후:
#runtime: python39
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: grpcio
version: latest
- name: setuptools
version: latest
- name: ssl
version: latest
변경사항은 주로 App Engine 서버에서 사용 가능한 Python 2 내장 라이브러리를 다루므로 이를 직접 번들로 제공하지 않아도 됩니다. 우리는 Flask와 함께 제공되는 Jinja2를 제거했으며, 이는 reqs.txt에 추가할 것입니다. Cloud NBS 및 Cloud Storage용 라이브러리와 같은 Google Cloud 클라이언트 라이브러리가 사용될 때마다 grpcio 및 setuptools가 필요합니다. 마지막으로 Cloud Storage 자체에는 ssl 라이브러리가 필요합니다. 상단에 있는 주석 처리된 런타임 지시문은 이 앱을 Python 3로 포팅할 준비가 된 경우를 위한 것입니다. 이 주제에 대해서는 이 가이드의 끝에서 다룹니다.
requirements.txt
requirements.txt
파일을 추가합니다. 여기에는 Flask 프레임워크와 Cloud NBS 및 Cloud Storage 클라이언트 라이브러리가 필요합니다. 이러한 파일은 모두 내장되어 있지 않습니다. 다음 내용으로 파일을 만듭니다.
flask
google-cloud-ndb
google-cloud-storage
Python 2 App Engine 런타임은 내장되지 않은 타사 라이브러리를 자체적으로 번들로 묶어야 하므로, 다음 명령어를 실행하여 이러한 라이브러리를 lib 폴더에 설치합니다.
pip install -t lib -r requirements.txt
개발 머신에 Python 2 및 3이 모두 있는 경우 pip2 명령어를 사용하여 이러한 라이브러리의 Python 2 버전을 가져와야 할 수 있습니다. Python 3로 업그레이드하면 더 이상 자체 번들로 묶을 필요가 없습니다.
appengine_config.py
내장 및 비내장 서드 파티 라이브러리를 지원하는 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)
방금 완료한 단계는 App Engine 문서의 Python 2 앱용 라이브러리 설치 섹션에 나열된 단계와 유사하거나 동일해야 하며, 더 구체적으로 appengine_config.py
의 내용은 5단계의 내용과 일치해야 합니다.
구성 파일 작업이 완료되었으므로 애플리케이션으로 넘어가겠습니다.
5. 애플리케이션 파일 수정
가져오기
main.py
의 첫 번째 변경사항에는 교체되는 모든 항목을 바꾸는 것이 포함됩니다. 변경되는 사항은 다음과 같습니다.
webapp2
가 Flask로 대체됨webapp2_extras
의 Jinja2를 사용하는 대신 Flask와 함께 제공되는 Jinja2를 사용하세요.- App Engine Blob 저장소 및 NBS가 Cloud NBS 및 Cloud Storage로 대체됨
webapp
의 blobstore 핸들러는io
표준 라이브러리 모듈, Flask,werkzeug
유틸리티의 조합으로 대체되었습니다.- 기본적으로 blobstore는 앱의 URL (
PROJECT_ID.appspot.com
)에 따라 이름이 지정된 Cloud Storage 버킷에 씁니다. Cloud Storage 클라이언트 라이브러리로 포팅하므로google.auth
를 사용하여 프로젝트 ID를 가져와 정확히 동일한 버킷 이름을 지정합니다. 버킷 이름은 더 이상 하드코딩되지 않으므로 변경할 수 있습니다.
이전:
import webapp2
from webapp2_extras import jinja2
from google.appengine.ext import blobstore, ndb
from google.appengine.ext.webapp import blobstore_handlers
main.py
의 현재 가져오기 섹션을 아래 코드 스니펫으로 바꿔 위 목록의 변경사항을 구현합니다.
변경 후:
import io
from flask import (Flask, abort, redirect, render_template,
request, send_file, url_for)
from werkzeug.utils import secure_filename
import google.auth
from google.cloud import exceptions, ndb, storage
초기화 및 불필요한 Jinja2 지원
대체할 다음 코드 블록은 webapp2_extras
의 Jinja2 사용을 지정하는 BaseHandler
입니다. Jinja2가 Flask와 함께 기본 템플릿 엔진이므로 이 작업이 필요하지 않으므로 삭제하세요.
모듈 16 측에서는 이전 앱에 없던 객체를 인스턴스화합니다. 여기에는 Flask 앱을 초기화하고 Cloud NBS 및 Cloud Storage용 API 클라이언트를 만드는 작업이 포함됩니다. 마지막으로 위의 가져오기 섹션에서 설명한 대로 Cloud Storage 버킷 이름을 조합합니다. 이러한 업데이트를 구현하기 전과 후는 다음과 같습니다.
이전:
class BaseHandler(webapp2.RequestHandler):
'Derived request handler mixing-in Jinja2 support'
@webapp2.cached_property
def jinja2(self):
return jinja2.get_jinja2(app=self.app)
def render_response(self, _template, **context):
self.response.write(self.jinja2.render_template(_template, **context))
변경 후:
app = Flask(__name__)
ds_client = ndb.Client()
gcs_client = storage.Client()
_, PROJECT_ID = google.auth.default()
BUCKET = '%s.appspot.com' % PROJECT_ID
Datastore 액세스 업데이트
Cloud Dataplex는 대부분 App Engine NBS와 호환됩니다. 이미 다룬 한 가지 차이점은 API 클라이언트가 필요하다는 것입니다. 또 다른 방법은 Datastore 액세스를 API 클라이언트의 Python 컨텍스트 관리자로 제어해야 하는 경우입니다. 즉, 이는 기본적으로 Cloud NBS 클라이언트 라이브러리를 사용하는 모든 Datastore 액세스 호출이 Python with
블록 내에서만 발생할 수 있음을 의미합니다.
한 가지 변화입니다. 다른 하나는 Blob 저장소와 그 객체(예: BlobKey
는 Cloud Storage에서 지원되지 않으므로 대신 file_blob
를 ndb.StringProperty
로 변경합니다. 다음은 데이터 모델 클래스와 이러한 변경사항을 반영하는 업데이트된 store_visit()
및 fetch_visits()
함수입니다.
이전:
class Visit(ndb.Model):
'Visit entity registers visitor IP address & timestamp'
visitor = ndb.StringProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
file_blob = ndb.BlobKeyProperty()
def store_visit(remote_addr, user_agent, upload_key):
'create new Visit entity in Datastore'
Visit(visitor='{}: {}'.format(remote_addr, user_agent),
file_blob=upload_key).put()
def fetch_visits(limit):
'get most recent visits'
return Visit.query().order(-Visit.timestamp).fetch(limit)
변경 후:
class Visit(ndb.Model):
'Visit entity registers visitor IP address & timestamp'
visitor = ndb.StringProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
file_blob = ndb.StringProperty()
def store_visit(remote_addr, user_agent, upload_key):
'create new Visit entity in Datastore'
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent),
file_blob=upload_key).put()
def fetch_visits(limit):
'get most recent visits'
with ds_client.context():
return Visit.query().order(-Visit.timestamp).fetch(limit)
다음은 지금까지 변경된 내용을 그림으로 나타낸 것입니다.
핸들러 업데이트
업로드 핸들러
webapp2
의 핸들러는 Flask에서 함수이지만 클래스입니다. Flask는 HTTP 동사 메서드 대신 동사를 사용하여 함수를 데코레이션합니다. blobstore 및 webapp
핸들러는 Cloud Storage의 기능과 Flask의 유틸리티로 대체되었습니다.
이전:
class UploadHandler(blobstore_handlers.BlobstoreUploadHandler):
'Upload blob (POST) handler'
def post(self):
uploads = self.get_uploads()
blob_id = uploads[0].key() if uploads else None
store_visit(self.request.remote_addr, self.request.user_agent, blob_id)
self.redirect('/', code=307)
변경 후:
@app.route('/upload', methods=['POST'])
def upload():
'Upload blob (POST) handler'
fname = None
upload = request.files.get('file', None)
if upload:
fname = secure_filename(upload.filename)
blob = gcs_client.bucket(BUCKET).blob(fname)
blob.upload_from_file(upload, content_type=upload.content_type)
store_visit(request.remote_addr, request.user_agent, fname)
return redirect(url_for('root'), code=307)
이 업데이트와 관련된 몇 가지 참고사항은 다음과 같습니다.
- 이제 파일 아티팩트는
blob_id
대신 파일 이름(fname
)으로 식별되고(있는 경우)None
로 식별됩니다(사용자가 파일 업로드를 선택 해제함). - blobstore 핸들러는 업로드 프로세스를 사용자로부터 추상화하지만 Cloud Storage는 추상화하지 않습니다. 따라서 파일의 blob 객체와 위치 (버킷)를 설정하는 새로 추가된 코드와 실제 업로드를 수행하는 호출을 확인할 수 있습니다. (
upload_from_file()
). webapp2
는 애플리케이션 파일 하단에 있는 라우팅 테이블을 사용하며 Flask 경로는 데코레이트된 각 핸들러에서 찾을 수 있습니다.- 두 핸들러는 모두 HTTP 307 반환 코드로
POST
요청을 유지하면서 홈 (/
)으로 리디렉션하여 기능을 마무리합니다.
핸들러 다운로드
다운로드 핸들러를 업데이트할 때는 업로드 핸들러와 비슷한 패턴을 따르며, 확인할 코드만 훨씬 적습니다. blobstore 및 webapp
기능을 Cloud Storage 및 Flask로 대체합니다.
이전:
class ViewBlobHandler(blobstore_handlers.BlobstoreDownloadHandler):
'view uploaded blob (GET) handler'
def get(self, blob_key):
self.send_blob(blob_key) if blobstore.get(blob_key) else self.error(404)
변경 후:
@app.route('/view/<path:fname>')
def view(fname):
'view uploaded blob (GET) handler'
blob = gcs_client.bucket(BUCKET).blob(fname)
try:
media = blob.download_as_bytes()
except exceptions.NotFound:
abort(404)
return send_file(io.BytesIO(media), mimetype=blob.content_type)
이 업데이트에 대한 참고사항:
- 다시 말하지만, Flask는 해당 경로로 핸들러 함수를 데코레이션하지만
webapp
는 하단의 라우팅 테이블에서 이를 수행하므로 후자의 패턴 일치 문법('/view/([^/]+)?'
와 Flask ('/view/<path:fname>'
)의 패턴을 구별합니다. - 업로드 핸들러와 마찬가지로, Cloud Storage 측에서 blobstore 핸들러에 의해 추상화된 기능, 즉 문제의 파일 (blob)을 식별하고 바이너리와 blobstore 핸들러의 단일
send_blob()
메서드 호출을 명시적으로 다운로드하는 등의 추가 작업이 필요합니다. - 두 경우 모두 아티팩트를 찾을 수 없으면 사용자에게 HTTP 404 오류가 반환됩니다.
기본 핸들러
기본 애플리케이션의 최종 변경사항은 기본 핸들러에서 이루어집니다. webapp2
HTTP 동사 메서드는 해당 기능을 결합한 단일 함수로 대체되었습니다. 아래와 같이 MainHandler
클래스를 root()
함수로 바꾸고 webapp2
라우팅 테이블을 삭제합니다.
이전:
class MainHandler(BaseHandler):
'main application (GET/POST) handler'
def get(self):
self.render_response('index.html',
upload_url=blobstore.create_upload_url('/upload'))
def post(self):
visits = fetch_visits(10)
self.render_response('index.html', visits=visits)
app = webapp2.WSGIApplication([
('/', MainHandler),
('/upload', UploadHandler),
('/view/([^/]+)?', ViewBlobHandler),
], debug=True)
변경 후:
@app.route('/', methods=['GET', 'POST'])
def root():
'main application (GET/POST) handler'
context = {}
if request.method == 'GET':
context['upload_url'] = url_for('upload')
else:
context['visits'] = fetch_visits(10)
return render_template('index.html', **context)
get()
메서드와 post()
메서드를 구분하는 것이 아니라 기본적으로 root()
의 if-else
문입니다. 또한 root()
는 단일 함수이므로 GET
와 POST
의 템플릿을 모두 렌더링하는 호출은 한 번만 있지만 webapp2
에서는 실제로 불가능합니다.
다음은 main.py
의 두 번째이자 마지막 변경사항 세트를 그림으로 나타낸 것입니다.
(선택사항) 이전 버전과의 호환성 '향상'
따라서 위에서 만든 솔루션은 완벽하게 작동하지만, 처음부터 새로 시작하고 blobstore에서 만든 파일이 없는 경우에만 가능합니다. BlobKey
대신 파일 이름으로 파일을 식별하도록 앱을 업데이트했으므로 완료된 모듈 16 앱은 있는 그대로 blobstore 파일을 볼 수 없습니다. 즉, 이 이전을 수행하는 동안 이전 버전과 호환되지 않는 변경사항을 적용했습니다. 이제 이 격차를 해소하기 위해 main.py
대체 버전인 main-migrate.py
(저장소에서 확인 가능)을 제공합니다.
첫 번째 '확장 프로그램'은 Cloud Storage로 만든 파일의 StringProperty
에 추가로 BlobKeyProperty
가 있는 데이터 모델입니다.
class Visit(ndb.Model):
'Visit entity registers visitor IP address & timestamp'
visitor = ndb.StringProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
file_blob = ndb.BlobKeyProperty() # backwards-compatibility
file_gcs = ndb.StringProperty()
file_blob
속성은 blobstore로 만든 파일을 식별하는 데 사용되며 file_gcs
는 Cloud Storage 파일용입니다. 이제 새 방문을 만들 때 file_blob
대신 file_gcs
에 값을 명시적으로 저장하므로 store_visit가 약간 다르게 표시됩니다.
이전:
def store_visit(remote_addr, user_agent, upload_key):
'create new Visit entity in Datastore'
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent),
file_blob=upload_key).put()
변경 후:
def store_visit(remote_addr, user_agent, upload_key):
'create new Visit entity in Datastore'
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent),
file_gcs=upload_key).put()
가장 최근 방문 데이터를 가져올 때 "정규화" 데이터를 템플릿에 전송하기 전에 다음과 같이 처리합니다.
이전:
@app.route('/', methods=['GET', 'POST'])
def root():
'main application (GET/POST) handler'
context = {}
if request.method == 'GET':
context['upload_url'] = url_for('upload')
else:
context['visits'] = fetch_visits(10)
return render_template('index.html', **context)
변경 후:
@app.route('/', methods=['GET', 'POST'])
def root():
'main application (GET/POST) handler'
context = {}
if request.method == 'GET':
context['upload_url'] = url_for('upload')
else:
context['visits'] = etl_visits(fetch_visits(10))
return render_template('index.html', **context)
그런 다음 file_blob
또는 file_gcs
의 존재 여부 (또는 둘 다 없음)를 확인합니다. 사용할 수 있는 파일이 있으면 존재하는 파일을 선택하고 해당 식별자 (blobstore에서 만든 파일의 경우 BlobKey
, Cloud Storage로 만든 파일의 경우 파일 이름)를 사용합니다. 'Cloud Storage로 만든 파일'이라고 하면 Cloud Storage 클라이언트 라이브러리를 사용하여 만든 파일을 의미합니다. Blobstore는 Cloud Storage에도 쓰기를 수행하지만 이 경우 blobstore에서 만든 파일입니다.
더 중요한 것은 최종 사용자를 위해 데이터를 정규화하거나 ETL (추출, 변환, 로드)하는 데 사용되는 이 etl_visits()
함수는 무엇인가요? 상태 메시지가 표시됩니다.
def etl_visits(visits):
return [{
'visitor': v.visitor,
'timestamp': v.timestamp,
'file_blob': v.file_gcs if hasattr(v, 'file_gcs') \
and v.file_gcs else v.file_blob
} for v in visits]
예상한 대로 코드가 모든 방문을 반복하고 각 방문에 대해 방문자 및 타임스탬프 데이터를 그대로 가져온 다음 file_gcs
또는 file_blob
이 있는지 확인하고, 둘 중 하나를 선택합니다 (존재하지 않는 경우 None
).
다음은 main.py
과 main-migrate.py
의 차이점을 보여줍니다.
blobstore로 만든 파일을 사용하지 않고 처음부터 새로 시작하는 경우 main.py
를 사용합니다. 하지만 Blob 저장소 및 Cloud Storage 둘 다에서 만든 파일을 전환하고 지원하고자 한다면 자체 앱의 마이그레이션을 계획하는 데 도움이 되는 시나리오 처리 방법의 예로 main-migrate.py
를 확인해 보세요. 복잡한 마이그레이션을 수행할 때는 특별한 사례가 발생할 수 있으므로 이 예시는 실제 데이터를 사용하여 실제 앱을 현대화하는 것이 얼마나 유용한지 설명하기 위한 것입니다.
6. 요약/삭제
이 섹션에서는 앱을 배포하고 의도한 대로 반영된 출력에서 작동하는지 확인하여 이 Codelab을 마무리합니다. 앱 유효성 검사 후 정리 단계를 실행하고 다음 단계를 고려합니다.
애플리케이션 배포 및 확인
앱을 재배포하기 전에 pip install -t lib -r requirements.txt
를 실행하여 자체 번들된 서드 파티 라이브러리를 lib 폴더에서 가져와야 합니다. 이전 버전과 호환되는 솔루션을 실행하려면 먼저 main-migrate.py
의 이름을 main.py
로 바꿉니다. 이제 gcloud app deploy
를 실행하고 앱이 모듈 15 앱과 동일하게 작동하는지 확인합니다. 양식 화면은 다음과 같습니다.
최근 방문 페이지는 다음과 같습니다.
축하합니다. App Engine blob을 Cloud Storage로, App Engine NBS를 Cloud Dataplex로, webapp2
를 Flask로 대체하는 이 Codelab을 완료했습니다. 이제 코드가 FINISH (모듈 16) 폴더에 있는 코드와 일치해야 합니다. 대체 main-migrate.py
도 이 폴더에 있습니다.
Python 3 '마이그레이션'
app.yaml
상단의 주석 처리된 Python 3 runtime
지시어만 있으면 이 앱을 Python 3로 포팅할 수 있습니다. 소스 코드 자체는 이미 Python 3와 호환되므로 변경할 필요가 없습니다. Python 3 앱으로 배포하려면 다음 단계를 실행합니다.
app.yaml
맨 위에서 Python 3runtime
지시문의 주석 처리를 삭제합니다.app.yaml
의 다른 모든 줄을 삭제합니다.appengine_config.py
파일을 삭제합니다. (Python 3 런타임에서는 사용되지 않음)lib
폴더가 있으면 삭제합니다. (Python 3 런타임에는 불필요)
삭제
일반
이 작업이 완료되면 요금이 청구되지 않도록 App Engine 앱을 사용 중지하는 것이 좋습니다. 하지만 추가 테스트 또는 실험을 원하는 경우 App Engine 플랫폼에서 무료 할당량을 사용할 수 있으므로 이 사용 등급을 초과하지 않는 한 요금이 청구되지 않습니다. 이는 컴퓨팅을 위한 것이며, 관련 App Engine 서비스에 대한 요금이 부과될 수 있으므로 자세한 내용은 가격 책정 페이지를 확인하세요. 이 마이그레이션에 다른 Cloud 서비스가 포함된 경우 별도로 요금이 청구됩니다. 두 경우 모두 해당하는 경우 '이 Codelab과 관련된 내용'을 참고하세요. 섹션을 참조하세요.
자세히 알려드리자면 App Engine과 같은 Google Cloud 서버리스 컴퓨팅 플랫폼에 배포할 경우 약간의 빌드 및 스토리지 비용이 발생합니다. Cloud Build에는 Cloud Storage와 마찬가지로 자체 무료 할당량이 있습니다. 해당 이미지의 스토리지가 할당량 중 일부를 사용합니다. 하지만 이러한 무료 등급이 없는 지역에 거주할 수도 있으므로 잠재적인 비용을 최소화하려면 저장용량 사용량에 유의해야 합니다. 특정 Cloud Storage '폴더' 다음을 포함해야 합니다.
console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
- 위의 스토리지 링크는
PROJECT_ID
및 *LOC
*기호에 따라 다릅니다(예: 'us
'). (앱이 미국에서 호스팅되는 경우)
반면 이 애플리케이션 또는 다른 관련 이전 Codelab을 계속 진행하지 않고 모든 항목을 완전히 삭제하려면 프로젝트를 종료합니다.
이 Codelab에만 해당
아래에 나열된 서비스는 이 Codelab의 고유한 서비스입니다. 자세한 내용은 각 제품의 문서를 참조하세요.
- App Engine blobstore 서비스에는 저장된 데이터 할당량 및 한도가 적용되므로 해당 할당량과 기존 번들 서비스의 가격 책정 페이지를 검토하세요.
- Cloud Storage에는 특정 리전에 대한 무료 등급이 있습니다. 자세한 내용은 일반 가격 책정 페이지를 참고하세요.
- App Engine Datastore 서비스는 무료 등급인 Cloud Datastore (Datastore 모드의 Cloud Firestore)에서 제공합니다. 자세한 내용은 가격 책정 페이지를 참고하세요."
모듈 15에서 16으로 이전해도 blobstore에 데이터가 남아 있으므로 위의 가격 정보를 포함했습니다.
다음 단계
이 튜토리얼 외에도 기존 번들 서비스에서 벗어나는 데 중점을 둔 다른 마이그레이션 모듈에는 다음이 포함됩니다.
- 모듈 2: App Engine
ndb
에서 Cloud Dataplex로 마이그레이션 - 모듈 7~9: App Engine 태스크 큐 푸시 태스크에서 Cloud Tasks로 마이그레이션
- 모듈 12~13: App Engine Memcache에서 Cloud Memorystore로 마이그레이션
- 모듈 18~19: App Engine 작업 대기열 (가져오기 작업)에서 Cloud Pub/Sub로 마이그레이션
Google Cloud의 서버리스 플랫폼은 더 이상 App Engine이 아닙니다. App Engine 앱이 작거나 기능이 제한적이며 독립형 마이크로서비스로 전환하려는 경우 또는 모놀리식 앱을 재사용 가능한 여러 구성요소로 분할하려는 경우 Cloud Functions로 이전하는 것이 좋습니다. 특히 CI/CD (지속적 통합/지속적 배포 또는 배포) 파이프라인으로 구성된 컨테이너화가 애플리케이션 개발 워크플로의 일부가 되었다면 Cloud Run으로 마이그레이션하는 것이 좋습니다. 이러한 시나리오는 다음 모듈에서 다룹니다.
- App Engine에서 Cloud Functions로 마이그레이션: 모듈 11 참조
- App Engine에서 Cloud Run으로 마이그레이션: Docker로 앱을 컨테이너화하려면 모듈 4를 참조하고, 컨테이너, Docker 지식 또는
Dockerfile
없이 마이그레이션하려면 모듈 5를 참조하세요.
다른 서버리스 플랫폼으로 전환하는 것은 선택사항이며 변경하기 전에 앱 및 사용 사례에 가장 적합한 옵션을 고려하는 것이 좋습니다.
다음으로 고려할 마이그레이션 모듈과 관계없이 모든 서버리스 마이그레이션 스테이션 콘텐츠 (Codelab, 동영상, 소스 코드[사용 가능한 경우])는 오픈소스 저장소에서 액세스할 수 있습니다. 저장소의 README
는 고려할 이전 및 관련 '순서'에 관한 안내도 제공합니다. 오신 것을 환영합니다
7. 추가 리소스
Codelab 문제/의견
이 Codelab에 문제가 발견된 경우 문제를 기록하기 전에 먼저 비슷한 기록이 있는지 검색해보세요. 검색 및 새 문제 만들기 링크:
마이그레이션 리소스
모듈 15 (START)와 모듈 16 (FINISH)의 저장소 폴더 링크는 아래 표에서 찾을 수 있습니다. 또한 ZIP 파일을 클론하거나 다운로드할 수 있는 모든 App Engine Codelab 이전 저장소에서도 액세스할 수 있습니다.
Codelab | Python 2 | Python 3 |
모듈 15 | 해당 사항 없음 | |
모듈 16 (본 Codelab) | (Python 2와 동일) |
온라인 리소스
다음은 이 튜토리얼과 관련이 있을 수 있는 온라인 리소스입니다.
App Engine Blob 저장소 및 Cloud Storage
App Engine 플랫폼
- App Engine 문서
- Python 2 App Engine (표준 환경) 런타임
- Python 2 App Engine에서 App Engine 기본 제공 라이브러리 사용
- Python 3 App Engine (표준 환경) 런타임
- Python 2와 Python 2의 차이점 3 App Engine (표준 환경) 런타임
- Python 2에서 3으로 App Engine (표준 환경) 마이그레이션 가이드
- App Engine 가격 책정 및 할당량 정보
- 2세대 App Engine 플랫폼 출시 (2018)
- 이전 기간과 2세대 플랫폼
- 기존 런타임 장기 지원
- 문서 마이그레이션 샘플 저장소
- 커뮤니티 제공 이전 샘플 저장소
기타 클라우드 정보
- Google Cloud Platform에서 Python 사용
- Google Cloud Python 클라이언트 라이브러리
- Google Cloud '항상 무료' 등급
- Google Cloud SDK (
gcloud
명령줄 도구) - 모든 Google Cloud 문서
Python
- Django 및 Jinja2 템플릿 시스템
webapp2
웹 프레임워크webapp2
문서- 링크
webapp2_extras
개 webapp2_extras
Jinja2 문서- Flask 웹 프레임워크
동영상
라이선스
이 작업물은 Creative Commons Attribution 2.0 일반 라이선스에 따라 사용이 허가되었습니다.