從 App Engine Blob 遷移至 Cloud Storage (單元 16)

1. 總覽

無伺服器遷移站系列程式碼實驗室 (可自行調整進度的實作教學課程) 和相關影片,旨在協助 Google Cloud 無伺服器開發人員翻新應用程式,引導他們完成一或多項遷移作業,主要是從舊版服務遷移。這樣一來,應用程式的可攜性會更高,您也能享有更多選項和彈性,整合及存取更多元的 Cloud 產品,並更輕鬆地升級至較新的語言版本。雖然本系列文章最初著重於最早的 Cloud 使用者,主要是 App Engine (標準環境) 開發人員,但內容廣泛,也涵蓋其他無伺服器平台,例如 Cloud Functions 和 Cloud Run,或其他適用平台。

本程式碼實驗室說明如何從 App Engine Blobstore 遷移至 Cloud Storage。此外,系統也會隱含遷移下列項目:

如需更多逐步操作資訊,請參閱任何相關的遷移模組。

在接下來的研究室中

  • 新增 App Engine Blobstore API/程式庫的使用方式
  • 將使用者上傳的內容儲存至 Blobstore 服務
  • 準備遷移至 Cloud Storage

軟硬體需求

問卷調查

您會如何使用這個教學課程?

只閱讀內容 閱讀內容並完成練習

您對 Python 的使用體驗評價如何?

新手 中級 精通

您對 Google Cloud 服務的使用體驗滿意度為何?

新手 中級 精通

2. 背景

本程式碼實驗室會從模組 15 的範例應用程式開始,示範如何從 Blobstore (和 NDB) 遷移至 Cloud Storage (和 Cloud NDB)。遷移程序包括替換 App Engine 舊版隨附服務的依附元件,讓您視需要將應用程式移至其他 Cloud 無伺服器平台或其他託管平台。

與本系列的其他遷移作業相比,這項遷移作業需要更多心力。Blobstore 依附於原始 webapp 框架,因此範例應用程式使用 webapp2 框架,而非 Flask。本教學課程會介紹如何遷移至 Cloud Storage、Cloud NDB、Flask 和 Python 3。

應用程式仍會記錄使用者「造訪」次數,並顯示最近十次造訪,但上一個 (模組 15) 程式碼實驗室新增了新功能,可配合 Blobstore 使用:應用程式會提示使用者上傳與「造訪」對應的構件 (檔案)。使用者可以選擇提供,或選取「略過」選擇不採用。無論使用者如何決定,下一個頁面都會顯示與這個應用程式先前版本相同的輸出內容,也就是最近的造訪記錄。此外,如果造訪記錄有對應的構件,就會顯示「查看」連結,點選即可查看造訪記錄的構件。本程式碼實驗室會實作上述遷移作業,同時保留所述功能。

3. 設定/事前準備

在進入教學課程的主要部分之前,請先設定專案、取得程式碼,然後部署基準應用程式,確保我們一開始使用的程式碼可以正常運作。

1. 設定專案

如果您已部署模組 15 應用程式,建議您重複使用相同的專案 (和程式碼)。或者,您也可以建立全新專案,或重複使用其他現有專案。確認專案有有效的帳單帳戶,且已啟用 App Engine。

2. 取得基準範例應用程式

本程式碼實驗室的其中一項先決條件,是具備可運作的單元 15 範例應用程式。如果沒有,可以從單元 15 的「START」資料夾取得 (連結如下)。本程式碼實驗室會逐步引導您完成各個步驟,最後產生的程式碼會與模組 16「FINISH」資料夾中的程式碼類似。

模組 15 START 檔案的目錄應如下所示:

$ ls
README.md       app.yaml        main-gcs.py     main.py         templates

main-gcs.py 檔案是單元 15 中 main.py 的替代版本,可讓您選取 Cloud Storage bucket,而非根據專案 ID 指派的應用程式預設網址:PROJECT_ID.appspot.com。這個檔案與本程式碼研究室 (模組 16) 無關,但如有需要,可對該檔案套用類似的遷移技術。

3. (重新) 部署基準應用程式

現在要執行的其餘前置作業步驟:

  1. 重新熟悉 gcloud 指令列工具
  2. 使用 gcloud app deploy 重新部署範例應用程式
  3. 確認應用程式在 App Engine 上順利執行

成功執行這些步驟並確認模組 15 應用程式正常運作後,初始頁面會顯示表單,提示使用者上傳造訪構件檔案,並提供「略過」按鈕,讓使用者選擇不提供:

f5b5f9f19d8ae978.png

使用者上傳檔案或略過後,應用程式會顯示熟悉的「最近造訪」頁面:

f5ac6b98ee8a34cb.png

如果造訪記錄包含構件,造訪時間戳記右側會顯示「查看」連結,點選即可查看或下載構件。確認應用程式功能正常後,即可從 App Engine 舊版服務 (webapp2、NDB、Blobstore) 遷移至新版替代服務 (Flask、Cloud NDB、Cloud Storage)。

4. 更新設定檔

更新後的應用程式版本會用到三個設定檔。必要工作如下:

  1. 更新 app.yaml 中必要的內建第三方程式庫,並為遷移至 Python 3 做好準備
  2. 新增 requirements.txt,指定所有非內建的必要程式庫
  3. 新增 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

AFTER:

#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 內建程式庫 (因此您不必自行套裝組合)。我們移除了 Jinja2,因為 Flask 隨附 Jinja2,而我們即將把 Flask 新增至 reqs.txt。只要使用 Google Cloud 用戶端程式庫 (例如 Cloud NDB 和 Cloud Storage 的程式庫),就需要 grpcio 和 setuptools。最後,Cloud Storage 本身需要 ssl 程式庫。頂端註解排除的執行階段指令,是為了在您準備好將這個應用程式移植到 Python 3 時使用。我們會在教學課程尾聲說明這個主題。

requirements.txt

新增 requirements.txt 檔案,要求 Flask 架構、Cloud NDB 和 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 的第一組變更包括換掉所有要替換的內容。異動內容如下:

  1. webapp2 已由 Flask 取代
  2. 請使用 Flask 隨附的 Jinja2,而非 webapp2_extras 的 Jinja2
  3. App Engine Blobstore 和 NDB 已由 Cloud NDB 和 Cloud Storage 取代
  4. webapp 中的 Blobstore 處理常式已由 io 標準程式庫模組、Flask 和 werkzeug 公用程式組合取代
  5. 根據預設,Blobstore 會寫入以應用程式網址 (PROJECT_ID.appspot.com) 命名的 Cloud Storage bucket。由於我們正在移植到 Cloud Storage 用戶端程式庫,因此會使用 google.auth 取得專案 ID,以指定完全相同的 bucket 名稱。(您可以變更值區名稱,因為該名稱不再是硬式編碼)。

之前:

import webapp2
from webapp2_extras import jinja2
from google.appengine.ext import blobstore, ndb
from google.appengine.ext.webapp import blobstore_handlers

請將 main.py 中目前的匯入部分替換為下列程式碼片段,實作上述清單中的變更。

AFTER:

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 支援

接下來要替換的程式碼區塊是 BaseHandler,用於指定從 webapp2_extras 使用 Jinja2。Jinja2 是 Flask 內建的預設範本引擎,因此不需要這項設定,請將其移除。

在模組 16 端,例項化舊版應用程式中沒有的物件,包括初始化 Flask 應用程式,以及為 Cloud NDB 和 Cloud Storage 建立 API 用戶端。最後,我們按照上述匯入部分所述,組合 Cloud Storage bucket 名稱。以下是導入這些更新前後的差異:

之前:

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))

AFTER:

app = Flask(__name__)
ds_client = ndb.Client()
gcs_client = storage.Client()
_, PROJECT_ID = google.auth.default()
BUCKET = '%s.appspot.com' % PROJECT_ID

更新 Datastore 存取權

Cloud NDB 大致上與 App Engine NDB 相容。其中一項差異是需要 API 用戶端,這點已在前面提過。另一個差異是,後者需要由 API 用戶端的 Python 內容管理工具控管 Datastore 存取權。基本上,這表示所有使用 Cloud NDB 用戶端程式庫的 Datastore 存取呼叫,都只能在 Python with 區塊中進行。

這是其中一項變更。另一項變更是 Cloud Storage 不支援 Blobstore 及其物件 (例如 BlobKey),因此請將 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)

AFTER:

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)

以下是目前為止所做變更的圖示:

a8f74ca392275822.png

更新處理常式

上傳處理常式

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)

AFTER:

@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)

這項更新的注意事項:

  • 檔案構件現在會以檔案名稱 (fname) 識別 (如有),否則會以 None 識別 (使用者選擇不上傳檔案),而非 blob_id。
  • Blobstore 處理常式會將上傳程序從使用者中抽象化,但 Cloud Storage 不會,因此您可以看到新加入的程式碼,用於設定檔案的 blob 物件和位置 (bucket),以及執行實際的上傳呼叫。(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)

AFTER:

@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)

AFTER:

@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」第二組 (也是最後一組) 異動的圖示:

5ec38818c32fec2.png

(選用) 回溯相容性「強化」

因此,上述解決方案只有在您從頭開始,且沒有 Blobstore 建立的檔案時,才能完美運作。由於我們更新了應用程式,改為依檔案名稱 (而非 BlobKey) 識別檔案,因此完成的模組 16 應用程式無法直接查看 Blobstore 檔案。換句話說,我們在執行這項遷移作業時,進行了無法回溯相容的變更。我們現在提供 main.py 的替代版本,稱為 main-migrate.py (位於存放區),嘗試彌補這項差距。

第一個支援 Blobstore 建立檔案的「擴充功能」是具有 BlobKeyProperty 的資料模型 (除了 Cloud Storage 建立檔案的 StringProperty 之外):

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_gcs 而非 file_blob 中,因此 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()

AFTER:

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)

AFTER:

@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 是否存在 (或兩者皆不存在)。如果有可用的檔案,請選擇現有的檔案,並使用該 ID (Blobstore 建立的檔案為 BlobKey,Cloud Storage 建立的檔案則為檔案名稱)。「Cloud Storage 建立的檔案」是指使用 Cloud Storage 用戶端程式庫建立的檔案。Blobstore 也會寫入 Cloud Storage,但這種情況下,這些檔案會是 Blobstore 建立的檔案。

更重要的是,這個 etl_visits() 函式是什麼?它用於正規化或 ETL (擷取、轉換和載入) 使用者資料。這是訂閱按鈕的圖示:

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 的差異:

718b05b2adadb2e1.png

如果您是從頭開始,沒有 Blobstore 建立的檔案,請使用 main.py,但如果您正在轉換,且希望支援 Blobstore 和 Cloud Storage 建立的檔案,請查看 main-migrate.py,瞭解如何處理這類情況,協助您規劃應用程式遷移。執行複雜的遷移作業時,可能會出現特殊情況,因此這個範例旨在展示如何使用實際資料,更有效地翻新實際應用程式。

6. 摘要/清除

本節將部署應用程式,並確認應用程式和任何反映的輸出內容是否正常運作,為這個程式碼實驗室畫下句點。應用程式驗證完成後,請執行所有清理步驟,並思考後續步驟。

部署及驗證應用程式

重新部署應用程式前,請務必執行 pip install -t lib -r requirements.txt,在 lib 資料夾中取得這些自行綁定的第三方程式庫。如要執行回溯相容解決方案,請先將 main-migrate.py 重新命名為 main.py。接著執行 gcloud app deploy,確認應用程式的運作方式與單元 15 應用程式相同。表單畫面如下所示:

f5b5f9f19d8ae978.png

「最近造訪」頁面如下所示:

f5ac6b98ee8a34cb.png

恭喜您完成本程式碼實驗室,成功將 App Engine Blobstore 替換為 Cloud Storage、App Engine NDB 替換為 Cloud NDB,以及 webapp2 替換為 Flask。您的程式碼現在應與 FINISH (Module 16) 資料夾中的內容相符。替代 main-migrate.py 也會出現在該資料夾中。

Python 3「遷移」

只要在 app.yaml 頂端加上註解排除的 Python 3 runtime 指令,即可將這個應用程式移植到 Python 3。原始碼本身已與 Python 3 相容,因此不需要變更。如要將其部署為 Python 3 應用程式,請執行下列步驟:

  1. 取消註解 app.yaml 頂端的 Python 3 runtime 指令。
  2. 刪除 app.yaml 中的所有其他行。
  3. 刪除 appengine_config.py 檔案。(Python 3 執行階段中未使用)
  4. 刪除 lib 資料夾 (如果有的話)。(Python 3 執行階段不需要)

清除所用資源

一般

如果目前已完成,建議您停用 App Engine 應用程式,以免產生費用。不過,如果您想進一步測試或實驗,App Engine 平台提供免費配額,只要不超過該用量層級,就不會產生費用。這是運算費用,但相關 App Engine 服務可能也會產生費用,詳情請參閱定價頁面。如果這項遷移作業涉及其他 Cloud 服務,則會另外計費。無論是哪一種情況,請視需要參閱下方的「本程式碼實驗室專屬」一節。

為求資訊公開,部署至 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」。

另一方面,如果您不打算繼續使用這個應用程式或其他相關遷移程式碼實驗室,並想完全刪除所有內容,請關閉專案。

本程式碼實驗室專用

下列服務是本程式碼實驗室專屬。詳情請參閱各項產品的說明文件:

請注意,如果您從單元 15 遷移至 16,Blobstore 中仍會有資料,因此我們在上方列出其定價資訊。

後續步驟

除了本教學課程外,您也可以考慮其他遷移模組,瞭解如何從舊版隨附服務遷移至其他服務:

  • 單元 2:從 App Engine ndb 遷移至 Cloud NDB
  • 模組 7 至 9:從 App Engine 工作佇列發送工作遷移至 Cloud Tasks
  • 模組 12-13:從 App Engine Memcache 遷移至 Cloud Memorystore
  • 模組 18-19:從 App Engine 工作佇列 (提取工作) 遷移至 Cloud Pub/Sub

App Engine 不再是 Google Cloud 唯一的無伺服器平台。如果您有一個小型 App Engine 應用程式,或功能有限的應用程式,並希望將其轉換為獨立的微服務,或者您想將單體應用程式拆分為多個可重複使用的元件,這些都是考慮改用 Cloud Functions 的好理由。如果容器化已成為應用程式開發工作流程的一部分,特別是包含 CI/CD (持續整合/持續推送軟體更新或部署) 管道,建議您遷移至 Cloud Run。下列單元會介紹這些情境:

  • 從 App Engine 遷移至 Cloud Functions:請參閱模組 11
  • 從 App Engine 遷移至 Cloud Run:請參閱單元 4,瞭解如何使用 Docker 將應用程式容器化,或參閱單元 5,瞭解如何在不使用容器、Docker 知識或 Dockerfile 的情況下完成這項操作

您可以選擇是否改用其他無伺服器平台。建議您先考量最適合應用程式和用途的選項,再進行任何變更。

無論您接下來考慮使用哪個遷移模組,所有 Serverless Migration Station 內容 (程式碼實驗室、影片、原始碼 [如有]) 都可以透過其開放原始碼存放區存取。存放區的 README 也會提供指引,說明應考慮哪些遷移作業,以及遷移模組的任何相關「順序」。

7. 其他資源

程式碼實驗室問題/意見回饋

如果您發現這個程式碼實驗室有任何問題,請先搜尋問題,再提出回報。搜尋及建立新問題的連結:

遷移資源

下表提供單元 15 (START) 和單元 16 (FINISH) 的存放區資料夾連結。您也可以從所有 App Engine 程式碼實驗室遷移作業的存放區存取這些檔案,並複製或下載 ZIP 檔案。

Codelab

Python 2

Python 3

單元 15

code

不適用

模組 16 (本程式碼研究室)

code

(與 Python 2 相同)

線上資源

以下是與本教學課程相關的線上資源:

App Engine Blobstore 和 Cloud Storage

App Engine 平台

其他雲端資訊

Python

影片

授權

這項內容採用的授權為創用 CC 姓名標示 2.0 通用授權。