GCP: AppEngine(GAE)的使用

一、基本概念

在全托管式的无服务器平台上构建可扩缩性极强的应用, 将应用从零无缝扩容到全球级规模,而不用费心管理底层基础架构。得益于零服务器管理和零配置部署,开发者可以专注于构建出色的应用,省去管理开销。App Engine 支持多种主流开发语言以及各种开发者工具,可帮助开发者提高工作效率和灵活性。

在其他云上与之对标的产品有:

  • Azure上的App Service,猛戳这里
  • AWS 上的AWS Elastic Beanstalk
  • 阿里云上的Web应用托管服务(Web+)

它有两种环境,通常我们使用第一种

二、 快速上手(python3)

(一)、创建应用及app.yaml文件

先上目录,创建得是一个基于python3.8的一个Flask应用,它足够简单,以便我们只关注感兴趣的部分。

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控制台看到的截图

到这里,你已经基本掌握了app engine的用法了。但仍然还有许多的问题需要解决:

  1. 它的实例默认是随着访问量自动扩缩的,是如何自动扩缩的呢,我可以控制吗?
  2. 它自动扩缩时,肯定是以某一代码源或者artifact为基础,那我上传的代码放在哪里呢?
  3. 如何绑定自定义域名及安全证书,当实例数自动扩展时,它是如何将证书自动安装到新的实例上?
  4. 如果我有多个服务,却只有一个域名,如何通过一个域名访问到多个服务,即反向代理是咋整的?
  5. 多个服务中,服务与服务之间如何调用,它们在同一个局域网内吗? 互相访问时可以走内网吗,走外网就慢了。
  6. 上图中有一个version 1,可以看出每个服务都有版本控制的,不同版本之间我能对流量进行控制吗?
  7. 灰度部署/蓝绿部署/AB测试这些都支持么?
  8. 对这些服务如何追踪和监控,有日志么,在哪里看到我的服务的使用情况。

 

三、 设计应用

为了回答上面所有的问题,只有一个服务显然不够。

以下示例展示了当您在本地开发应用时,一个含有三项服务的应用可能具有的结构。可选的 dispatch.yaml 已添加到该应用的根目录中。在根目录下还有三个目录,分别对应于应用的每项服务。service1 的子目录包含该服务的源文件和配置文件。同样,service2 和 service3 均位于独立的目录中,这些目录分别包含对应服务的文件,而 service3 包含 YAML 配置文件的两个版本:

上面的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

来一个实际的例子,如下图:

 看到这里相信你应该明白的三点:

  • 为什么第一个服务名必须是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层)的,不需要我们作额外的控制。

七、流量管理

一些相关的概念

  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个版本,你准备怎么称呼?

(二)、部署一个新的版本后,对流量进行拆分

 例如,你担心这个新版本可能会有问题,只将一部分流量,比如5%分给新的版本,剩余95%继续给旧版本。点击下图的按钮就可以拆分流量,前提是要有至少2个版本。

那它可以有以下几种形式进行拆:

  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]"

九、总结

还记得上面第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

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值