前言
本文以一個Nodejs前端開發者角度出發,從零基于阿裡雲平台能力搭建一個彈性的Serverless平台的記錄。希望對也想了解這個産品整體的小夥伴們有一定幫助。
官方文檔:
https://help.aliyun.com/document_detail/121509.html控制台:
https://cs.console.aliyun.com/為什麼是Knative
項目首頁:
https://knative.dev/項目倉庫:
https://github.com/knative總結為下面兩張之前我分享的PPT
- knative 定位:
阿裡雲K8s+Istio+Knative搭建Serverless平台 - knative 三大元件:
阿裡雲K8s+Istio+Knative搭建Serverless平台
前置依賴
- 建立一個k8s叢集,且叢集中Worker節點的數量大于等于3個。
- 部署 Istio。
下圖可知它們之間的關系:
部署k8s叢集
文檔:
https://help.aliyun.com/document_detail/86488.htmlKubernetes 是流行的開源容器編排技術,按照以下步驟快速建立一個k8s叢集
- 選擇标準托管k8s
- 建立專有網絡和虛拟交換機, 否則無法選擇購買執行個體規格
- 選擇worker執行個體規格,因為是體驗平台,故我選擇了3台最小規格支援Pod的執行個體, 這是最低要求。因為是托管k8s叢集,故不需要選擇master
阿裡雲K8s+Istio+Knative搭建Serverless平台 - 建立和選擇 密鑰對,後面在本機電腦操作遠端服務的認證
- 公網通路:使用 EIP 暴露 API Server 記得選擇上,
, 不然無法在本機電腦上通過http url 通路服務叢集建立好不能修改
- 選擇上日志服務
- 保障賬戶餘額不低于100
- 其他預設配置
點選建立k8s叢集,所有檢查項通過後,約10 分鐘建立成功所有資源
部署Istio
https://help.aliyun.com/document_detail/89805.htmlIstio為解決微服務的分布式應用架構在運維、調試、和安全管理等次元存在的問題,可通過部署Istio建立微服務網絡,并提供負載均衡、服務間認證以及監控等能力,同時Istio不需要修改服務即可實作以上功能
通過下面步驟快速在上面的k8s中部署istio
- 選擇對應叢集部署istio
阿裡雲K8s+Istio+Knative搭建Serverless平台 - 如果要實作 Tracing 分布式追蹤服務,勾選開啟
- 在鍊路追蹤服務,打開Region對應資訊檢視token, 複制與叢集region一直的内網接入http url 到istio配置中
- 其他預設配置,點選部署,很快相應服務部署成功再k8s叢集上
阿裡雲K8s+Istio+Knative搭建Serverless平台
部署Knative
在控制台左側,找到Knative(公測),選擇元件管理,點選右上方一鍵部署,部署我們前面講到的Knative 三大元件
- Tekton 元件 (原build 元件不在推薦) - v0.9.2
- Serving 元件 - v0.11.0
- Eventing 元件 - v0.11.0
阿裡雲K8s+Istio+Knative搭建Serverless平台
檢查未通過,需要開啟 istio-ingressgateway,解決:
在控制台> 服務網格 > istio管理, 點右側更新
将如下,光标高亮 gateways enabled 預設false 修改為 true, 點選更新後,
再次部署kantive元件,很快即可部署成功
部署服務
下載下傳Knative 官方服務demo 工程
git clone https://github.com/knative/docs
# nodejs demo 服務
cd docs/serving/samples/hello-world/helloworld-nodejs
檢視修複成,你想要的服務
const express = require('express');
const app = express();
app.get('/', (req, res) => {
console.log('Hello world received a request.');
const target = process.env.TARGET || 'World';
// 我添加了輸出,可以檢視流量通路的不同服務版本
const kRevision = process.env.K_REVISION || '';
res.send(`Hello ${target} (revision: ${kRevision}) \n`);
});
const port = process.env.PORT || 8080;
app.listen(port, () => {
console.log('Hello world listening on port', port);
});
鏡像建構與釋出
# 目前 Docker 官方維護了一個公共倉庫Docker Hub 我們将自己建構的鏡像釋出上去
# https://hub.docker.com/
# 進行鏡像建構, 其中859652049替換成你的賬号名
docker build -t 859652049/helloworld-nodejs .
# 推送鏡像到公共倉庫Docker Hub
docker push 859652049/helloworld-nodejs
控制台可視化部署
- 回到控制台 > Knative > 服務管理 > 選擇k8s叢集命名空間default, 建立服務
- 支援根據模闆快速建立 和 可視化編輯建立。
- 我們選擇可視化建立
- 鏡像名稱輸入:docker.io/859652049/helloworld-nodejs (也可以用你上面自己建立的鏡像)
- 配置環境變量 TARGET: NodeX 1 (服務代碼裡用到這個環境變量)
- 其他預設配置,可以自由配置
- 最大并發不控制
- 彈性執行個體最小0, 最大100
- CPU 0.25Core, 記憶體 125M
- 不挂載額外存儲資料卷
服務部署成功
通路服務,其中下面的ip 和 host 對應,上圖中預設域名和通路網關ip
curl -H "HOST: nodejs.default.example.com" http://47.111.223.97
或者通過綁定公網ip 到預設域名上
# 推薦工具SwitchHosts https://github.com/oldj/SwitchHosts/blob/master/README_cn.md
47.111.223.97 nodejs.default.example.com
兩種方式,接口資料傳回成功
Kubectl指令行部署
https://help.aliyun.com/document_detail/86494.html- 安裝 kubectl 用戶端,根據文檔, 我這邊mac 通過docker 用戶端 Preferences 設定中 enable kubernetes 後安裝了。
- 配置登入憑據
- 叢集清單,點選叢集名,選擇KubeConfig(公網通路)頁簽,并單擊複制,将内容複制到本地計算機的 $HOME/.kube/config
阿裡雲K8s+Istio+Knative搭建Serverless平台 - 執行 kubectl get revisions 檢視部署服務的版本,如下可以看到我們上面通過控制台可視化部署的服務nodejs, 一個版本nodejs-dn5vh
阿裡雲K8s+Istio+Knative搭建Serverless平台
5.通過kubectl 部署新的一個版本
還是我們之前使用的 helloworld-nodejs 工程, 将配置檔案service.yaml
apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
name: nodejs # 服務名
namespace: default # 服務部署的命名空間
spec:
template:
metadata:
name: nodejs-dn5vh-v2
spec:
containers:
- image: docker.io/859652049/helloworld-nodejs
env:
- name: TARGET
value: "NodeX 2" # 環境變量更新為2
traffic: # 設定流量配置設定到不同服務版本, 也可通過如下圖可視化修改配置
- tag: current
revisionName: nodejs-dn5vh # 修改為自動可視化自動生成的版本号
percent: 50 # 50% 流量版本1
- tag: candidate
revisionName: nodejs-dn5vh-v2 # 與目前版本号一緻
percent: 50 # 50% 流量版本2
- tag: latest
latestRevision: true
percent: 0
kubectl --namespace default apply -f ./service.yaml
- 多次通路服務,流量按比例導入到2個版本
阿裡雲K8s+Istio+Knative搭建Serverless平台
自定義域名
在Knative Serving route 路由中預設使用 example.com 作為預設域名,route 完全定義的域名格式預設為:
{service}.{namespace}.{default-domain} ,如:nodejs.default.example.com
域名A記錄到網關
- 首先你要有個阿裡雲備案過的域名,否則最後通路會顯示需要接入備案
-
将域名 A記錄 指向自己的公網網關位址,如上:47.111.223.97
這個有個注意點,因為服務部署的命名空間和服務名 都會不斷變化,或者有多個。故A記錄時候使用泛域名綁定
比如 dev.lianxuify.com 這個子域名是我用來開發測試的
dev.lianxuify.com
nodejs.default.dev.lianxuify.com
nodejs-1.default.dev.lianxuify.com
- 修改預設域名example.com 為 dev.lianxuify.com
通過控制台配置
菜單 Knative > 元件管理 > 點選核心元件Serving 詳情 > 自定義域名模闆 > 點選檢視yaml
apiVersion: v1
data:
_example: |
################################
# #
# EXAMPLE CONFIGURATION #
# #
################################
# This block is not actually functional configuration
# ....
example.org: |
selector:
app: nonprofit
# Routes having domain suffix of 'svc.cluster.local' will not be exposed
# through Ingress. You can define your own label selector to assign that
# ...
svc.cluster.local: |
selector:
app: secret
# 以上都是注釋
dev.lianxuify.com: '' # 自定義域名,僅需要添加該行,前面添加兩個空格,與頂部_example對齊
kind: ConfigMap
metadata:
creationTimestamp: '2020-02-05T15:21:13Z'
labels:
serving.knative.dev/release: v0.11.0
name: config-domain
namespace: knative-serving
resourceVersion: '83466654'
selfLink: /api/v1/namespaces/knative-serving/configmaps/config-domain
uid: 257133b2-482b-11ea-9d30-8e59b18ed506
yaml文法 基本文法
http://www.ruanyifeng.com/blog/2016/07/yaml.htmlyaml轉換為json:
http://www.bejson.com/validators/yaml/- 大小寫敏感
- 使用縮進表示層級關系,幾個空格不重要
- 縮進時不允許使用Tab鍵,隻允許使用空格 已驗證
- 縮進的空格數目不重要,隻要相同層級的元素左側對齊即可
- #表示注釋
- | 保留換行符 字元串
通過 kubectl 配置
kubectl edit cm config-domain --namespace knative-serving
# 同上添加一行,儲存即生效
# 驗證生效
kubectl get route
# NAME URL READY REASON
# nodejs http://nodejs.default.dev.lianxuify.com True
路由轉發
當我們有多個服務使用相同的域名,通過請求的Path不同,将流量轉發到不同服務中
坑:knative 官方demo 工程,不支援路徑通路,隻處理根路徑通路。 因為這個一直接口傳回失敗,以為配置搭建問題。
const express = require('express');
const app = express();
// 修改/ 為 *
// app.get('/', (req, res) => {
app.get('*', (req, res) => {
// ...
});
//
- 修改代碼路由為*,重新建構鏡像,釋出鏡像 (docker.io/859652049/helloworld-nodejs:latest 已經修改過)
- 重新部署服務, 按照上面可視化、或者 kubectl 方式重新部署兩個服務 nodejs、nodejs2
- 選擇 Knative > 服務管理 > 點選服務名 > 選擇路由轉發 > 點選配置
阿裡雲K8s+Istio+Knative搭建Serverless平台 - 配置儲存後立即生效,通路符合預期
- dev.lianxuify.com/nodejs 到服務1 nodejs
- dev.lianxuify.com/nodejs 到服務2 nodejs2
彈性驗證與配置
kubectl get pods -w // 檢視運作的容器組,sidecar+業務服務
如下所示,當沒有流量後 pod 自動會删除,流量進來會彈性擴充
流量根據如下配置進行擴縮容,可根據業務場景要求配置
Knative > 元件管理 > 點選Serving元件詳情> 點選擴縮容配置
這些參數是服務彈性算法的關鍵配置,需要結合業務配置出最佳實踐,滑鼠hover小綠點有詳細說明。
日志監控
在Knative 上對分布式的日志,監控接入這裡沒有進行深度探索。文檔整體看下來,流程與正常服務接入沒差別,開通對應産品進行接入即可。
以下是建立叢集預設建立的部分日志和監控
復原
在Knative 上對釋出進行復原,沒有進行深度探索。大緻了解如下
- 復原曆史版本,通過流量配置修改,将流量切到老版本
- 對應同版本復原,找到如下復原面闆
阿裡雲K8s+Istio+Knative搭建Serverless平台
CICD
持續內建持續傳遞這塊,還在探索中。看到 GitHub 事件源add-on 元件,通過github 倉庫的鈎子事件能觸發到
Knative平台去建構鏡像、部署服務。另一種方式自己監聽gitlab 鈎子事件,建構推送鏡像,調用平台OpenAPI接口 (如上圖有個觸發重新部署的接口)或者 自己的部署平台調用kubectl 指令行工具部署
總結
以上我們利用阿裡雲K8s+Istio+Knative 搭建Serverless平台
- 部署了k8s叢集
- 部署了Istio
- 部署了Knative 三大元件
- 部署了業務服務,驗證了彈性擴縮容
- 自定義了域名 + 路由轉發 到不同服務
- 不停服藍綠部署、按流量灰階釋出, 同個服務多個版本
該平台提供可視化配置 + 以及其yaml配置檔案,對一個新手認識、使用這個生态能力有很好的幫助。
整套方案對應傳統服務遷移到Serverless平台上靈活性、友好性較高,未來大有可為。但目前開發者工具相關還不是這麼豐富,平台在公測中,整體使用成本和門檻相對阿裡雲函數計算更高些。因為最低叢集3台worker要求,一直占用, 我目前是體驗,選擇了低配置,大概是4元多一個小時 (不知道能不能更低)
這裡還有篇我對阿裡雲函數計算整體調研的文章:
https://yq.aliyun.com/articles/743665希望兩篇文章對大家整體上認識兩款産品,以及搭建serverless有幫助。
如有了解有誤,歡迎指出,共同成長。
其間感謝阿裡雲 @元毅 的幫助與解答。