在 Kubernetes 環境中,管理資料函式庫和其結構描述常常需要繁瑣的設定。本文將示範如何使用 Crossplane 的組合函式簡化這個流程。首先,我們利用 Go 範本函式根據複合資源的定義動態產生 AtlasSchema 資源,讓 Crossplane 能夠自動建立和管理資料函式庫結構描述。接著,我們引入 Auto-Ready 函式,它能自動偵測受管資源的狀態,並將其同步到複合資源,解決先前版本中複合資源狀態不同步的問題。透過這些技術,我們可以更有效率地管理資料函式庫,同時降低設定的複雜度。

透過組合函式擴充套件 Crossplane:資料函式庫與模式管理

在先前的設定中,我們成功將兩個資料函式庫(db-01 和 db-02)新增到伺服器。然而,目前存在一個問題,需要先離開 psql CLI 和容器才能解決。

追蹤 Claim 發現問題

透過執行 Claim 的追蹤,我們發現 SQL 複合資源的狀態顯示為「Creating」,即使資料函式庫資源實際上已經可用。這是因為 Go 範本函式無法提供資源的狀態,導致父資源無法正確判斷子資源的可用性。這個問題需要後續修正。

crossplane beta trace sqlclaim my-db --namespace a-team

輸出(已截斷):

NAME SYNCED READY STATUS
SQLClaim/my-db (a-team) True False Waiting: ...resource...
└─ SQL/my-db-rmwkj True False Creating: ...resources: my-db-...-db-01,\
my-db-...-db-02
├─ ResourceGroup/my-db-... True True Available
├─ FirewallRule/my-db-... True True Available
├─ Server/my-db-... True True Available
├─ Database/my-db-...-db-01 True True Available
├─ Database/my-db-...-db-02 True True Available
└─ ProviderConfig/my-db-... - -

整合 Atlas Operator 管理資料函式庫模式

為了讓 Crossplane 能夠管理資料函式庫模式,玄貓(BlackCat)使用 Atlas Operator。這個 Operator 已經透過設定指令碼佈署。

以下是如何更新 Composite Resource Definition 以支援模式管理:

apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: sqls.devopstoolkitseries.com
spec:
  ...
  versions:
  ...
  schema:
    openAPIV3Schema:
      type: object
      properties:
        spec:
          type: object
          properties:
            ...
        parameters:
          type: object
          properties:
            ...
            schemas:
              description: Database schema. Atlas operator...
              type: array
              items:
                type: object
                properties:
                  database:
                    description: The name of the database...
                    type: string
                  sql:
                    description: The SQL to apply.
                    type: string
                required:
                  - version
        required:
          - parameters

在這個定義中,玄貓(BlackCat)新增了一個名為 schemas 的陣列,用於儲存資料函式庫模式。每個模式物件包含 database 欄位(指定模式應套用的資料函式庫名稱)和 sql 欄位(包含 SQL 陳述式)。

套用更新後的 Composite Resource Definition:

kubectl apply --filename compositions/sql-v10/definition.yaml

修改 Composition 以應用 AtlasSchema

接下來,玄貓(BlackCat)修改了 Composition,以使用 Go 範本函式來應用 AtlasSchema 資源。

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: azure-postgresql
...
spec:
  ...
  pipeline:
  ...
  - functionRef:
    name: upbound-function-go-templating
    step: schema
    input:
      apiVersion: gotemplating.fn.crossplane.io/v1beta1
      kind: GoTemplate
      source: Inline
      inline: |
        {{ range .observed.composite.resource.spec.parameters.schemas }}
        ---
        apiVersion: kubernetes.crossplane.io/v1alpha1
        kind: Object
        metadata:
          name: {{ $.observed.composite.resource.spec.id }}-schema-{{ .database }}
          annotations:
            gotemplating.fn.crossplane.io/composition-resource-name: {{ $.observed.composite.resource.spec.id }}-{{ .database }}
        spec:
          providerConfigRef:
            name: {{ $.observed.composite.resource.spec.id }}-sql
          forProvider:
            manifest:
              apiVersion: db.atlasgo.io/v1alpha1
              kind: AtlasSchema
              metadata:
                name: {{ $.observed.composite.resource.spec.id }}-{{ .database }}
                namespace: {{ $.observed.composite.resource.spec.claimRef.namespace }}
              toFieldPath: spec.credentials.connectionSecretRef.namespace
              spec:
                credentials:
                  scheme: postgres
                  hostFrom:
                    secretKeyRef:
                      key: endpoint
                      name: {{ $.observed.composite.resource.spec.id }}
                  port: 5432
                  userFrom:
                    secretKeyRef:
                      key: username
                      name: {{ $.observed.composite.resource.spec.id }}
                  passwordFrom:
                    secretKeyRef:
                      key: password
                      name: {{ $.observed.composite.resource.spec.id }}
                database: {{ .database }}
                parameters:
                  sslmode: disable
                schema:
                  sql: "{{ .sql }}"
        {{ end }}

這個 Composition 新增了一個步驟,使用 Go 範本函式迭代 schemas 欄位中的所有專案。對於每個專案,它都會建立一個新的 Object 資源,該資源使用來自 Secret 的身份驗證資料來套用 AtlasSchemaschema 欄位使用在 Composite Resource Definition 中定義的 schemas[].sql 欄位填充。

套用更新後的 Composition:

kubectl apply --filename compositions/sql-v10/$HYPERSCALER.yaml

在 Claim 中指定模式

為了實際應用模式,玄貓(BlackCat)需要在 Claim 中指定它們。

以下是一個更新後的 Composite Claim 範例:

apiVersion: devopstoolkitseries.com/v1alpha1
kind: SQLClaim
...
spec:
  ...
  parameters:
    ...
    schemas:
      - database: db-01
        sql: |
          create table videos (
            id varchar(50) not null,
            description text,
            primary key (id)
          )

在這個範例中,玄貓(BlackCat)指定了一個模式,該模式將在 db-01 資料函式庫中建立一個名為 videos 的表。

為資料函式庫加入結構描述:組合函式

我們已經新增了一個包含一個專案的結構描述。資料函式庫 db-01 的 SQL 設定是用於建立 videoscomments 資料表。請不要對這些 create table 陳述式感到困惑。

Atlas Operator 會建立一個暫時的資料函式庫,建立這些資料表,然後將結構描述與「真實」的伺服器進行比較,並套用差異。在這個例子中,它會建立這兩個資料表。但如果之後我們修改其中一個資料表,或是新增一個資料表,它也會套用這些差異。這非常棒,建議您自行深入研究,或者觀看這個影片。

總而言之,一個結構描述會被套用到 db-01,而 db-02 則不會有結構描述,因為我們沒有指定任何結構描述。

讓我們套用修改後的複合宣告…

kubectl --namespace a-team apply \
--filename examples/$HYPERSCALER-sql-v10.yaml

…並檢索 atlasschemas。

kubectl --namespace a-team get atlasschemas

輸出如下(為了簡潔起見,已截斷):

NAME READY REASON
my-db-...-db-01 False GettingDevDB

我們可以看到 atlasschema 已經被建立。

我們可以透過建立一個包含 psql 客戶端的 Pod 來確認複合資源是否完成了它應該做的事情…

kubectl run postgresql-client --rm -ti --restart='Never' \
--image docker.io/bitnami/postgresql:16 \
--env PGPASSWORD=$PGPASSWORD --env PGHOST=$PGHOST \
--env PGUSER=$PGUSER --command -- sh

內容解密:

這段程式碼建立一個名為 postgresql-client 的 Pod,使用 bitnami/postgresql:16 映像檔。它設定了連線到 PostgreSQL 資料函式庫所需的環境變數,然後啟動一個 shell 供使用者互動。

…使用伺服器連線 psql…

psql --host $PGHOST -U $PGUSER -d postgres -p 5432

內容解密:

這行程式碼使用 psql 命令列工具連線到 PostgreSQL 資料函式庫。它使用先前設定的環境變數來指定主機、使用者名稱、資料函式庫名稱和連線埠。

…切換到 db-01 資料函式庫…

\c db-01

內容解密:

\cpsql 中的一個指令,用於變更目前連線的資料函式庫。在這個例子中,它將連線切換到 db-01 資料函式庫。

…並列出所有資料表。

\dt

輸出如下:

List of relations
Schema | Name | Type | Owner
--------+----------+-------+----------
public | comments | table | postgres
public | videos | table | postgres
(2 rows)

兩個資料表都已建立。

我們可以透過輸出 videos 資料表的結構描述來進一步確認。

\d videos

輸出如下:

Table "public.videos"
Column | Type | Collation | Nullable | Default
-------------+-----------------------+-----------+----------+---------
id | character varying(50) | | not null |
description | text | | |
Indexes:
"videos_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "comments" CONSTRAINT "fk_videos" FOREIGN KEY (video_id) REFERENCES videos\
(id)

我們可以看到 videos 資料表包含我們指定的欄位,並且它正在參考 comments 資料表。

一切似乎都運作正常,所以讓我們離開 psql…

exit

…以及 Pod。

exit

解決複合資源狀態的問題:Auto-Ready 函式

現在我們剩下一個問題要解決。我們需要讓複合資源理解透過 Go 樣板函式建立的受管資源的「真實」狀態。

讓我們再次追蹤複合宣告。

crossplane beta trace sqlclaim my-db --namespace a-team

輸出如下(為了簡潔起見,已截斷):

NAME SYNCED READY STATUS
SQLClaim/my-db (a-team) True False Waiting: ...resource claim is waiti\
ng...
└─ SQL/my-db-rmwkj True False Creating: ...y-db-...-db-02, and my\
-db-...-schema-db-01
├─ ResourceGroup/my-db-... True True Available
├─ FirewallRule/my-db-... True True Available
├─ Server/my-db-... True True Available
├─ Object/my-db-...-schema-db-01 True True Available
├─ ProviderConfig/my-db-...-sql - -
├─ Database/my-db-...-db-01 True True Available
├─ Database/my-db-...-db-02 True True Available
└─ ProviderConfig/my-db-... - -

我們可以看到,Database 以及包含結構描述的 Object 受管資源都是 Available,但 SQL 複合資源仍然認為這三個受管資源正在被建立 (Creating)。

玄貓認為,我們可以用幾種方式解決這個問題,其中一種方式是最簡單的。既然玄貓很懶,我們就選擇最簡單和最快的方式。我們將使用另一個組合函式。

這是套件資訊清單。

cat providers/function-auto-ready.yaml

輸出如下:

apiVersion: pkg.crossplane.io/v1beta1
kind: Function
metadata:
name: upbound-function-auto-ready
spec:
package: xpkg.upbound.io/crossplane-contrib/function-auto-ready:v0.2.1

這次我們新增了 function-auto-ready 函式,它有一個非常簡單的目的:自動偵測已準備好的組合資源,並更新它們的狀態。由於每個步驟中的函式都會收到(除其他事項外)之前步驟中組裝的所有組合資源,如果我們將該函式作為最後一個步驟,它就能夠評估到目前為止組裝的所有組合資源,並更新狀態。這是一個函式如何解決不一定像 Go 樣板那樣典型的任務的例子。

讓我們套用這個套件…

kubectl apply --filename providers/function-auto-ready.yaml

…並看看修改後的組合版本。

cat compositions/sql-v11/$HYPERSCALER.yaml

輸出如下(為了簡潔起見,已截斷):

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
...
spec:
...
pipeline:
...
- functionRef:
name: upbound-function-auto-ready
step: automatically-detect-ready-composed-resources

這很簡單。automatically-detect-ready-composed-resources 甚至沒有定義輸入。該函式不需要任何額外資訊,除了到目前為止組裝的所有組合資源的清單。每個函式都會收到它們,無論它們是否需要額外輸入。

讓我們看看它是否有效,方法是套用新版本的組合…

kubectl apply --filename compositions/sql-v11/$HYPERSCALER.yaml

…並追蹤宣告。

crossplane beta trace sqlclaim my-db --namespace a-team

玄貓總結:

這段內容涵蓋瞭如何使用 Crossplane 的組合函式來建立和管理資料函式庫結構描述,以及如何使用 function-auto-ready 函式來自動更新複合資源的狀態。透過這些技術,我們可以更輕鬆地管理複雜的雲端基礎架構,並確保資源的狀態與實際情況保持一致。

組合函式:開發更強大的 Crossplane 應用

在 Kubernetes 的世界裡,Crossplane 讓我們能夠以宣告式的方式管理雲端資源。為了進一步提升 Crossplane 的能力,我們可以利用組合函式(Composition Functions)。這些函式就像是樂高積木,讓我們能將複雜的組態邏輯拆解成可重用的模組。

從狀態觀察到自動偵測:組合函式的演進

在前一篇文章中,我們透過觀察資源的狀態來判斷 SQL 複合資源是否可用。現在,我們將更進一步,使用自動偵測函式(Auto-Detect Function)來自動將受管資源的狀態傳播到複合資源。

以下是 SQL 複合資源的狀態範例:

NAME SYNCED READY STATUS
SQLClaim/my-db (a-team) True True Available
└─ SQL/my-db-rmwkj True True Available
├─ ResourceGroup/my-db-... True True Available
├─ FirewallRule/my-db-... True True Available
├─ Server/my-db-... True True Available
├─ Object/my-db-...-schema-db-01 True True Available
├─ ProviderConfig/my-db-...-sql - -
├─ Database/my-db-...-db-01 True True Available
├─ Database/my-db-...-db-02 True True Available
└─ ProviderConfig/my-db-... - -

這次,SQL 複合資源的狀態是 Available。新加入的自動偵測函式正確地將受管資源的狀態傳播到複合資源。

組合函式如何運作?

我們在控制平面叢集佈署了三個函式:

  1. 修補與轉換函式(Patch and Transform Function): 用於執行修補和轉換操作。
  2. Go 範本函式(Go Templating Function): 用於執行 Go 範本。
  3. 自動就緒函式(Auto-Ready Function): 用於確保資源的狀態正確。

接著,我們應用了設定為以 Pipeline 模式執行的組合,包含四個步驟:

  1. 修補與轉換: 第一步使用修補與轉換函式來處理不需要特殊處理的資源。複合資源(XR)將所有資源傳送到此函式,函式會傳回修補後的相同資源。
  2. Go 範本: 第二步使用 Go 範本函式。它將範本傳送到此函式,該範本會疊代資料函式庫清單以及所有先前組裝的資源。此函式將資料函式庫新增到資源清單,並將所有資源傳回給複合資源。
  3. 修補與轉換(再次): 第三步再次使用修補與轉換函式。它將輸入(範本)與所有先前組裝的資源一起傳送,此函式將 Schema 新增到資源清單,並將所有資源傳回給複合資源。
  4. 自動就緒: 最後一步使用自動就緒函式,此函式沒有輸入,因此只會接收先前組裝的資源,並傳回具有正確狀態的資源。

執行完所有步驟後,每個步驟都會修改資源的狀態,複合資源(XR)會建立、更新或刪除受管資源(MR)。

組合函式:Crossplane 的核心動力

幾乎所有繁重的工作都由函式完成,而複合資源則作為 Pipeline 步驟的協調者,透過傳送輸入並預期資源作為輸出來呼叫函式。

封裝與推播組態包

現在我們已經完成了組合和複合資源定義的改進,接下來該將所有內容封裝並將新版本推播到 Registry,以便其他人可以輕鬆使用我們正在建構的 Database-as-a-Service 的改進版本。

但在建構套件之前,我們需要對上一章中建立的組態進行一些變更。

讓我們看看組態的更新版本。

apiVersion: meta.pkg.crossplane.io/v1
kind: Configuration
...
spec:
...
dependsOn:
...
- provider: crossplane/provider-sql
  version: ">=v0.5.0"
- function: xpkg.upbound.io/crossplane-contrib/function-patch-and-transform
  version: ">=v0.1.4"
- function: xpkg.upbound.io/crossplane-contrib/function-go-templating
  version: ">=v0.4.0"
- function: xpkg.upbound.io/crossplane-contrib/function-auto-ready
  version: ">=v0.2.1"
...

我們使用組態來定義它所依賴的 Provider。因此,每次我們佈署組態包時都會佈署這些 Provider。這些 Provider 被定義為 provider,我們應該對函式執行相同的操作。它們也是組態的依賴項。

將函式新增為依賴項與 Provider 相同。唯一的區別是我們需要使用 function 而不是 provider。這就是全部,所以讓我們建構一個新版本的組態包。

我不會詳細介紹後續步驟,因為它們與我們在上一章中探索的步驟相同。相反,我們將快速瀏覽已經知道的內容。

我們將進入包含組合、複合資源定義和組態的目錄,…

cd compositions/sql-v11

…並建構組態包。

crossplane xpkg build

接下來,我們將使用 Registry 使用者名稱建立 UP_USER 環境變數,…

export UP_USER=[...]

…登入,…

crossplane xpkg login --username $UP_USER

…推播套件,…

crossplane xpkg push xpkg.upbound.io/$UP_USER/dot-sql:v0.0.11

…從檔案系統中移除它,…

rm dot-sql-*.xpkg

…然後回到儲存函式庫的根目錄。

cd ../../

就是這樣。新版本的組態包已在 Registry 中,任何人都可以使用它。

我們改進了 Database-as-a-Service 的功能,而沒有增加終端使用者的複雜性,只是在複合資源定義中新增了一些額外的欄位。從使用者的角度來看,我們所做的事情都不相關。他們所要做的就是繼續建立、更新和刪除複合宣告。他們需要處理大約 10 行 YAML。複雜性增加了,但仍然是「隱藏的」。至少從建立宣告的終端使用者的角度來看,複雜性仍然是一個實作細節。

我們尚未探索如何建構自己的函式。到目前為止,我們使用的所有函式都是公開的。我們充當函式使用者,而不是函式建構者。

總有一天,沒有任何公開可用的函式能滿足我們的需求。當那一天到來時,我們會希望使用我們自己的邏輯來建構我們自己的函式。然而,那一天不是今天。

本章幾乎結束了。剩下的就是摧毀一切。

摧毀一切

你知道該怎麼做。

讓指令碼可執行,…

chmod +x destroy/04-functions.sh

…執行它,…

./destroy/04-functions.sh

待辦事項:快轉

…然後離開 Nix Shell。

exit

結束?

這不是結束。隨著 Crossplane 繼續發展,我將繼續為本章新增章節。如果你從 LeanPub 取得本章,你將收到下載本章更新版本的通知。從 Amazon 購買的電子書版本也應該如此。如果你從 Amazon 取得「死樹」(印刷)版本,那就是這個格式。但是,你可以在 LinkedIn 或 Twitter 上傳送訊息給我,我會回覆你,並提供從 LeanPub 免費下載電子書的連結(並在更新時收到通知)。

最後,請訂閱 https://youtube.com/@DevOpsToolkit。你可以在該頻道上找到源源不斷的影片,其中許多影片都與 Crossplane 相關。