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

CBA — Backstage認定アソシエイト

カタログに登録したサービスが黙って消える

TT Labで続きを見る

目標

VMの中で本物のカタログバックエンドを起動し、エンティティがカタログに入ってこない4つの原因を、自分で作り出して、どこに痕跡が残るかを探します。静的なlocationの自動収集、APIで登録するlocation、孤立エンティティ(orphan)の整理、locationの削除までを、実際のAPI応答で確認します。

なぜ重要なのか

「catalog-info.yamlをアップロードしたのに、ポータルに表示されません」は、Backstageの運用で最もよくある問い合わせです。検証ライブラリでYAMLを1つ確認するだけでは、足りません。動いているカタログでは、失敗がAPI応答にも、デフォルトのログにも現れないことがあり、1つのエンティティの問題が、同じファイル全体を止めることもあります。登録APIが201を返しても、処理の段階で失敗することがあります。どこを見るべきかを知っていてはじめて、直せます。

最初のVMの起動に4分ほどかかり、ステップ1のインストールは、インターネットから約30秒かかります。GitHubのような外部システムを走査する探索(discovery)プロバイダーは、外部アカウントが必要なので、扱いません。ここでの「自動収集」は、設定に書いたlocationを、カタログが定期的に再び読み取ることです。

ステップ

  1. /usr/local/cba-ingestに、カタログバックエンドのパッケージを、固定バージョンでインストールします。
  2. 設定に書いたファイルのlocationが、自動で収集されることを確認します。
  3. ownerが欠けたエンティティが、痕跡なしに抜け落ちることを記録します。
  4. ログモジュールを付けて、処理エラーをwarnログに引き出します。
  5. 許可されていないkindが、ファイル全体を止めるのを見て、locationごとのルールで解決します。
  6. APIでurl locationを登録し、読み取りの許可リストの問題を直します。
  7. ファイルから抜いたエンティティが、孤立してから削除されるのを見ます。
  8. locationを削除して、収集障害のレポートを書きます。

参考

動いているカタログの材料を、固定バージョンで取得する

/usr/local/cba-ingestにnpmプロジェクトを作成し、4つのパッケージを範囲指定なしの正確なバージョンでインストールしてください(package.jsonにも^なしで)。npmキャッシュはnpm_config_cache=/usr/local/cba-ingest/.npmcacheに置きます。@backstage/backend-defaults@0.17.8、@backstage/plugin-catalog-backend@3.9.1、@backstage/plugin-catalog-backend-module-logs@0.1.25、better-sqlite3@12.4.1です。

npm install --save-exactを使ってください。ログモジュールは、インストールだけしておき、ステップ4で付けます。better-sqlite3 13.xは、このNode 20用のビルド済みバイナリがなく、コンパイルを試みて失敗します。

設定に書いたファイルが、自動で収集される

/usr/local/cba-ingest/app-config.yamlに次の内容を置き、カタログプラグインだけを入れたバックエンド(index.js)を、7007番ポートで起動してください(出力は/usr/local/cba-ingest/backend.log)。backend.baseUrl: http://localhost:7007、backend.listen.port: 7007、DBはbetter-sqlite3・':memory:'、backend.auth.externalAccessにtype static・token ingest-lab-token-7f3a9c・subject ingest-cli、catalog.processingInterval: { seconds: 5 }、catalog.rules: [{allow: [Component, Group, Location]}]、catalog.locationsにtype: file・target: ./catalog/team.yamlです。catalog/team.yamlには、Group team-searchと、そのチームが所有するComponent search-api・search-indexerを入れます。Authorization: Bearer ingest-lab-token-7f3a9cで/api/catalog/entitiesを呼び出して、3つのエンティティが見えれば、完了です。

カタログAPIは、デフォルトの認証ポリシーの内側にあるので、トークンなしで呼び出すと401です。静的トークンは、運用では${환경변수}(プレースホルダーは環境変数です)の形で入れるべきですが、このラボでは、流れを見るために、ファイルに書きます。入ってきたエンティティのbackstage.io/managed-by-locationアノテーションが、どのファイルを指しているかを確認してください。

ownerを抜かしたエンティティは、痕跡なしに抜け落ちる

team.yamlの末尾に、spec.ownerがないComponent search-ui(type website、lifecycle production)を追記してください。再起動せずに数秒待ってから、カタログとログを見て、/root/cba-ingest/silent.txtに3行を書いてください。search_ui_in_catalog=(yes/no)、search_api_in_catalog=(yes/no)、log_lines_mentioning_search_ui=(その瞬間のbackend.logで、search-uiが出てくる行数)です。search-uiは、このラボの最後まで直さずに置いておきます(あとのステップと採点が、この状態を使います)。

処理周期を5秒に縮めたので、ファイルを直すと、すぐに再び読み取られます。エンティティ1つが検証に失敗したとき、同じファイルの残りがどうなるか、そしてその失敗がどこに残るのか(あるいは残らないのか)を見てください。grep -c search-ui backend.logで数えます。

処理エラーをログに引き出す

index.jsに@backstage/plugin-catalog-backend-module-logsをaddして、バックエンドを再起動してください。backend.logにcomponent:default/search-uiについてのwarnの行が出力されたら、色の制御文字を取り除いたその行を1つ、/root/cba-ingest/owner-error.txtに保存してください。team.yamlは直しません。

カタログは、処理エラーをイベントとして出すだけで、それをログに書くのは、別のモジュールです。モジュールを付けたあとも、処理周期が1回まわってはじめて、行ができます。sed 's/\x1b\[[0-9;]*m//g' backend.log | grep search-uiで探してください。events backend not foundの警告は、eventsプラグインがないために出るもので、この課題とは無関係です。

APIが1つあるために、ファイル全体が入ってこない

/usr/local/cba-ingest/catalog/billing.yamlに、Component billing-api(owner team-search、providesApis [billing-openapi])と、API billing-openapi(type openapi、owner team-search)を入れ、catalog.locationsにtype: file・target: ./catalog/billing.yamlを追加してから、再起動してください。2つのエンティティがどちらも入ってこないことを確認し、api:default/billing-openapiについてのwarnの行を1つ、/root/cba-ingest/kind-error.txtに保存してください。そのあと、グローバルのcatalog.rulesはそのままにして、billing.yamlのlocationだけにrules: [{allow: [API]}]を付けて再起動し、billing-apiとbilling-openapiの両方が入ってくるようにしてください。

許可されていないkindは、そのエンティティ1つだけが捨てられるのではなく、そのlocationの処理結果全体を失敗させます。ownerの欠落と比べてみてください。グローバルのルールにAPIを入れると、どのファイルからでもAPIが入ってくるようになります。ドキュメントの、locationごとのrulesを見てください。

登録は201なのに、何も入ってこない

/usr/local/cba-ingest/incoming/data.yamlに、Component etl-runnerとetl-scheduler(どちらもowner team-search)を置き、そのディレクトリをpython3 -m http.server 8088 --bind 127.0.0.1で配信してください(バックグラウンド)。①カタログAPIでtype: file・target /usr/local/cba-ingest/incoming/data.yamlの登録を試みて、応答(400)を見て、②type: url・target http://localhost:8088/data.yamlでPOST /api/catalog/locationsを送り、201なのにエンティティが入ってこないことを確認したあと、そのurlについてのwarnの行を1つ、/root/cba-ingest/reading-error.txtに保存してください。③backend.reading.allowにhost: localhost:8088を入れて再起動してから、同じurlをもう一度登録して、2つのエンティティが入ってくるようにしてください。最後の登録のPOST応答のJSONを、/root/cba-ingest/location.jsonに保存します。

APIで登録するlocationは、url形式しか受け付けません。urlを読み取るのはUrlReaderで、統合(integration)がないホストは、許可リストにあってはじめて読み取れます。この検査は、登録の時点ではなく処理の時点で行われるので、登録の応答は成功です。:memory:のDBなので、再起動すると、先に登録したlocationが消えるので、GET /api/catalog/locationsで確認してください。http.serverも、シェルが終了しても生き続けるように、setsid nohup ... > 로그 2>&1 < /dev/null &(プレースホルダーはログファイルです)で起動してください。

ファイルから抜いたエンティティは、孤立してから削除される

incoming/data.yamlから、etl-runnerのドキュメントを削除してください(etl-schedulerは残します)。カタログで、etl-runnerにbackstage.io/orphan: "true"アノテーションが付く瞬間のエンティティのJSON(GET /api/catalog/entities/by-name/component/default/etl-runnerの応答)を、/root/cba-ingest/orphan.jsonに保存してください。そのあと、待って、そのエンティティがカタログから削除される様子(by-nameで404)と、ログのDeleted ... orphaned entitiesの行を確認してください。

エンティティを出力していたlocationが、もうそのエンティティを出力しなくなると、孤立します。孤立したものを残すか削除するかは、catalog.orphanStrategyで決め、デフォルトでは、整理の作業(ログのcatalog_orphan_cleanup、30秒周期)が削除します。アノテーションは、ほんの一瞬しか見えないので、1秒間隔でポーリングして、付く瞬間を捉えてください。

locationを削除して、収集障害のレポートを書く

location.jsonのidでDELETE /api/catalog/locations/<id>を送って登録を解除し、etl-schedulerがカタログから消えることを確認してください。そのあと、/root/cba-ingest/report.mdの最初の5行に、今測った値を書いてください。registered_location_status=(GET /api/catalog/locations/)、etl_scheduler_status=(by-nameの照会)、search_ui_status=(by-nameの照会)、api_location_count=(結果の個数。静的なlocationの2つが、ここに出るかどうか。GET /api/catalog/locations)、file_register_status=(type fileの登録を試みた応答)です。その下に、このラボで収集が失敗した4つの原因と、それぞれどこに痕跡が残ったかを、整理してください。

すべての値は、トークンを付けたcurlで、今測ったものです。静的なlocationは、設定ファイルが管理するので、APIでは削除できず、一覧にも出ません。4つの原因は、ownerの欠落、許可されていないkind、読み取りの許可リスト、ファイルから抜けたエンティティ(孤立)です。