1. 總覽
本系列程式碼研究室 (自助教學和實作教學課程) 旨在引導 Google App Engine (標準環境) 開發人員透過一系列遷移作業,協助他們翻新自家應用程式。最重要的步驟就是捨棄原始執行階段套裝組合服務,因為新一代執行階段更有彈性,為使用者提供更多種服務選項。轉換至新一代的執行階段可讓您更輕鬆地整合 Google Cloud 產品、使用更多元的支援服務,以及支援目前的語言版本。
這個選用教學課程可讓開發人員瞭解如何從 Cloud NDB 遷移至 Cloud Datastore 做為用戶端程式庫,以便與 Datastore 服務通訊。偏好 NDB 的開發人員可以繼續使用,因為這個與 Python 3 相容,所以這就是選擇遷移的必要性。只有當使用者想與已使用 Cloud Datastore 的其他應用程式建立一致的程式碼集和共用程式庫時,才需要進行這項遷移作業。詳細資訊請參閱「背景」專區。
你將瞭解如何
- 使用 Cloud NDB (如果您不熟悉)
- 從 Cloud NDB 遷移至 Cloud Datastore
- 將應用程式進一步遷移至 Python 3
軟硬體需求
- 具備有效 GCP 帳單帳戶的 Google Cloud Platform 專案
- 基本 Python 技能
- 具備基本 Linux 指令的知識
- 開發及部署 App Engine 應用程式的基本知識
- 可正常運作的模組 2 App Engine 2.x 或 3.x 應用程式。
問卷調查
您會如何使用本程式碼研究室?
2. 背景
雖然 Cloud NDB 是對長期 App Engine 開發人員而言的絕佳 Datastore 解決方案,而且可協助轉移至 Python 3,但不是 App Engine 開發人員存取 Datastore 的唯一方式。當 App Engine 的 Datastore 在 2013 年成為獨立產品時,Google Cloud Datastore 已建立新的用戶端程式庫,以便所有使用者都能使用 Datastore。
Python 3 App Engine 和非 App Engine 開發人員必須使用 Cloud Datastore (而非 Cloud NDB)。我們建議 Python 2 App Engine 開發人員從 ndb
遷移至 Cloud NDB,並將通訊埠遷移至 Python 3,但也可以選擇進一步遷移至 Cloud Datastore。這是一項邏輯決定,對於已使用 Cloud Datastore 編寫程式碼的開發人員 (例如剛才提到的程式碼),並想為所有應用程式建立共用程式庫的開發人員,更是如此。程式碼重複使用是程式碼一致性的最佳做法,這也能降低整體維護成本,摘要說明如下:
從 Cloud NDB 遷移至 Cloud Datastore
- 讓開發人員專注於單一程式碼集,以便存取 Datastore
- 避免使用 Cloud NDB 維護部分程式碼,或避免使用 Cloud Datastore 維護部分程式碼
- 提升程式碼集的一致性,並提升程式碼重複性
- 可使用通用/共用程式庫,進而降低整體維護成本
這項遷移包含下列主要步驟:
- 設定/事前作業
- 將 Cloud NDB 替換為 Cloud Datastore 用戶端程式庫
- 更新應用程式
3. 設定/事前作業
在開始教學課程的主要部分之前,我們先設定專案、取得程式碼,然後部署基準應用程式,以便瞭解要開始使用有效的程式碼。
1. 設定專案
如果您已完成單元 2 程式碼研究室,建議您重複使用相同的專案和程式碼。或者,您可以建立新的專案,或是重複使用其他現有專案。請確認專案具備有效的帳單帳戶,且 App Engine (應用程式) 已啟用。
2. 取得基準範例應用程式
其中一項必要條件是,擁有能正常運作的模組 2 範例應用程式。完成該教學課程後,請採用您的解決方案。你可以立即完成這項程序 (如上方連結)。如果想略過這個步驟,請複製模組 2 存放區 (連結如下)。
無論您使用自有還是我們的模組,我們都會開始使用單元 2 程式碼。本單元單元 3 會逐步引導您完成每個步驟,完成後,應該會與 FINISH 點的程式碼類似。本教學課程有 Python 2 和 3 版本,請在下方擷取正確的程式碼存放區。
Python 2
Python 2 單元 2 START 的目錄 (您或我們的檔案) 應如下所示:
$ ls
README.md appengine_config.py requirements.txt
app.yaml main.py templates
如果您完成單元 2 教學課程,也會有含有 Flask 及其依附元件的 lib
資料夾。如果您沒有 lib
資料夾,請使用 pip install -t lib -r requirements.txt
指令建立資料夾,以便我們在下一個步驟中部署這個基準應用程式。如果您同時安裝 Python 2 和 3,建議您使用 pip2
而非 pip
,以免和 Python 3 產生混淆。
Python 3
Python 3 單元 2 啟動檔案 (您自己或我們的) 的目錄應如下所示:
$ ls
README.md main.py templates
app.yaml requirements.txt
Python 3 不會使用 lib
和 appengine_config.py
。
3. (重新) 部署模組 2 應用程式
您目前需執行的準備作業步驟:
- 請先熟悉
gcloud
指令列工具 (如果沒有的話), - (重新) 將模組 1 程式碼部署至 App Engine (如果沒有)
一旦您成功執行上述步驟並確認程序運作正常後,我們就會繼續在本教學課程中,從設定檔開始。
4. 將 Cloud NDB 替換為 Cloud Datastore 用戶端程式庫
唯一的設定變更是 requirements.txt
檔案中的次要套件替換。
1. 更新「requirements.txt
」
完成單元 2 後,您的 requirements.txt
檔案會如下所示:
- 之前 (Python 2 和 3):
Flask==1.1.2
google-cloud-ndb==1.7.1
將 Cloud NDB 程式庫 (google-cloud-ndb
) 替換為最新版的 Cloud Datastore 程式庫 (google-cloud-datastore
),以更新 requirements.txt
,保留 Flask 的項目。請注意,與 Python 2 相容的 Cloud Datastore 最終版本為 1.15.3:
- 之後 (Python 2):
Flask==1.1.2
google-cloud-datastore==1.15.3
- 之後 (Python 3):
Flask==1.1.2
google-cloud-datastore==2.1.0
請注意,存放區的維護頻率相較於本教學課程較為定期,因此 requirements.txt
檔案可能會反映較新版本。建議您使用每個程式庫的最新版本,如果無法順利執行,則可復原至先前的版本。以上版本編號是本程式碼研究室上次更新時的最新版本。
2. 其他設定檔
其他設定檔 (app.yaml
和 appengine_config.py
) 應與上一個遷移步驟保持不變:
app.yaml
應 (仍然) 參照第三方套裝套件grpcio
和setuptools
。appengine_config.py
應 (仍在) 將pkg_resources
和google.appengine.ext.vendor
指向lib
中的第三方資源。
接著來看看應用程式檔案
5. 更新應用程式檔案
template/index.html
沒有任何異動,但有幾項 main.py
更新。
1. 匯入
「匯入」部分的起始程式碼應如下所示:
- 更新前:
from flask import Flask, render_template, request
from google.cloud import ndb
將 google.cloud.ndb
匯入替換為 Cloud Datastore 的匯入項目:google.cloud.datastore
。由於 Datastore 用戶端程式庫不支援在實體中自動建立時間戳記欄位,因此請一併匯入標準程式庫 datetime
模組,以手動建立。按照慣例,標準程式庫匯入作業會高於第三方套件匯入作業。完成變更後,畫面會如下所示:
- 更新後:
from datetime import datetime
from flask import Flask, render_template, request
from google.cloud import datastore
2. 初始化和資料模型
初始化 Flask 後,模組 2 範例應用程式會建立 NDB 資料模型類別及其欄位,如下所示:
- 更新前:
app = Flask(__name__)
ds_client = ndb.Client()
class Visit(ndb.Model):
visitor = ndb.StringProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
Cloud Datastore 程式庫沒有這類類別,因此請刪除 Visit
類別宣告。您仍然需要用戶端才能與 Datastore,因此請將 ndb.Client()
變更為 datastore.Client()
。Datastore 程式庫更具彈性可讓您在不「預先宣告」的情況下建立實體建構應用程式更新之後,這部分 main.py
應如下所示:
- 更新後:
app = Flask(__name__)
ds_client = datastore.Client()
3. 資料儲存庫存取權
遷移至 Cloud Datastore 時,您必須變更建立、儲存及查詢 Datastore 實體的方式 (使用者層級)。對於您的應用程式而言,這項遷移作業的難度取決於 Datastore 程式碼的複雜程度。在範例應用程式中,我們嘗試盡可能簡化更新程序。以下是我們的起始程式碼:
- 更新前:
def store_visit(remote_addr, user_agent):
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
def fetch_visits(limit):
with ds_client.context():
return (v.to_dict() for v in Visit.query().order(
-Visit.timestamp).fetch_page(limit)[0])
使用 Cloud Datastore 建立一般實體,使用「金鑰」識別實體中的分組物件。使用鍵/值組合的 JSON 物件 (Python dict
) 建立資料記錄,然後使用預期的 put()
寫入 Datastore。使用 Datastore 進行查詢也相似,但簡單明瞭。以下說明相等的 Datastore 程式碼有何不同:
- 更新後:
def store_visit(remote_addr, user_agent):
entity = datastore.Entity(key=ds_client.key('Visit'))
entity.update({
'timestamp': datetime.now(),
'visitor': '{}: {}'.format(remote_addr, user_agent),
})
ds_client.put(entity)
def fetch_visits(limit):
query = ds_client.query(kind='Visit')
query.order = ['-timestamp']
return query.fetch(limit=limit)
按照上述方式更新 store_visit()
和 fetch_visits()
的函式主體,保持其簽章與先前版本相同。主要處理常式 root()
沒有任何變更。完成這些變更之後,您的應用程式現在已經適合使用 Cloud Datastore 了,因此隨時可供測試。
6. 摘要/清除
部署應用程式
使用 gcloud app deploy
重新部署應用程式,並確認應用程式可以正常運作。您的程式碼現在應與單元 3 存放區資料夾中的內容相符:
如果您進入本系列課程,但未執行先前的任何程式碼研究室,應用程式本身並不會改變。它會記錄主網頁 (/
) 的所有造訪,而且在您造訪此網站足夠的時間後看起來像下面這樣:
恭喜您完成單元 3 程式碼研究室。您已經知道可以同時使用 Cloud NDB「和」Cloud Datastore 用戶端程式庫存取 Datastore。遷移至後者,您就可以享有以下好處:共用程式庫、通用程式碼和重複使用程式碼,以維持一致性,並降低維護成本。
選用:清除
在準備進入下一個遷移程式碼研究室之前,您該如何清除所用資源,以免產生費用?身為現有開發人員,您可能已經能快速瞭解 App Engine 的定價資訊。
選用:停用應用程式
如果尚未準備好進行下一個教學課程,請停用應用程式,以免產生費用。當您準備好前往下一個程式碼研究室時,即可重新啟用。停用的應用程式不會獲得任何流量,不過如果用量超過免費配額,我們就會向您收取 Datastore 用量的費用,因此刪除費用就會低於配額上限。
另一方面,如果不想繼續進行遷移作業,想要完全刪除所有項目,請關閉專案。
後續步驟
您可以在此探索下列下一個遷移單元:
- 單元 3 額外說明:請繼續閱讀獎勵一節,瞭解如何移植到 Python 3 和新一代的 App Engine 執行階段。
- 單元 7:App Engine 推送工作佇列 (如果您使用 [push] 工作佇列,則為必要項目)
- 將 App Engine
taskqueue
推送工作新增至模組 1 應用程式 - 協助使用者做好準備,以便遷移至 Cloud Tasks。
- 將 App Engine
- 模組 4:透過 Docker 遷移至 Cloud Run
- 將應用程式容器化,讓應用程式透過 Docker 在 Cloud Run 中執行
- 允許您繼續使用 Python 2
- 單元 5:遷移至 Cloud Run 與 Cloud Buildpacks
- 將應用程式容器化,讓應用程式透過 Cloud Buildpacks 在 Cloud Run 中執行
- 不必瞭解 Docker、容器或
Dockerfile
的任何相關資訊 - 您需要將應用程式遷移至 Python 3
- 模組 6:遷移至 Cloud Firestore
- 遷移至 Cloud Firestore 即可使用 Firebase 功能
- Cloud Firestore 支援 Python 2,但本程式碼研究室僅適用於 Python 3。
7. BONUS:遷移至 Python 3
如要存取最新的 App Engine 執行階段和功能,建議您遷移至 Python 3。在範例應用程式中,Datastore 是我們唯一使用的內建服務,而由於已經從 ndb
遷移至 Cloud NDB,現在可以攜碼至 App Engine 的 Python 3 執行階段。
總覽
雖然移植到 Python 3 不在 Google Cloud 教學課程的討論範圍內,但這部分程式碼研究室可讓開發人員瞭解 Python 3 App Engine 執行階段的差異。新一代執行階段的其中一項實用功能是簡化第三方套件的存取方式:您不需要在 app.yaml
中指定內建套件,也不必複製或上傳非內建程式庫。系統會從 requirements.txt
中直接安裝這些程式碼。
由於我們的範例非常基本,「而且」Cloud Datastore 與 Python 2 至 3 相容,因此您不需要明確將應用程式程式碼移植至 3.x:應用程式在 2.x 和 3.x 上執行,這表示本範例只對設定進行必要的變更:
- 簡化
app.yaml
來參照 Python 3,並移除隨附第三方程式庫的參照。 - 刪除
appengine_config.py
和lib
資料夾,不再需要操作。
main.py
和 templates/index.html
應用程式檔案維持不變。
更新「requirements.txt
」
支援 Python 2 的 Cloud Datastore 最終版本為 1.15.3。使用 Python 3 的最新版本更新 requirements.txt
(目前可能較新)。編寫本教學課程時,最新版本為 2.1.0,因此請將該行修改如下 (或任何最新版本):
google-cloud-datastore==2.1.0
簡化app.yaml
更新前:
此範例應用程式唯一的變更是大幅縮短 app.yaml
。以下是我們在 app.yaml
單元 3 總結的內容:
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
指令均已淘汰;所有應用程式都會假設為執行緒安全,且 Python 3 中未使用 api_version
。App Engine 服務中不再預先安裝第三方套件,因此 libraries
也已淘汰。如要進一步瞭解這些異動,請參閱 app.yaml
異動的說明文件。因此,您應從 app.yaml
中全部刪除三個項目,並更新為支援的 Python 3 版本 (請見下方說明)。
選用:使用 handlers
指令
此外,引導 App Engine 應用程式流量的 handlers
指令也已淘汰。由於新一代執行階段預期網路架構會管理應用程式轉送作業,因此所有「處理常式指令碼」必須改為「auto
」。結合上述的變更,到達這個 app.yaml
:
runtime: python38
handlers:
- url: /.*
script: auto
如要進一步瞭解script: auto
,請前往 app.yaml
參考資料頁面。
正在移除 handlers
指令
由於 handlers
已淘汰,您也可以移除整個區段,保留單行 app.yaml
:
runtime: python38
根據預設,這會啟動所有應用程式皆可使用的 Gunicorn WSGI 網路伺服器。如果您熟悉 gunicorn
,以下是系統透過該區域 app.yaml
預設啟動時執行的指令:
gunicorn main:app --workers 2 -c /config/gunicorn.py
選用:使用 entrypoint
指令
但是,如果應用程式需要特定的啟動指令,可以使用 entrypoint
指令指定,從而產生 app.yaml
,如下所示:
runtime: python38
entrypoint: python main.py
這個範例特別要求使用 Flask 開發伺服器,而不是 gunicorn
。您也必須將啟動開發伺服器的程式碼新增到應用程式中,才能透過 main.py
的底部加入以下小部分,以透過通訊埠 8080 啟動 0.0.0.0
介面:
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080, debug=True)
如要進一步瞭解entrypoint
,請前往 app.yaml
參考資料頁面。如需更多範例和最佳做法,請參閱 App Engine 標準環境啟動說明文件以及 App Engine 彈性環境啟動文件。
刪除「appengine_config.py
」和「lib
」
刪除 appengine_config.py
檔案和 lib
資料夾。在遷移至 Python 3 時,App Engine 會取得並安裝 requirements.txt
中列出的套件。
無論您是自行複製的第三方程式庫/套件,還是使用內建於 App Engine 伺服器 (內建) 中的程式庫/套件,appengine_config.py
設定檔都可用於辨識這類資訊。移至 Python 3 時,重大變更摘要如下:
- 沒有包含複製的第三方程式庫 (列於
requirements.txt
) - 沒有
pip install
放入lib
資料夾,意味著沒有任何lib
資料夾效期 app.yaml
中沒有列出內建第三方程式庫- 不需將應用程式參照至第三方程式庫,因此不需要
appengine_config.py
檔案
您只需要在 requirements.txt
中列出所有必要的第三方程式庫。
部署應用程式
重新部署應用程式,確保應用程式可正常運作。您也可以確認解決方案與單元 3 範例 Python 3 程式碼的距離。為了視覺化呈現與 Python 2 之間的差異,請比較此程式碼與Python 2 版本。
恭喜您完成單元 3 的額外步驟!參閱準備 Python 3 執行階段設定檔的說明文件。最後,請查看上方的摘要,瞭解後續步驟和清除所用資源。
準備應用程式
當您遷移「您的」應用程式時,必須將 main.py
和其他應用程式檔案移植為 3.x,因此最佳做法是將 2.x 應用程式改為「具有前瞻相容性」。。
為協助您達成這個目標,我們提供了許多線上資源,以下列出幾項重要訣竅:
- 確保所有應用程式依附元件完全相容
- 確認您的應用程式至少在 2.6 版上執行 (建議使用 2.7)
- 確保應用程式通過整個測試套件 (且涵蓋率至少有 80%)
- 使用相容性程式庫,例如
six
、Future 和/或翻新 - 請說明無法回溯相容的 2.x 版和 3.x 版主要差異
- 任何 I/O 都可能造成 Unicode 與位元組字串不相容
範例應用程式在設計上符合上述所有需求,因此可以直接在 2.x 和 3.x 平台執行這個應用程式,方便我們專心說明使用新一代平台時需要做出哪些變更。
8. 其他資源
App Engine 遷移模組程式碼研究室問題/意見回饋
如果您在本程式碼研究室中發現任何問題,請先搜尋您的問題再提出申請。搜尋及建立新問題的連結:
遷移資源
下表提供單元 2 (START) 和單元 3 (FINISH) 的存放區資料夾連結。您也可以透過所有 App Engine 遷移作業的存放區存取這些檔案,複製或下載 ZIP 檔案。
Codelab | Python 2 | Python 3 |
Module 3 |
App Engine 資源
以下是這項特定遷移作業的其他資源:
- Python Cloud NDB 和 Cloud Datastore 參考資料
- 遷移至 Python 3 和 GAE 新一代執行階段
- 一般