前一篇讓 Operator 回報 Todo API 的新版是否就緒。不過,要更新版本,開發者仍得先準備 Microservice YAML。假設這次只是換一個 image,服務名稱、Namespace 和 port 都沒變,還需要每次重新填寫整份設定嗎?
Day 17 介紹過 Backstage 的 Software Catalog(軟體目錄)與 Software Templates(軟體範本):Catalog 讓我們找到服務與負責團隊,Templates 則收集輸入、執行指定的工作。今天集中在後者,替 todo-api 準備一個換版模板,讓開發者只填 CI 產出的 digest,再由模板產生 Microservice 設定。
既然要減少重複填寫,我們先把這次不會改變的值固定下來:服務是 todo-api,Dev 沿用既有的 todo Namespace,port 是 8080,image repository 是 ghcr.io/yrw9281/it30-todo-api。唯一要從表單取得的,就是新版 digest。
將這些值寫進 microservice.yaml,在 digest 的位置留下變數,這份檔案就能重複用來產生每次換版的設定:
apiVersion: platform.example.io/v1alpha1
kind: Microservice
metadata:
name: todo-api
namespace: todo
spec:
image: ghcr.io/yrw9281/it30-todo-api@sha256:${{ values.digest }}
port: 8080
${{ values.digest }} 是待替換的部分。模板執行時會將它換成使用者填入的字串,這個過程稱為渲染(render)。替換後,spec.image 就會指向新的 digest;服務名稱、Namespace 和 port 則維持原值。含有變數的檔案不能直接提交 Kubernetes,要使用渲染後的 YAML。
這次的檔案還包含一份 kustomization.yaml,與 microservice.yaml 一起放在 skeleton 目錄。它列出 Kustomize 要讀取的資源,沒有需要替換的值,產生後會原樣出現在任務 log 裡:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- microservice.yaml
知道要產生什麼內容後,我們就可以回頭定義表單,以及產生這些檔案的步驟。
我們希望開發者填完 digest,就能在任務頁面看到產生的設定。這些工作都定義在同一份 Template 裡:spec.parameters 決定表單要收集什麼,spec.steps 負責產生檔案與顯示內容,spec.output 則設定任務完成後的結果說明。以下是這次操作使用的完整 template.yaml:
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: todo-api-dev-preview
title: Todo API Dev Config Preview (D23)
description: Render Microservice YAML from an image digest without creating a PR or deploying the service.
tags:
- todo
- preview
spec:
owner: todo
type: service
parameters:
- title: Todo API image update
required:
- digest
additionalProperties: false
properties:
digest:
title: Image digest
description: "Enter the 64 lowercase hex characters after sha256:, without the prefix."
type: string
minLength: 64
maxLength: 64
pattern: "^[0-9a-f]{64}$"
steps:
- id: render
name: Render Microservice YAML
action: fetch:template
input:
url: ./skeleton
values:
digest: ${{ parameters.digest }}
- id: inspect
name: Inspect rendered files (no deployment)
action: debug:log
input:
message: Preview only. No Git changes or Kubernetes writes were performed.
listWorkspace: with-contents
output:
text:
- title: Config preview complete
content: |
The Todo API Dev configuration has been rendered. Open the logs for
"Inspect rendered files (no deployment)" to view the actual
`microservice.yaml` and `kustomization.yaml` contents.
This task only renders and displays files. No PR was created and no service was deployed.
表單只收集 digest,因此我們用 required 要求必填,再用 minLength、maxLength 和 pattern 限制它必須是 64 位的小寫十六進位字串。additionalProperties: false 則不接受額外的參數,所以使用者不能透過多送一個參數來指定 Namespace 或 port。
因為 microservice.yaml 的 image 已經包含 @sha256:,填表時只需貼上 CI 輸出中 sha256: 後面的 64 位字元。若連前綴一起填入,就不符合欄位的長度與格式,無法繼續建立任務。
表單的輸入通過檢查後,render 步驟會執行 fetch:template。這是 Backstage 用來讀取檔案模板、填入變數的 action。url: ./skeleton 告訴它要處理模板旁的 skeleton 目錄,也就是前面放置 microservice.yaml 與 kustomization.yaml 的地方。
讀取檔案時,fetch:template 也會取得 input.values 裡的值。我們用 ${{ parameters.digest }} 取出表單的 digest,放進 input.values.digest,讓 microservice.yaml 中的 ${{ values.digest }} 能使用它。兩種寫法的差別在於讀取的位置:parameters 是表單輸入,values 是傳給檔案模板的值。
檔案產生後,我們還需要在 Backstage 裡看見內容,所以接上 inspect 步驟。它執行 debug:log,並用 listWorkspace: with-contents 把工作目錄裡的檔名與內容寫進 log。這個步驟只顯示檔案,不會部署它們。
output.text 則負責任務完成後的結果說明。畫面上的 Config preview complete 與下方文字都來自這裡,讓使用者知道設定已產生,以及要開啟 Inspect rendered files (no deployment) 的 log 查看內容。
把前面的設定串起來:開發者填入 digest,fetch:template 讀取 microservice.yaml,替換其中的變數,再把產生的檔案放進這次任務的工作目錄。完成這個步驟後,工作目錄裡會有一份 image 已帶入 digest 的 Microservice YAML:

表單的欄位限制與產生邏輯沿用前面的設定,今天的操作只產生檔案,不會提交 Git 或更新叢集。
在 Backstage 的 Create 頁面可以看到我們擁有的 Templates:

選好今天做好的模板後,只會要求填寫 Image digest。貼上 digest 的 64 位小寫十六進位字元,不包含 sha256:,再點 Review 確認輸入,確認後建立任務。服務名稱、Namespace 和 port 不需要在這裡重填:

如果輸入 AAA 再點 Review,表單會同時提示長度不足 64 位、字元不符合小寫十六進位格式,讓我們留在這一頁修正輸入。換回符合格式的 digest 後,才能繼續確認並建立任務:

建立任務後,Backstage 會依序執行產生檔案與顯示內容的步驟。如果離開了執行畫面,可以從頁面上的 Tasks 找回這次任務。畫面中的 completed 表示模板任務已完成,還不代表 Todo API 已更新:

點進任務,查看 Inspect rendered files (no deployment) 的 log,就能看到實際產生的 microservice.yaml。畫面中 spec.image 已帶入表單的 digest,而服務名稱仍是 todo-api、Namespace 仍是 todo、port 仍是 8080:

這樣就能從表單一路對照到產物。不過,欄位限制只會擋下長度或字元不符的輸入,不會查詢 image 是否存在,也不會確認它來自哪次 CI;填寫時仍要使用 Todo API 的 CI 輸出。
今天把換版時需要重複填寫的內容收進模板,開發者只提供 digest,Template 就能依設定產生 Microservice YAML。下一篇接著處理這份產物:讓模板用 Git Pull Request(PR)提出變更,經過設定檢查與人工 review,再進入部署來源。