使用 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 |
2.1. 設計思路
-
使用者會先透過 ingress 進入到 k8s cluster 內的會員註冊網站,並且經由後端傳送註冊會員的資料到
Users API
寫入資料庫中。 -
使用者就能透過 LINE App 發送訊息到 LINE,而 LINE 再發送 webhook event 一樣通過 ingress 給我們的
webhook
處理,webhook
再與Users API
詢問是否該 LINE UID 為會員並做相對應的處理。 -
有個 CronJob (
push-msg
) 會自動定期推播訊息給會員。
系統架構圖大概會長這樣:
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 . | k 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 處):
6. 總結
使用 k8s 來開發較為龐大的系統可以大大的減少維護成本,例如當有問題發生時,可以利用 microservice 的優點,快速的排查問題原因,提升 debug 效率。
現在的 chatbot 基本上都沒有身份驗證的功能,因此需要開發者自己維護一個會員系統,會員系統又包含了註冊、登入等等服務,如此一來如果使用 k8s 來開發、部署,就可以讓他們完美的配合、溝通。不但之後可以再以這套基礎加上其他服務 (ex: 購物車),更能處理大量請求的尖峰時段。
Comments