Backstage: Xây dựng Developer Portal cho team của bạn từ A đến Z
Backstage là framework mã nguồn mở từ Spotify giúp bạn xây dựng developer portal, gom tất cả service, docs, tooling về một nơi. Mình sẽ hướng dẫn setup chi tiết.
Nguyễn Nhật Long
@nguyennhatlong1303
Backstage: Xây dựng Developer Portal cho team của bạn từ A đến Z
Mình nhớ cái thời mới vào một công ty có hơn 50 microservices. Muốn tìm owner của một service thì phải hỏi trên Slack. Muốn biết service đó dùng database gì thì phải đọc README (nếu có). Muốn tạo một service mới thì copy-paste từ service cũ rồi sửa tay. Documentation thì nằm rải rác từ Confluence, Google Docs đến Notion. Nghe quen không?
Đó chính xác là vấn đề mà Backstage giải quyết. Và hôm nay mình sẽ đi sâu vào nó không phải kiểu overview chung chung, mà là thực sự setup, config, và hiểu cách nó hoạt động.
Backstage giải quyết cái gì mà Spotify phải tự build?
Backstage được Spotify tạo ra từ nội bộ, ban đầu chỉ để dùng cho chính họ. Bạn thử tưởng tượng Spotify có hơn 2000 microservices, hàng trăm team dev nếu không có một nơi trung tâm để quản lý tất cả thì sẽ loạn. Sau đó họ open-source nó và donate cho CNCF (Cloud Native Computing Foundation), hiện tại đang ở mức Incubation tức là đã đủ mature để production dùng được.
Core idea của Backstage xoay quanh 3 trụ cột chính:
Ngoài 3 cái core đó, Backstage còn có một hệ sinh thái plugin cực kỳ phong phú Kubernetes, CI/CD, monitoring, cost management... gần như cái gì cũng có plugin.
| Tính năng | Mô tả | Giải quyết vấn đề gì |
|---|---|---|
| **Software Catalog** | Quản lý tất cả service, library, website, data pipeline, ML model trong một nơi | Không còn phải hỏi "ai own cái service này?" |
| **Software Templates** | Template để tạo project mới theo chuẩn của tổ chức | Không còn copy-paste rồi sửa tay |
| **TechDocs** | Documentation as code, viết bằng Markdown, render trực tiếp trong portal | Docs không còn nằm rải rác khắp nơi |
Bắt tay vào setup Backstage
Điều kiện tiên quyết: bạn cần Node.js (phiên bản 18 hoặc 20), Yarn, và Git. Backstage dùng Yarn Berry (v3+) nên anh em đừng dùng npm nhé.
1# Tạo Backstage app mới2npx @backstage/create-app@latest
Command này sẽ hỏi bạn tên app, rồi nó scaffold ra một monorepo hoàn chỉnh. Cấu trúc folder trông sẽ như thế này:
1my-backstage-app/2├── app-config.yaml # Config chính3├── catalog-info.yaml # Catalog entity của chính app này4├── packages/5│ ├── app/ # Frontend (React)6│ └── backend/ # Backend (Node.js/Express)7├── plugins/ # Custom plugins của bạn8└── package.json
Sau khi scaffold xong, chạy:
1cd my-backstage-app2yarn install3yarn dev
yarn dev sẽ start cả frontend (port 3000) và backend (port 7007) cùng lúc. Mở browser lên http://localhost:3000 là bạn sẽ thấy giao diện Backstage.
Theo kinh nghiệm của mình, bước setup ban đầu này rất smooth. Cái khó nằm ở phần config và customize sau đó.
Hiểu Software Catalog trái tim của Backstage
Software Catalog là thứ quan trọng nhất trong Backstage. Nó là nơi bạn đăng ký tất cả "entities" trong hệ thống service, API, website, library, team, user... Mỗi entity được mô tả bằng một file YAML gọi là catalog-info.yaml, đặt ngay trong repo của service đó.
Đây là một ví dụ thực tế cho một service:
1apiVersion: backstage.io/v1alpha12kind: Component3metadata:4 name: payment-service5 description: Handles payment processing via Stripe and VNPay6 annotations:7 github.com/project-slug: my-org/payment-service8 backstage.io/techdocs-ref: dir:.9 tags:10 - java11 - spring-boot12 - payments13 links:14 - url: https://grafana.internal.com/d/payment15 title: Grafana Dashboard16 icon: dashboard17spec:18 type: service19 lifecycle: production20 owner: team-payment21 system: checkout-system22 providesApis:23 - payment-api24 consumesApis:25 - user-api26 - notification-api27 dependsOn:28 - resource:payment-db
Bạn thấy không? Chỉ với file YAML này, Backstage đã biết: service này do team nào own, đang ở lifecycle nào (production/experimental/deprecated), cung cấp API gì, consume API gì, phụ thuộc vào resource nào. Khi bạn mở Backstage lên, nó sẽ render thành một trang chi tiết với tất cả thông tin này, kèm theo link đến Grafana, GitHub, và docs.
Để Backstage biết tìm file catalog-info.yaml ở đâu, bạn config trong app-config.yaml:
1catalog:2 import:3 entityFilename: catalog-info.yaml4 pullRequestBranchName: backstage-integration5 rules:6 - allow: [Component, System, API, Resource, Location, Template, Group, User]7 locations:8 # Scan toàn bộ org trên GitHub9 - type: github-discovery10 target: https://github.com/my-org/*/blob/main/catalog-info.yaml1112 # Hoặc add từng repo cụ thể13 - type: url14 target: https://github.com/my-org/payment-service/blob/main/catalog-info.yaml
Mình thấy cái hay ở chỗ là bạn dùng github-discovery thì Backstage sẽ tự động scan tất cả repo trong org, tìm file catalog-info.yaml và import vào. Team chỉ cần thêm file YAML vào repo của mình là xong không cần vào Backstage UI để đăng ký gì cả.
Anh em lưu ý: lần đầu scan một org lớn (vài trăm repo) có thể mất khá lâu và hit rate limit của GitHub API. Config thêm schedule để nó scan định kỳ thay vì liên tục:
1catalog:2 providers:3 github:4 myOrg:5 organization: 'my-org'6 catalogPath: '/catalog-info.yaml'7 filters:8 branch: 'main'9 schedule:10 frequency: { minutes: 30 }11 timeout: { minutes: 3 }
Software Templates Standardize cách tạo project mới
Đây là feature mà theo mình, nó mang lại giá trị ngay lập tức cho team. Thay vì mỗi dev tự tạo project theo cách riêng, bạn define template trong Backstage. Dev chỉ cần vào portal, chọn template, điền vài thông tin, rồi Backstage sẽ tự tạo repo trên GitHub, setup CI/CD pipeline, đăng ký service vào catalog tất cả tự động.
Một template trông như thế này:
1apiVersion: scaffolder.backstage.io/v1beta32kind: Template3metadata:4 name: spring-boot-service5 title: Spring Boot Microservice6 description: Tạo một Spring Boot service mới với đầy đủ CI/CD, Docker, và monitoring7 tags:8 - java9 - spring-boot10spec:11 owner: team-platform12 type: service1314 parameters:15 - title: Thông tin service16 required:17 - name18 - owner19 properties:20 name:21 title: Tên service22 type: string23 description: Unique name cho service (kebab-case)24 pattern: '^[a-z0-9-]+$'25 owner:26 title: Team owner27 type: string28 ui:field: OwnerPicker29 ui:options:30 catalogFilter:31 kind: Group32 description:33 title: Mô tả34 type: string3536 - title: Infrastructure37 properties:38 database:39 title: Database40 type: string41 enum: ['postgresql', 'mysql', 'none']42 default: 'postgresql'43 javaVersion:44 title: Java Version45 type: string46 enum: ['17', '21']47 default: '21'4849 steps:50 - id: fetch-template51 name: Fetch skeleton code52 action: fetch:template53 input:54 url: ./skeleton55 values:56 name: ${{ parameters.name }}57 owner: ${{ parameters.owner }}58 database: ${{ parameters.database }}59 javaVersion: ${{ parameters.javaVersion }}6061 - id: publish62 name: Tạo GitHub repository63 action: publish:github64 input:65 allowedHosts: ['github.com']66 repoUrl: github.com?owner=my-org&repo=${{ parameters.name }}67 defaultBranch: main68 repoVisibility: internal6970 - id: register71 name: Đăng ký vào Backstage Catalog72 action: catalog:register73 input:74 repoContentsUrl: ${{ steps['publish'].output.repoContentsUrl }}75 catalogInfoPath: '/catalog-info.yaml'7677 output:78 links:79 - title: Repository80 url: ${{ steps['publish'].output.remoteUrl }}81 - title: Mở trong Backstage82 icon: catalog83 entityRef: ${{ steps['register'].output.entityRef }}
Folder skeleton bên cạnh file template này chứa source code mẫu với các placeholder dùng Nunjucks syntax (${{ values.name }}). Khi dev chọn template và điền form, Backstage sẽ render skeleton code, tạo repo, push code, rồi đăng ký vào catalog. Cực kỳ mượt.
TechDocs Docs nằm cạnh code
Backstage dùng approach "docs like code": bạn viết docs bằng Markdown, config MkDocs, và Backstage render nó thành một trang docs đẹp ngay trong portal.
Thêm file mkdocs.yml vào root repo:
1site_name: Payment Service2nav:3 - Home: index.md4 - Architecture: architecture.md5 - API Reference: api.md6 - Runbook: runbook.md7 - Troubleshooting: troubleshooting.md89plugins:10 - techdocs-core
Rồi tạo folder docs/ với các file Markdown tương ứng. Trong catalog-info.yaml, thêm annotation:
1metadata:2 annotations:3 backstage.io/techdocs-ref: dir:.
Khi dev mở service trong Backstage, tab "Docs" sẽ hiện toàn bộ documentation. Docs luôn cập nhật theo code vì nó nằm cùng repo. Mình thấy approach này giải quyết triệt để vấn đề docs outdated vì khi dev sửa code, họ sửa docs luôn trong cùng một PR.
Config authentication và database cho production
Default Backstage dùng SQLite in-memory, tức là restart là mất hết data. Cho production, bạn cần PostgreSQL:
1# app-config.production.yaml2backend:3 database:4 client: pg5 connection:6 host: ${POSTGRES_HOST}7 port: ${POSTGRES_PORT}8 user: ${POSTGRES_USER}9 password: ${POSTGRES_PASSWORD}
Về authentication, Backstage hỗ trợ nhiều provider. Phổ biến nhất là GitHub OAuth:
1auth:2 environment: production3 providers:4 github:5 production:6 clientId: ${AUTH_GITHUB_CLIENT_ID}7 clientSecret: ${AUTH_GITHUB_CLIENT_SECRET}
Rồi trong code backend, bạn cần config sign-in resolver để map GitHub user với Backstage entity:
1// packages/backend/src/index.ts2import { createBackend } from '@backstage/backend-defaults';34const backend = createBackend();56backend.add(import('@backstage/plugin-auth-backend'));7backend.add(import('@backstage/plugin-auth-backend-module-github-provider'));8backend.add(import('@backstage/plugin-catalog-backend'));9backend.add(import('@backstage/plugin-techdocs-backend'));10backend.add(import('@backstage/plugin-scaffolder-backend'));1112backend.start();
Backstage mới chuyển sang "new backend system" dùng declarative approach như trên, thay vì phải wire mọi thứ manually. Nếu anh em đọc tutorial cũ thấy code backend dài dằng dặc thì đừng hoảng version mới clean hơn nhiều.
Plugin ecosystem sức mạnh thực sự
Backstage có hơn 200+ plugin từ community. Đây là một số plugin mình thấy hữu ích nhất:
Cài plugin thường chỉ cần:
| Plugin | Chức năng | Khi nào cần |
|---|---|---|
| `@backstage/plugin-kubernetes` | Xem pods, deployments, logs trực tiếp trong Backstage | Team dùng K8s |
| `@backstage/plugin-github-actions` | Xem CI/CD status từ GitHub Actions | Dùng GitHub Actions |
| `@roadiehq/backstage-plugin-argo-cd` | Quản lý ArgoCD deployments | Dùng ArgoCD |
| `@backstage/plugin-cost-insights` | Theo dõi cloud cost theo service | Muốn control chi phí |
| `@backstage/plugin-api-docs` | Render OpenAPI/AsyncAPI specs | Có API documentation |
| `@pagerduty/backstage-plugin` | Xem on-call schedule, incidents | Dùng PagerDuty |
1# Cài plugin frontend2yarn --cwd packages/app add @backstage/plugin-kubernetes34# Cài plugin backend5yarn --cwd packages/backend add @backstage/plugin-kubernetes-backend
Rồi thêm vào backend và frontend config. Mỗi plugin có docs riêng khá chi tiết.
Deploy Backstage lên production
Backstage cung cấp sẵn Dockerfile. Build image:
1yarn install --frozen-lockfile2yarn tsc3yarn build:backend45docker build -t backstage:latest -f packages/backend/Dockerfile .
Một docker-compose.yml đơn giản cho staging:
1version: '3.8'2services:3 backstage:4 image: backstage:latest5 ports:6 - '7007:7007'7 environment:8 POSTGRES_HOST: db9 POSTGRES_PORT: 543210 POSTGRES_USER: backstage11 POSTGRES_PASSWORD: backstage12 depends_on:13 - db1415 db:16 image: postgres:1517 environment:18 POSTGRES_USER: backstage19 POSTGRES_PASSWORD: backstage20 POSTGRES_DB: backstage21 volumes:22 - pgdata:/var/lib/postgresql/data2324volumes:25 pgdata:
Cho production thực sự, mình recommend deploy lên Kubernetes với Helm chart. Community có maintain chart tại backstage/charts trên GitHub.
Những bài học mình rút ra sau khi triển khai
Sau khi đưa Backstage vào dùng cho team ~40 dev, mình có vài điều muốn chia sẻ:
Bắt đầu nhỏ. Đừng cố enable tất cả plugin cùng lúc. Bắt đầu với Software Catalog trước chỉ cần mọi người thêm catalog-info.yaml vào repo là đã có giá trị rồi. Sau đó mới thêm Templates, rồi TechDocs.
Ownership là key. Cái giá trị lớn nhất mình thấy không phải là technology, mà là việc mọi service đều có owner rõ ràng. Khi có incident, bạn mở Backstage lên, tìm service, biết ngay team nào own, ai đang on-call.
Đừng underestimate effort maintain. Backstage release rất thường xuyên (gần như hàng tuần). Upgrade version đôi khi có breaking changes. Team platform cần allocate time để maintain. Backstage có tool backstage-cli versions:bump để giúp việc upgrade, nhưng vẫn cần test kỹ.
Custom plugin không khó như bạn nghĩ. Backstage dùng React cho frontend và Express cho backend. Nếu team bạn cần integrate với internal tool, viết custom plugin khá straightforward. Scaffold plugin bằng:
1yarn new --select plugin
Nó sẽ tạo sẵn structure cho bạn, chỉ cần fill logic vào.
Nếu team bạn đang ở giai đoạn 20+ services trở lên và bắt đầu thấy chaos trong việc quản lý Backstage là một investment rất đáng. Nó không phải silver bullet, vẫn cần effort để setup và maintain, nhưng cái giá trị nó mang lại cho developer experience là rất rõ ràng. Mỗi lần onboard dev mới, thay vì phải giải thích "service A gọi service B qua Kafka, rồi service C poll từ S3..." thì chỉ cần nói: "mở Backstage lên, tất cả ở đó".
Nguyễn Nhật Long
@nguyennhatlong1303Nguyễn Nhật Long is a Senior Frontend Engineer and Frontend Team Leader with 7 years of experience building real-time fintech platforms. Specializing in React, Next.js, TypeScript, and React Native, shipping 10+ products across Web, Mobile, Telegram Mini-Apps, and Web3.
Thấy hay? Chia sẻ cho bạn bè!