Skip to main content

将后端插件迁移至新的后端系统

将现有的后端插件迁移到新的后端系统相当简单。 迁移过程与大多数插件类似,只需返回一个Router然后在index.ts我们需要做的首要事情是确保插件所需的依赖项可用,然后向 HTTP 路由器服务注册路由器。

让我们来看一个迁移 Kubernetes 后端插件的例子。 在现有(旧)系统中,kubernetes 后端是这样的结构:

// @backstage/plugin-kubernetes-backend/src/service/router.ts

import { KubernetesBuilder } from './KubernetesBuilder';
export interface RouterOptions {
logger: Logger;
config: Config;
catalogApi: CatalogApi;
clusterSupplier?: KubernetesClustersSupplier;
discovery: PluginEndpointDiscovery;
}

export async function createRouter(
options: RouterOptions,
): Promise<express.Router> {
const { router } = await KubernetesBuilder.createBuilder(options)
.setClusterSupplier(options.clusterSupplier)
.build();
return router;
}

我们可以重复使用router创建的KubernetesBuilder我们只需确保在新的后端系统中指定的依赖项与RouterOptions所有这些都属于coreServices这使得迁移非常容易。

import {
coreServices,
createBackendPlugin,
} from '@backstage/backend-plugin-api';
import { catalogServiceRef } from '@backstage/plugin-catalog-node';
import { Router } from 'express';
import { KubernetesBuilder } from './KubernetesBuilder';

export const kubernetesPlugin = createBackendPlugin({
pluginId: 'kubernetes',
register(env) {
env.registerInit({
deps: {
logger: coreServices.logger,
config: coreServices.rootConfig,
catalogApi: catalogServiceRef,
discovery: coreServices.discovery,
// The http router service is used to register the router created by the KubernetesBuilder.
http: coreServices.httpRouter,
},
async init({ config, logger, catalogApi, discovery, http }) {
const { router } = await KubernetesBuilder.createBuilder({
config,
logger,
catalogApi,
discovery,
}).build();

// We register the router with the http service.
http.use(router);
},
});
},
});

最后,确保重新导出插件实例,将其作为软件包的默认导出,在src/index.ts:

export { kubernetesPlugin as default } from './plugin.ts';

完成!该插件的用户现在可以导入您的插件包,并在其后端程序中注册,使用

// packages/backend/src/index.ts
backend.add(import('@backstage/plugin-kubernetes-backend'));

眼尖的读者可能会注意到少了一样东西:"......"。clusterSupplier选项在原始插件中缺失。 让我们添加该选项并讨论替代方案。

另一种方法是使用静态配置来构建集群供应商。 例如,可以提供多种内置实现供用户选择,或 者可以将集群供应商的运行逻辑设置为"......"。ClusterSupplier在这种情况下,我们可以设想这样配置我们的集群供应商:

/* omitted imports but they remain the same as above */

const kubernetesPlugin = createBackendPlugin({
pluginId: 'kubernetes',
register(env) {
env.registerInit({
deps: {
/* omitted dependencies but they remain the same as above */
},
async init({ config, logger, catalogApi, discovery, http }) {
// Note that in a real implementation this would be done by the `KubernetesBuilder` instead,
// but here we've extracted it into a separate call to highlight the example.
const configuredClusterSupplier = readClusterSupplierFromConfig(config);

const { router } = await KubernetesBuilder.createBuilder({
config,
logger,
catalogApi,
discovery,
})
.setClusterSupplier(configuredClusterSupplier)
.build();
http.use(router);
},
});
},
});

然而,有许多类型的自定义配置是静态配置无法实现的。 在这种情况下,我们希望集成商能够创建任意的ClusterSupplier这就是新后端系统的扩展点派上用场。

新的扩展点应用程序接口允许模块将功能添加到后端插件本身,在本例中就是增加一个ClusterSupplier让我们来看看如何使用扩展点为安装自定义供应商添加支持。 这将允许集成商使用自定义的ClusterSupplier执行。

首先,我们将创建一个@backstage/plugin-kubernetes-node使用单独的软件包是为了避免直接依赖插件包本身。 创建新软件包后,我们可以这样定义扩展点:

import { createExtensionPoint } from '@backstage/backend-plugin-api';

export interface KubernetesClusterSupplierExtensionPoint {
setClusterSupplier(supplier: KubernetesClustersSupplier): void;
}

/**
* An extension point that allows other plugins to set the cluster supplier.
*/
export const kubernetesClustersSupplierExtensionPoint =
createExtensionPoint<KubernetesClusterSupplierExtensionPoint>({
id: 'kubernetes.cluster-supplier',
});

有关如何设计扩展点的更多信息,请参阅扩展点文件。

接下来,我们需要为 Kubernetes 后端插件本身添加对该扩展点的支持:

/* omitted other imports but they remain the same as above */
import { kubernetesClustersSupplierExtensionPoint } from '@backstage/plugin-kubernetes-node';

export const kubernetesPlugin = createBackendPlugin({
pluginId: 'kubernetes',
register(env) {
let clusterSupplier: KubernetesClustersSupplier | undefined = undefined;

// We register the extension point with the backend, which allows modules to
// register their own ClusterSupplier.
env.registerExtensionPoint(kubernetesClustersSupplierExtensionPoint, {
setClusterSupplier(supplier) {
if (clusterSupplier) {
throw new Error('ClusterSupplier may only be set once');
}
clusterSupplier = supplier;
},
});

env.registerInit({
deps: {
/* omitted dependencies but they remain the same as above */
},
async init({ config, logger, catalogApi, discovery, http }) {
const { router } = await KubernetesBuilder.createBuilder({
config,
logger,
catalogApi,
discovery,
})
.setClusterSupplier(clusterSupplier)
.build();
http.use(router);
},
});
},
});

就是这样!现在可以构建模块,将集群添加到 kubernetes 后端插件中。GoogleContainerEngineSupplier到 kubernetes 后端:

import { kubernetesClustersSupplierExtensionPoint } from '@backstage/plugin-kubernetes-node';

// This is a custom implementation of the ClusterSupplier interface.
import { GoogleContainerEngineSupplier } from './GoogleContainerEngineSupplier';

export default createBackendModule({
pluginId: 'kubernetes',
moduleId: 'gke-supplier',
register(env) {
env.registerInit({
deps: {
supplier: kubernetesClustersSupplierExtensionPoint,
},
async init({ supplier }) {
supplier.setClusterSupplier(new GoogleContainerEngineSupplier());
},
});
},
});

然后,集成者可将上述模块与 kubernetes 后端插件一起安装:

backend.add(import('@backstage/plugin-kubernetes-backend'));
backend.add(import('@internal/gke-cluster-supplier'));