1. 總覽
本系列的程式碼研究室 (自助教學和實作教學課程) 旨在引導 Google App Engine (Standard) 開發人員透過一系列遷移作業,協助他們翻新自家應用程式。最重要的步驟就是捨棄原始執行階段套裝組合服務,因為新一代執行階段更有彈性,為使用者提供更多種服務選項。轉換至新一代的執行階段可讓您更輕鬆地整合 Google Cloud 產品、使用更多元的支援服務,以及支援目前的語言版本。
本教學課程說明如何從 App Engine 的內建 ndb
(下一個資料庫) 用戶端程式庫遷移至 Cloud NDB 用戶端程式庫。
你將瞭解如何
- 使用 App Engine
ndb
程式庫 (如果您不熟悉) - 從
ndb
遷移至 Cloud NDB - 將應用程式進一步遷移至 Python 3
軟硬體需求
- 含有以下項目的 Google Cloud Platform 專案:
- 基本 Python 技能
- 熟悉常見的 Linux 指令
- 對開發和部署 App Engine 應用程式有基本瞭解
- 可正常運作的 模組 1 App Engine 應用程式
問卷調查
您會如何使用本程式碼研究室?
2. 背景
在單元 1 中,我們將網路架構從 App Engine 內建的 webapp2
遷移至 Flask。在本程式碼研究室中,我們會繼續從 App Engine 的 ndb
程式庫切換至 Google Cloud NDB,藉此停用 App Engine 的內建服務。
完成這項遷移程序後,您可以:
- 遷移至 Python 3 及新一代 App Engine 執行階段
- 遷移至 Cloud Datastore (非 App Engine 應用程式的用戶端程式庫)
- 將 Python 2 (或 3) 應用程式容器化,然後遷移至 Cloud Run
- 新增使用 App Engine (推送) 工作佇列,然後遷移至 Cloud Tasks
我們目前尚未支援這項功能。請先完成本程式碼研究室,再考慮後續步驟。本教學課程的遷移包含以下主要步驟:
- 設定/事前作業
- 新增 Cloud NDB 程式庫
- 更新應用程式檔案
3. 設定/事前作業
在開始教學課程的主要部分之前,我們先設定專案、取得程式碼,然後部署基準應用程式,以便瞭解要開始使用有效的程式碼。
1. 設定專案
如果您已完成單元 1 程式碼研究室,建議您重複使用相同的專案和程式碼。或者,您可以建立新的專案,或是重複使用其他現有專案。請確認專案具備有效的帳單帳戶,且 App Engine 已啟用。
2. 取得基準範例應用程式
其中一項必要條件是,擁有能正常運作的模組 1 範例應用程式。完成該教學課程後,請採用您的解決方案。你可以立即完成這項程序 (如上方連結)。如果想略過這個步驟,請複製模組 1 存放區 (連結如下)。
無論您使用自有還是我們的模組,我們都會開始使用單元 1 程式碼。本單元的單元 2 會逐步引導您完成每個步驟,完成後應該會與 FINISH 點的程式碼類似 (包括從 Python 2 到 3 的選用「獎勵」通訊埠):
- START:模組 1 程式碼
- 結束:模組 2 Python 2 程式碼 (BONUS:Python 3 程式碼)
- 整個存放區 (複製或下載 ZIP 檔案)
您的 START 模組 1 程式碼資料夾應有下列內容:
$ ls
README.md appengine_config.py requirements.txt
app.yaml main.py templates
如果您完成單元 1 教學課程,也會有含有 Flask 及其依附元件的 lib
資料夾。如果您沒有 lib
資料夾,請使用 pip install -t lib -r requirements.txt
指令建立資料夾,以便我們在下一個步驟中部署這個基準應用程式。如果您同時安裝 Python 2 和 3,建議您使用 pip2
而非 pip
,以免和 Python 3 產生混淆。
3. (重新) 部署模組 1 應用程式
您目前需執行的準備作業步驟:
- 請先熟悉
gcloud
指令列工具 (如果沒有的話), - (重新) 將模組 1 程式碼部署至 App Engine (如果沒有)
一旦您成功執行上述步驟並確認程序運作正常後,我們就會繼續在本教學課程中,從設定檔開始。
4. 更新設定檔 (新增 Cloud NDB 程式庫)
許多原先的 App Engine 內建服務都依賴各自的產品,而 Datastore 就是其中之一。目前非 App Engine 應用程式都可以使用 Cloud Datastore。針對長期使用 ndb
的使用者,Google Cloud 團隊建立了 Cloud NDB 用戶端程式庫,以便與 Cloud Datastore 通訊。適用於 Python 2 和 Python 3。
讓我們更新確認檔案,將 App Engine ndb
取代為 Cloud NDB,然後修改應用程式。
1. 更新「requirements.txt
」
在單元 1 中,應用程式唯一的外部依附元件是 Flask。現在,我們將新增 Cloud NDB您的 requirements.txt
檔案在單元 1 結束時會如下所示:
- 更新前:
Flask==1.1.2
如要從 App Engine ndb
遷移,必須使用 Cloud NDB 程式庫 (google-cloud-ndb
),因此請將套件新增至 requirements.txt
。
- 更新後:
Flask==1.1.2
google-cloud-ndb==1.7.1
編寫本程式碼研究室時,建議的最新版本為 1.7.1,但存放區中的 requirements.txt
可能有較新版本。建議您每個程式庫的最新版本,如果無法順利執行,則可復原至先前的版本。
請刪除 lib
資料夾 (如有),但不在上方建立資料夾。現在,請使用 pip install -t lib -r requirements.txt
指令來安裝更新過的程式庫,並視需要使用 pip2
而不是 pip
。
2. 更新「app.yaml
」
新增 google-cloud-ndb
等 Google Cloud 用戶端程式庫有幾個要求,其設計都是以納入「內建」選項為主軸資料庫、Google 伺服器中已有的第三方套件。這些位置不在 requirements.txt
中,也不會使用 pip install
複製。唯一的必要條件:
- 指定
app.yaml
中的內建程式庫 - 指向使用者可能使用已複製的第三方程式庫 (位於
lib
)
以下從單元 1 開始的 app.yaml
:
- 更新前:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
現在請在 app.yaml
中加入以下幾行程式碼,以參照新的 libraries
區段中的一組第三方套裝套件:grpcio
和 setuptools
:
libraries:
- name: grpcio
version: 1.0.0
- name: setuptools
version: 36.6.0
為什麼要使用這些內建程式庫?gRPC 是所有 Google Cloud 用戶端程式庫 (包括 google-cloud-ndb
) 使用的開放式 RPC 架構。grpcio
程式庫是 Python gRPC 轉接器,因此需要。加入「setuptools
」的理由即將開始。
- 更新後:
完成上述變更後,更新後的 app.yaml
應如下所示:
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
3. 更新「appengine_config.py
」
pkg_resources
工具是 setuptools
程式庫的一部分,用於允許「內建」的第三方程式庫存取隨附程式庫。更新 appengine_config.py
以使用 pkg_resources
,將其指向 lib
中的套裝程式庫。完成這項變更後,整個檔案看起來會像這樣:
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)
5. 更新應用程式檔案
設定檔正式終止後,您現在可以從 ndb
遷移至 Cloud NDB。如要完成遷移,請更新匯入的程式庫,並在 main.py
中新增結構定義管理功能。
1. 匯入
在 main.py
中進行下列匯入替換:
- 更新前
from google.appengine.ext import ndb
- 更新後:
from google.cloud import ndb
從 App Engine 程式庫到 Google Cloud 程式庫的變更,有時可能會與這個執行個體類似。對於成為完整 Google Cloud 產品的內建服務,您將匯入 google.cloud
中的屬性,而非 google.appengine
。
2. 資料儲存庫存取權
如要使用 Cloud NDB 程式庫,您的應用程式必須使用 Python 結構定義管理員。目的是「阻止」而且必須先取得資源才能使用。結構定義管理員是以名為資源分配為初始化 (或 RAII) 的電腦科學控制技術為基礎。內容管理員可與 Python 檔案 (必須先開啟) 存取) 和並行作業 (即「旋轉鎖定」)必須先取得,才能在「重要部分」中取得程式碼可以執行
同樣地,您必須先取得用戶端的內容,才能在使用 Datastore 指令執行任何 Datastore 指令前,先取得用戶端的內容,以便與 Datastore 通訊。首先,在 Flask 初始化後立即在 main.py
中新增 ds_client = ndb.Client()
來建立用戶端 (ndb.Client()
):
app = Flask(__name__)
ds_client = ndb.Client()
Python with
指令只能用來取得物件的背景資訊。使用 with
陳述式納入存取 Datastore 的所有程式碼區塊。
以下是單元 1 中的函式,用於將新實體寫入 Datastore,以及讀取最近新增的實體:
- 更新前:
以下是不含內容管理的原始程式碼:
def store_visit(remote_addr, user_agent):
'create new Visit entity in Datastore'
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
def fetch_visits(limit):
'get most recent visits'
return (v.to_dict() for v in Visit.query().order(
-Visit.timestamp).fetch(limit))
- 更新後:
現在新增 with ds_client.context():
,並將 Datastore 存取程式碼移至 with
區塊:
def store_visit(remote_addr, user_agent):
'create new Visit entity in Datastore'
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
def fetch_visits(limit):
'get most recent visits'
with ds_client.context():
return (v.to_dict() for v in Visit.query().order(
-Visit.timestamp).fetch(limit))
主要驅動程式應用程式會與單元 1 中的程式碼相同,因為這裡沒有 ndb
(n 或 Cloud NDB) 程式碼:
@app.route('/')
def root():
'main application (GET) handler'
store_visit(request.remote_addr, request.user_agent)
visits = fetch_visits(10)
return render_template('index.html', visits=visits)
最佳做法是確實區分應用程式的程式碼與資料存取權。這樣一來,當基礎資料儲存機制有所改變時,主要應用程式的程式碼就不會改變。
6. 摘要/清除
部署應用程式
使用 gcloud app deploy
重新部署應用程式,並確認應用程式可以正常運作。您的程式碼現在應與模組 2 存放區中的內容相符。
如果您進入本系列課程,但未執行先前的任何程式碼研究室,應用程式本身並不會改變。它會記錄主網頁 (/
) 的所有造訪,而且在您造訪此網站足夠的時間後看起來像下面這樣:
恭喜您完成單元 2 程式碼研究室。您剛剛完成了這個系列的終點線,因為這是截至 Datastore 運作為止,這個系列中最後一次強烈建議的遷移作業。
選用:清除
在準備進入下一個遷移程式碼研究室之前,您該如何清除所用資源,以免產生費用?身為現有開發人員,您可能已經能快速瞭解 App Engine 的定價資訊。
選用:停用應用程式
如果尚未準備好進行下一個教學課程,請停用應用程式,以免產生費用。當您準備好前往下一個程式碼研究室時,即可重新啟用。停用的應用程式不會獲得任何流量,不過如果用量超過免費配額,我們就會向您收取 Datastore 用量的費用,因此刪除費用就會低於配額上限。
另一方面,如果不想繼續進行遷移作業,想要完全刪除所有項目,請關閉專案。
後續步驟
方便您進行下一步。選擇下列任一選項:
- 單元 2 額外步驟:請繼續參閱本教學課程的額外部分,瞭解如何移植到 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
- 單元 3:
- 翻新從 Cloud NDB 存取 Cloud Datastore 的 Datastore 存取權
- 這是 Python 3 的 App Engine 應用程式和非 App Engine 應用程式所使用的程式庫。
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 NDB 與 Python 2-3 相容,因此應用程式程式碼不需要明確移植至 3.x。應用程式在未經過修改的 2.x 和 3.x 版本上執行,代表本例中唯一所需變更:
- 簡化
app.yaml
來參照 Python 3 並移除第三方程式庫。 - 刪除
appengine_config.py
和lib
資料夾,不再需要操作。
除 main.py
外,requirements.txt
和 templates/index.html
檔案則維持不變。
簡化app.yaml
更新前:
此範例應用程式唯一的變更是大幅縮短 app.yaml
。以下是我們在 app.yaml
單元 2 總結的內容:
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
,請前往這個說明文件頁面。
正在移除 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 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
中列出所有必要的第三方程式庫。
部署應用程式
重新部署應用程式,確保應用程式可正常運作。您也可以確認解決方案與模組 2 範例 Python 3 程式碼有關聯。為了視覺化呈現與 Python 2 之間的差異,請比較此程式碼與Python 2 版本。
恭喜您完成單元 2 的額外步驟!參閱準備 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 遷移模組程式碼研究室問題/意見回饋
如果您在本程式碼研究室中發現任何問題,請先搜尋您的問題再提出申請。搜尋及建立新問題的連結:
遷移資源
下表提供單元 1 (START) 和單元 2 (FINISH) 的存放區資料夾連結。您也可以透過所有 App Engine 程式碼研究室遷移作業的存放區存取這些資料,可以複製或下載 ZIP 檔案。
Codelab | Python 2 | Python 3 |
(不適用) | ||
Module 2 |
App Engine 資源
以下是這項特定遷移作業的其他資源:
- Python NDB 參照
- (舊) 從 Python 2.5 和
webapp
遷移至 2.7,以及webapp2
- 遷移至 Python 3 和 GAE 新一代執行階段
- 一般