無伺服器架構的核心價值在於簡化應用程式佈署和維運的複雜度,讓開發者更專注於業務邏輯的開發。這需要平台提供完善的觀察能力,以便追蹤應用程式效能瓶頸並快速診斷問題。同時,有效管理應用程式例項的生命週期,包含資源分配、初始化、啟動、服務、關閉和終止等環節,對於確保應用程式穩定性和成本效益至關重要。觀察能力的工具,例如日誌收集、分散式追蹤和效能分析,能幫助開發者深入瞭解應用程式行為,並識別潛在問題。無伺服器平台透過控制應用程式程式的生命週期,可以最佳化資源利用率,並根據需求自動擴充套件或縮減例項數量,從而提高效率並降低成本。
無伺服器架構的優勢與觀察能力
無伺服器(Serverless)架構不僅能為應用程式開發節省時間,還能為缺乏監控和可觀察性專業知識的團隊提供佈署保障。同樣,無伺服器基礎設施可能需要並希望在其管理的作業單元上實施應用程式追蹤。此追蹤服務有兩個不同的目的:
- 為基礎設施使用者提供調查和確定應用程式延遲來源的方法,包括平台引起的延遲和應用程式啟動延遲(如果適用)。
- 為基礎設施營運商提供有關底層平台瓶頸的豐富資訊,包括應用程式擴充套件和整體觀察到的延遲。
觀察能力的關鍵特性
其他常見的可觀察性功能包括日誌收集和聚合、效能分析和堆積疊追蹤。第10章將探討使用這些工具在即時短暫環境中除錯無伺服器應用程式的具體細節。透過控制相鄰環境(在某些情況下,還包括應用程式構建過程),無伺服器環境可以輕鬆地在應用程式程式旁邊執行可觀察性代理,以收集這些型別的資料。
圖表說明:無伺服器系統中的測量點
此圖示展示了無伺服器系統中可以實施的測量點。
圖表翻譯: 此圖表呈現了無伺服器架構中的請求流程與觀察能力實作。首先,使用者請求透過HTTP/3協定到達無伺服器閘道器,閘道器將請求轉換為HTTP/1.1協定後傳遞給應用程式例項。應用程式例項在執行過程中產生日誌和追蹤資料,分別被日誌收集系統和分散式追蹤系統捕捉。這些資料最終都被傳送到監控系統,用於後續的分析和預警。
管理輸入的最佳實踐
由於無伺服器環境為工作單元提供了基礎設施控制的入口點,因此基礎設施本身可以用來實施最佳實踐,以向外界公開服務。例如,自動組態TLS(包括支援的加密演算法和取得及輪換有效的憑證,如果需要的話)用於可能透過HTTPS或其他伺服器協定呼叫的無伺服器服務。將這些責任轉移到無伺服器層允許基礎設施提供者僱用專業團隊來確保遵循最佳實踐;然後,該團隊的工作在使用的所有無伺服器消費者之間攤銷。其他常見的功能可能超出“無差異的重複工作”,包括授權、策略執行和協定轉換。
圖表說明:輸入轉換
此圖示展示了Knative對輸入請求的轉換過程。
圖表翻譯: 此圖表呈現了Knative服務對外部請求的處理流程。外部請求透過複雜協定到達Knative服務,服務將請求轉換為簡化協定後再傳遞給應用程式。這樣的設計使得應用程式開發者可以選擇更廣泛的應用程式函式庫和程式語言。
管理流程生命週期
作為擴充套件和分發工作的一部分,無伺服器例項在管理應用程式程式的生命週期以及可能由平台本身產生的任何輔助程式方面發揮著積極作用。根據平台和飛行中的工作量,平台可能需要擱置(排隊)該工作,直到有例項可用來處理請求。這種情況被稱為冷啟動,即使已經有活動的應用程式例項,也可能發生(例如,突然湧入的工作可能超過已組態例項的容量)。一些無伺服器平台可能會選擇過度組態例項作為這些情況下的緩衝區,而其他平台可能會最小化額外例項的數量以降低成本。
無伺服器例項中的應用程式程式生命週期階段
- 佈置
在啟動程式之前,必須將例項分配給實際的伺服器節點。無伺服器平台會考慮以下幾個條件:
- 資源可用性
- 共用構件
- 鄰近性
- 競爭和對抗效應
def placement_decision(resource_availability, shared_artifacts, adjacency, contention):
"""
根據資源可用性、共用構件、鄰近性和競爭效應決定是否將例項分配給節點。
:param resource_availability: 資源可用性評估
:param shared_artifacts: 共用構件評估
:param adjacency: 鄰近性評估
:param contention: 競爭效應評估
:return: 是否分配例項給節點的布林值
"""
score = resource_availability + shared_artifacts + adjacency - contention
return score > threshold
#### 內容解密:
此函式根據多個因素計算一個分數,以決定是否將例項分配給特定的伺服器節點。資源可用性、共用構件和鄰近性對分數有正向貢獻,而競爭效應則會降低分數。只有當最終分數超過預設閾值時,才會將例項分配給該節點。
無伺服器運算的生命週期
無伺服器運算(Serverless Computing)是一種雲端運算模式,它允許開發者構建和執行應用程式而無需管理底層的基礎設施。無伺服器平台負責執行和擴充套件應用程式,開發者只需專注於撰寫程式碼。
1. 放置(Placement)
無伺服器平台的第一步是將應用程式例項放置在適當的節點上。這涉及將應用程式分配到不同的節點上,並確保它們能夠有效地分享資源。
放置的挑戰
- 資源爭用(Resource Contention):當多個應用程式爭用相同的資源時,可能會導致效能下降。
- 租戶排程(Tenancy Scheduling):在多租戶環境中,需要確保不同租戶之間的資源隔離,以防止安全漏洞。
2. 初始化(Initialization)
一旦例項被放置在節點上,就需要準備應用程式環境。這可能包括:
- 取得程式碼構件(Fetching Code Artifacts):如果程式碼構件尚未存在,則需要取得它們。
- 取得組態(Fetching Configuration):應用程式可能需要特定的組態資訊,包括例項級別或分享的秘密。
- 檔案系統掛載(Filesystem Mounts):一些無伺服器系統支援將分享檔案系統掛載到例項上,以管理分享資料。
- 網路組態(Network Configuration):新建立的例項需要向負載平衡器註冊,以便接收流量。
- 資源隔離(Resource Isolation):例項可能需要組態隔離機制,以確保應用程式使用公平的節點資源。
- 安全隔離(Security Isolation):在多租戶系統中,可能需要設定沙箱或輕量級虛擬機器,以防止使用者破壞鄰近的租戶。
- 輔助程式(Helper Processes):無伺服器環境可能提供額外的服務,例如日誌或指標收集、服務代理或身份代理。
- 安全策略(Security Policies):這些策略可能涵蓋入站和出站網路流量策略,以限制應用程式程式可以存取的網路服務。
3. 啟動(Startup)
一旦環境準備就緒,應用程式程式就會啟動。通常,應用程式必須執行一些設定和內部初始化,然後才能處理工作。
啟動階段的挑戰
- 冷啟動(Cold Start):對於某些語言實作,應用程式啟動階段可能是冷啟動延遲的主要原因。
4. 服務(Serving)
一旦應用程式程式指示它已準備好接收工作,它就會根據平台策略接收工作單元。一些平台限制了程式中正在進行的工作數量,而其他平台則允許多個工作項同時進行。
服務階段的最佳化
- 重用活動服務程式:重用活動服務程式有助於攤銷放置、初始化和啟動的成本,並減少應用程式經歷的冷啟動次數。
5. 關閉(Shutdown)
一旦應用程式程式不再需要,平台就會發出訊號,指示程式應該離開。平台可能會提供一些保證,例如:
- 排空(Draining):在發出終止訊號之前,例項將確保沒有工作單元正在進行。
- 優雅關閉(Graceful Shutdown):一些無伺服器平台可能會為正在執行的程式提供機會,在關閉之前執行某些操作,例如重新整理快取、更新快照或記錄最終的應用程式指標。
6. 終止(Termination)
一旦關閉訊號發出,並且任何優雅關閉期間都已過,程式將被終止,並且在初始化期間分配的所有輔助程式、安全策略和其他資源都將被清理。
從零開始設計無伺服器應用程式
要真正瞭解無伺服器應用程式開發的精髓,我們將從一個全新的應用程式開始設計——一個我們尚未撰寫任何程式碼的應用程式,並且可以充分利用無伺服器的優勢。在這個練習中,我們將建立一個狀態儀錶板應用程式。雖然這是一個相當簡單的應用程式,沒有複雜的讀寫和交易語義,但無伺服器的好處之一是它使得建立和佈署這些型別的應用程式變得非常容易。當啟動和執行應用程式的成本接近於零時,你往往會建立更多的小型“有用的”應用程式,因為這既簡單又有趣。
技術堆疊選擇
我們還將根據2023年可用的技術做出一些其他的選擇,以使本文中的範例盡可能廣泛地被接受和重複。為了簡化設定,我們在這些範例中避免使用資料函式庫;如果你決定對範例進行擴充,使用SQL資料函式庫或“鍵值儲存”中建議的鍵值儲存來新增儲存是一個很好的練習。具體來說,我們將從以下技術堆疊開始:
- 無伺服器執行時:本地安裝的Knative Serving
- UI提供者:網頁瀏覽器(HTML + JavaScript)
- UI框架:React
- 後端語言:Python
選擇Knative Serving的原因
我們使用本地安裝的Knative Serving是因為可以在本地Kubernetes叢集上執行Knative,而無需設定任何計費或合約。如果你更喜歡在託管的Kubernetes叢集上執行範例,大多數初始設定後的步驟應該保持相同。
本章設定
本章的所有檔案和指示都可以在GitHub上找到。每個部分對應於儲存函式庫的不同分支;如果您不熟悉git,每個部分將提供有關如何簽出適當分支的指示。
要快速開始使用本地(非生產!)Knative叢集,Knative專案已建立了kn quickstart命令。它可以使用kind工具自動設定本地Kubernetes叢集,然後自動安裝Knative。更詳細的安裝工具說明可在GitHub儲存函式庫中的SETUP.md檔案中找到。我們將安裝的工具如下:
- Docker
- kind
- kubectl
- kn和kn quickstart
- Node.js
Docker簡介
Docker提供了一個容器執行時;容器是一個包含執行應用程式所需的所有依賴項的軟體包。容器是Knative和Kubernetes的基本佈署工具;其他無伺服器解決方案通常內部構建類別似型別的工件,即使它們不使用容器作為公共格式。除了是容器執行時之外,Docker還提供了構建容器的工具。
# 使用Docker構建容器的範例
docker build -t my-app .
內容解密:
上述Docker命令用於構建一個名為my-app的容器映象。其中,-t引數指定了映象的名稱,.表示Dockerfile位於當前目錄。這個命令會根據Dockerfile中的指示構建一個包含應用程式及其依賴項的容器映象。
kind簡介
kind是一個在本地執行Kubernetes的工具。其名稱代表“Kubernetes in Docker”,它可以在本地Docker例項上設定和管理Kubernetes叢集。這對於測試和嘗試非常方便,尤其是在不需要持久資料的情況下。
kubectl簡介
kubectl是官方的Kubernetes命令列工具。kn quickstart使用kubectl在kind叢集建立後安裝Knative。你可能不需要直接使用kubectl,但如果你願意,可以使用kubectl管理Knative資源。kubectl還透過根據資源清單(一個包含資源定義的YAML檔案)宣告資源,使管理Kubernetes資源變得更加容易。
kn和kn quickstart簡介
kn是官方的Knative CLI。我們將在大多數範例中使用CLI,因為Kubernetes資源定義可能會變得難以管理,但需要注意的是,這裡沒有什麼神奇的地方——你可以自由地混合使用kn和kubectl。kn甚至支援將Kubernetes資源定義寫入檔案,以便稍後與kubectl一起使用。
Node.js簡介
如果你想跟隨前端構建和測試的命令,你需要一份Node.js來構建和執行React。(我們將使用Node.js命令下載和執行React以及其他依賴項,因此你不需要安裝任何React特定的東西。)
安裝工具
下載和安裝這些工具應該需要15到30分鐘。一旦你安裝了這些工具,你就可以執行範例2-1中的命令來建立一個叢集並安裝Knative。
範例2-1:Knative安裝
kn quickstart kind --registry
該命令應該會給出進度輸出:
- 取得Kubernetes映像
- 啟動Kubernetes
- 安裝Knative
- 等待Knative準備就緒
圖表說明
圖表翻譯:
此圖示展示了使用kn quickstart kind --registry命令安裝Knative的流程。首先,系統會取得Kubernetes所需的映像,接著啟動Kubernetes叢集,然後安裝Knative,最後等待Knative服務準備就緒。整個流程清晰地展示了從開始到結束的每一步驟。
設計單頁應用程式(SPA)與Knative整合
在前一章節中,我們已經成功地安裝了Knative,並驗證了其基本功能。本章節將著重於建立一個使用React框架的單頁應用程式(SPA),並將其佈署到Knative上。
建立React應用程式
首先,我們需要建立一個新的React應用程式。我們將使用create-react-app指令碼來完成這項任務。請執行以下命令:
npx create-react-app . --template typescript
npm install @mui/material @emotion/react @emotion/styled
內容解密:
npx create-react-app . --template typescript:使用create-react-app指令碼建立一個新的React應用程式,並使用TypeScript範本。npm install @mui/material @emotion/react @emotion/styled:安裝Material-UI函式庫及其相關依賴項,以用於UI設計。
接下來,我們將啟動React本地開發伺服器,以檢視我們的變更是否即時更新:
npm start
建立基本網頁UI
現在,我們將開始建立一個簡單的網頁UI。首先,我們需要替換src/App.tsx中的程式碼,如下所示:
import React from 'react';
import './App.css';
import { Button, Card, CardActionArea, CardActions, CardContent, CardMedia, Container, CssBaseline, Grid, ThemeProvider, createTheme } from '@mui/material';
function App() {
const imgUrl = 'https://knative.dev/docs/images/logo/rgb/knative-logo-rgb.png';
return (
<ThemeProvider theme={createTheme({})}>
<CssBaseline enableColorScheme />
<Container maxWidth={false}>
<Grid container justifyContent='center' alignItems='center' spacing={2}>
<Grid item xs={6}>
<Card>
<CardActionArea>
<CardMedia component='img' alt='Knative logo' image={imgUrl} />
<CardContent>
<h2>第一個專案</h2>
一些資訊
</CardContent>
</CardActionArea>
<CardActions>
<Button size='small'>取得資訊</Button>
</CardActions>
</Card>
</Grid>
</Grid>
</Container>
</ThemeProvider>
);
}
export default App;
內容解密:
- 我們從
@mui/material匯入所需的元件,以建立Material-UI風格的UI。 - 使用
ThemeProvider和createTheme來設定主題。 CssBaseline用於重置CSS樣式。Container和Grid用於佈局。Card、CardActionArea、CardMedia、CardContent和CardActions用於建立卡片元件。Button用於建立按鈕。
封裝應用程式
要將我們的應用程式佈署到Knative,我們需要將其封裝成容器映像檔。這將包括以下內容:
- 應用程式原始碼(JavaScript依賴項、樣式、圖片和App.tsx檔案)
- Node.js執行環境
- 支援Node.js的Linux工具和函式庫
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title 無伺服器架構觀察能力與生命週期管理
package "資料視覺化流程" {
package "資料準備" {
component [資料載入] as load
component [資料清洗] as clean
component [資料轉換] as transform
}
package "圖表類型" {
component [折線圖 Line] as line
component [長條圖 Bar] as bar
component [散佈圖 Scatter] as scatter
component [熱力圖 Heatmap] as heatmap
}
package "美化輸出" {
component [樣式設定] as style
component [標籤註解] as label
component [匯出儲存] as export
}
}
load --> clean --> transform
transform --> line
transform --> bar
transform --> scatter
transform --> heatmap
line --> style --> export
bar --> label --> export
note right of scatter
探索變數關係
發現異常值
end note
@enduml
圖表翻譯: 此圖示展示了建立容器映像檔的過程。應用程式原始碼、Node.js執行環境和Linux工具和函式庫都被封裝到容器映像檔中。
下一章節中,我們將繼續探討如何將我們的應用程式佈署到Knative上。