Service Mesher 社区牵头启动 Istio 文档翻译工作之后,为降低维护工作量,我们开发了一个 Github Webhook 项目,用 Github Issue 的方式对社区翻译工作流程提供自动化支持。同时也开发了一个 Chatbot 来完成任务的维护工作。
在上海 KubeCon 上,经过和 Kubernetes 文档工作组进行一番交流之后,决定将这一套方法推行到 Kubernetes 文档的本地化工作之中。
经过一番准备之后,两个项目用相似的 Flask 代码,以在 VPS 上运行的 Docker Image 的形式支撑了两个本地化工作组的工作流程。
然而两组代码始终是一个隐患,并且工作流程固化在代码之中,也给流程改进带来很大阻碍;另外使用高配 Linode 运行 Webhook 是个非常奢侈的事情。因此也就有了利用公有云 Free Tier 提供 Webhook 响应的想法。
未解决这些问题,新建了 Webhook 项目,经过对代码的修改,将流程定制工作全部转移到配置文件之中,并将流程处理代码进行了固化,在此基础上,分别实现了 Flask、AWS Lambda 以及 GCP Function 的三个版本。
Lambda 版本的 Webhook,使用 lambda.py
作为入口文件,入口函数为 webhook
,在创建 Lambda 的页面中,可以指定 lambda.webhook
为入口。
def webhook(event, context):
中的 event
参数中包含了请求数据,context
顾名思义,包含 Lambda 的上下文信息。例如用下面的代码获取 METHOD、POST Data 以及 Header(强烈鄙视标头这个译法):
if event["httpMethod"] != "POST": return { "isBase64Encoded": "false", "statusCode": 405, "headers": {}, "body": "Method Not Allowed!"
}data = json.loads(event["body"])
event_type = event["headers"]["X-GitHub-Event"]
event_id = event["headers"]["X-GitHub-Delivery"]
如下代码可以将日志写入 CloudWatch Log。
logger = logging.getLogger()
logger.setLevel(int(LOG_LEVEL))
需要注意的两个问题:
选择 API Gateway 作为 Lambda 触发器,其返回内容需要是一个固定的 JSON 格式,例如:
return { "isBase64Encoded": "false", "statusCode": 405, "headers": {}, "body": "Method Not Allowed!"}
Lambda 没有为 Python 提供依赖处理功能,需要自行下载依赖包,并统一打包为 ZIP 文件上传,代码中提供了 build.sh,用于生成发布包。
GCP Function 版本的 Webhook 以 main.py
为入口,这是强制规定。可以指定入口函数,我在这里指定使用 webhook
入口,其中的 request
参数实际上就是 Flask 的 Request 对象。因此可以很方便的查找文档。
这里的日志稍嫌复杂,但是和 AWS 不同的是,StackDriver Log 是免费的,因此可以忍。
创建 ServiceAccount:
gcloud iam service-accounts \
create [account] --project [project-id]
为新账号赋权:
gcloud projects add-iam-policy-binding [project-id] \
--member "serviceAccount:[account]@[project-id].iam.gserviceaccount.com" \
--role "roles/owner"
获取账号文件:
gcloud iam service-accounts keys create permission.json \
--iam-account [account]@[project-id].iam.gserviceaccount.com
应用中需要定义 GOOGLE_APPLICATION_CREDENTIALS
环境变量,指定上传的 permission.json 文件的位置。
日志需要使用 Google 自己的库来完成:
from google.cloud import logging
...logging_client = logging.Client()
log_name = "github-webhook-{}".format(WORKFLOW)
logger = logging_client.logger(log_name)
...
logger.log_struct(
{"workflow": WORKFLOW, "admins": ADMINS}
)
...
requirments.txt
中需要加入如下依赖:
google-cloud
google-cloud-logging
返回值无需像 Lambda 一样特别处理,直接 return
即可。
GCP Function 提供了依赖处理能力,只需要在 requirements.txt
中写明依赖包即可。无需下载上传大量的依赖包文件。
Azure 提供了 func cli 来完成初始化工作,并通过 VS Code 提供了 Azure Function 的开发支持。然而 func cli 只支持 Python 3.6.x,测试未能完成。