TT Lab
はじめる
学ぶ 学習パス コース

CBA — Backstage認定アソシエイト

スキャフォルダはなぜアクションの組み合わせなのか — そしてTechDocsがmkdocsを使う理由

TT Labで続きを見る

一言でいうと

Backstageのソフトウェアテンプレートは、フォーム(parameters) → 作業リスト(steps) → 結果(output)という3つの層でできていて、各stepは、再利用可能なアクション(action)を呼び出します。この組み立て式の構造のおかげで、組織ごとに違うゴールデンパスを、同じ部品で作れます。

なぜ必要なのか

「新しいサービスを作る」ことを自動化する最初の試みは、たいていシェルスクリプトです。ところが、そのスクリプトがやっていることを並べてみると、こうなります。

  1. 入力を受け取る(名前、担当チーム、言語、デプロイ環境)
  2. 入力がルールに合っているかを検証する(名前がDNSの規則に合っているか)
  3. テンプレートのリポジトリから骨組みを取得し、値を置換する
  4. 新しいGitリポジトリを作成してプッシュする
  5. CIを設定する
  6. カタログに登録する
  7. 結果のリンクを人に見せる

スクリプトで作ると、2つ目(検証)はいい加減になり、4–6つ目はトークンが必要なので、開発者のローカルに認証情報を置くことになり、7つ目はありません。そして、別の言語用のスクリプトを作るときは、1–2つ目と4–7つ目を丸ごとコピーすることになります。

スキャフォルダーは、この構造を分解します。入力の定義はJSON Schemaで、各作業はアクションで、結果はoutputで分けます。そうすれば、「Nodeサービスのテンプレート」と「Pythonサービスのテンプレート」は、1つ目の骨組みの取得だけが違い、残りは同じアクションを使います。

どう動くのか

Templateマニフェストの3つの層

apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
  name: node-service
  title: Node.js 서비스
spec:
  owner: group:team-platform
  type: service
  parameters:      # ← 사용자에게 보여 줄 폼 (JSON Schema)
    - title: 기본 정보
      required: [name, owner]
      properties:
        name:
          type: string
          pattern: '^[a-z0-9-]+$'
        owner:
          type: string
          ui:field: OwnerPicker
  steps:           # ← 실제로 하는 일
    - id: fetch
      name: 뼈대 가져오기
      action: fetch:template
    - id: publish
      name: 저장소 만들기
      action: publish:github
    - id: register
      name: 카탈로그 등록
      action: catalog:register
  output:          # ← 끝나고 보여 줄 것
    links:
      - title: Repository

parametersは、JSON Schemaです。type、required、pattern、enumがそのまま動作するので、間違った入力がフォームの段階で止まります。ここにBackstage固有のui:接頭辞のキーが付いて、ウィジェットを指定します。OwnerPicker(カタログのGroupの一覧から選ぶ)、RepoUrlPicker(ホスト/組織/リポジトリ名の組み合わせ)、EntityPickerのようなものです。これらのウィジェットが重要な理由は、自由テキストをなくすためです。オーナーを手でタイプさせると、タイプミスしたオーナーがカタログに入ってしまいます。

stepsの各項目は、id、name、action、inputを持ちます。代表的なアクションは、次のとおりです。

アクション 役割
fetch:template スケルトンのディレクトリを取得して変数を置換し、ワークスペースに展開します
fetch:plain 置換せずに、ファイルをそのまま取得します
publish:github / publish:gitlab 新しいリポジトリを作成し、ワークスペースの内容をプッシュします
catalog:register 生成されたcatalog-info.yamlをカタログに登録します
fs:rename、fs:delete ワークスペースのファイルの操作

アクション間の値の受け渡しは、テンプレート式で行います。フォームの入力はparametersで、前のステップの結果はsteps.<id>.output.<필드>(プレースホルダーはステップのidとフィールドです)で参照します。publish:githubの出力にはremoteUrlとrepoContentsUrlがあり、catalog:registerは、登録されたエンティティの参照を返します。

outputは、作業が終わったあとに、ユーザーに見せるリンクとテキストです。些細に見えますが、開発者体験では大きな役割を果たします。5秒後に「作成されました」としか表示されず、どこへ行けばよいかを教えてくれなければ、人々は再び検索を始めます。

ここで、認証情報がどこにあるかが重要です。publish:githubを実行するのは、ユーザーのブラウザーではなく、Backstageバックエンドです。トークンはサーバーにあり、ユーザーはそのトークンを見られません。これが、「ポータルを通じたセルフサービス」が、「全員にトークンを配る」よりも安全な理由です。

TechDocsとdocs-as-code

TechDocsは、mkdocsを使います。なぜよりによってmkdocsなのかというと、ドキュメントのソースがただのMarkdownファイルで、設定がmkdocs.yml1つで、結果が静的ファイルなので、どこにでも置けるからです。重いドキュメントプラットフォームを導入しなくても、docs-as-codeが成り立ちます。

動作の流れは、こうです。

  1. サービスのリポジトリに、mkdocs.ymlとdocs/index.mdを置きます。
  2. エンティティにアノテーションbackstage.io/techdocs-ref: dir:.を付けます。「このエンティティのドキュメントは、このリポジトリの同じディレクトリにある」という意味です。
  3. ビルドされた静的な結果がストレージに保存され、ポータルのDocsタブでレンダリングされます。

ビルドの時点には、2つの戦略があります。ローカルビルド(ポータルがリクエスト時にビルド)は設定が簡単ですが、遅く、大規模には不向きです。外部ビルド(CIがビルドして、オブジェクトストレージにアップロード)が、運用で推奨される方式です。CBAでは、この区別が問われます。

docs-as-codeの核心となる価値は、繰り返し言うに値します。ドキュメントがコードと同じリポジトリ、同じPR、同じレビューを経れば、ずれる確率が大きく下がります。別のWikiにあるドキュメントは、3か月で間違ったものになり、間違ったドキュメントは、ないドキュメントよりも悪いものです。

現場での姿

著者のホームラボでスキャフォルディングが必要な理由は、事故の一覧が証明しています。Gateway APIにはCRD v1.6.1が必要で、v1.2ではtlsroutesとreferencegrantsがv1ではなく、Cilium Gatewayコントローラーが起動を拒否しました。KubeVirtはcontainerDiskのパスに欠陥があり、DataVolume(PVC)のパスに回避する必要がありました。GPU Operatorは、containerdのランタイム設定で事故が起きました。

これらの知識は、一度踏んだら、二度と踏む理由のない落とし穴です。人の頭の中に残れば、次の人がまったく同じように踏み、テンプレートのスケルトンとドキュメントとして固めれば、誰も踏みません。スキャフォルダーの価値が「タイピングを減らしてくれること」だと考えると、過小評価です。本当の価値は、検証された経路をデフォルトにすることです。

もう1つあります。このクラスターは、kubeadm initのとき、--control-plane-endpointをVIPやDNSではなく、最初のノードの物理IPとして入れました。あとからコントロールプレーンを3台に増やしても、その値のために、最初のノードが落ちるとAPIへのアクセスが途切れます。著者は、「最初からやり直すなら、間接的なアドレスを入れていた」と書きました。初期の選択が、あとから変えるのが非常に苦痛になる値があるという意味であり、そうした値こそ、テンプレートのデフォルト値に埋め込んでおくべきものです。

次のラボですること

/root/cba-template/に、Templateマニフェストを書きます。parametersのJSON Schema、stepsのアクションと入力、outputのリンクまでです。続けて、mkdocs.ymlとdocs/index.md、そしてスケルトンのcatalog-info.yamlに、techdocsのアノテーションを付けます。最後に、このテンプレートが作り出すマニフェストを、実際のクラスターに適用して、結果を検証します。