https://yq.aliyun.com/articles/743865javascript
前言
本文以一個Nodejs前端開發者角度出發,從零基於阿里雲平臺能力搭建一個彈性的Serverless平臺的記錄。但願對也想了解這個產品總體的小夥伴們有必定幫助。html
官方文檔:https://help.aliyun.com/document_detail/121509.html
控制檯:https://cs.console.aliyun.com/
前端
爲何是Knative
項目主頁:https://knative.dev/
項目倉庫:https://github.com/knative
java
總結爲下面兩張以前我分享的PPTnode
- knative 定位:
- knative 三大組件:
前置依賴
- 建立一個k8s集羣,且集羣中Worker節點的數量大於等於3個。
- 部署 Istio。
下圖可知它們之間的關係:
git
部署k8s集羣
文檔:https://help.aliyun.com/document_detail/86488.html
Kubernetes 是流行的開源容器編排技術,按照如下步驟快速建立一個k8s集羣
github
- 選擇標準託管k8s
- 建立專有網絡和虛擬交換機, 不然沒法選擇購買實例規格
- 選擇worker實例規格,由於是體驗平臺,故我選擇了3臺最小規格支持Pod的實例, 這是最低要求。由於是託管k8s集羣,故不須要選擇master
- 建立和選擇 密鑰對,後面在本機電腦操做遠端服務的認證
- 公網訪問:使用 EIP 暴露 API Server 記得選擇上,
集羣建立好不能修改
, 否則沒法在本機電腦上經過http url 訪問服務 - 選擇上日誌服務
- 保障帳戶餘額不低於100
- 其餘默認配置
點擊建立k8s集羣,全部檢查項經過後,約10 分鐘建立成功全部資源
算法
部署Istio
文檔:https://help.aliyun.com/document_detail/89805.html
Istio爲解決微服務的分佈式應用架構在運維、調試、和安全管理等維度存在的問題,可經過部署Istio建立微服務網絡,並提供負載均衡、服務間認證以及監控等能力,同時Istio不須要修改服務便可實現以上功能
經過下面步驟快速在上面的k8s中部署istio
docker
- 選擇對應集羣部署istio
- 若是要實現 Tracing 分佈式追蹤服務,勾選開啓
- 在鏈路追蹤服務,打開Region對應信息查看token, 複製與集羣region一直的內網接入http url 到istio配置中
- 其餘默認配置,點擊部署,很快相應服務部署成功再k8s集羣上
部署Knative
文檔:https://help.aliyun.com/document_detail/121509.html
在控制檯左側,找到Knative(公測),選擇組件管理,點擊右上方一鍵部署,部署咱們前面講到的Knative 三大組件
express
- Tekton 組件 (原build 組件不在推薦) - v0.9.2
- Serving 組件 - v0.11.0
- Eventing 組件 - v0.11.0
檢查未經過,須要開啓 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
- 執行 kubectl get revisions 查看部署服務的版本,以下能夠看到咱們上面經過控制檯可視化部署的服務nodejs, 一個版本nodejs-dn5vh
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個版本
自定義域名
在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.html
yaml轉換爲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 > 服務管理 > 點擊服務名 > 選擇路由轉發 > 點擊配置
-
配置保存後當即生效,訪問符合預期
- dev.lianxuify.com/nodejs 到服務1 nodejs
- dev.lianxuify.com/nodejs 到服務2 nodejs2
彈性驗證與配置
kubectl get pods -w // 查看運行的容器組,sidecar+業務服務
以下所示,當沒有流量後 pod 自動會刪除,流量進來會彈性擴展
流量根據以下配置進行擴縮容,可根據業務場景要求配置
Knative > 組件管理 > 點擊Serving組件詳情> 點擊擴縮容配置
這些參數是服務彈性算法的關鍵配置,須要結合業務配置出最佳實踐,鼠標hover小綠點有詳細說明。
日誌監控
在Knative 上對分佈式的日誌,監控接入這裏沒有進行深度探索。文檔總體看下來,流程與常規服務接入沒區別,開通對應產品進行接入便可。
如下是建立集羣默認建立的部分日誌和監控
回滾
在Knative 上對發佈進行回滾,沒有進行深度探索。大體理解以下
- 回滾歷史版本,經過流量配置修改,將流量切到老版本
- 對應同版本回滾,找到以下回滾面板
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有幫助。若有理解有誤,歡迎指出,共同成長。其間感謝阿里雲 @元毅 的幫助與解答。