本文将介绍如何使用 Helm Chart 在 Kubernetes 上部署 Backstage,并与 Argo CD 和 Prometheus 集成。
译自 Backstage on Kubernetes - Piotr's TechBlog,作者 Piotr Minkowski。
本文将介绍如何将 Backstage 与 Kubernetes 集成。我们将通过两种不同的方式运行 Backstage。首先,它将在集群外部运行,并通过 API 与 Kubernetes 连接。在第二种情况下,我们将使用官方的 Helm Chart 直接将其部署到集群中。我们的 Backstage 实例将连接到 Kubernetes 上部署的 Argo CD 和 Prometheus,以可视化 Argo CD 同步状态和与应用程序相关的基本指标。
本练习延续了我之前文章中描述的关于 Backstage 的工作。因此,在开始之前,您应该阅读那篇文章以了解整个概念。在很多地方,我会提到之前文章中描述和完成的内容。我在那里描述了如何配置和运行 Backstage,以及如何为示例 Spring Boot 应用程序构建基本模板。您应该熟悉所有这些基本术语,才能完全理解当前练习中发生的事情。
如果您想自己尝试,可以随时查看我的源代码。我们的示例 GitHub 仓库 包含使用 Backstage 技术 Skaffolder 编写的软件模板。在本文中,我们将分析一个专门针对 Kubernetes 的模板,该模板位于 templates/spring-boot-basic-on-kubernetes
目录中。克隆此仓库后,您只需按照我的说明操作即可。
以下是我们仓库的结构。除了模板之外,它还包含 Argo CD 模板,其中包含要应用于 Kubernetes 的 YAML 部署清单。
.
├── skeletons
│ └── argocd
│ └── manifests
│ ├── deployment.yaml
│ └── service.yaml
├── templates
│ └── spring-boot-basic-on-kubernetes
│ ├── skeleton
│ │ ├── README.md
│ │ ├── catalog-info.yaml
│ │ ├── k8s
│ │ │ ├── deployment.yaml
│ │ │ └── kind-cluster-test.yaml
│ │ ├── pom.xml
│ │ ├── renovate.json
│ │ ├── skaffold.yaml
│ │ └── src
│ │ ├── main
│ │ │ ├── java
│ │ │ │ └── ${{values.javaPackage}}
│ │ │ │ ├── Application.java
│ │ │ │ ├── controller
│ │ │ │ │ └── ${{values.domainName}}Controller.java
│ │ │ │ └── domain
│ │ │ │ └── ${{values.domainName}}.java
│ │ │ └── resources
│ │ │ └── application.yml
│ │ └── test
│ │ ├── java
│ │ │ └── ${{values.javaPackage}}
│ │ │ └── ${{values.domainName}}ControllerTests.java
│ │ └── resources
│ │ └── k6
│ │ └── load-tests-add.js
│ └── template.yaml
└── templates.yaml
还有一个与本文相关的 Git 仓库。它包含修改后的 Backstage 源代码,其中安装和配置了多个插件。本文详细介绍了使用插件扩展 Backstage 的过程。因此,您可以从头开始,一步一步地按照我的说明操作。但您也可以克隆该仓库中提交的代码的最终版本,并在您的笔记本电脑上运行它。
在开始使用 Backstage 之前,我们需要运行和配置我们的 Kubernetes 集群实例。例如,它可以是 Minikube。一旦您拥有运行的集群,您就可以通过执行以下命令获取其控制平面 URL。如您所见,我的 Minikube 可在 https://127.0.0.1:55782
地址下访问,因此我以后需要在 Backstage 配置中设置它。
$ kubectl cluster-info
Kubernetes control plane is running at https://127.0.0.1:55782
...
$ export K8S_URL=https://127.0.0.1:55782
我们需要在 Kubernetes 上安装 Prometheus 和 Argo CD。为了安装 Prometheus,我们将使用 kube-prometheus-stack
Helm Chart。首先,我们应该使用以下命令添加 Prometheus Chart 仓库:
$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
然后,我们可以运行以下命令在 monitoring
命名空间中安装 Prometheus:
$ helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack \
--version 60.3.0 \
-n monitoring --create-namespace
与 Prometheus 相同,对于 Argo CD,我们首先需要添加Chart 仓库:
$ helm repo add argo https://argoproj.github.io/argo-helm
对于 Argo CD,我们需要在 values.yaml
文件中提供额外的配置。我们必须为 Backstage 创建用户,该用户具有使用 apiKey
身份验证调用 HTTP API 的权限。这需要从 Skaffolder 模板自动创建 Argo CD Application
。
configs:
cm:
accounts.backstage: apiKey,login
rbac:
policy.csv: |
p, backstage, applications, *, */*, allow
让我们使用 values.yaml 文件中的配置在 argocd 名称空间中安装 Argo CD:
$ helm install argo-cd argo/argo-cd \
--version 7.2.0 \
-f values.yaml \
-n argocd --create-namespace
除此之外,我们还需要为 backstage
用户生成 apiKey
。首先,让我们为 Argo CD 和 Prometheus 服务启用端口转发,以便通过本地主机访问它们的 API。
$ kubectl port-forward svc/argo-cd-argocd-server 8443:443 -n argocd
$ kubectl port-forward svc/kube-prometheus-stack-prometheus 9090 -n monitoring
为了为 backstage 用户生成 apiKey,我们需要使用 argocd
CLI 以 admin
用户身份登录 Argo CD。然后,我们需要为 backstage 帐户运行以下命令,并将生成的令牌导出为 ARGOCD_TOKEN
环境变量:
$ argocd account generate-token --account backstage
$ export ARGOCD_TOKEN='argocd.token=<generated_token>'
最后,让我们通过创建秘密来获取 Kubernetes 的长期 API 令牌:
apiVersion: v1
kind: Secret
metadata:
name: default-token
namespace: default
annotations:
kubernetes.io/service-account.name: default
type: kubernetes.io/service-account-token
YAML然后,我们可以使用以下命令将其复制并导出为 K8S_TOKEN
环境变量:
$ export K8S_TOKEN=$(kubectl get secret default-token -o go-template='{{.data.token | base64decode}}')
仅出于测试目的,我们将 cluster-admin
角色添加到默认的 ServiceAccount
。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: default-admin
subjects:
- kind: ServiceAccount
name: default
namespace: default
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
首先,我们将修改应用程序源代码框架中的几个方面。为了构建容器镜像,我们在 Maven pom.xml
中包含 jib-maven-plugin
。此插件将在 jib
Maven 配置文件中激活。
<profiles>
<profile>
<id>jib</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>3.4.3</version>
<configuration>
<from>
<image>eclipse-temurin:21-jdk-ubi9-minimal</image>
</from>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
XML我们的源代码存储库还将包含 Skaffold 配置文件。使用 Skaffold,我们可以轻松地构建镜像并将应用程序部署到 Kubernetes,只需一步即可。镜像地址取决于 Skaffolder 模板中的 orgName
和 appName
参数。在镜像构建过程中,我们跳过测试并激活 Maven jib
配置文件。
apiVersion: skaffold/v4beta5
kind: Config
metadata:
name: ${{ values.appName }}
build:
artifacts:
- image: ${{ values.orgName }}/${{ values.appName }}
jib:
args:
- -Pjib
- -DskipTests
manifests:
rawYaml:
- k8s/deployment.yaml
deploy:
kubectl: {}
YAML为了在 Kubernetes 上部署应用程序,Skaffold 正在寻找 k8s/deployment.yaml
清单。我们只将此部署清单用于开发和自动化测试目的。在“生产”环境中,我们将 YAML 清单保存在单独的 Git 存储库中,并通过 Argo CD 应用它们。一旦我们在源代码中提供更改,CircleCI 将尝试将应用程序部署到临时 Kind 集群。因此,我们的 Service
在 30000
端口下作为 NodePort
公开。
apiVersion: apps/v1
kind: Deployment
metadata:
name: ${{ values.appName }}
spec:
selector:
matchLabels:
app: ${{ values.appName }}
template:
metadata:
annotations:
prometheus.io/path: /actuator/prometheus
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
labels:
app: ${{ values.appName }}
spec:
containers:
- name: ${{ values.appName }}
image: ${{ values.orgName }}/${{ values.appName }}
ports:
- containerPort: 8080
readinessProbe:
httpGet:
port: 8080
path: /actuator/health/readiness
scheme: HTTP
timeoutSeconds: 1
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
resources:
limits:
memory: 1024Mi
---
apiVersion: v1
kind: Service
metadata:
name: ${{ values.appName }}
spec:
type: NodePort
selector:
app: ${{ values.appName }}
ports:
- port: 8080
nodePort: 30000
YAML让我们切换到 CircleCi 配置文件。它还包含与 Kubernetes 相关的几个更改。我们需要包含 image-build
作业,该作业负责使用 Jib 构建应用程序镜像并将其推送到目标注册表。我们还包含 deploy-k8s
作业以执行对 Kind 集群的测试部署。在此作业中,我们必须在 CircleCI 执行器机器上安装 Skaffold 和 Kind 工具。一旦 Kind 集群启动并准备就绪,我们通过执行 skaffold run
命令将应用程序部署到那里。
version: 2.1
jobs:
analyze:
docker:
- image: 'cimg/openjdk:21.0.2'
steps:
- checkout
- run:
name: Analyze on SonarCloud
command: mvn verify sonar:sonar -DskipTests
test:
executor: machine_executor_amd64
steps:
- checkout
- run:
name: Install OpenJDK 21
command: |
java -version
sudo apt-get update && sudo apt-get install openjdk-21-jdk
sudo update-alternatives --set java /usr/lib/jvm/java-21-openjdk-amd64/bin/java
sudo update-alternatives --set javac /usr/lib/jvm/java-21-openjdk-amd64/bin/javac
java -version
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
- run:
name: Maven Tests
command: mvn test
deploy-k8s:
executor: machine_executor_amd64
steps:
- checkout
- run:
name: Install Kubectl
command: |
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv ./kubectl /usr/local/bin/kubectl
- run:
name: Install Skaffold
command: |
curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64
chmod +x skaffold
sudo mv skaffold /usr/local/bin
- run:
name: Install Kind
command: |
[ $(uname -m) = x86_64 ] && curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind
- run:
name: Install OpenJDK 21
command: |
java -version
sudo apt-get update && sudo apt-get install openjdk-21-jdk
sudo update-alternatives --set java /usr/lib/jvm/java-21-openjdk-amd64/bin/java
sudo update-alternatives --set javac /usr/lib/jvm/java-21-openjdk-amd64/bin/javac
java -version
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
- run:
name: Create Kind Cluster
command: |
kind create cluster --name c1 --config k8s/kind-cluster-test.yaml
- run:
name: Deploy to K8s
command: |
export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
skaffold run
- run:
name: Delete Kind Cluster
command: |
kind delete cluster --name c1
image-push:
docker:
- image: 'cimg/openjdk:21.0.2'
steps:
- checkout
- run:
name: Build and push image to DockerHub
command: mvn compile jib:build -Pjib -Djib.to.image=${{ values.orgName }}/${{ values.appName }}:latest -Djib.to.auth.username=${DOCKER_LOGIN} -Djib.to.auth.password=${DOCKER_PASSWORD} -DskipTests
executors:
machine_executor_amd64:
machine:
image: ubuntu-2204:2023.10.1
environment:
architecture: "amd64"
platform: "linux/amd64"
workflows:
maven_test:
jobs:
- test
- analyze:
context: SonarCloud
- deploy-k8s:
requires:
- test
- image-push:
context: Docker
requires:
- deploy-k8s
在上一篇关于 Backstage 的文章中,我们学习了如何安装 GitHub、CircleCI 和 Sonarqube 集成的插件。我们仍然会使用这些插件,但也会将我们的 Backstage 实例扩展一些额外的插件,主要用于 Kubernetes 原生环境。我们将安装以下插件:Kubernetes(后端 + 前端)、HTTP 请求操作(后端)、Argo CD(前端)和 Prometheus(前端)。让我们从 Kubernetes 插件开始。
第一步,我们安装 Kubernetes 前端插件。它允许我们在 Backstage UI 中查看在 Kubernetes 上运行的应用程序 Pod。为了安装它,我们需要执行以下 yarn
命令:
$ yarn --cwd packages/app add @backstage/plugin-kubernetes
然后,我们需要在 packages/app/src/components/catalog/EntityPage.tsx
文件中进行一些更改。我们应该导入 EntityKubernetesContent
组件,然后将其包含在 serviceEntityPage
对象中,作为前端上的新路由。
import { EntityKubernetesContent } from '@backstage/plugin-kubernetes';
const serviceEntityPage = (
<EntityLayout>
...
<EntityLayout.Route path="/kubernetes" title="Kubernetes">
<EntityKubernetesContent refreshIntervalMs={30000} />
</EntityLayout.Route>
...
</EntityLayout>
);
我们还需要安装 Kubernetes 后端插件,以使其在前端站点上正常工作。以下是所需的 yarn
命令:
$ yarn --cwd packages/backend add @backstage/plugin-kubernetes-backend
然后,我们应该在 packages/backend/src/index.ts
文件中注册 plugin-kubernetes-backend
模块。
import { createBackend } from '@backstage/backend-defaults';
const backend = createBackend();
backend.add(import('@backstage/plugin-app-backend/alpha'));
backend.add(import('@backstage/plugin-proxy-backend/alpha'));
backend.add(import('@backstage/plugin-scaffolder-backend/alpha'));
backend.add(import('@backstage/plugin-techdocs-backend/alpha'));
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-guest-provider'));
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(
import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
);
backend.add(import('@backstage/plugin-permission-backend/alpha'));
backend.add(import('@backstage/plugin-permission-backend-module-allow-all-policy'));
backend.add(import('@backstage/plugin-search-backend/alpha'));
backend.add(import('@backstage/plugin-search-backend-module-catalog/alpha'));
backend.add(import('@backstage/plugin-search-backend-module-techdocs/alpha'));
backend.add(import('@backstage/plugin-scaffolder-backend-module-github'));
backend.add(import('@backstage-community/plugin-sonarqube-backend'));
backend.add(import('@backstage/plugin-kubernetes-backend/alpha'));
backend.start();
该插件与 Kubernetes 无关。它允许我们通过 HTTP API 服务与第三方解决方案集成。正如你可能记得的,我们已经在 Backstage UI 中与 Sonarcloud 和 CircleCI 集成了。然而,我们并没有在那里创建任何项目。我们只能查看 Sonarcloud 或 CircleCI 中先前创建的项目的构建或扫描历史。是时候在我们的模板中更改它了!借助 HTTP 请求操作插件,我们将通过 REST API 创建 Argo CD 应用程序。和往常一样,我们需要执行 yarn add 命令来安装后端插件:
import { createBackend } from '@backstage/backend-defaults';
const backend = createBackend();
backend.add(import('@backstage/plugin-app-backend/alpha'));
backend.add(import('@backstage/plugin-proxy-backend/alpha'));
backend.add(import('@backstage/plugin-scaffolder-backend/alpha'));
backend.add(import('@backstage/plugin-techdocs-backend/alpha'));
backend.add(import('@backstage/plugin-auth-backend'));
backend.add(import('@backstage/plugin-auth-backend-module-guest-provider'));
backend.add(import('@backstage/plugin-catalog-backend/alpha'));
backend.add(
import('@backstage/plugin-catalog-backend-module-scaffolder-entity-model'),
);
backend.add(import('@backstage/plugin-permission-backend/alpha'));
backend.add(
import('@backstage/plugin-permission-backend-module-allow-all-policy'),
);
backend.add(import('@backstage/plugin-search-backend/alpha'));
backend.add(import('@backstage/plugin-search-backend-module-catalog/alpha'));
backend.add(import('@backstage/plugin-search-backend-module-techdocs/alpha'));
backend.add(import('@backstage/plugin-scaffolder-backend-module-github'));
backend.add(import('@backstage-community/plugin-sonarqube-backend'));
backend.add(import('@backstage/plugin-kubernetes-backend/alpha'));
backend.add(import('@roadiehq/scaffolder-backend-module-http-request/new-backend'));
backend.start();
接下来,我们可以使用前一篇文章中用到的一些附加步骤来修改一个 Skaffolder 模版。
一旦将所有内容放到位, 我们可以修改标准 Spring Boot 应用程序的先前模板, 以便将其适应 Kubernetes 要求。
首先, 我们添加一个单一的输入参数, 该参数表示运行我们的应用程序的 Kubernetes 中的目标命名空间 (1)。然后, 我们添加一些其他操作步骤。在其第一个步骤中, 我们生成 Argo CD 的 YAML 配置清单存储库 (2)。然后, 我们将在 GitHub 上发布该存储库, 仓库名为 ${{parameters.appName}}-gitops (3)。
之后, 我们将使用 HTTP 请求操作插件在 CircleCI 中自动跟踪新存储库 (5)。一旦我们在上一步中创建了此类存储库, CircleCI 便会在检测到该存储库后自动开始构建。我们还使用 HTTP 请求操作插件在 Sonarcloud 上创建与 ${{parameters.appName}} 相同名称的新存储库 (4)。最后, 我们通过 API 与 Argo CD 集成, 以创建一个新的应用程序, 该应用程序负责将应用程序部署应用到 Kubernetes (6)。此 Argo CD 应用程序将使用先前发布的配置存储库, 仓库名中带有 -config 后缀, 并应用 manifests 目录内的清单 。
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: spring-boot-basic-on-kubernetes-template
title: Create a Spring Boot app for Kubernetes
description: Create a Spring Boot app for Kubernetes
tags:
- spring-boot
- java
- maven
- circleci
- renovate
- sonarqube
- kubernetes
- argocd
spec:
owner: piomin
system: microservices
type: service
parameters:
- title: Provide information about the new component
required:
- orgName
- appName
- domainName
- repoBranchName
- groupId
- javaPackage
- apiPath
- namespace
- description
properties:
orgName:
title: Organization name
type: string
default: piomin
appName:
title: App name
type: string
default: sample-spring-boot-app-k8s
domainName:
title: Name of the domain object
type: string
default: Person
repoBranchName:
title: Name of the branch in the Git repository
type: string
default: master
groupId:
title: Maven Group ID
type: string
default: pl.piomin.services
javaPackage:
title: Java package directory
type: string
default: pl/piomin/services
apiPath:
title: REST API path
type: string
default: /api/v1
# (1)
namespace:
title: The target namespace on Kubernetes
type: string
default: demo
description:
title: Description
type: string
default: Spring Boot App Generated by Backstage
steps:
- id: sourceCodeTemplate
name: Generating the Source Code Component
action: fetch:template
input:
url: ./skeleton
values:
orgName: ${{ parameters.orgName }}
appName: ${{ parameters.appName }}
domainName: ${{ parameters.domainName }}
groupId: ${{ parameters.groupId }}
javaPackage: ${{ parameters.javaPackage }}
apiPath: ${{ parameters.apiPath }}
- id: publish
name: Publishing to the Source Code Repository
action: publish:github
input:
allowedHosts: ['github.com']
description: ${{ parameters.description }}
repoUrl: github.com?owner=${{ parameters.orgName }}&repo=${{ parameters.appName }}
defaultBranch: ${{ parameters.repoBranchName }}
repoVisibility: public
- id: register
name: Registering the Catalog Info Component
action: catalog:register
input:
repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
catalogInfoPath: /catalog-info.yaml
# (2)
- id: configCodeTemplate
name: Generating the Config Code Component
action: fetch:template
input:
url: ../../skeletons/argocd
values:
orgName: ${{ parameters.orgName }}
appName: ${{ parameters.appName }}
targetPath: ./gitops
# (3)
- id: publish
name: Publishing to the Config Code Repository
action: publish:github
input:
allowedHosts: ['github.com']
description: ${{ parameters.description }}
repoUrl: github.com?owner=${{ parameters.orgName }}&repo=${{ parameters.appName }}-config
defaultBranch: ${{ parameters.repoBranchName }}
sourcePath: ./gitops
repoVisibility: public
# (4)
- id: sonarqube
name: Follow new project on Sonarcloud
action: http:backstage:request
input:
method: 'POST'
path: '/proxy/sonarqube/projects/create?name=${{ parameters.appName }}&organization=${{ parameters.orgName }}&project=${{ parameters.orgName }}_${{ parameters.appName }}'
headers:
content-type: 'application/json'
# (5)
- id: circleci
name: Follow new project on CircleCI
action: http:backstage:request
input:
method: 'POST'
path: '/proxy/circleci/api/project/gh/${{ parameters.orgName }}/${{ parameters.appName }}/follow'
headers:
content-type: 'application/json'
# (6)
- id: argocd
name: Create New Application in Argo CD
action: http:backstage:request
input:
method: 'POST'
path: '/proxy/argocd/api/applications'
headers:
content-type: 'application/json'
body:
metadata:
name: ${{ parameters.appName }}
namespace: argocd
spec:
project: default
source:
# (7)
repoURL: https://github.com/${{ parameters.orgName }}/${{ parameters.appName }}-config.git
targetRevision: master
path: manifests
destination:
server: https://kubernetes.default.svc
namespace: ${{ parameters.namespace }}
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
output:
links:
- title: Open the Source Code Repository
url: ${{ steps.publish.output.remoteUrl }}
- title: Open the Catalog Info Component
icon: catalog
entityRef: ${{ steps.register.output.entityRef }}
我们的 catalog-info.yaml 文件应该包含与之前章节安装的插件相关的更多注释。argocd/app-name 注释表示负责在 Kubernetes 上部署的目标 Argo CD 应用程序的名称。backstage.io/kubernetes-id 注释包含用于在 Backstage UI 中显示的 Kubernetes 上搜索 Pod 的标签值。最后,prometheus.io/rule 注释包含 Prometheus 查询的逗号分隔列表。我们将创建显示应用程序 Pod CPU 和内存使用情况的图形。
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: ${{ values.appName }}
title: ${{ values.appName }}
annotations:
circleci.com/project-slug: github/${{ values.orgName }}/${{ values.appName }}
github.com/project-slug: ${{ values.orgName }}/${{ values.appName }}
sonarqube.org/project-key: ${{ values.orgName }}_${{ values.appName }}
backstage.io/kubernetes-id: ${{ values.appName }}
argocd/app-name: ${{ values.appName }}
prometheus.io/rule: container_memory_usage_bytes{pod=~"${{ values.appName }}-.*"}|pod,rate(container_cpu_usage_seconds_total{pod=~"${{ values.appName }}-.*"}[5m])|pod
tags:
- spring-boot
- java
- maven
- circleci
- renovate
- sonarqube
spec:
type: service
owner: piotr.minkowski@gmail.com
lifecycle: experimental
我们需要在 app-config.yaml 文件中包含一些配置设置。它包括 proxy 部分,应包含 HTTP Request 动作插件和前端插件所需的所有 API。我们应该包含 CircleCI (1)、Sonarcloud (2)、Argo CD (3) 和 Prometheus (4) 的代理地址。之后,我们包括 Skaffolder 模板 (5) 的地址。我们还必须包含具有 Minikube 集群地址和先前生成的 service 帐户令牌的 kubernetes 部分 (6)。
app:
title: Scaffolded Backstage App
baseUrl: http://localhost:3000
organization:
name: piomin
backend:
baseUrl: http://localhost:7007
listen:
port: 7007
csp:
connect-src: ["'self'", 'http:', 'https:']
cors:
origin: http://localhost:3000
methods: [GET, HEAD, PATCH, POST, PUT, DELETE]
credentials: true
database:
client: better-sqlite3
connection: ':memory:'
integrations:
github:
- host: github.com
token: ${GITHUB_TOKEN}
proxy:
# (1)
'/circleci/api':
target: https://circleci.com/api/v1.1
headers:
Circle-Token: ${CIRCLECI_TOKEN}
# (2)
'/sonarqube':
target: https://sonarcloud.io/api
allowedMethods: [ 'GET', 'POST' ]
auth: "${SONARCLOUD_TOKEN}:"
# (3)
'/argocd/api':
target: https://localhost:8443/api/v1/
changeOrigin: true
secure: false
headers:
Cookie:
$env: ARGOCD_TOKEN
# (4)
'/prometheus/api':
target: http://localhost:9090/api/v1/
auth:
providers:
guest: {}
catalog:
import:
entityFilename: catalog-info.yaml
pullRequestBranchName: backstage-integration
rules:
- allow: [Component, System, API, Resource, Location]
locations:
- type: file
target: ../../examples/entities.yaml
- type: file
target: ../../examples/template/template.yaml
rules:
- allow: [Template]
# (5)
- type: url
target: https://github.com/piomin/backstage-templates/blob/master/templates/spring-boot-basic-on-kubernetes/template.yaml
rules:
- allow: [ Template ]
- type: file
target: ../../examples/org.yaml
rules:
- allow: [User, Group]
sonarqube:
baseUrl: https://sonarcloud.io
apiKey: ${SONARCLOUD_TOKEN}
# (6)
kubernetes:
serviceLocatorMethod:
type: 'multiTenant'
clusterLocatorMethods:
- type: 'config'
clusters:
- url: ${K8S_URL}
name: minikube
authProvider: 'serviceAccount'
skipTLSVerify: false
skipMetricsLookup: true
serviceAccountToken: ${K8S_TOKEN}
dashboardApp: standard
caFile: '/Users/pminkows/.minikube/ca.crt'
我们的 Backstage 源代码存储库包含所有必需的插件和配置。现在,我们将使用 yarn 工具构建它。这里列出一些执行构建所需的命令。
$ yarn clean
$ yarn install
$ yarn tsc
$ yarn build:backend
后端已经包含了 Backstage 的存储库。它在 packages/backend 目录。
FROM node:18-bookworm-slim
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && \
apt-get install -y --no-install-recommends python3 g++ build-essential && \
yarn config set python /usr/bin/python3
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update && \
apt-get install -y --no-install-recommends libsqlite3-dev
USER node
WORKDIR /app
ENV NODE_ENV production
COPY --chown=node:node yarn.lock package.json packages/backend/dist/skeleton.tar.gz ./
RUN tar xzf skeleton.tar.gz && rm skeleton.tar.gz
RUN --mount=type=cache,target=/home/node/.cache/yarn,sharing=locked,uid=1000,gid=1000 \
yarn install --frozen-lockfile --production --network-timeout 300000
COPY --chown=node:node packages/backend/dist/bundle.tar.gz app-config*.yaml ./
RUN tar xzf bundle.tar.gz && rm bundle.tar.gz
CMD ["node", "packages/backend", "--config", "app-config.yaml"]
为了使用 packages/backend 目录中的 Dockerfile 构建镜像,我们需要从项目根目录运行以下命令。
$ yarn build-image
如果您看到类似结果,表示生成已成功完成。
镜像可作为 backstage:latest 本地获取。使用以下命令可在 Docker 中运行它:
$ docker run -it -p 7007:7007 \
-e GITHUB_TOKEN=${GITHUB_TOKEN} \
-e SONARCLOUD_TOKEN=${SONARCLOUD_TOKEN} \
-e CIRCLECI_TOKEN=${CIRCLECI_TOKEN} \
-e ARGOCD_TOKEN=${ARGOCD_TOKEN} \
-e K8S_TOKEN=${K8S_TOKEN} \
-e K8S_URL=${K8S_URL} \
-e NODE_ENV=development \
backstage:latest
不过我们今天的目标是直接在 Kubernetes 中运行它。我的 Docker 注册表中提供了我们自定义的 Backstage 镜像:piomin/backstage:latest。
我们将使用官方 Helm Chart 来在 Kubernetes 上安装 Backstage。在第一步中,让我们添加下列图表存储库:
$ helm repo add backstage https://backstage.github.io/charts
以下是用于 Helm 安装的 values.yaml 文件。我们需要将所有必需的令牌设置为 Backstage pod 中的额外环境变量。我们还将安装中使用的默认映像更改为之前构建的自定义映像。为了简化练习,我们可以禁用外部数据库并使用内部 SQLite 实例。不必重建 Docker 映像(my-app-config),只要将额外配置文件定义为 ConfigMap,即可对其进行传递。
backstage:
extraEnvVars:
- name: NODE_ENV
value: development
- name: GITHUB_TOKEN
value: ${GITHUB_TOKEN}
- name: SONARCLOUD_TOKEN
value: ${SONARCLOUD_TOKEN}
- name: CIRCLECI_TOKEN
value: ${CIRCLECI_TOKEN}
- name: ARGOCD_TOKEN
value: ${ARGOCD_TOKEN}
image:
registry: docker.io
repository: piomin/backstage
extraAppConfig:
- filename: app-config.extra.yaml
configMapRef: my-app-config
postgresql:
enabled: false
我们将通过修改 app-config.yaml 文件来将 Kubernetes 集群、Argo CD 和 Prometheus 的地址更改为内部集群位置。
proxy:
.
'/argocd/api':
target: https://argo-cd-argocd-server.argocd.svc/api/v1/
changeOrigin: true
secure: false
headers:
Cookie:
$env: ARGOCD_TOKEN
'/prometheus/api':
target: http://kube-prometheus-stack-prometheus.monitoring.svc:9090/api/v1/
catalog:
locations:
...
- type: url
target: https://github.com/piomin/backstage-templates/blob/master/templates/spring-boot-basic-on-kubernetes/template.yaml
rules:
- allow: [ Template ]
kubernetes:
serviceLocatorMethod:
type: 'multiTenant'
clusterLocatorMethods:
- type: 'config'
clusters:
- url: https://kubernetes.default.svc
name: minikube
authProvider: 'serviceAccount'
skipTLSVerify: false
skipMetricsLookup: true
然后,我们将创建幕后命名空间和额外的 ConfigMap,其中包含 Kubernetes 集群内部运行的幕后的新配置。
$ kubectl create ns backstage
$ kubectl create configmap my-app-config \
--from-file=app-config.extra.yaml=app-config-kubernetes.yaml -n backstage
最后,执行以下命令在 backstage 命名空间中安装我们自定义的后端实例:
$ envsubst < values.yaml | helm install backstage backstage/backstage \
--values - -n backstage
因此,在 Kubernetes 中有一个正在运行的 Backstage pod:
$ kubectl get po -n backstage
NAME READY STATUS RESTARTS AGE
backstage-7bfbc55647-8cj5d 1/1 Running 0 16m
启用端口转发以在 http://localhost:7007 访问 Backstage UI:
$ kubectl port-forward svc/backstage 7007 -n backstage
这次我们给我们实例 Backstage 所使用的后台命名空间的默认 ServiceAccount 增加权限:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: default-admin
subjects:
- kind: ServiceAccount
name: default
namespace: backstage
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
通过访问后台 UI,我们可以从模板创建新的 Spring Boot 应用。选择“创建 Kubernetes 的 Spring Boot 应用”模板,如下所示:
如果您想自行尝试,则需要将组织名称更改为您的 GitHub 帐户名称。然后点击下一页上的“Review”和“Create”。
将创建两个 GitHub 存储库。第一个存储库包含示例应用程序源代码。
第二个包含用于 Argo CD 部署的 YAML 清单。Argo CD 应用程序将自动创建。
我们可以在 Backstage UI 中验证同步状态。
我们的应用程序在 demo 命名空间中运行。我们可以“KUBERNETES”选项卡中显示 Pod 列表。
我们还可以验证每个 Pod 的详细信息状态。
或者查看日志。
在本文中,我们学习了如何使用 Argo CD 或 Prometheus 等 Kubernetes 原生服务安装并集成 Backstage。我们使用 Backstage 构建了自定义镜像,然后使用 Helm Chart 将其部署到 Kubernetes 上。