本系列文章已來到了尾聲,在過程中我們學習如何建構服務功能,使用模組套件與工具,最後我們要來學習如何選擇架構以及部署微服務。
部署之前,我們需要知道 Moleculer 框架可以支援哪些應用程式架構。
在本系列開始的時候,我們提到了我們熟悉的單體式系統,而 Moleculer 框架也支援這種架構模式。在單體式架構中,每個服務都像是單體一樣,在單一個節點上運作。不會有網路延遲問題,不需要 Transporter ,直接在本地呼叫是最快的。這種架構也可以應用在單機軟體,例如將服務直接內嵌到 WebView2[3] 架構,讓使用者可以直接離線使用。
Fig. 1. 單體式架構圖
當所有的服務都在單一個節點上運作,並且透過 Transporter 來進行通訊時,這就是一種典型的微服務架構。在這種架構下,網路延遲問題是肯定會發生的,但是你的服務能夠依賴容錯機制,而且可以自行擴充服務來解決此問題。
Fig. 2. 微服務架構圖
混合式架構結合了單體式架構與微服務架構的優勢,它會在同一個節點下運行關聯性高的服務,依循此規則來建立多個節點。例如 post
服務經常需要請求 user
、 comments
服務,這個時候就會將它們放在同一個節點上,如此一來就能降低服務間的網路延遲。如果 user
節點超過請求負荷,你只要透過微服務的特性來擴展它。
Fig. 3. 混合式架構圖
ServiceBroker 會優先嘗試向本地服務請求來減少網路延遲,但你也可以在配置檔中的
registry
屬性設定關閉此功能preferLocal: false
。
我們已經學習了 Moleculer 框架支援的各種架構,接下來我們可以使用 moleculer-runner 與 Docker[3] 來部署多個容器,容器化的微服務能夠使系統更快的部署且方便管理。透過 moleculer-runner 的好處是它可以讀取 Docker 部署時環境變數。
以下的範例來自於 Moleculer 的 project 樣板。
使用 Dockerfile 來建立 Moleculer 服務啟動腳本。
FROM node:current-alpine
ENV NODE_ENV=production
RUN mkdir /app
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install --production
COPY . .
CMD ["npm", "start"]
使用 Docker compose 檔案來建立並執行 Moleculer 服務,並啟動 mongo 、 NATS 及 traefik[4] 服務。
設定所需的環境變數。
docker-compose.env
NAMESPACE=
LOGGER=true
LOGLEVEL=info
SERVICEDIR=services # 設定本地服務目錄
TRANSPORTER=nats://nats:4222 # 設定所有容器的 Transporter
MONGO_URI=mongodb://mongo/project-demo # 設定 MongoDB URI
容器配置。
docker-compose.yml
version: "3.3"
services:
api:
build:
context: .
image: project-demo
env_file: docker-compose.env
environment:
SERVICES: api # 這個容器中的 Moleculer Runner 只會啟動 'api' 服務
PORT: 3000 # API 閘道器連接埠
depends_on:
- nats
labels:
- "traefik.enable=true"
- "traefik.http.routers.api-gw.rule=PathPrefix(`/`)"
- "traefik.http.services.api-gw.loadbalancer.server.port=3000"
networks:
- internal
greeter:
build:
context: .
image: project-demo
env_file: docker-compose.env
environment:
SERVICES: greeter # 這個容器中的 Moleculer Runner 只會啟動 'greeter' 服務
depends_on:
- nats
networks:
- internal
products:
build:
context: .
image: project-demo
env_file: docker-compose.env
environment:
SERVICES: products # 這個容器中的 Moleculer Runner 只會啟動 'products' 服務
depends_on:
- mongo
- nats
networks:
- internal
mongo:
image: mongo:4
volumes:
- data:/data/db
networks:
- internal
nats:
image: nats:2
networks:
- internal
traefik:
image: traefik:v2.1
command:
- "--api.insecure=true" # 不安全模式[5] ,請不要在生產環境使用
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
ports:
- 3000:80
- 3001:8080
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- internal
- default
networks:
internal:
volumes:
data:
啟動容器。
$ docker-compose up -d
你可以由 http://<docker-host>:3000/
來瀏覽你的應用。也可以由 http://<docker-host>:3001/
來進入 Traefik 儀表板。
Moleculer 社群仍在努力建立 Kubernetes[7] 部署的解決方案[8] ,你可以參考以下範例:
在開發全新的系統時,你可能會面臨單體式與微服務的抉擇,你可能會因為單體式系統容易開發而選擇它,也可能因為微服務的靈活性而計畫使用它。
Moleculer 官方手冊中建議,使用 Moleculer 的話,可以先不用擔心這個問題,只要在開發時期先以單體式架構開發,將所有的服務都放在單一節點,就能快速的測試你的程式邏輯。開發完成後,只需要將服務部署到單一節點即可。當系統逐漸長大後,你不需要修改任何程式,只需要建立一個 Transporter ,把每個服務都部署到單一節點上即可,這時候就會是微服務架構。
筆者並不完全認同此說法,微服務在程式架構規劃上較為複雜,而開發時程也相對較長,如果你不清楚業務邏輯而規劃錯誤,可能會比使用單體式架構還差。但不可否認的是 Moleculer 使用上相當容易,筆者認為非常適合新手入門,假如你的應用非常簡單,開發上也沒有太大的時程壓力,那不妨試試看這套相對容易上手的微服務框架吧。
[1] Clustering, https://moleculer.services/docs/0.14/clustering.html
[2] Deploying, https://moleculer.services/docs/0.14/deploying.html
[3] Microsoft Edge WebView2, https://developer.microsoft.com/en-us/microsoft-edge/webview2/
[4] Docker, https://www.docker.com/
[5] Traefik proxy, https://traefik.io/traefik/
[6] Traefik Insecure Mode, https://doc.traefik.io/traefik/operations/dashboard/#insecure-mode
[7] Kubernetes, https://kubernetes.io/
[8] Kubernetes deployment in Docs, https://github.com/moleculerjs/moleculer/issues/512
[9] step by step tutorial, Dan Kuida, https://dankuida.com/moleculer-deployment-thoughts-8e0fc8c0fb07
[10] code samples, lehno, https://github.com/lehno/moleculer-k8s-examples
[11] deployment guide, https://gist.github.com/tobydeh/0aa33a5b672821f777165159b6a22cc5