本文介紹了如何使用開源Backstage構建自己的開發者門戶,并基于此實踐平臺工程。本系列共兩篇文章,這是第二篇。原文: Platform Engineering: Building Your Developer Portal with Backstage — Part 2

在本教程第一部分中我們了解了Backstage這個用于構建開發者門戶的開源CNCF工具,還創建了一個軟件模板,用于在GitHub中為引導項目/存儲庫構建默認安全的軟件組件。
本文將繼續開發這一開發者門戶,并將其帶到下一個層次。
1. 使用PostgreSQL數據庫
1.1. Backstage數據庫
在本教程第一部分中,我們了解到Backstage由前端和后端兩部分組成。
如果稍微用一下創建的門戶,就會發現一旦重新啟動yarn dev服務器,之前導入的組件將不再存在。
這是因為Backstage后端(及其插件)需要數據庫來存儲其狀態。
注: Backstage主要針對兩個數據庫進行了測試,分別是SQLite(主要用作內存中的模擬/測試數據庫)和PostgreSQL(首選的生產數據庫)。其他數據庫,如MySQL之類,據說可以工作,但沒有經過完整測試。
因此,接下來我們將配置Backstage使用PostgreSQL數據庫。
1.2. 安裝和配置PostgreSQL
注: 如果已經安裝了 PostgreSQL 服務器并創建了schema和用戶,可以跳過這些說明。例如,你可能已經在Linux服務器上通過apt-get安裝了PostgreSQL,或者你可能在Docker容器甚至云數據庫服務中運行PostgreSQL。
下面的例子是針對Mac用戶的。如果你不用Mac進行開發,PostgresSQL官網[1]有關于如何安裝PostgreSQL的詳細說明。
使用brew安裝:
brew?install?postgresql@14
啟動PostgreSQL并在登錄時重新啟動,運行:
brew?services?start?postgresql@14
如果需要停止/重啟,可以執行如下命令:
brew?services?stop?postgresql@14
brew?services?restart?postgresql@14
運行psql postgres
命令登錄Postgres shell,應該可以看到歡迎的交互式命令行,如下所示:
tiexin@mbp?~/work/my-portal?$?psql?postgres
psql?(14.8?(Homebrew))
Type?“help”?for?help.
postgres=#
在本教程中,我們將創建用戶"backstage",密碼為"backstage",作為超級用戶。請注意,這只適用于本地開發,而不適用于生產:
postgres=#?create?user?backstage?with?encrypted?password?‘backstage’;
CREATE?ROLE
postgres=#?alter?role?backstage?with?superuser;
ALTER?ROLE
1.3. 配置Backstage使用PostgreSQL
進入開發者門戶目錄的根目錄,使用以下命令啟動PostgreSQL客戶端安裝:
yarn?add?—?cwd?packages/backend?pg
然后再次打開配置文件app-config.yaml
并更新backend.database
部分:
backend:
??database:
????client:?pg
????connection:
??????host:?127.0.0.1
??????port:?5432
??????user:?backstage
??????password:?backstage
注1: PostgreSQL的默認端口是5432或5433,如果本地安裝,主機名可以是127.0.0.1。
注2: 上面的示例使用了前一步中的連接細節。如果使用已存在的PostgreSQL數據庫,請相應地更新主機/端口/用戶/密碼信息。
注3: 一般來說,不建議在配置文件中使用連接詳細信息,因為包含用戶名和密碼等敏感信息。對于生產環境,可以從環境變量中讀取信息(使用Helm chart部署到Kubernetes,并使用Kubernetes secrets存儲這些敏感信息)。例如:
backend:
??database:
????client:?pg
????connection:
??????host:?${POSTGRES_HOST}
??????port:?${POSTGRES_PORT}
??????user:?${POSTGRES_USER}
??????password:?${POSTGRES_PASSWORD}
更新配置后,可以啟動開發者門戶:
yarn?dev
當Backstage完全啟動后,添加一個新組件并保存在數據庫中,以供測試:
-
使用教程第一部分中的模板來引導一個版本庫; -
重新啟動yarn服務器; -
進入軟件目錄,檢查創建的組件是否仍然存在(持久化在DB中)。
2. Backstage插件介紹
Backstage是由一組插件組成的單頁應用,通過插件實現的功能使開發者門戶更強大,可以滿足特定需求。請參見下面的架構圖:

在創建門戶之后,默認情況下已經有了一些核心功能,比如:
-
軟件目錄 -
軟件模板 -
文檔 -
搜索功能
實際上,這些默認/標準的核心功能都是由插件提供的,只是當我們啟動開發者門戶時,Backstage已經默認啟用了。
有了這些核心功能/插件,我們的開發者門戶已經相當強大,能夠顯示 CI/CD 狀態和文檔,并瀏覽軟件目錄。不過,有了插件,就能讓開發者門戶網站更上一層樓。
插件可以是開源和可重用的,也可以是特定于某個公司的,甚至可以根據特定需求創建自定義插件,訪問Backage官方網站[2]可以獲得所有現有插件的概述。目前已經有了相當多的插件,其中許多是CI/CD工具,如Circle CI, Buildkite, Argo CD, Go CD等,所以無論使用哪種CI/CD工具鏈,都可以將其集成到開發者門戶中。
3. 創建插件
因為Backstage有前端和后端,可以為前端和后端創建插件。
3.1. 前端
要創建前端插件,確保已經運行了yarn install并安裝了依賴項,然后在開發者門戶目錄的根目錄下運行以下命令:
yarn?new?—?select?plugin
例如,我們可以在這里將插件命名為"my-plugin"。
根據提供的 ID 創建新的 Backstage 插件,插件將自動生成并添加到 Backstage 前端應用程序中。
要開發前端插件,需要一些TypeScript和React的知識。然而,即使你不是TypeScript/React開發人員,也不難上手,因為上面的命令引導了一個帶有基本代碼和模擬數據的樣例插件。
例如,如果你將插件命名為"my-plugin",在啟動yarn dev服務器后,可以訪問http://localhost:3000/my-plugin
并查看結果。
可以對菜單/導航欄進行一些定制,也可以編輯packages/app/src/components/Root/Root.tsx
實現定制,向下滾動到代碼的Root
部分:
export?const?Root?=?({?children?}:?PropsWithChildren<{}>)?=>?(
??<SidebarPage>
????<Sidebar>
??????<SidebarLogo?/>
??????<SidebarGroup?label="Search"?icon={<SearchIcon?/>}?to="/search">
????????<SidebarSearchModal?/>
??????</SidebarGroup>
??????<SidebarDivider?/>
??????<SidebarGroup?label="Menu"?icon={<MenuIcon?/>}>
????????{/*?Global?nav,?not?org-specific?*/}
????????<SidebarItem?icon={HomeIcon}?to="catalog"?text="Home"?/>
????????<SidebarItem?icon={ExtensionIcon}?to="api-docs"?text="APIs"?/>
????????<SidebarItem?icon={LibraryBooks}?to="docs"?text="Docs"?/>
????????<SidebarItem?icon={CreateComponentIcon}?to="create"?text="Create..."?/>
????????{/*?End?global?nav?*/}
????????<SidebarDivider?/>
????????<SidebarScrollWrapper>
??????????<SidebarItem?icon={MapIcon}?to="tech-radar"?text="Tech?Radar"?/>
????????</SidebarScrollWrapper>
??????</SidebarGroup>
??????<SidebarSpace?/>
??????<SidebarDivider?/>
??????<SidebarGroup
????????label="Settings"
????????icon={<UserSettingsSignInAvatar?/>}
????????to="/settings"
??????>
????????<SidebarSettings?/>
??????</SidebarGroup>
????</Sidebar>
????{children}
??</SidebarPage>
);
這里可以看到側邊欄頁面,我們可以添加一個側邊欄項目,指定圖標,以及應該鏈接到哪個 URI。
然而,如果我們更深入的研究生成的插件代碼,在生成的文件plugins/my-plugin/src/components/ExampleFetchComponent/ExampleFetchComponent.tsx
中,它返回模擬數據,而不是通過API獲取的數據:
export?const?ExampleFetchComponent?=?()?=>?{
??const?{?value,?loading,?error?}?=?useAsync(async?():?Promise<User[]>?=>?{
????//?Would?use?fetch?in?a?real?world?example
????return?exampleUsers.results;
??},?[]);
??if?(loading)?{
????return?<Progress?/>;
??}?else?if?(error)?{
????return?<ResponseErrorPanel?error={error}?/>;
??}
??return?<DenseTable?users={value?||?[]}?/>;
};
在真實環境中,這里是調用API從后端獲取數據以顯示在插件中的地方。接下來,讓我們快速瀏覽一下后端插件。
3.2. 后端
新的后端插件包(但是是空的,不像前端插件帶有樣例代碼)可以通過在開發者門戶根目錄中執行以下命令來創建:
yarn?new?—?select?backend-plugin
類似的,需要為后端插件提供一個名稱,就像我們在前一節為前端插件所做的那樣。
值得注意的是,為了簡單的開發目的,可以在獨立模式下啟動后端插件:
cd?plugins/plugin-name
yarn?start
這將啟動一個監聽7007端口的開發服務器,直接帶有一個健康檢查端點,這樣你就可以:
curl?localhost:7007/plugin-name/health
這應該返回{"status":"ok"}
。
然而到目前為止,新創建的后端插件還沒有做任何事情。你需要編輯src/service/router.ts
添加路由,并將其連接到將要實現的實際底層功能。
值得注意的是,后端提供了用于SQL數據庫訪問的內置功能,以滿足持久化需求,還可以檢索登錄用戶的身份,如果希望向不同用戶顯示不同數據,這就能派上用場。
4. 生產部署
我們已經介紹了平臺工程/開發者門戶、核心特性、數據持久化和插件(以及創建它們)的概念。我們有所有工具,可以建立特定的、定制化的開發者門戶,以滿足我們的需求。
接下來,我想討論一下在生產環境中部署開發者門戶的問題。
4.1. 面向Docker的主機構建
更快的方法是在Docker之外構建大部分內容,然后將包放在Docker鏡像中,因此稱為"主機構建"。優點是這幾乎總是更快的方法,因為構建步驟在主機上執行得更快,并且可以更有效緩存主機上的依賴項,其中單個更改不會破壞整個緩存。
為了在主機上構建,我們首先使用yarn install
安裝依賴項,然后用yarn tsc
生成類型定義,然后使用yarn build:backend
構建后端包。
在我們創建開發者門戶時已經提供了Dockerfile,位于packages/backend/Dockerfile
,我們可以用這個Docker鏡像來使用我們的主機構建包。
4.2. 多階段構建
有時候,CI運行在Docker中,因此主機構建的docker-in-docker方法可能不適合。另外,也許你不想像照顧寵物(而不是家畜)那樣維護基礎設施,所以實際上你可能更喜歡在Docker中構建所有內容,即使有時可能比主機構建慢。
為此,我們需要使用Docker多階段構建并創建自己的Dockerfile。以下是每個階段需要做的事情:
-
階段1: 創建yarn安裝層,例如git clone,然后將包和插件復制到該層。 -
階段2: 安裝依賴項并運行yarn build。依賴項可能包括: libsqlite3-dev, python3, build-essential,與主機構建部分類似。 -
階段3: 與上一節中的Docker鏡像相同,使用上一階段構建的包構建實際的后端鏡像。
參考Backstage的多階段Docker構建示例:https://backstage.io/docs/deployment/docker#multi-stage-build[3]。
4.3. 將前端與后端分離
在本教程中,當我們運行yarn dev
時,只依賴于yarn dev服務器,并且這個命令啟動兩個服務器,一個服務于前端單頁應用,另一個服務于后端。
無論是使用主機構建還是多階段構建,docker 鏡像都會將前端和后端構建到同一個 Docker 中。
你可能已經猜到我要干嘛了,對于生產開發,有時需要將前端與后端分開提供服務,要么從一個單獨的Docker鏡像,要么例如在帶有CDN的靜態文件服務器(技術上,CDN也可以與Docker容器一起工作)。
為此,我們希望將前端與后端分開。例如,靜態前端文件可以在AWS S3中作為靜態文件服務器,然后在S3 bucket前使用CloudFront作為CDN。對于后端,可以將其部署在k8s Pod中,并使用Ingress公開服務。
為了分離前端,需要刪除packages/backend/src/plugins/app.ts
(并從packages/backend/src/index.ts
中刪除相應的導入),并從packages/backend/packages.json
中刪除@backstage/plugin-app-backend
(它為后端捆綁前端,為前端提供服務,并將前端配置注入到應用中)。
4.4. Kubernetes 部署
現在可以使用Helm chart將后端鏡像部署到Kubernetes。
Github上有一個社區Helm charts[4],通過設置值并傳遞自己構建的Docker鏡像,可以將開發者門戶部署到Kubernetes集群。
默認情況下,這個Helm charts不安裝PostgreSQL,因為在生產環境中,很可能希望單獨管理數據庫。例如,如果在云服務提供商中運行基礎設施,可以使用Terraform將數據庫作為服務來管理,以便在為開發者門戶運行Helm install之前創建PostgreSQL數據庫。
但是,如果愿意的話,上面的Helm charts也可以使用PostgreSQL作為依賴項,并在k8s中同時部署數據庫和門戶,在這種情況下,需要選擇正確的PersistentVolume存儲類型,例如,作為云卷或網絡附加存儲(任何比Kubernetes節點的臨時存儲更持久的存儲)。
你可能還希望選擇Igress類,以便在內部或外部公開服務。
總結
在這個平臺工程迷你系列中,首先介紹了平臺工程的概念以及平臺工程和 DevOps 之間的區別。然后,我們通過實踐教程介紹了構建開發者門戶的工具(Backstage),以及如何使用該工具創建開發者門戶、構建軟件目錄和創建軟件模板。最后學習了如何持久化保存開發者門戶網站的數據、如何為其添加更多功能以及如何將其部署到生產環境中。
這只是一個開始,還可以做很多其他事情,例如:
-
添加持續部署插件,例如,從Argo CD直接在開發者門戶中顯示部署歷史和狀態; -
將Kubernetes集成到門戶中,這樣在每個組件中,可以直接看到k8s中部署的應用,而無需運行kubectl命令或打開k8s儀表板; -
添加更多功能,比如將secrets管理器作為插件集成到開發者門戶,這樣就可以查看secrets列表,創建secrets,甚至顯示每個組件中使用的secrets; -
將7×24支持的日程安排甚至警報集成到門戶中; -
更重要的是: 可以決定在門戶中需要什么,構建該插件并集成,以便可以作為查看所有內容的單一入口,為開發團隊增加價值。
你好,我是俞凡,在Motorola做過研發,現在在Mavenir做技術工作,對通信、網絡、后端架構、云原生、DevOps、CICD、區塊鏈、AI等技術始終保持著濃厚的興趣,平時喜歡閱讀、思考,相信持續學習、終身成長,歡迎一起交流學習。為了方便大家以后能第一時間看到文章,請朋友們關注公眾號"DeepNoMind",并設個星標吧,如果能一鍵三連(轉發、點贊、在看),則能給我帶來更多的支持和動力,激勵我持續寫下去,和大家共同成長進步!
PostgreSQL Install Guide: https://www.postgresql.org/download
[2]Backstage Plugins: https://backstage.io/plugins
[3]Backstage Multi Stage Build for Docker: https://backstage.io/docs/deployment/docker#multi-stage-build
[4]Backstage Helm Charts: https://github.com/backstage/charts/tree/main/charts/backstage
本文由 mdnice 多平臺發布