将后端迁移到新的后端系统
概览
本节将介绍如何迁移现有的 Backstage 后端服务包(一般在packages/backend) 来使用新的后端系统。
新后端系统的主要优点之一是抽象化了插件及其依赖关系的连接方式,从而大大简化了后端软件包,当插件或其依赖关系发生变化时,后端软件包很少需要更改。 一般来说,您不必先将所有内部插件和支持类本身转换为后端系统,这里的迁移主要是在后端软件包中尽可能地连接和使用兼容性封装器。 我们希望您会发现,通过这些步骤,您的软件包最终会变得更小、更易懂、更易维护,然后能够迁移插件作为以后的一项单独工作。
整体结构
典型的后端软件包有几个总体组成部分:
- 一个 "index.ts "文件,包含所有插件及其依赖项的创建和连接 * 一个 "types.ts "文件,定义 "环境",即后端创建并传递给每个插件的各种依赖项 * 一个 "plugins "文件夹,每个插件都有一个文件,例如 "plugins/catalog.ts
 
索引文件的整体形状是这样的
import todo from './plugins/todo'; // repeated for N plugins
function makeCreateEnv(config: Config) {
  return (plugin: string): PluginEnvironment => {
    // ... build per-plugin environment
  };
}
async function main() {
  // ... early init
  const createEnv = makeCreateEnv(config);
  const todoEnv = useHotMemoize(module, () => createEnv('todo')); // repeated for N plugins
  const apiRouter = Router();
  apiRouter.use('/todo', await todo(todoEnv)); // repeated for N plugins
  // ... wire up and start http server
}
module.hot?.accept();
main().catch(...);
迁移索引文件
这次迁移将尝试让plugins文件夹保持不变,首先删除环境类型,并将索引文件减少到最低限度。plugins文件夹中的文件,一般用索引文件中的单行文字代替。
首先,让我们建立新索引文件的基础。 您可能需要注释掉旧文件的内容,或将旧文件重命名为index.backup.ts这些就是索引文件中新的空白内容:
import { createBackend } from '@backstage/backend-defaults';
const backend = createBackend();
backend.start();
请注意,环境构建器和main舞蹈完全消失了。
我们还需要添加一些后端系统软件包 作为依赖项。 运行以下命令:
# from the repository root
yarn add --cwd packages/backend @backstage/backend-defaults @backstage/backend-plugin-api
现在,您可以使用熟悉的yarn workspace backend start但这只是一个空白的服务,没有添加任何真正的功能。 因此,让我们用Ctrl+C并重新引入一些插件。
import { createBackend } from '@backstage/backend-defaults';
import { legacyPlugin } from '@backstage/backend-common';
const backend = createBackend();
backend.add(legacyPlugin('todo', import('./plugins/todo')));
backend.start();
todo上面使用的插件只是一个示例,您可能没有在自己的后端启用它。 请随意将它更改为您的plugins文件夹,例如backend.add(legacyPlugin('catalog', import('./plugins/catalog'))).
legacyPlugin帮助器可以轻松地在旧式插件文件和新的后端系统之间架起桥梁。 它可以确保在 env 中手动声明的依赖关系在Backstage被收集起来,然后将它们传递到相关的createPlugin导出函数,并确保其返回的路由处理程序以给定的前缀传递给 HTTP 路由器。
处理自定义环境
在简单的情况下,我们上面所做的就足够了,TypeScript 会很高兴,后端也会运行新的功能。 如果他们这样做了,请随意跳过这整个部分,并删除types.ts.
但有时,在新添加的行上会报告类型错误,说部分PluginEnvironment如果环境与默认设置不一致,也许是你自定义添加了一些内容,就会出现这种情况。 如果你安装的系统出现这种情况,你  也不是没有办法--你可以创建一个自定义的legacyPlugin功能。
import { createBackend } from '@backstage/backend-defaults';
import { legacyPlugin } from '@backstage/backend-common';
import {
  makeLegacyPlugin,
  loggerToWinstonLogger,
} from '@backstage/backend-common';
import { coreServices } from '@backstage/backend-plugin-api';
const legacyPlugin = makeLegacyPlugin(
  {
    cache: coreServices.cache,
    config: coreServices.rootConfig,
    database: coreServices.database,
    discovery: coreServices.discovery,
    logger: coreServices.logger,
    permissions: coreServices.permissions,
    scheduler: coreServices.scheduler,
    tokenManager: coreServices.tokenManager,
    reader: coreServices.urlReader,
    identity: coreServices.identity,
    // ... and your own additions
  },
  {
    logger: log => loggerToWinstonLogger(log),
  },
);
const backend = createBackend();
backend.add(legacyPlugin('todo', import('./plugins/todo')));
backend.start();
的第一个参数是makeLegacyPlugin是环境键与实际后端系统服务第二个参数允许您 "调整 "这些服务的类型,使其更适合您的 env。 例如,您会看到日志记录器服务的 API 类型已从过去的原始 Winston 日志记录器变为另一种自定义 API,因此我们使用一个辅助函数来转换这种特定的 API。
要对环境进行上述添加,您将开始深入了解后端系统布线的工作原理。 您需要有一个服务引用和一个服务工厂来执行服务的实际创建。服务条款如果你愿意,可以将代码直接放在索引文件中,或者放在相关的实际实现类附近。
在本例中,我们假设添加的环境字段名称为example创建的 ref 被命名为exampleServiceRef.
import { exampleServiceRef } from '<somewhere>'; // if the definition is elsewhere
const legacyPlugin = makeLegacyPlugin(
  {
    // ... the above core services still go here
    example: exampleServiceRef,
  },
  {
    logger: log => loggerToWinstonLogger(log),
  },
);
在这之后,你的后端就会知道如何按需实例化你的东西,并将其放置在传统插件环境中。
注意:如果您处理的服务 ref 恰好没有 > 默认实现,而是有一个单独的服务工厂,那么您 > 还需要导入该工厂,并将其传递给
createBackend的services数组 > 参数。
清理插件文件夹
对于您自己的私人插件,您可以按照专用迁移指南如果您认为合适,可以稍后再使用。
对于第三方后端插件,特别是由 Backstage 维护者维护的大型核心插件,你可能会发现它们已经迁移到了新的后端系统。 本节将介绍你可以进行的一些具体的此类迁移。
注意:请注意,您的后端仍然需要 > 依赖于这些插件包(例如在
packages/backend/package.json中),并且仍然需要在应用程序配置中正确配置这些插件包。 这些 > 机制仍然与旧后端系统中的机制相同。
应用程序插件
从后端(backend)为前端(frontend)提供服务的应用程序后端(backend)插件可以琐碎地以新形式使用。
const backend = createBackend();
backend.add(import('@backstage/plugin-app-backend/alpha'));
如果需要覆盖应用程序软件包名称(默认为"app"您可以通过app.packageName配置键。
您应该可以删除plugins/app.ts文件。
目录插件
目录插件的基本安装如下。
const backend = createBackend();
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(
  import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
);
请注意,这也会为目录安装脚手架模块,从而可以使用Template如果完全不使用模板,可以删除这一行。
如果您对plugins/catalog.ts否则,你可以直接删除该文件。
亚马逊网络服务
AwsEksClusterProcessor和AwsOrganizationCloudAccountProcessor尚未迁移到新的后端系统,请参见其他目录扩展了解如何在新的后端系统中使用这些功能。
对于AwsS3DiscoveryProcessor首先迁移到AwsS3EntityProvider.
迁移AwsS3EntityProvider到新的后端系统,添加对@backstage/plugin-catalog-backend-module-aws模块。
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(import('@backstage/plugin-catalog-backend-module-aws/alpha'));
如果您提供的是schedule中的所有其他 AWS 配置。app-config.yaml保持不变。
catalog:
  providers:
    awsS3:
      yourProviderId:
        # ...
        schedule:
          frequency: PT1H
          timeout: PT50M
Azure DevOps
对于AzureDevOpsDiscoveryProcessor首先迁移到AzureDevOpsEntityProvider.
迁移AzureDevOpsEntityProvider到新的后端系统,添加对@backstage/plugin-catalog-backend-module-azure模块。
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(import('@backstage/plugin-catalog-backend-module-azure/alpha'));
如果您提供的是schedule中的所有其他 Azure DevOps 配置。app-config.yaml保持不变。
catalog:
  providers:
    azureDevOps:
      yourProviderId:
        # ...
        schedule:
          frequency: PT1H
          timeout: PT50M
开放式应用程序接口
InternalOpenApiDocumentationProvider尚未迁移到新的后端系统,请参见其他目录扩展了解如何在新的后端系统中使用。
Bitbucket
对于BitbucketDiscoveryProcessor迁移到BitbucketCloudEntityProvider或BitbucketServerEntityProvider
迁移BitbucketCloudEntityProvider到新的后端系统,添加对@backstage/plugin-catalog-backend-module-bitbucket-cloud模块。
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(
  import('@backstage/plugin-catalog-backend-module-bitbucket-cloud/alpha'),
);
如果您提供的是schedule中的所有其他 Bitbucket 云配置。app-config.yaml保持不变。
catalog:
  providers:
    bitbucketCloud:
      yourProviderId:
        # ...
        schedule:
          frequency: PT30M
          timeout: PT3M
迁移BitbucketServerEntityProvider的引用,为新的后端系统添加对@backstage/plugin-catalog-backend-module-bitbucket-server.
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(
  import('@backstage/plugin-catalog-backend-module-bitbucket-server/alpha'),
);
如果您提供的是schedule中的所有其他 Bitbucket 服务器配置。app-config.yaml保持不变。
catalog:
  providers:
    bitbucketServer:
      yourProviderId:
        # ...
        schedule:
          frequency: PT30M
          timeout: PT3M
Google 云平台
迁移GkeEntityProvider的引用,为新的后端系统添加对@backstage/plugin-catalog-backend-module-gcp.
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(import('@backstage/plugin-catalog-backend-module-gcp'));
app-config.yaml 中的配置保持不变。
Gerrit
迁移GerritEntityProvider的引用,为新的后端系统添加对@backstage/plugin-catalog-backend-module-gerrit.
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(import('@backstage/plugin-catalog-backend-module-gerrit/alpha'));
如果您提供的是schedule中的所有其他 Gerrit 配置。app-config.yaml保持不变。
catalog:
  providers:
    gerrit:
      yourProviderId:
        # ...
        schedule:
          frequency: PT30M
          timeout: PT3M
Github
对于GithubDiscoveryProcessor,GithubMultiOrgReaderProcessor和GithubOrgReaderProcessor因此,首先要迁移到对等的实体提供程序。
迁移GithubEntityProvider的引用,为新的后端系统添加对@backstage/plugin-catalog-backend-module-github.
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(import('@backstage/plugin-catalog-backend-module-github/alpha'));
如果您提供的是schedule中的所有其他 Github 配置。app-config.yaml保持不变。
catalog:
  providers:
    github:
      yourProviderId:
        # ...
        schedule:
          frequency: PT30M
          timeout: PT3M
迁移GithubMultiOrgEntityProvider和GithubOrgEntityProvider的引用,为新的后端系统添加对@backstage/plugin-catalog-backend-module-github-org.
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(import('@backstage/plugin-catalog-backend-module-github-org'));
如果您提供的是schedule中的所有其他 Github 配置。app-config.yaml保持不变。
catalog:
  providers:
    githubOrg:
      yourProviderId:
        # ...
        schedule:
          frequency: PT30M
          timeout: PT3M
如果提供变压器,可通过延长githubOrgEntityProviderTransformsExtensionPoint
import { createBackendModule } from '@backstage/backend-plugin-api';
import { githubOrgEntityProviderTransformsExtensionPoint } from '@backstage/plugin-catalog-backend-module-github-org';
backend.add(
  createBackendModule({
    pluginId: 'catalog',
    moduleId: 'githubOrgTransformers',
    register(env) {
      env.registerInit({
        deps: {
          githubOrgTransformers:
            githubOrgEntityProviderTransformsExtensionPoint,
        },
        async init({ githubOrgTransformers }) {
          githubOrgTransformers.setUserTransformer(myUserTransformer);
          githubOrgTransformers.setTeamTransformer(myTeamTransformer);
        },
      });
    },
  }),
);
Microsoft Graph
对于MicrosoftGraphOrgReaderProcessor首先迁移到MicrosoftGraphOrgEntityProvider
迁移MicrosoftGraphOrgEntityProvider的引用,为新的后端系统添加对@backstage/plugin-catalog-backend-module-msgraph.
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(import('@backstage/plugin-catalog-backend-module-msgraph/alpha'));
如果您提供的是schedule中的所有其他 Microsoft Graph 配置。app-config.yaml保持不变。
catalog:
  providers:
    microsoftGraphOrg:
      provider:
        schedule:
          frequency: PT4H
          timeout: PT30M
如果提供变压器,可通过延长microsoftGraphOrgEntityProviderTransformExtensionPoint
import { createBackendModule } from '@backstage/backend-plugin-api';
import { microsoftGraphOrgEntityProviderTransformExtensionPoint } from '@backstage/plugin-catalog-backend-module-msgraph/alpha';
backend.add(
  createBackendModule({
    pluginId: 'catalog',
    moduleId: 'microsoft-graph-extensions',
    register(env) {
      env.registerInit({
        deps: {
          microsoftGraphTransformers:
            microsoftGraphOrgEntityProviderTransformExtensionPoint,
        },
        async init({ microsoftGraphTransformers }) {
          microsoftGraphTransformers.setUserTransformer(myUserTransformer);
          microsoftGraphTransformers.setGroupTransformer(myGroupTransformer);
          microsoftGraphTransformers.setOrganizationTransformer(
            myOrganizationTransformer,
          );
        },
      });
    },
  }),
);
其他目录扩展
您将使用扩展点机制来扩展或调整插件的功能。模块取决于相应的扩展点,并与之交互。
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { createBackendModule } from '@backstage/backend-plugin-api';
const catalogModuleCustomExtensions = createBackendModule({
  pluginId: 'catalog', // name of the plugin that the module is targeting
  moduleId: 'custom-extensions',
  register(env) {
    env.registerInit({
      deps: {
        catalog: catalogProcessingExtensionPoint,
        // ... and other dependencies as needed
      },
      async init({ catalog /* ..., other dependencies */ }) {
        // Here you have the opportunity to interact with the extension
        // point before the plugin itself gets instantiated
        catalog.addEntityProvider(new MyEntityProvider()); // just an example
        catalog.addProcessor(new MyProcessor()); // just an example
      },
    });
  },
});
const backend = createBackend();
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(
  import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
);
backend.add(catalogModuleCustomExtensions());
这还需要依赖于相应的节点软件包(如果还没有的话)。
# from the repository root
yarn add --cwd packages/backend @backstage/plugin-catalog-node
在这里,我们将模块直接放在后端索引文件中,以方便使用,但您也可以将其移至最合适的位置。 当您将整个插件群迁移到新的后端系统时,您可能会将越来越多的这些模块作为 "一级 "模块,与它们所代表的实现相邻,并从那里导出。
活动插件
事件插件的基本安装如下。
const backend = createBackend();
backend.add(import('@backstage/plugin-events-backend'));
如果您对plugins/events.ts否则,你可以直接删除该文件。
您将使用扩展点机制来扩展或调整插件的功能。模块取决于相应的扩展点,并与之交互。
import { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha';
import { createBackendModule } from '@backstage/backend-plugin-api';
const eventsModuleCustomExtensions = createBackendModule({
  pluginId: 'events', // name of the plugin that the module is targeting
  moduleId: 'custom-extensions',
  register(env) {
    env.registerInit({
      deps: {
        events: eventsExtensionPoint,
        // ... and other dependencies as needed
      },
      async init({ events /* ..., other dependencies */ }) {
        // Here you have the opportunity to interact with the extension
        // point before the plugin itself gets instantiated
        events.addSubscribers(new MySubscriber()); // just an example
      },
    });
  },
});
const backend = createBackend();
backend.add(import('@backstage/plugin-events-backend'));
backend.add(eventsModuleCustomExtensions());
这还需要依赖于相应的节点软件包(如果还没有的话)。
# from the repository root
yarn add --cwd packages/backend @backstage/plugin-events-node
在这里,我们将模块直接放在后端索引文件中,以方便使用,但您也可以将其移至最合适的位置。 当您将整个插件群迁移到新的后端系统时,您可能会将越来越多的这些模块作为 "一级 "模块,与它们所代表的实现相邻,并从那里导出。
Scaffolder 插件
Scaffolder 插件的基本安装如下。
const backend = createBackend();
backend.add(import('@backstage/plugin-scaffolder-backend/alpha'));
有了 Scaffolder 插件的新后端(Backend System)版本,任何特定于提供商的操作都需要单独安装。 例如,GitHub 操作现在收集在@backstage/plugin-scaffolder-backend-module-github包装
const backend = createBackend();
backend.add(import('@backstage/plugin-scaffolder-backend/alpha'));
backend.add(import('@backstage/plugin-scaffolder-backend-module-github'));
当然,您也需要单独安装这些设备。
# from the repository root
yarn add --cwd packages/backend @backstage/plugin-scaffolder-backend-module-github
您可以在插件目录在 monorepo 中。
如果您对plugins/scaffolder.ts否则,你可以直接删除该文件。
您将使用扩展点机制来扩展或调整插件的功能。模块取决于相应的扩展点,并与之交互。
import { scaffolderActionsExtensionPoint } from '@backstage/plugin-scaffolder-node/alpha';
import { createBackendModule } from '@backstage/backend-plugin-api';
const scaffolderModuleCustomExtensions = createBackendModule({
  pluginId: 'scaffolder', // name of the plugin that the module is targeting
  moduleId: 'custom-extensions',
  register(env) {
    env.registerInit({
      deps: {
        scaffolder: scaffolderActionsExtensionPoint,
        // ... and other dependencies as needed
      },
      async init({ scaffolder /* ..., other dependencies */ }) {
        // Here you have the opportunity to interact with the extension
        // point before the plugin itself gets instantiated
        scaffolder.addActions(new MyAction()); // just an example
      },
    });
  },
});
const backend = createBackend();
backend.add(import('@backstage/plugin-scaffolder-backend/alpha'));
backend.add(scaffolderModuleCustomExtensions());
这还需要依赖于相应的节点软件包(如果还没有的话)。
# from the repository root
yarn add --cwd packages/backend @backstage/plugin-scaffolder-node
在这里,我们将模块直接放在后端索引文件中,以方便使用,但您也可以将其移至最合适的位置。 当您将整个插件群迁移到新的后端系统时,您可能会将越来越多的这些模块作为 "一级 "模块,与它们所代表的实现相邻,并从那里导出。
Auth 插件
使用微软提供商安装 auth 插件的基本情况如下。
const backend = createBackend();
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));
您还需要在配置中添加解析器,下面是一个例子:
auth:
  environment: development
  providers:
    microsoft:
      development:
        clientId: ${AZURE_CLIENT_ID}
        clientSecret: ${AZURE_CLIENT_SECRET}
        tenantId: ${AZURE_TENANT_ID}
        signIn:
          resolvers:
            - resolver: emailMatchingUserEntityAnnotation
            - resolver: emailMatchingUserEntityProfileEmail
            - resolver: emailLocalPartMatchingUserEntityName
注意:将按顺序尝试解析器,但只有在它们抛出
NotFoundError时才会跳过。
Auth 插件模块及其解析器
您可能已经注意到,在上面的示例中,您需要导入auth-backend和一个auth-backend-module下文将逐一概述这些问题及其解决方法。
以下所有模块都包含以下常用解析器:
Atlassian
设置:
const backend = createBackend();
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-atlassian-provider'));
附加解析器:
GCP IAM
设置:
const backend = createBackend();
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-gcp-iap-provider'));
附加解析器:
GitHub
设置:
const backend = createBackend();
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-github-provider'));
附加解析器:
GitLab
设置:
const backend = createBackend();
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-gitlab-provider'));
附加解析器:
Google
设置:
const backend = createBackend();
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-google-provider'));
附加解析器:
微软
设置:
const backend = createBackend();
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-microsoft-provider'));
附加解析器:
oauth2
设置:
const backend = createBackend();
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-oauth2-provider'));
附加解析器:
oauth2 代理
设置:
const backend = createBackend();
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(
  import('@backstage/plugin-auth-backend-module-oauth2-proxy-provider'),
);
附加解析器:
Okta
设置:
const backend = createBackend();
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-okta-provider'));
附加解析器:
凤头鱼
设置:
const backend = createBackend();
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-pinniped-provider'));
VMware 云
设置:
const backend = createBackend();
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(
  import('@backstage/plugin-auth-backend-module-vmware-cloud-provider'),
);
附加解析器:
自定义解析器
在某些情况下,常用的解析器或您使用的 auth 模块中包含的解析器无法满足您的需求。 在这种情况下,您需要创建一个自定义解析器。 您可以提供自己的解析器,而不是为您的 auth 提供商模块导入第二个解析器:
export const authModuleGoogleProvider = createBackendModule({
  pluginId: 'auth',
  moduleId: 'googleProvider',
  register(reg) {
    reg.registerInit({
      deps: { providers: authProvidersExtensionPoint },
      async init({ providers }) {
        providers.registerProvider({
          providerId: 'google',
          factory: createOAuthProviderFactory({
            authenticator: googleAuthenticator,
            async signInResolver(info, ctx) {
              // custom resolver ...
            },
          }),
        });
      },
    });
  },
});
const backend = createBackend();
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(authModuleGoogleProvider);