天天看點

GCP: AppEngine(GAE)的使用

一、基本概念

在全托管式的無伺服器平台上建構可擴縮性極強的應用, 将應用從零無縫擴容到全球級規模,而不用費心管理底層基礎架構。得益于零伺服器管理和零配置部署,開發者可以專注于建構出色的應用,省去管理開銷。App Engine 支援多種主流開發語言以及各種開發者工具,可幫助開發者提高工作效率和靈活性。

在其他雲上與之對标的産品有:

  • Azure上的App Service,猛戳這裡
  • AWS 上的AWS Elastic Beanstalk
  • 阿裡雲上的Web應用托管服務(Web+)

它有兩種環境,通常我們使用第一種

GCP: AppEngine(GAE)的使用

二、 快速上手(python3)

(一)、建立應用及app.yaml檔案

先上目錄,建立得是一個基于python3.8的一個Flask應用,它足夠簡單,以便我們隻關注感興趣的部分。

GCP: AppEngine(GAE)的使用

main.py 檔案:是應用程式的入口,代碼如下,使用者通路此網站時,會顯示方法show_hello傳回的内容

import os
from flask import Flask
from dotenv import load_dotenv, find_dotenv

app = Flask(__name__)


@app.route('/')
def show_hello():
    myname = os.getenv('myname')
    return myname


if __name__ == '__main__':
    load_dotenv()
    app.run(port=1234)           

requirements.txt檔案:是依賴包

python-dotenv
flask           

.env檔案:是配置環境變量的,也就是說當使用者通路此應用的時候,在本地運作會直接會顯示congcong這個名字。它是敏感檔案。

myname=congcong           

以上是Flask Web應用的基本的幾個檔案,下面我們來看一下gcloud需要的檔案

app.yaml檔案:最重要就是它了,它定義了目前應用在GCP上的運作時是python3.7,服務的名字是default,設定了一個環境變量myname,在我們在GCP上部署好此應用後,那網頁上就會顯示myname的值。

注意:App Engine上第一個服務的服務名必須是default,第二個至第N個的務的名字随便你自己定義,不然它會報錯”ERROR: (gcloud.app.deploy) INVALID_ARGUMENT: The first service (module) you upload to a new application must be the 'default' service (module). “,它會将我們的代碼上傳到GCP的某個地方。

runtime: python37
service: default

env_variables:
  myname: "Hello, this is from environment"           

.gcloudignore檔案:由于python3中的虛拟環境venv檔案裡面的内容較多,如果将它部署上去顯然有些費時費力,我們需要把一些不需要的檔案都排除掉,使用.gcloudignore

.gcloudignore
.git
.gitignore

# Python pycache:
__pycache__/
# Ignored by the build system
/setup.cfg

venv
.env           

(二)、部署應用到GCP

下載下傳并安裝Google SDK, 右擊以管理者身份運作,并配置好Service Account, 如果不會配置,猛戳如何建立并使用service account直接檢視裡面的第二節,之後你就可以運作如下指令進行部署了,關鍵的指令隻有一行

gcloud app deploy app.yaml           

隻需要上面的一行指令就可以把本地的代碼部署到雲端,這麼智能? 因為用到了DevOps,實際上就是上面提到的Google的一個pipeline 服務。下面是完整的指令行及提示:

# 運作以下指令,安裝包含 Python 3.7 版 App Engine 擴充程式的 gcloud 元件:
gcloud components install app-engine-python

# 定位到你項目的根目錄,即包含app.yaml的檔案夾下
cd C:\CongStudy\python-flask-nginx-demo

# 運作此指令部署你的應用程式,後面的app.yaml可以省略
c:\CongStudy\python-flask-nginx-demo>gcloud app deploy app.yaml
You are creating an app for project [qwiklabs-gcp-01-dbddd1fe79f0].
WARNING: Creating an App Engine application for a project is irreversible and the region
cannot be changed. More information about regions is at
<https://cloud.google.com/appengine/docs/locations>.

Please choose the region where you want your App Engine application
located:

 [1] asia-east2    (supports standard and flexible)
 [2] asia-northeast1 (supports standard and flexible)
 [3] asia-northeast2 (supports standard and flexible)
 [4] asia-northeast3 (supports standard and flexible)
 [5] asia-south1   (supports standard and flexible)
 ...
 [18] cancel
Please enter your numeric choice:  1

Creating App Engine application in project [qwiklabs-gcp-01-dbddd1fe79f0] and region [asia-east2]..
..done.
Services to deploy:

descriptor:      [c:\CongStudy\python-flask-nginx-demo\app.yaml]
source:          [c:\CongStudy\python-flask-nginx-demo]
target project:  [qwiklabs-gcp-01-dbddd1fe79f0]
target service:  [default]
target version:  [20200314t165844]
target url:      [https://qwiklabs-gcp-01-dbddd1fe79f0.appspot.com]


Do you want to continue (Y/n)?  y

Beginning deployment of service [default]...
╔════════════════════════════════════════════════════════════╗
╠═ Uploading 2 files to Google Cloud Storage                ═╣
╚════════════════════════════════════════════════════════════╝
File upload done.
Updating service [default]...done.
Setting traffic split for service [default]...done.
Deployed service [default] to [https://qwiklabs-gcp-01-dbddd1fe79f0.appspot.com]

You can stream logs from the command line by running:
  $ gcloud app logs tail -s default

To view your application in the web browser run:
  $ gcloud app browse

# 運作此指令,它會在浏覽器中打開此網站
c:\CongStudy\python-flask-nginx-demo>gcloud app browse
Opening [https://qwiklabs-gcp-01-dbddd1fe79f0.appspot.com] in a new tab in your default browser.           

(三)、效果

這是網頁

GCP: AppEngine(GAE)的使用

這是在GCP控制台看到的截圖

GCP: AppEngine(GAE)的使用

到這裡,你已經基本掌握了app engine的用法了。但仍然還有許多的問題需要解決:

  1. 它的執行個體預設是随着通路量自動擴縮的,是如何自動擴縮的呢,我可以控制嗎?
  2. 它自動擴縮時,肯定是以某一代碼源或者artifact為基礎,那我上傳的代碼放在哪裡呢?
  3. 如何綁定自定義域名及安全證書,當執行個體數自動擴充時,它是如何将證書自動安裝到新的執行個體上?
  4. 如果我有多個服務,卻隻有一個域名,如何通過一個域名通路到多個服務,即反向代理是咋整的?
  5. 多個服務中,服務與服務之間如何調用,它們在同一個區域網路内嗎? 互相通路時可以走内網嗎,走外網就慢了。
  6. 上圖中有一個version 1,可以看出每個服務都有版本控制的,不同版本之間我能對流量進行控制嗎?
  7. 灰階部署/藍綠部署/AB測試這些都支援麼?
  8. 對這些服務如何追蹤和監控,有日志麼,在哪裡看到我的服務的使用情況。

三、 設計應用

為了回答上面所有的問題,隻有一個服務顯然不夠。

以下示例展示了當您在本地開發應用時,一個含有三項服務的應用可能具有的結構。可選的 dispatch.yaml 已添加到該應用的根目錄中。在根目錄下還有三個目錄,分别對應于應用的每項服務。service1 的子目錄包含該服務的源檔案和配置檔案。同樣,service2 和 service3 均位于獨立的目錄中,這些目錄分别包含對應服務的檔案,而 service3 包含 YAML 配置檔案的兩個版本:

GCP: AppEngine(GAE)的使用

上面的service<num>.yaml,如service1.yaml,和我們之間定義的app.yaml是同類型檔案,它定義了運作時的環境等,專門用于部署的。但上圖中多出來了一個dispatch.yaml,從字面上就可以看出它是用于路由分發的,即所謂的反向代理。這裡我們先列出所有的配置檔案出來,共有4個:

(一)、app.yaml

這個我們已經見過了,不僅定義了運作時的環境,而且可以處理擴縮、緩存等,這裡我們列出一個稍複雜的例子。

runtime: python37 # 定義運作時

service: service_name # 定義你的服務名,注意第一個服務名隻能叫default

instance_class: F2 # 定義執行個體了類型,類型有F1、F2、F4、F4_1G

env_variables: #定義環境變量
  BUCKET_NAME: "example-gcs-bucket"

handlers: # 配置單個服務内的路由
# Matches requests to /images/... to files in static/images/...
- url: /images
  static_dir: static/images
  http_headers:   # 還可以設定http頭哦
    X-Foo-Header: foo
    X-Bar-Header: bar value
    Access-Control-Allow-Origin: http://mygame.appspot.com  # 來個CORS 跨域支援

- url: /.* # 重定向
  secure: always
  redirect_http_response_code: 301
  script: auto

error_handlers: # 對錯誤請求的處理
  - file: default_error.html

  - error_code: over_quota
    file: over_quota.html

# 自動擴縮的配置在這裡
automatic_scaling:
  target_cpu_utilization: 0.65           # CPU使用率達到 65% 後會啟動新執行個體
  min_instances: 5                       # 最小執行個體數是5            
  max_instances: 100                     # 最大執行個體數是100
  min_pending_latency: 30ms              # 最小冷卻時間,即允許請求在待處理隊列中等待的最短時間。當處理請求時達到某一門檻值後,不會立即擴縮,會等待30ms,例如:當服務過載時,一個請求在待處理隊列中等待,appengine不會立即新增執行個體,至少等待30ms才會擴充執行個體數, 30ms之前肯定不會擴充執行個體數
  max_pending_latency: 100ms             # 最大冷卻時間,App Engine 允許某請求在待處理隊列中等待的最長時間。App Engine 可以在“min-pending-latency”與“max-pending-latency”中指定的時間之間随時建立執行個體。也就是說,App Engine 不會在“min-pending-latency”中指定的時間之前建立執行個體來處理待處理請求,但 App Engine 會在達到“max-pending-latency”之後建立執行個體。
  max_concurrent_requests: 50            # 自動擴縮執行個體可接受的并發請求數
  max_idle_instances                     # App Engine 應為此版本保留的最大空閑執行個體數

# 手動擴縮
manual_scaling:
  instances: 5                           # 在開始時配置設定給服務的執行個體數
             

(二)、dispatch.yaml 

定義路由規則的配置檔案,顧名思義,它就是通過url中的path來查找相應的服務的。例如下面有三個服務分别是service1/service2/service3,你隻有一個域名是www.example.com,當你通路www.example.com/BBB的時候,執行個體調用得服務是service2

dispatch:
  - url: 'www.example.com/default/*'
    service: default
  - url: 'www.example.com/AAA*'
    service: service1
  - url: 'www.example.com/BBB*'
    service: service2
  - url: 'www.example.com/CCC*'
    service: service3           

 如何部署此檔案,隻需要一行指令,如下:

gcloud app deploy dispatch.yaml           

來一個實際的例子,如下圖:

GCP: AppEngine(GAE)的使用

 看到這裡相信你應該明白的三點:

  • 為什麼第一個服務名必須是default, 因為當你不定義dispatch.yaml時,即沒有路由規則時,它會調用服務default
  • 拿我第二節建立的demo為例,可以看出我沒有建立dispatch.yaml檔案,是以上圖紅色塊中是為空的。
  • 隻有先部署了你的所有服務之後,才能部署dispatch.yaml檔案。即運作了gcloud app deploy app.yaml 後,才能運作gcloud app deploy dispatch.yaml 

(三)、cron.yaml 

這個配置檔案是可選的,它是搞定期計劃任務的。漲下面這樣,就不多解釋了

cron:
- description: "daily summary job"
  url: /tasks/summary
  schedule: every 24 hours
- description: "monday morning mailout"
  url: /mail/weekly
  schedule: every monday 09:00
  timezone: Australia/NSW
- description: "new daily summary job"
  url: /tasks/summary
  schedule: every 24 hours
  target: beta           

 如何部署此檔案,隻需要一行指令,如下:

gcloud app deploy cron.yaml           

 (四)、index.yaml 

這個配置檔案更可選了,不想研究了,是配置 Datastore 索引,有了它,執行查詢時,Datastore 可快速傳回結果。下面是官網解釋。

您可以将标準環境中運作的應用的資料存儲在 Cloud Datastore 中。Cloud Datastore 使用索引來處理應用執行的每個查詢。實體發生變化時這些索引也會得到更新,是以在應用執行查詢時,Datastore 可快速傳回結果。

四、服務之間通信

重要!單獨列為一節,要與您的 App Engine 服務進行通信,最簡單的方法是發送定向 HTTP 請求,在網址中包含資源的名稱或 ID。例如,除相應的 GCP 項目 ID 之外,您還可以包含要定位的服務或版本的 ID:

http://[VERSION_ID].[SERVICE_ID].[MY_PROJECT_ID].appspot.com
https://[VERSION_ID]-dot-[SERVICE_ID]-dot-[MY_PROJECT_ID].appspot.com           

 App Engine 服務還可以使用 Cloud Pub/Sub 通信,以便在程序(包括 App Engine)之間提供可靠的異步多對多消息傳遞。

五、AppEngine存儲資料和檔案

App Engine隻允許你存入臨時檔案,隻能存入 

/tmp

 目錄。 我在實際項目中用到了,是以列出來了,雖然不是重點。

AppEngine裡的執行個體原則上是不允許你存任何東西的,因為自動擴縮的時候,執行個體随時會銷毀,執行個體銷毀後,你存的東西全部會删除。但有時候程式需要存一些臨時檔案,舉個例子:使用者點選下載下傳時生成一個Excel檔案、壓縮一下再傳到Google Storage裡供使用者下載下傳,那個Excel檔案就需要臨時存一下。

六、使用自定義域名和安全證書

直接在控制台裡面配置就可以了,注意這裡是cname,将AppEngine自動生成的域名和你定義的域名在域名解析的地方綁定起來就好了。AppEngine自動生成的域名與它背後的伺服器之間是天生自帶負載勻衡(7層/4層)的,不需要我們作額外的控制。

GCP: AppEngine(GAE)的使用

七、流量管理

一些相關的概念

  1. 藍綠部署(Blue/Green Deployment):  它是最常見的一種0 downtime部署的方式,就是準備兩個版本,舊版本A在生環境中正常運作,要發部署新版本B後,直接将流量切換到新版本B,如果測試發現新版本B有問題,可以将流量快速切回到舊版本A。
  2. 紅黑部署(Red-Black Deployment):與藍綠部署很相似,藍綠表示生産環境有兩個版本都可用,綠表示生産環境正在用,藍表也可用,但是個備胎;紅黑部署中,紅是正在用,黑是不可用的。但在雲環境中,這兩個概念似乎弱化了,感覺就是同一個意思。
  3. 灰階釋出/金絲雀釋出:就是流量拆分,例如90%的使用者維持使用老版本,10%的使用者嘗鮮新版本。
  4. 滾動釋出(rolling update):一般是取出一個或者多個伺服器停止服務,執行更新,并重新将其投入使用。周而複始,直到叢集中所有的執行個體都更新成新版本,例如每次隻取出叢集的20%進行更新,Kubernetes中的滾動更新就是屬于這種。
  5. A/B 測試(A/B Testing): A版本是線上穩定版本,B版本是新版本,如果一下子切到B環境,可能使用者會難以适應,是以先部署一個B環境,分一部分流量出來,收集使用者回報後逐漸改進B版本,直到使用者可以完全接受用B版本替換A版本的程度。

總結:它們之間都是有差別的。 另外,灰階釋出經常與A/B 測試一起使用,用于測試選擇多種方案。AB test就是一種灰階釋出方式,讓一部分使用者繼續用A,一部分使用者開始用B,如果使用者對B沒有什麼反對意見,那麼逐漸擴大範圍,把所有使用者都遷移到B上面來。

當一個服務有多個版本時,有兩種辦法來控制多個版本之間的流量

(一)、部署一個新的版本後,将流量100%從舊版本切換到新版本(Swap方式)

适合小項目,紮心了,沒權限,但它就在這裡,如下圖。

但有個小問題,它是屬于藍綠部署,還是紅黑部署呢?  因為對于流量為0版本我也不知道它有沒有死,并且它不止兩個版本,如果有7個版本,你準備怎麼稱呼?

GCP: AppEngine(GAE)的使用

(二)、部署一個新的版本後,對流量進行拆分

 例如,你擔心這個新版本可能會有問題,隻将一部分流量,比如5%分給新的版本,剩餘95%繼續給舊版本。點選下圖的按鈕就可以拆分流量,前提是要有至少2個版本。

GCP: AppEngine(GAE)的使用

那它可以有以下幾種形式進行拆:

  1. IP 位址拆分: 當該應用收到請求時,它會将 IP 位址哈希處理為介于 0-999 之間的值,并使用該數字來路由請求。IP 位址拆分具有很大的局限性,比如IP 位址可能會不斷變化,使用者一會用新版本一會用舊版本,體驗不好。
  2. Cookie 拆分:應用會在HTTP頭部查找名為 

    GOOGAPPUID

     的 Cookie,該 Cookie 中包含一個 0 至 999 之間的值,如果存在此 Cookie,則使用該值路由請求,如果沒有此 Cookie,則會随機路由請求。

總結:

  1. 流量拆分最容易遇到緩存問題,比如A和B兩個版本,新版本B對CSS檔案作改動了,而使用者本地緩存了此檔案,A 和 B 兩個版本之間拆分流量後,很可能導緻舊版本使用新的CSS檔案,最好是在HTTP頭部加上Cache-Control和Expires來解決。
  2. 服務與服務之間的調用最好改用 Cookie 拆分。
  3. 這裡能按人拆分?例如:隻有張三登入才能使用最新版本。  不支援,隻有以上兩種方式!!!

八、日志與監控

GCP有專門的服務來解決這類問題。

  • 查日志請通路Logging
  • 查流量、與監控請通路Trace, "projects/[PROJECT_ID]/traces/[TRACE_ID]"
GCP: AppEngine(GAE)的使用
GCP: AppEngine(GAE)的使用

九、總結

還記得上面第2節中的8個問題麼? 還有一個問題沒有回答。

1. ”它自動擴縮時,肯定是以某一代碼源或者artifact為基礎,那我上傳的代碼放在哪裡呢“ ?

答:它會将你上傳的代碼或artifact放在Google Storage中,當你釋出你的應用時,它會自動在Google Storage建立一個Buket來存放你的代碼。

2. 我們建立的Python Web應用,它得Web伺服器是用得什麼,為什麼隻需要上傳代碼後Web應用自動能運作?

答:Python Web應用最常使用得Web伺服器是uswgi,當你部署代碼時,實際上你的代碼會被打包成一個自定義的Docker Image裡,當你選擇運作時時,這個對應的Base Image也就標明好了,Base Image是Google預先定義的,裡面早已有了Python需要的Web伺服器及相應的元件,預設使用

gunicorn

 用作 Web 伺服器,參考這裡

3. 上面的8個問題歸納一下

答:用一話來說,就是你的服務治理是如何實作的,我們可以将這些問題總結為4點:連接配接、保護、控制、觀測。這些問題由GCP平台都幫你實作了,我們隻需要使用就可以了,如果你想繼續深入的研究,可以學習微服務,本主将會後緒一一更新。解決問題的能力來源于你深入的研究與實踐,加油!

4. 注意事項

答:AppEngine應用應該是“無狀态”的,且執行個體上不存儲任何内容。

5. 既然AppEngine包含服務治理的功能,豈不是把Api Gateway的活給幹了?那還需要配置Api Gateway嗎?

答:可以和API Gateway結合使用,也可以單獨使用,如果結合使用,請參考這裡

參考文獻

https://cloud.google.com/appengine/docs/standard/python3

gcp

繼續閱讀