FlixTube 是一個根據微服務架構的影片平臺,採用 Azure Storage 作為外部儲存方案。前端使用 HTML5 影片元素播放影片,並透過 HTTP POST 請求將影片上傳至入口微服務。影片上傳流程涉及前端、入口微服務、影片上傳微服務和 Azure Storage 微服務之間的協作。前端使用 Fetch API 傳送影片檔案,入口微服務接收請求後轉發至影片上傳微服務,最後儲存至 Azure Storage。文章也說明瞭如何使用 Docker 和 Kubernetes 佈署 FlixTube,包含本地佈署、生產環境佈署的步驟和注意事項,以及如何使用相關工具管理和監控應用程式。此外,文章還探討瞭如何使用 Terraform 和 Azure CLI 建立和管理雲端基礎設施,為 FlixTube 的穩定執行提供基礎。
影片上傳微服務
影片上傳微服務負責處理影片上傳的業務邏輯。它會接收從入口微服務轉發過來的影片檔案,並將其儲存在外部雲端儲存中。在 FlixTube 的實作中,外部雲端儲存是由 Azure Storage 提供的。
Azure Storage 微服務
Azure Storage 微服務負責與 Azure Storage 互動,以安全地儲存和管理影片檔案。當影片上傳微服務將影片檔案轉發給 Azure Storage 微服務時,後者會將檔案儲存於 Azure Storage 中。
前端實作
前端的實作使用 HTML5 的影片元素來顯示串流影片。當使用者上傳了一個影片檔案後,前端會向入口微服務的 /api/video
路由傳送請求,以便在影片元素中顯示該影片。
程式碼實作
以下是前端程式碼的一個片段,展示瞭如何使用 fetch
函式透過 HTTP POST 請求上傳影片:
// chapter-10/gateway/public/js/upload.js
const uploadVideo = async (videoFile) => {
const response = await fetch('/api/video', {
method: 'POST',
body: videoFile,
});
// 處理回應
};
這段程式碼使用 fetch
函式向 /api/video
路由傳送一個 HTTP POST 請求,請求體中包含了使用者選擇的影片檔案。
網頁瀏覽器中的檔案上傳
當使用者透過網頁瀏覽器上傳檔案至FlixTube時,檔案會先被送到外部雲端儲存服務。以下是上傳檔案的流程圖:
flowchart TD A[使用者上傳檔案] --> B[網頁瀏覽器] B --> C[外部雲端儲存服務] C --> D[檔案儲存完成]
圖表翻譯:
此圖表描述了使用者上傳檔案的流程。首先,使用者上傳檔案至網頁瀏覽器,然後網頁瀏覽器將檔案送到外部雲端儲存服務,最後,檔案被儲存至雲端儲存服務中。
在FlixTube的前端程式碼中,我們使用了瀏覽器的fetch
函式來傳送HTTP請求。由於我們沒有使用Axios函式庫,所以我們選擇使用fetch
函式來簡化前端程式碼。
fetch("/api/upload", {
body: file,
method: "POST",
headers: {
"File-Name": file.name,
"Content-Type": file.type,
},
})
.then(() => {
//... 更新UI後上傳...
})
.catch((err) => {
//... 處理上傳錯誤...
});
內容解密:
在此程式碼中,我們使用fetch
函式來傳送HTTP請求至/api/upload
路由。請求體中包含了上傳的檔案,方法為POST,且包含了檔案名稱和型別的header。然後,我們使用then
方法來處理上傳成功的事件,並使用catch
方法來處理上傳錯誤的事件。
在閘道器程式碼中,我們使用了Express.js框架來處理HTTP請求。當收到上傳請求時,我們將請求轉發至影片上傳微服務。
app.post("/api/upload", (req, res) => {
const response = await axios({
method: "POST",
data: req,
responseType: "stream",
headers: {
//...
},
});
//...
});
內容解密:
在此程式碼中,我們使用Express.js框架來定義一個路由,當收到HTTP POST請求至/api/upload
路由時,我們將請求轉發至影片上傳微服務。請求方法為POST,請求體中包含了原始請求物件,且設定了responseType為stream。
上傳視訊檔案到微服務的實作
在實作上傳視訊檔案到微服務的功能時,我們需要進行以下幾個步驟:
步驟1:設定HTTP請求
首先,我們需要設定HTTP請求的方法為POST,並將檔案設定為請求體。同時,我們需要在請求頭中儲存檔案名稱和MIME型別。
app.post("/upload", async (req, res) => {
const fileName = req.headers["file-name"];
const videoId = new mongodb.ObjectId();
步驟2:轉發請求到視訊上傳微服務
接下來,我們需要轉發請求到視訊上傳微服務。這裡,我們使用axios函式庫來傳送HTTP請求。
const response = await axios({
method: "POST",
data: req,
responseType: "stream",
步驟3:處理上傳成功的事件
當上傳成功後,我們需要廣播一個訊息來通知其他微服務有一個新的視訊檔案可用。這裡,我們使用訊息佇列來實作這個功能。
//...
}).then(() => {
// 上傳成功,廣播訊息
console.log("video uploaded");
//...
步驟4:處理上傳失敗的事件
如果上傳失敗,我們需要捕捉錯誤並進行相應的處理。
//...
}).catch((error) => {
// 上傳失敗,處理錯誤
console.error(error);
//...
步驟5:儲存視訊檔案的資料
最後,我們需要儲存視訊檔案的資料到資料函式庫中。這裡,我們使用mongodb來儲存資料。
//...
const metadata = {
"content-type": req.headers["content-type"],
"file-name": req.headers["file-name"],
};
//...
完整的程式碼
以下是完整的程式碼:
app.post("/upload", async (req, res) => {
const fileName = req.headers["file-name"];
const videoId = new mongodb.ObjectId();
const response = await axios({
method: "POST",
data: req,
responseType: "stream",
});
response.data.pipe(res);
// 上傳成功,廣播訊息
console.log("video uploaded");
// 儲存視訊檔案的資料
const metadata = {
"content-type": req.headers["content-type"],
"file-name": req.headers["file-name"],
};
//...
});
內容解密:
- 在這個程式碼中,我們使用axios函式庫來傳送HTTP請求。
- 我們使用mongodb來儲存視訊檔案的資料。
- 我們使用訊息佇列來廣播訊息。
- 我們需要捕捉錯誤並進行相應的處理。
圖表翻譯:
flowchart TD A[上傳視訊檔案] --> B[設定HTTP請求] B --> C[轉發請求到視訊上傳微服務] C --> D[處理上傳成功的事件] D --> E[廣播訊息] E --> F[儲存視訊檔案的資料] F --> G[傳回結果]
圖表解說:
- 上傳視訊檔案:這是整個流程的起點。
- 設定HTTP請求:我們需要設定HTTP請求的方法為POST,並將檔案設定為請求體。
- 轉發請求到視訊上傳微服務:我們需要轉發請求到視訊上傳微服務。
- 處理上傳成功的事件:當上傳成功後,我們需要廣播一個訊息來通知其他微服務有一個新的視訊檔案可用。
- 廣播訊息:我們使用訊息佇列來實作這個功能。
- 儲存視訊檔案的資料:我們需要儲存視訊檔案的資料到資料函式庫中。
- 傳回結果:最終,我們需要傳回結果給使用者。
處理影片上傳的HTTP POST請求
當使用者上傳影片時,會觸發一個HTTP POST請求,該請求會被轉發到影片上傳微服務。以下是處理影片上傳的HTTP POST請求的步驟:
步驟1:定義HTTP POST路由處理器
首先,需要定義一個HTTP POST路由處理器來接收影片上傳請求。這個處理器會提取原始檔名從請求標頭,並建立一個唯一的ID для新的影片。
步驟2:轉發HTTP請求
接下來,HTTP請求會被轉發到影片儲存微服務。注意,影片上傳微服務不知道它是否正在與azure-storage或mock-storage微服務通訊。
步驟3:增加影片ID到標頭
在轉發HTTP請求之前,需要增加影片ID到標頭中。
步驟4:管道化請求
然後,需要管道化來自影片上傳微服務的回應到當前請求的回應中。
步驟5:廣播“影片上傳”訊息
最後,需要廣播一個“影片上傳”訊息,包含影片ID和檔名。
以下是相關程式碼:
headers: {
"content-type": req.headers["content-type"],
"id": videoId,
},
response.data.pipe(res);
broadcastVideoUploadedMessage({
id: videoId,
name: fileName
});
這些步驟確保了影片上傳的成功,並且影片被儲存到Azure Storage中。如果您想更深入地瞭解如何將檔案增加到Azure Storage,可以在Visual Studio Code中載入azure-storage微服務的完整index.js檔案。
佈署 FlixTube 到本地 Kubernetes
在嘗試將 FlixTube 佈署到雲端的生產 Kubernetes 叢集之前,我們應該先練習將其佈署到 Docker Desktop 附帶的本地 Kubernetes 例項。雖然我不會為開發或測試而以這種方式執行 FlixTube,因為使用 Docker Compose 啟動、重新啟動和關閉整個應用程式比使用 Kubernetes 容器更容易。但是,使用本地 Kubernetes 例項來練習佈署是值得的,這樣我們就可以在嘗試將其佈署到生產環境之前,先在一個簡單的環境中進行練習。
如果你渴望將 FlixTube 佈署到生產環境,可以跳過這一節。但請記住,佈署到本地 Kubernetes 例項比佈署到雲端的生產 Kubernetes 叢集要容易一些,所以如果你遇到困難,應該傳回這一節來練習你的佈署。
上傳影片到 Azure Storage
當使用者上傳影片時,FlixTube 會將影片儲存到 Azure Storage。以下是上傳影片的 HTTP POST 處理器:
app.post("/upload", async (req, res) => {
const videoId = req.headers.id;
const contentType = req.headers["content-type"];
const blobService = createBlobService();
const containerClient =
blobService.getContainerClient(STORAGE_CONTAINER_NAME);
await containerClient.createIfNotExists();
const blockBlobClient = containerClient.getBlockBlobClient(videoId);
await blockBlobClient.uploadStream(req);
await blockBlobClient.setHTTPHeaders({
blobContentType: contentType
});
res.sendStatus(200);
});
這個處理器從請求頭部提取影片 ID 和內容型別,然後建立一個 Azure Blob Service 使用者端。它檢查儲存容器是否存在,如果不存在則建立它。然後,它上傳影片到 Blob Storage,並設定 Blob 的 HTTP 專案。
佈署 FlixTube 到本地 Kubernetes
要佈署 FlixTube 到本地 Kubernetes,我們需要建立一個 Kubernetes 佈署組態檔案。以下是 deployment.yaml
檔案的內容:
apiVersion: apps/v1
kind: Deployment
metadata:
name: flixtube
spec:
replicas: 1
selector:
matchLabels:
app: flixtube
template:
metadata:
labels:
app: flixtube
spec:
containers:
- name: flixtube
image: <your-docker-image-name>
ports:
- containerPort: 3000
這個組態檔案定義了一個名為 flixtube
的佈署,具有 1 個複製品。它選擇具有 app: flixtube
標籤的 Pod,並定義了一個容器,使用你的 Docker 映象,並將容器連線埠 3000 暴露給外界。
執行佈署
要執行佈署,請執行以下命令:
kubectl apply -f deployment.yaml
這將建立一個名為 flixtube
的佈署,並啟動一個具有 1 個複製品的 Pod。
測試 FlixTube
要測試 FlixTube,請執行以下命令:
kubectl port-forward deployment/flixtube 3000:3000 &
這將轉發本地主機的 3000 連線埠到 Pod 的 3000 連線埠。然後,你可以使用 curl
或瀏覽器存取 http://localhost:3000
來測試 FlixTube。
圖表翻譯:
graph LR A[使用者] -->| 上傳影片 | B[FlixTube] B -->| 儲存影片 | C[Azure Storage] C -->| 傳回結果 | B B -->| 傳回結果 | A
這個圖表展示了使用者上傳影片到 FlixTube,然後 FlixTube 將影片儲存到 Azure Storage 的過程。
佈署 FlixTube 到本地 Kubernetes
在開始佈署 FlixTube 到本地 Kubernetes 之前,您需要確保已經安裝了 Docker Desktop 並啟用了 Kubernetes(請參考第 6 章,第 6.5 節)。這樣您就會自動獲得 kubectl
命令列介面工具,如果沒有,您需要單獨安裝它(請參考第 6 章,第 6.6 節)。如果您剛剛啟用了本地 Kubernetes,kubectl
應該已經連線到您的本地例項並準備就緒。如果您需要檢查連線或重新連線 kubectl
到您的本地 Kubernetes,請參考第 6 章,第 6.8.4 節。對於本地佈署,您不需要容器註冊中心。
本地佈署
在 chapter-10 的程式碼倉函式庫中提供了一個 shell 指令碼來進行本地 Kubernetes 佈署。您可以透過以下命令來呼叫它:
cd chapter-10/scripts/local-kub
./deploy.sh
對於 Windows 使用者,在這個階段,您需要使用 WSL2 Linux 終端,因為這些 shell 指令碼不會在普通的 Windows 終端下工作。
系統架構
以下是 FlixTube 佈署到本地 Kubernetes 的系統架構概覽:
- 開發電腦:您的本地機器,用於開發和佈署應用程式。
- Docker:用於封裝您的應用程式成容器。
- 本地 Kubernetes:您的本地 Kubernetes 叢集,用於佈署和管理容器化應用程式。
- 影片串流:FlixTube 的核心功能,負責串流影片內容。
- Mock-storage:模擬儲存系統,用於測試和開發目的。
- 影片上傳:允許使用者上傳影片內容到平臺。
- Metadata:管理和儲存影片的相關元資料。
- History:記錄使用者的觀看歷史。
- Gateway:作為入口,負責路由請求到適當的服務。
- Kubectl:Kubernetes 的命令列工具,用於管理和佈署應用程式到 Kubernetes 叢集。
內容解密:
上述指令碼 deploy.sh
負責佈署 FlixTube 到您的本地 Kubernetes 叢集。指令碼會自動建立必要的 Kubernetes 物件,如佈署、服務等,以便應用程式能夠正常執行。使用 kubectl
工具,您可以輕鬆地管理和監控您的應用程式。
圖表翻譯:
graph LR A[開發電腦] -->|封裝應用程式|> B[Docker] B -->|佈署到|> C[本地 Kubernetes] C -->|管理和路由|> D[Gateway] D -->|轉發請求|> E[影片串流] E -->|儲存影片|> F[Mock-storage] F -->|記錄元資料|> G[Metadata] G -->|記錄觀看歷史|> H[History]
這個 Mermaid 圖表展示了 FlixTube 在本地 Kubernetes 的佈署架構,從開發電腦開始,到封裝應用程式,佈署到本地 Kubernetes,然後管理和路由請求,最終到達影片串流和儲存。
佈署微服務到 Kubernetes
在本文中,我們將學習如何佈署微服務到 Kubernetes。首先,我們需要使用 kubectl
來佈署微服務到 Kubernetes。
佈署到本地 Kubernetes
首先,我們需要使用 kubectl
來佈署微服務到本地 Kubernetes。這可以透過以下步驟完成:
- 使用
docker build
命令來構建每個微服務的 Docker 映象。 - 使用
kubectl apply
命令來佈署每個微服務到 Kubernetes。 - 傳遞 YAML 檔案給
kubectl
來指定每個微服務的佈署組態。
以下是 shell 指令碼的範例:
# 使用 docker build 命令來構建每個微服務的 Docker 映象
docker build -t my-microservice.
# 使用 kubectl apply 命令來佈署每個微服務到 Kubernetes
kubectl apply -f deployment.yaml
測試本地佈署
佈署完成後,我們需要測試本地佈署是否正常工作。這可以透過以下步驟完成:
- 使用
kubectl get pods
命令來檢視 Kubernetes 資源是否已經建立並執行。 - 使用
kubectl get deploy
命令來檢視佈署組態是否正確。 - 使用
kubectl get services
命令來檢視服務是否已經建立並執行。
以下是範例輸出:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
my-microservice-75694b57c4-2r5k6 1/1 Running 0 10s
$ kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
my-microservice 1 1 1 1 10s
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-microservice NodePort 10.96.123.45 <none> 80:30080 10s
刪除本地佈署
當我們完成測試後,我們需要刪除本地佈署。這可以透過以下步驟完成:
- 使用
kubectl delete
命令來刪除每個微服務的佈署組態。 - 使用
kubectl delete
命令來刪除每個微服務的服務。
以下是範例命令:
# 刪除佈署組態
kubectl delete -f deployment.yaml
# 刪除服務
kubectl delete svc my-microservice
手動佈署到生產環境
在本文中,我們將學習如何手動佈署微服務到生產環境。首先,我們需要滿足以下條件:
- 容器登入倉函式庫:我們需要一個容器登入倉函式庫來發布 Docker 映象。
- Kubernetes 叢集:我們需要一個 Kubernetes 叢集來佈署微服務。
- 連線容器登入倉函式庫和 Kubernetes 叢集:我們需要連線容器登入倉函式庫和 Kubernetes 叢集,以便叢集可以提取映象。
以下是範例步驟:
- 建立容器登入倉函式庫:我們可以透過 Azure 入口網站 UI 或 Terraform 來建立容器登入倉函式庫。
- 建立 Kubernetes 叢集:我們可以透過 Azure 入口網站 UI 或 Terraform 來建立 Kubernetes 叢集。
- 連線容器登入倉函式庫和 Kubernetes 叢集:我們需要連線容器登入倉函式庫和 Kubernetes 叢集,以便叢集可以提取映象。
以下是範例命令:
# 建立容器登入倉函式庫
az acr create -n myregistry -g myresourcegroup -l westus
# 建立 Kubernetes 叢集
az aks create -n mycluster -g myresourcegroup -l westus
# 連線容器登入倉函式庫和 Kubernetes 叢集
az aks update -n mycluster -g myresourcegroup --attach-acr myregistry
佈署到生產環境
在本文中,我們將學習如何佈署微服務到生產環境。首先,我們需要使用 docker build
命令來構建每個微服務的 Docker 映象。然後,我們需要使用 docker push
命令來發布映象到容器登入倉函式庫。最後,我們需要使用 kubectl apply
命令來佈署每個微服務到 Kubernetes。
以下是範例命令:
# 使用 docker build 命令來構建每個微服務的 Docker 映象
docker build -t my-microservice.
# 使用 docker push 命令來發布映象到容器登入倉函式庫
docker push myregistry.azurecr.io/my-microservice
# 使用 kubectl apply 命令來佈署每個微服務到 Kubernetes
kubectl apply -f deployment.yaml
測試生產環境佈署
佈署完成後,我們需要測試生產環境佈署是否正常工作。這可以透過以下步驟完成:
- 使用
kubectl get pods
命令來檢視 Kubernetes 資源是否已經建立並執行。 - 使用
kubectl get deploy
命令來檢視佈署組態是否正確。 - 使用
kubectl get services
命令來檢視服務是否已經建立並執行。
以下是範例輸出:
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
my-microservice-75694b57c4-2r5k6 1/1 Running 0 10s
$ kubectl get deploy
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
my-microservice 1 1 1 1 10s
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-microservice LoadBalancer 10.96.123.45 <none> 80:30080 10s
建立雲端基礎設施
在建立雲端基礎設施時,我們有多種工具可供選擇,包括 Terraform、Azure 使用者介面以及 Azure CLI。這些工具可以幫助我們建立一個穩定且高效的雲端環境。
從系統架構的整體最佳化角度來看,FlixTube 的影片上傳流程,經由微服務拆分與容器化佈署,展現了良好的擴充套件性和彈性。透過入口微服務、影片上傳微服務和 Azure Storage 微服務的協同工作,有效地分離了關注點,提升了系統的維護性和可測試性。前端使用 HTML5 的影片元素和 Fetch API 簡化了上傳流程,同時後端利用 Express.js 和 Axios 進行高效的請求處理和轉發。
然而,微服務架構也引入了複雜性。跨服務的請求鏈路增加了除錯和追蹤的難度。此外,雖然程式碼範例中展示了上傳成功和失敗的處理邏輯,但缺乏更完善的錯誤處理機制和監控手段,例如針對網路中斷、儲存服務異常等情況的處理。此外,訊息佇列的運用雖提升了系統的非同步處理能力,但程式碼中並未詳細說明訊息格式和處理機制,這在實際開發中需要更明確的定義。
展望未來,FlixTube 可以考慮整合更進階的技術,例如 Service Mesh,來增強微服務之間的通訊管理和可觀測性。此外,匯入更全面的監控和日誌系統,可以更有效地追蹤系統執行狀態,並及時發現和解決潛在問題。從商業價值角度出發,FlixTube 可以藉由最佳化影片上傳流程和提升使用者經驗,進一步提升平臺的競爭力。對於重視長期穩定性的團隊而言,建議逐步完善錯誤處理、監控和日誌機制,並持續探索新技術,以確保 FlixTube 能夠應對未來的業務增長和技術挑戰。玄貓認為,隨著影片串流服務的持續發展,FlixTube 的架構演進將持續關注效能、可靠性和使用者經驗的提升。