天天看點

阿裡雲K8s+Istio+Knative搭建Serverless平台

前言

本文以一個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+Istio+Knative搭建Serverless平台

部署k8s叢集

文檔:

https://help.aliyun.com/document_detail/86488.html

Kubernetes 是流行的開源容器編排技術,按照以下步驟快速建立一個k8s叢集

  1. 選擇标準托管k8s
  2. 建立專有網絡和虛拟交換機, 否則無法選擇購買執行個體規格
  3. 選擇worker執行個體規格,因為是體驗平台,故我選擇了3台最小規格支援Pod的執行個體, 這是最低要求。因為是托管k8s叢集,故不需要選擇master
    阿裡雲K8s+Istio+Knative搭建Serverless平台
  4. 建立和選擇 密鑰對,後面在本機電腦操作遠端服務的認證
  5. 公網通路:使用 EIP 暴露 API Server 記得選擇上,

    叢集建立好不能修改

    , 不然無法在本機電腦上通過http url 通路服務
  6. 選擇上日志服務
  7. 保障賬戶餘額不低于100
  8. 其他預設配置

點選建立k8s叢集,所有檢查項通過後,約10 分鐘建立成功所有資源

阿裡雲K8s+Istio+Knative搭建Serverless平台

部署Istio

https://help.aliyun.com/document_detail/89805.html

Istio為解決微服務的分布式應用架構在運維、調試、和安全管理等次元存在的問題,可通過部署Istio建立微服務網絡,并提供負載均衡、服務間認證以及監控等能力,同時Istio不需要修改服務即可實作以上功能

通過下面步驟快速在上面的k8s中部署istio

  1. 選擇對應叢集部署istio
    阿裡雲K8s+Istio+Knative搭建Serverless平台
  2. 如果要實作 Tracing 分布式追蹤服務,勾選開啟
  3. 在鍊路追蹤服務,打開Region對應資訊檢視token, 複制與叢集region一直的内網接入http url 到istio配置中
  4. 其他預設配置,點選部署,很快相應服務部署成功再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, 點選更新後,

阿裡雲K8s+Istio+Knative搭建Serverless平台

再次部署kantive元件,很快即可部署成功

阿裡雲K8s+Istio+Knative搭建Serverless平台

部署服務

下載下傳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           

控制台可視化部署

  1. 回到控制台 > Knative > 服務管理 > 選擇k8s叢集命名空間default, 建立服務
  2. 支援根據模闆快速建立 和 可視化編輯建立。
  3. 我們選擇可視化建立
  4. 鏡像名稱輸入:docker.io/859652049/helloworld-nodejs (也可以用你上面自己建立的鏡像)
  5. 配置環境變量 TARGET: NodeX 1 (服務代碼裡用到這個環境變量)
  6. 其他預設配置,可以自由配置
    • 最大并發不控制
    • 彈性執行個體最小0, 最大100
    • CPU 0.25Core, 記憶體 125M
    • 不挂載額外存儲資料卷
阿裡雲K8s+Istio+Knative搭建Serverless平台

服務部署成功

阿裡雲K8s+Istio+Knative搭建Serverless平台

通路服務,其中下面的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           

兩種方式,接口資料傳回成功

阿裡雲K8s+Istio+Knative搭建Serverless平台
阿裡雲K8s+Istio+Knative搭建Serverless平台

Kubectl指令行部署

https://help.aliyun.com/document_detail/86494.html
  1. 安裝 kubectl 用戶端,根據文檔, 我這邊mac 通過docker 用戶端 Preferences 設定中 enable kubernetes 後安裝了。
  2. 配置登入憑據
  3. 叢集清單,點選叢集名,選擇KubeConfig(公網通路)頁簽,并單擊複制,将内容複制到本地計算機的 $HOME/.kube/config
    阿裡雲K8s+Istio+Knative搭建Serverless平台
  4. 執行 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            
  1. 多次通路服務,流量按比例導入到2個版本
    阿裡雲K8s+Istio+Knative搭建Serverless平台
阿裡雲K8s+Istio+Knative搭建Serverless平台
阿裡雲K8s+Istio+Knative搭建Serverless平台

自定義域名

在Knative Serving route 路由中預設使用 example.com 作為預設域名,route 完全定義的域名格式預設為:

{service}.{namespace}.{default-domain} ,如:nodejs.default.example.com

域名A記錄到網關

  1. 首先你要有個阿裡雲備案過的域名,否則最後通路會顯示需要接入備案
  2. 将域名 A記錄 指向自己的公網網關位址,如上:47.111.223.97

    這個有個注意點,因為服務部署的命名空間和服務名 都會不斷變化,或者有多個。故A記錄時候使用泛域名綁定

比如 dev.lianxuify.com 這個子域名是我用來開發測試的

dev.lianxuify.com

nodejs.default.dev.lianxuify.com

nodejs-1.default.dev.lianxuify.com

  1. 修改預設域名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           
阿裡雲K8s+Istio+Knative搭建Serverless平台

路由轉發

當我們有多個服務使用相同的域名,通過請求的Path不同,将流量轉發到不同服務中

坑:knative 官方demo 工程,不支援路徑通路,隻處理根路徑通路。 因為這個一直接口傳回失敗,以為配置搭建問題。

const express = require('express');
const app = express();
// 修改/ 為 *
// app.get('/', (req, res) => {
app.get('*', (req, res) => {
  // ...
});

//            
  1. 修改代碼路由為*,重新建構鏡像,釋出鏡像 (docker.io/859652049/helloworld-nodejs:latest 已經修改過)
  2. 重新部署服務, 按照上面可視化、或者 kubectl 方式重新部署兩個服務 nodejs、nodejs2
阿裡雲K8s+Istio+Knative搭建Serverless平台
  1. 選擇 Knative > 服務管理 > 點選服務名 > 選擇路由轉發 > 點選配置
    阿裡雲K8s+Istio+Knative搭建Serverless平台
  2. 配置儲存後立即生效,通路符合預期
    • dev.lianxuify.com/nodejs 到服務1 nodejs
    • dev.lianxuify.com/nodejs 到服務2 nodejs2
阿裡雲K8s+Istio+Knative搭建Serverless平台
阿裡雲K8s+Istio+Knative搭建Serverless平台

彈性驗證與配置

kubectl get pods -w  // 檢視運作的容器組,sidecar+業務服務           

如下所示,當沒有流量後 pod 自動會删除,流量進來會彈性擴充

阿裡雲K8s+Istio+Knative搭建Serverless平台

流量根據如下配置進行擴縮容,可根據業務場景要求配置

Knative > 元件管理 > 點選Serving元件詳情> 點選擴縮容配置

阿裡雲K8s+Istio+Knative搭建Serverless平台

這些參數是服務彈性算法的關鍵配置,需要結合業務配置出最佳實踐,滑鼠hover小綠點有詳細說明。

日志監控

在Knative 上對分布式的日志,監控接入這裡沒有進行深度探索。文檔整體看下來,流程與正常服務接入沒差別,開通對應産品進行接入即可。

以下是建立叢集預設建立的部分日志和監控

阿裡雲K8s+Istio+Knative搭建Serverless平台
阿裡雲K8s+Istio+Knative搭建Serverless平台

復原

在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有幫助。

如有了解有誤,歡迎指出,共同成長。

其間感謝阿裡雲 @元毅 的幫助與解答。

繼續閱讀