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

1. 總覽

無伺服器遷移站系列的程式碼研究室系列 (自助式實作教學課程) 和相關影片,旨在引導 Google Cloud 無伺服器開發人員透過一或多種遷移作業 (主要用於遷移舊版服務) 逐步翻新應用程式。這麼一來,您的應用程式就能更具可攜性,並提供更多選擇和使用彈性,進而整合及使用更多 Cloud 產品,也更容易升級至較新的語言版本。本系列課程一開始將著重在最早的 Cloud 使用者 (主要是 App Engine (標準環境) 開發人員),但涵蓋其他無伺服器平台,包括 Cloud FunctionsCloud Run 或其他無伺服器平台 (如適用)。

本程式碼研究室將說明如何從 App Engine Blob 遷移至 Cloud Storage。以下來源也有隱含的遷移作業:

如需逐步說明,請參閱任何相關的遷移模組。

在接下來的研究室中

  • 新增 App Engine Blob API/程式庫的用法
  • 將使用者上傳至 Blob 服務儲存起來
  • 為遷移至 Cloud Storage 的後續步驟做好準備

軟硬體需求

問卷調查

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

僅供閱讀 閱讀並完成練習

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

新手 中級 還算容易

針對使用 Google Cloud 服務的經驗,您會給予什麼評價?

新手 中級 還算容易

2. 背景

本程式碼研究室會從單元 15 的範例應用程式開始,示範如何從 Blob (和 NDB) 遷移至 Cloud Storage (和 Cloud NDB)。遷移程序需要替換 App Engine 舊版套裝組合服務的依附元件,這樣您就能視需要將應用程式移至其他 Cloud 無伺服器平台或其他託管平台。

與本系列的其他遷移作業相比,這項遷移作業需要花更多精力。Blob 與原始的 Web 架構具有依附關係,因此範例應用程式採用 Web2 架構,而非 Flask。本教學課程提供遷移至 Cloud Storage、Cloud NDB、Flask 和 Python 3 等功能。

應用程式仍會登錄使用者「造訪」並顯示最近 10 項,但先前的 (單元 15) 程式碼研究室新增了功能來支援 Blob 使用:應用程式會提示使用者上傳與其「造訪」相對應的成果 (檔案)。使用者可以這麼做或選取「略過」。無論使用者的決定為何,下一頁會顯示與這個應用程式先前的載入內容相同的輸出內容,顯示最近的造訪記錄。另一個差別是,造訪具備對應構件的造訪次數會顯示為「檢視畫面」可顯示造訪構件的連結。本程式碼研究室會實作上述遷移作業,並保留上述功能。

3. 設定/事前作業

在開始教學課程的主要部分之前,我們先設定專案、取得程式碼,然後部署基準應用程式,以便瞭解要開始使用有效的程式碼。

1. 設定專案

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

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

本程式碼研究室的必要條件之一,是擁有正常運作的模組 15 範例應用程式。如果沒有,可從單元 15「開始」取得資料夾 (連結如下)。本程式碼研究室將引導您完成每個步驟,最後程式碼會與單元 16「FINISH」單元中顯示的程式碼類似資料夾。

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

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

main-gcs.py 檔案是模組 15 中的 main.py 替代版本,可根據專案 ID 從應用程式指派的網址,選用不同的 Cloud Storage 值區:PROJECT_ID.appspot.com。在本 (單元 16) 程式碼研究室中,除了類似遷移技術,這個檔案無法套用至該檔案。

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

您目前需執行的準備作業步驟:

  1. 請重新熟悉 gcloud 指令列工具。
  2. 使用 gcloud app deploy 重新部署範例應用程式
  3. 確認應用程式在 App Engine 上執行,沒有問題

成功執行上述步驟後,確認模組 15 應用程式可正常運作。初始頁面以表單提示使用者要上傳的造訪構件檔案,並提供「略過」選項按鈕,如要停用,請按照下列步驟操作:

f5b5f9f19d8ae978.png

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

f5ac6b98ee8a34cb.png

有構件的造訪會顯示「檢視畫面」造訪時間戳記右方的連結,即可顯示 (或下載) 構件。確認應用程式的功能後,您就能從 App Engine 舊版服務 (Web2、NDB、Blob) 遷移至現代化的替代方案 (Flask、Cloud NDB、Cloud Storage)。

4. 更新設定檔

應用程式的更新版本使用了三個設定檔,所需工作如下:

  1. 更新 app.yaml 中必要的內建第三方程式庫,並保持執行 Python 3 遷移作業
  2. 新增 requirements.txt,指定所有未內建的必要程式庫
  3. 新增 appengine_config.py,讓應用程式支援內建和非內建的第三方程式庫

app.yaml

更新 libraries 部分,即可編輯 app.yaml 檔案。移除 jinja2 並新增 grpciosetuptoolsssl。請針對三個程式庫選擇可用的最新版本,接著新增 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 內建程式庫,因此您不必自行組合。我們移除了 Jinja2,因為該 Jinja2 隨附 Flask,稍後會新增至 reqs.txt。每當使用 Google Cloud 用戶端程式庫 (例如 Cloud NDB 和 Cloud Storage 的用戶端程式庫) 時,都必須使用 grpcio 和設定工具。最後,Cloud Storage 本身需要 SSL 程式庫。準備好將應用程式移植至 Python 3 時,可以使用頂端的註解排除執行階段指令。本教學課程結尾會說明這個主題。

requirements.txt

新增需要 Flask 架構的 requirements.txt 檔案,以及 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 Blob 和 NDB 已由 Cloud NDB 和 Cloud Storage 取代
  4. webapp 中的 Blob 處理常式會由 io 標準程式庫模組、Flask 和 werkzeug 公用程式的組合取代
  5. 根據預設,Blob 會以應用程式網址 (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 支援

下一個要取代的程式碼區塊是 BaseHandler,指定從 webapp2_extras 使用 Jinja2。這是不必要的,因為 Jinja2 是 Flask 的預設範本引擎,因此請將其移除。

在模組 16 端,將舊版應用程式中沒有的物件執行個體化。這包括初始化 Flask 應用程式,以及為 Cloud NDB 和 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 NDB 與 App Engine NDB 最為相容。已說明的其中一項差異是必須使用 API 用戶端。另一種方式是,資料儲存庫存取權需要由 API 用戶端的 Python 結構定義管理員控管。基本上,這表示所有使用 Cloud NDB 用戶端程式庫的 Datastore 存取呼叫都只能在 Python with 區塊中執行。

就是一次變更另一種則是 blob 及其物件,例如Cloud Storage 不支援 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)

變更後:

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 動詞方法,而是使用動詞來修飾函式。blob 及其 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 (使用者選擇不上傳檔案) 來辨識。
  • Blob 處理常式將上傳程序從使用者卸除,但 Cloud Storage 不會,因此您可以看到新增的程式碼來設定檔案的 blob 物件和位置 (值區),以及執行實際上傳作業的呼叫。(upload_from_file())。
  • webapp2 會使用應用程式檔案底部的路徑表,而每個裝飾的處理常式都會找到 Flask 路徑。
  • 這兩個處理常式都會重新導向至首頁 ( /),將功能包裝完成,同時保留使用 HTTP 307 傳回代碼的 POST 要求。

下載處理常式

更新下載處理常式的模式與上傳處理常式類似,只需查看的程式碼少很多。將 Blob 和 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>')。
  • 與上傳處理常式一樣,為了使用 Blob 處理常式抽取的功能,在 Cloud Storage 端需要進行一些額外工作,也就是識別有問題的檔案 (blob),並明確下載二進位檔與 blob 處理常式的單一 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)

這些方法基本上是 root() 中的 if-else 陳述式,並未分開 get()post() 方法。此外,由於 root() 是單一函式,只會呼叫一次算繪 GETPOST 的範本,但 webapp2 實際上無法執行。

以下是 main.py 第二組與最後一組變更的圖片示意圖:

5ec38818c32fec2.png

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

因此,上述建立的解決方案可以完美運作...但僅適用於您從頭開始建立,且沒有 Blob 建立檔案的情況。由於我們更新了應用程式,以檔案名稱 (而非 BlobKey) 來識別檔案,因此完成的模組 16 應用程式將無法查看 Blob 檔案。換句話說,我們做出了回溯不相容的變更,導致這項遷移作業執行時無法回溯相容。我們現在提供名為 main-migrate.pymain.py 替代版本 (可在存放區中找到),嘗試填補此缺口。

第一個「額外資訊」是一種資料模型,除了 StringProperty Cloud Storage 建立的檔案之外,還有一個包含 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 屬性將用來識別 Blob 建立的檔案,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()

變更後:

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_blobfile_gcs (或兩者皆無)。如果有可用的檔案,請選取存在的檔案,並使用該識別碼 (BlobKey適用於 Blob 建立的檔案或 Cloud Storage 建立檔案的檔案名稱)。說到「Cloud Storage 建立的檔案」我們是指使用 Cloud Storage 用戶端程式庫建立的檔案Blob 也會寫入 Cloud Storage,但在這個範例中,就是 Blob 建立的檔案。

更重要的是,這個 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_gcsfile_blob,如果有,請選擇其中一個 (如果沒有的話,請選擇 None)。

下圖說明 main.pymain-migrate.py 的差異:

718b05b2adb2e1.png

如果您要從頭開始,而沒有建立 Blob 建立的檔案,請使用 main.py。不過,如果您要轉換並想支援 Blob「和」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

恭喜您完成本程式碼研究室,以 Cloud Storage 取代 App Engine Blob、將 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 服務,我們會另外計費。無論採用哪種情況,請參閱「本程式碼研究室的專屬」以下章節。

如要完整揭露,部署至 Google Cloud 無伺服器運算平台 (如 App Engine) 會產生少許建構和儲存空間費用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 單元,您仍會在 blob 中保留資料,因此在上方說明相關定價資訊的原因。

後續步驟

除了本教學課程之外,其他著重於淘汰舊版套裝組合服務的其他遷移模組,建議提供以下建議:

  • 模組 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 的情況下執行應用程式

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

無論接下來選擇使用哪個遷移模組,所有無伺服器遷移站內容 (程式碼研究室、影片、原始碼 [如有]) 都可以透過其開放原始碼存放區存取。存放區的 README 還針對應考慮遷移的項目和任何相關的「訂單」提供指引接下來介紹遷移模組

7. 其他資源

程式碼研究室問題/意見回饋

如果您在本程式碼研究室中發現任何問題,請先搜尋您的問題再提出申請。搜尋及建立新問題的連結:

遷移資源

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

Codelab

Python 2

Python 3

單元 15

程式碼

不適用

單元 16 (本程式碼研究室)

程式碼

(與 Python 2 相同)

線上資源

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

App Engine Blob 與 Cloud Storage

App Engine 平台

其他 Cloud 資訊

Python

影片

授權

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