はじめに
前回はGateway APIを利用して最小限のプラットフォームを構築しました。今回はプラットフォームで「ゴールデンパス」を提供します。
ゴールデンパスとは、Webアプリケーションを構築、スキャン、テスト、デプロイ、オブザーバビリティなど、開発者がプロジェクトの立ち上げから運用までの一連のプロセスを迅速かつ効率的に実行できるようにするためのベストプラクティスやツール、ワークフローのセットです。ゴールデンパスの重要な要素として「ゴールデンパステンプレート」(ソースコードと各種ワークフローのテンプレート)があります。開発者はテンプレートからプロジェクトを作成することで、必要な構成があらかじめ用意された状態でプロジェクトの開発を迅速に開始できます。
また、今回はゴールデンパステンプレートを管理するツールとして「Backstage」を利用します。BackstageはSpotifyが開発したオープンソースの開発者ポータル(IDP: Internal Developer Portal)で、組織内のツールやサービスを統合し、開発者が効率的に作業できる環境を提供します。
Backstageの機能の1つである「Software Templates」はソースコードのテンプレートを管理し、テンプレートから新しいプロジェクトを作成できる機能です。本記事では、Software Templates機能を利用して、Go言語で書かれたシンプルなWebサーバーのゴールデンパステンプレートを作成する方法を解説します。
構築する構成の説明
今回構築するのは、図1の赤い点線で囲った部分です。Namespace backstageにBackstageをデプロイし、GitHubと連携させます。GitHubはゴールデンパステンプレートの保管、および各プロダクトのコード保管場所として利用します。
Backstageの初期化
Backstageの設定やカスタマイズはTypescriptで行います。そのため、まずはBackstageのGetting Startedに従ってBackstageアプリケーションを初期化します。
BackstageはNode.js上で動作するため、事前にNode.jsをインストールしておく必要があります。今回はNode.js v24.12.0を使用して検証しています。
以下のコマンドを実行して、Backstageアプリケーションの雛形を作成します。
npx @backstage/create-app@0.7.8以下のようにBackstageアプリケーションの名前(ディレクトリ名)が聞かれるため、任意の名前を入力します。
今回は、backstage-appと入力しました。
ローカルで実行
BackstageをKubernetesにデプロイする前に、ローカルで動作確認を行うケースは多いと思うので、その方法を紹介します。初期化したBackstageアプリのルートディレクトリでyarn startを実行するだけで動作確認ができます。
cd backstage-app/
yarn startブラウザでhttp://localhost:3000にアクセスすると、Backstageの初期画面が表示されます。
Kubernetesへのデプロイ
BackstageをKubernetesにデプロイするための手順を説明します。
Backstageの設定更新
まず、Backstageの設定ファイル(app-config.production.yaml)を更新します。今回は検証環境ということもありHTTPで運用します。HTTPで運用する場合、upgrade-insecure-requestsを無効化する必要があります。また、ゲストユーザーログインを許可するための設定を追加します。
backend:
+ csp:
+ upgrade-insecure-requests: false
auth:
providers:
- guest: {}
+ guest:
+ userEntityRef: user:default/guest
+ ownershipEntityRefs: [group:default/guests]
+ dangerouslyAllowOutsideDevelopment: true上記は今回の検証用に特別に入れた設定で、セキュリティ上のリスクがあります。本番環境向けにはHTTPSでの運用、およびゲストユーザーでのログインを許可しない設定を推奨します。
コンテナイメージのビルド
コンテナをビルドする前に、バックエンドパッケージをビルドしておきます。
yarn install --immutable
yarn tsc
yarn build:backendコンテナイメージをプッシュするため、コンテナレジストリにログインします。今回はBackstageを含むプラットフォームのコンテナイメージの保管に、GitHubが提供するコンテナレジストリであるGitHub Container Registryを利用します。
まず、GitHubのPersonal Access Tokenを発行します。必要な権限はwrite:packagesです。
export GHCR_PUSH_TOKEN=xxxxxx # GitHub Personal Access Token
docker login ghcr.io -u GH_USERNAME --password $GHCR_PUSH_TOKENコンテナイメージをビルドし、プッシュします。IMGの部分は適宜書き換えてください。
export IMG=ghcr.io/GH_USERNAME/REPOSITORY:TAG
docker image build . -f packages/backend/Dockerfile -t $IMG
docker push $IMGPostgreSQLのデプロイ
BackstageのデータベースとしてPostgreSQLを使用するため、Kubernetesにデプロイします。Backstage用のNamespaceを作成して、その中にPostgreSQLをデプロイします。
kubectl create namespace backstage
kubectl apply -n backstage -f https://raw.githubusercontent.com/Hitachi/oss-assets/main/article/thinkit-smallplatform/03-backstage-software-template/deploy/postgres.yamlImage Pull Secretを作成
GitHubのPersonal Access Tokenを発行し、プライベートリポジトリからイメージをプルできるようにImage Pull Secretを作成します。必要な権限はread:packagesです。
export GHCR_PULL_TOKEN=xxxxxx # GitHub Personal Access Token
export GH_USERNAME=xxxxxx # GitHubのユーザー名
kubectl create secret docker-registry regcred \
--docker-server=ghcr.io \
--docker-username=$GH_USERNAME \
--docker-password=$GHCR_PULL_TOKENBackstageのデプロイ
Backstage用のSecretを作成します。Secretに書かれた環境変数がBackstageのコンテナに渡されるようにDeploymentを設定します。今はPostgreSQLの接続情報のみを記載していますが、後ほどGitHub連携のための環境変数も追加します。
kubectl apply -n backstage -f- <<EOF
apiVersion: v1
kind: Secret
metadata:
name: backstage-secret
type: Opaque
stringData:
# PostgreSQL接続情報
POSTGRES_HOST: "postgres"
POSTGRES_PORT: "5432"
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: "postgres"
POSTGRES_DB: "backstage"
EOFBackstageをデプロイ
kubectl apply -n backstage -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: backstage
namespace: backstage
spec:
replicas: 1
selector:
matchLabels:
app: backstage
template:
metadata:
labels:
app: backstage
spec:
containers:
- name: backstage
image: ${IMG}
imagePullPolicy: Always
ports:
- name: http
containerPort: 7007
envFrom:
- secretRef:
name: backstage-secret
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
imagePullSecrets:
- name: regcred
---
apiVersion: v1
kind: Service
metadata:
name: backstage
namespace: backstage
spec:
selector:
app: backstage
ports:
- protocol: TCP
port: 8080
targetPort: 7007
type: ClusterIP
EOFBackstageの公開
Gateway APIを使ってBackstageを公開します。Gateway APIのセットアップ方法と解説は第2回を参照してください。
Backstageを公開するために、Gatewayを編集してHTTPRouteを作成します。第2回で作成した共有GatewayにBackstage用のリスナーを追加します。なお、公開設定のホスト名部分はご自身の環境に合わせて変更してください。
# shared-gateway/shared-gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: shared-gateway
namespace: shared-gateway
spec:
gatewayClassName: envoy-gateway
listeners:
# Keycloak用リスナー
- name: keycloak
protocol: HTTP
port: 80
hostname: keycloak.172.32.4.127.nip.io
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
kubernetes.io/metadata.name: keycloak
kinds:
- kind: HTTPRoute
+ # backstage用リスナー
+ - name: backstage
+ protocol: HTTP
+ port: 80
+ hostname: "backstage.172.32.4.127.nip.io"
+ allowedRoutes:
+ namespaces:
+ from: Selector
+ selector:
+ matchLabels:
+ kubernetes.io/metadata.name: backstage
+ kinds:
+ - kind: HTTPRoute
# echo API用リスナー (テナント)
- name: echo
protocol: HTTP
port: 80
hostname: "echo.172.32.4.127.nip.io"
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
kubernetes.io/metadata.name: echo
kinds:
- kind: HTTPRouteBackstage用のHTTPRouteを作成します。
# backstage/deploy/httproute.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: backstage-route
spec:
hostnames:
- backstage.172.32.4.127.nip.io
parentRefs:
- name: shared-gateway
namespace: shared-gateway
sectionName: backstage
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: backstage
port: 8080
kind: Service
weight: 1GatewayとHTTPRouteをKubernetesに適用します。
kubectl apply -n shared-gateway -f shared-gateway/shared-gateway.yaml
kubectl apply -n backstage -f backstage/deploy/httproute.yamlまた、共有Gatewayにはデフォルトで全ての通信を拒否するAuthPolicyが設定されているため、全ての通信を許可するAuthPolicyで上書きします。
# backstage/deploy/authpolicy.yaml
apiVersion: kuadrant.io/v1
kind: AuthPolicy
metadata:
name: backstage-authpolicy-allow-all
namespace: backstage
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: backstage-route
defaults:
rules:
authentication:
"anonymous":
anonymous: {}上記のAuthPolicyをKubernetesに適用します。
kubectl apply -n backstage -f backstage/deploy/authpolicy.yamlBackstageにアクセス
ブラウザでhttp://backstage.172.32.4.127.nip.ioにアクセスします。
現在、ゲストユーザーしか設定していないため、ゲストユーザーでログインします。
Software Templates機能の設定
Software Templatesはソースコードのテンプレートを管理し、テンプレートから新しいプロジェクトを作成するBackstageの機能です。今回は私が作成してGitHubで公開しているゴールデンパステンプレートを例に、ゴールデンパステンプレートの構成とBackstageでの管理方法を紹介します。
私が作成したゴールデンパステンプレートは開発者が新しいプロジェクトを開始し、本番環境へのデプロイするまでのフローを支援することを目的としたもので、Go言語で書かれたシンプルなWebサーバーのテンプレートです。
このゴールデンパステンプレートは以下を含んでいます。
- IDE(Visual Studio Code)の設定ファイル
- OpenAPI仕様からエンドポイントのインターフェースを自動生成するスクリプト
- Hello Worldが実装されたソースコード
- CI(テスト、ビルド、スキャン)
- 本番環境へのデプロイに必要なKubernetesのマニフェスト
- ビルド方法からデプロイまでの手順を記したドキュメント
逆に、以下のような内容は今回作成するゴールデンパスには含まれません。
- DevContainerなどの開発環境を容易に立ち上げる手段
- GitOpsなどのCDワークフロー
- オブザーバビリティ
テンプレートの準備
今回は私が作成したテンプレートを使って説明します。本番環境では自作テンプレートを使うことになりますが、動作確認が目的であれば私が作成したものを指定するのが手軽です。
テンプレートは、テンプレート定義ファイルtemplate.yamlとスケルトンソースコード(テンプレートから新しいプロジェクト作成時にコピーされるソースコード)を格納するskeleton/ディレクトリで構成されています。
template.yaml # テンプレートの定義ファイル
skeleton/ # スケルトンソースコード
├── go.mod
├── go.sum
├── main.go
├── README.md
└── ...テンプレート定義ファイル
テンプレート定義ファイル(template.yaml)はYAML形式で記述されます。Kubernetesのマニフェストに似た形式ですが、Kubernetesにデプロイするのではなく、Backstageに読み込ませて使用します。
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: go-echo-template
title: Go echo template
description: GoのechoによるREST APIテンプレート
spec:
owner: backstageadmin
type: service
parameters:
# パラメーターの定義
...
steps:
# ワークフローの定義
...テンプレート定義は、主に以下の2つの要素で構成されています。
- パラメーター定義: ワークフローで使用するパラメーターを定義
- ワークフロー: テンプレートからのリポジトリ生成プロセスを定義(ソースコードのコピー、Gitリポジトリへのプッシュなど)
パラメーター定義(spec.parameters)はJSON Schemaで記述します。すべてのパラメーターを紹介すると長くなるため、一部のみ抜粋して紹介します。
parameters:
...
- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts:
- github.comui:field: RepoUrlPickerはリポジトリを指定するためのUIコンポーネントで、上記により以下のようなパラメーター入力画面になります。
ワークフローでは、以下の実装がされています。
- GitHubからスケルトンコードを取得してパラメーターを埋め込む
- GitHubリポジトリにコードをプッシュする
- Backstageのソフトウェアカタログにコンポーネントを登録する
- BackstageのソフトウェアカタログにAPIを登録する
「ソフトウェアカタログ」はBackstageの機能の1つで、組織内のソフトウェアコンポーネントを管理するためのカタログです。ソフトウェアカタログにコンポーネントを登録することで、ユーザーがBackstageの画面からコンポーネントの情報を検索したり、ソースコードにアクセスしたりできるようになります。また、APIを登録することで、APIドキュメントを統合して管理できます。
ワークフローは、spec.stepsに定義します。
steps:
# スケルトンコードを取得して、パラメータを埋め込む
- id: fetchBase
name: Fetch Base
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
image: ${{ parameters.image }}
destination: ${{ parameters.repoUrl | parseRepoUrl }}
k8sResource: ${{ parameters.k8sResource }}
domain: ${{ parameters.domain }}
keycloakRealm: ${{ parameters.keycloakRealm }}
# リポジトリにコードをプッシュする
- id: publish
name: Publish
action: publish:github
input:
description: This is ${{ parameters.name }}
repoUrl: ${{ parameters.repoUrl }}
defaultBranch: 'main'
# ソフトウェアカタログにコンポーネントを登録する
- id: registerComponent
name: Register Component
action: catalog:register
input:
repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}
catalogInfoPath: '/catalog-info.yaml'
# ソフトウェアカタログにAPIを登録する
- id: registerApi
name: Register API
action: catalog:register
input:
repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}
catalogInfoPath: '/catalog-api.yaml'ユーザーがSoftware Templatesの画面でリポジトリ作成を実行すると、上記ワークフローの各ステップが順番に実行され、テンプレートから新しいリポジトリが作成されます。
・スケルトンソースコード
skeleton/ディレクトリには、Go言語で書かれたシンプルなWebサーバーのソースコードが含まれています。リポジトリごとに変更される部分は ${{values.<パラメーター名>}} の形式でプレースホルダーとして記述されています。プレースホルダーはテンプレート定義のワークフローのfetch:templateアクションで定義された値に置き換えられます。
例えば、go.modファイルは以下のようになります。
module github.com/${{values.destination.owner + "/" + values.destination.repo}}
go 1.25.1GitHub Actionsのワークフロー内にある ${{ xxx }} のような表現は、そのままではBackstageがプレースホルダーと誤認して置き換えてしまいます。これを避けるには ${{ '${{ xxx }}' }} のようにエスケープして記載するとリポジトリ作成後に ${{ xxx }} が残ります。以下はGitHub Actionsのワークフローの例です。
- name: Build and push Docker image
id: build
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ '${{ steps.meta.outputs.tags }}' }} # エスケープ
labels: ${{ '${{ steps.meta.outputs.labels }}' }} # エスケープ
cache-from: type=gha,scope=build
cache-to: type=gha,mode=max,scope=buildBackstageの設定更新
Backstageのapp-config.production.yamlに以下の設定を追加します。
catalog:
locations:
+ - type: url
+ target: https://github.com/makihh/software-templates/blob/main/templates/go-echo/template.yaml
+ rules:
+ - allow: [Template]
+integrations:
+ github:
+ - host: github.com
+ token: ${GITHUB_TOKEN}catalog.locationsにはテンプレート定義ファイルのURLを指定します。これによりBackstageがテンプレート定義ファイルを読み込み、Software Templatesの画面にテンプレートを表示します。また、integrations.githubはGitHubの認証情報を追加し、テンプレートのワークフローでGitHubリポジトリからコードを取得・プッシュできるようにします。
GitHubの設定
GitHubとBackstageを連携するための設定を行います。
・GitHub Personal Access Token作成
BackstageをGitHubに連携するため、Personal Access Token(classic)を作成します。詳細はGitHubのドキュメントを参照してください。
必要な権限は以下の通りです。
- repo(全て)
- workflow
- read:org
- read:user
- user:email
今回はPersonal Access Tokenを使いましたが、本番環境ではGitHub Appsの使用を推奨します。
・Secretの更新
GitHubのPersonal Access TokenをBackstage用のSecretに追加します。
export GITHUB_TOKEN="xxxxxx" # GitHub Personal Access Token
kubectl apply -n backstage -f- <<EOF
apiVersion: v1
kind: Secret
metadata:
name: backstage-secret
type: Opaque
stringData:
# PostgreSQL接続情報
POSTGRES_HOST: "postgres"
POSTGRES_PORT: "5432"
POSTGRES_USER: "postgres"
POSTGRES_PASSWORD: "postgres"
POSTGRES_DB: "backstage"
# GitHub連携 (追加)
GITHUB_TOKEN: "${GITHUB_TOKEN}"
EOF動作確認
コンテナイメージをビルドしなおして、Podを再起動します。
docker image build . -f packages/backend/Dockerfile -t $IMG docker push $IMG kubectl rollout restart deployment backstage -n backstageBackstageにアクセスして、KindをTemplateでフィルタします。先ほど追加した「Go echo template」テンプレートが表示されるので、選択します。
テンプレートの詳細画面で「LAUNCH TEMPLATE」ボタンをクリックして、リポジトリ作成を開始します。
各種パラメーターを入力します。
確認画面で「CREATE」ボタンをクリックします。
ワークフローが実行され、テンプレートからリポジトリが作成されます。
作成したコンポーネントがコンポーネント一覧に表示されるので、選択します。
コンポーネントとして登録されます。「VIEW SOURCE」をクリックすると、作成されたGitHubリポジトリに遷移します。
スケルトンコードにはデプロイ手順が記載されており、開発者がアプリケーションをKubernetesに容易にデプロイできます。
また、ワークフローはAPIドキュメントをBackstageに登録するように構成されており、OpenAPI形式のドキュメントが統合されます。これにより、APIの利用者は開発者ポータルから最新のAPI仕様を確認できます。
利用したソフトウェアのバージョン
| コンポーネント | バージョン |
| create-app | 0.7.8 |
| Node.js | v24.12.0 |
| Backstage | 1.47.0 |
| PostgreSQL | 17.0 |
まとめ
Backstageを導入し、Software Templates機能を利用してGo言語でのシンプルなWebサーバーのゴールデンパステンプレートを作成しました。これにより、開発者はテンプレートから新しいプロジェクトを迅速に開始でき、開発プロセスの効率化が期待できます。ゴールデンパスの整備により、プラットフォームエンジニアリングの成熟度モデルのインターフェース レベル2の要素の1つが満たされました。
ただし、本実装ではCDが含まれず手動でデプロイする必要があります。実運用ではGitOpsやオブザーバビリティなどの要素も含めて、より実用的なゴールデンパスを提供することが望ましいです。
また、Backstage導入前後での開発プロセスの変化を下表にまとめます。変わっていない箇所は今後の連載の中で改善していきます。
| 大プロセス | 小プロセス | プラットフォーム導入前 | 第2回 | 第3回のゴールデンパステンプレート導入後 |
| セキュリティ要件定義 | 認証要件の設計 | 手動 | Keycloakで標準化 | Keycloakで標準化 |
| 認可要件の設計 | 手動 | Authorinoで部分自動化 | Authorinoで部分自動化 | |
| OpenAPI仕様作成 | OpenAPIの設計 | 1から手書き | 1から手書き | テンプレートから開発開始 |
| セキュリティスキーマの定義 | 1から手書き | Keycloak定義 | Keycloak定義 | |
| API仕様の公開 | メール送付など | メール送付など | Backstageで公開 | |
| 実装 | APIの実装 | 手動実装 | 手動実装 | OpenAPI仕様からエンドポイントのインターフェースを自動生成 |
| 認証・認可の実装 | コード実装 | Authorinoで自動化 | Authorinoで自動化 | |
| ルーティング設定 | 手動設定 | Gateway APIで宣言管理 | Gateway APIで宣言管理 | |
| Kubernetesマニフェスト実装 | ー | 1から手書き | テンプレートから開発 | |
| デプロイと運用 | デプロイ | 手動 | Kubernetesで自動化 | Kubernetesで自動化 |
| 監視・可観測性の導入 | ログ出力と手動確認 | ログ出力と手動確認 | ログ出力と手動確認 | |
| ポリシー準拠チェック | 手動レビュー | 手動レビュー | 手動レビュー | |
| 認可ポリシーの連携 | 手動実装 | 手動実装 | 手動実装 |
次回は、ユーザーからのフィードバックを収集できるよう、Backstageにフィードバック収集機能を追加していきます。
