使用 Kubernetes 打造具有會員註冊、身份驗證的多功能聊天機器人

各位在開發比較龐大的 chatbot 系統時是否會遇到一個問題?就是功能越來越多、程式碼越來越難管理、發生問題時很難找到問題點?這次我們要利用 Kubernetes (k8s) 來打造一個穩定、分散式、擴展性高的 chatbot 系統。

本篇程式碼都會放在我的 GitHub repo

這此內容主要為我在 COSCUP 2021 中所分享的內容

1. 目標 

這次我們打算做出有以下功能的聊天機器人系統:

  • 使用 LINE Login 會員註冊
  • 使用 LINE Messaging API 處理聊天室身份驗證
  • 定期自動推播訊息給會員

2. 設計系統 / 微服務 

為了讓系統更簡潔、清楚、好管理,我們會把整套服務切成以下 5 個微服務:

微服務名稱工作
webhook處理 LINE Webhook events
register-web-client會員註冊網站前端
register-web-server會員註冊網站後端
api-users會員使用者 API
push-msg定期推播訊息的 CronJob

3. 開發工具 

為了能夠在 local 先測試 / 開發,我們必須安裝 / 準備一些工具。

3.1. K8S

Kubectl + Kustomize

3.2. KInD

我選擇使用 KInD (Kubernetes in Docker) 來作為 k8s cluster,這裡會選擇 KInD 的原因主要是因為能夠模擬多個 nodes 的 cluster 環境,另外也能做到相同目的的還有 k3d,也可以選擇使用 k3d。

3.2.1. docker-tuntap-osx

如果是使用 Mac OS 的人,必須要安裝 docker-tuntap-osx,因為在 Mac OS 裡的 docker 中間是依靠一個 VM Hyperkit 來作為橋樑,因此如果要在本機連到 container 內的 k8s cluster 的話就需要依照外部教學串接。

3.3. Traefik

使用 Traefik 作為 k8s 的 ingress controller,會選擇使用 Traefik 的主要原因是他提供了許多好用、彈性的 middlewares,只要簡單的在 yaml 裡設定,就能夠使用強大的功能。

4. 開始開發 

4.1. coding

為了能夠有 image 讓 k8s 跑,我們必須先將程式碼打包成 image,然後我這裡是直接 push 到 docker hub,如此一來 k8s 就能直接從 docker hub pull image 了。

4.2. 定義 deployment.yaml

設定 deployment.yaml 可以讓 k8s 自動地去 deploy 我們要的 docker image。以 api-users 這個 microservice 來說,deployment 大概會像這樣:

kind: Deployment
apiVersion: apps/v1
metadata:
  name: api-users
  labels:
    k8s-app: api-users
spec:
  selector:
    matchLabels:
      k8s-app: api-users
  template:
    metadata:
      labels:
        k8s-app: api-users
        name: api-users
    spec:
      containers:
      - image: disam8853/api-users
        name: api-users
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
        envFrom:
        - configMapRef:
           name: api-users-config

4.3. 定義 service.yaml

此步驟是為了能夠創建 microservice。以 api-users 來說,service 大概會像這樣:

kind: Service
apiVersion: v1
metadata:
  name: api-users
spec:
  selector:
    k8s-app: api-users
  ports:
    - protocol: TCP
      port: 8080

4.4. 定義 ingressroute.yaml

為了能讓我們的 ingress controller 可以正確地設定 ingress,我們必須要設定 ingressroute.yaml。以 api-users 來說,ingressroute.yaml 大概會像這樣:

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: api-users-ingress
spec:
  entryPoints:
    - web
  routes:
  - match: PathPrefix(`/users`) || PathPrefix(`/register`)
    kind: Rule
    services:
    - name: api-users
      port: 8080

4.5. 定義 CronJob

不要忘了我們還需要一個 cronjob 來幫助我們自動定期推播訊息給會員,因此我們一樣需要將程式碼打包成 image 後 push 到 docker hub,之後再設定 k8s 的 cronjob.yaml

apiVersion: batch/v1
kind: CronJob
metadata:
  name: push-msg
spec:
  schedule: '*/5 * * * *'
  concurrencyPolicy: Forbid
  successfulJobsHistoryLimit: 7
  failedJobsHistoryLimit: 3
  startingDeadlineSeconds: 60
  jobTemplate:
    spec:
      backoffLimit: 0
      template:
        spec:
          restartPolicy: Never
          containers:
            - name: push-msg
              image: disam8853/push-msg
              envFrom:
                - configMapRef:
                    name: webhook-config
                - secretRef:
                    name: webhook-secret

以這個例子來說,*/5 * * * * 代表每 5 分鐘執行一次這個 cronjob,這個就跟 linux 的 crontab 一樣,如果不熟語法的人可以在 crontab.guru 中設定自己的行程表。

4.6. Apply

都設定好了之後只要在最上層 kustmize.yaml 的路徑執行:

kustomize build . | kube-ctl apply -f -

就會將我們的設定 apply 到 KInD 的 k8s cluster 裡了,接下來 k8s 就會自動去 docker hub 抓我們的 images,並且依照我們的設定去 deploy、設定 ingress。

4.7. 設定 LINE Webhook

為了能夠讓本機 有個對外的網址可以設定 LINE Webhook 的 URL,我們可以使用免費的 reserve proxy 來幫助開發,這裡我建議使用 localtunnel,因為 localtunnel 免費版就能夠自己設定 subdomain name,不像 ngrok 需要付費才能有此功能。

5. Demo

Demo 影片可以參考我之前在 COSCUP 2021 所分享的影片 (15:15 處)

總結 

使用 k8s 來開發較為龐大的系統可以大大的減少維護成本,例如當有問題發生時,可以利用 microservice 的優點,快速的排查問題原因,提升 debug 效率。

現在的 chatbot 基本上都沒有身份驗證的功能,因此需要開發者自己維護一個會員系統,會員系統又包含了註冊、登入等等服務,如此一來如果使用 k8s 來開發、部署,就可以讓他們完美的配合、溝通。不但之後可以再以這套基礎加上其他服務 (ex: 購物車),更能處理大量請求的尖峰時段。

關於 TECH FRESH 計畫

更多關於 TECH FRESH 實習生計畫,請大家持續關注官方部落格,歡迎讀者們參閱以下文章,更多的 FAQ 都已經整理在其中: