Skip to content

feat: [PRD] API7 Developer Portal Frontend Helm Chart #265

@gxthrj

Description

@gxthrj

1. 背景 (Background)

API7 开发者门户由两部分组成:

  • Portal API(后端)api7/api7-ee-developer-portal,监听端口 4321,已经作为 api7 umbrella chart 的一部分部署在 Kubernetes 中
  • Developer Portal FE(前端)api7/api7-ee-developer-portal-fe,监听端口 3001,基于 api7-portal-boilerplate 构建的 Next.js 应用,目前只有 Docker Compose 部署方式

本 PRD 的目标是为 Developer Portal FE 创建一个独立的 Helm Chart,使其可以在 Kubernetes 集群中部署。

参考文档使用提供方门户设置开发者门户


2. 架构概览

┌─────────────────────────────────────────────────┐
│  api7 umbrella chart (已有)                       │
│  ┌──────────┐  ┌──────────┐  ┌──────────────┐   │
│  │ Dashboard │  │DP Manager│  │  Portal API  │   │
│  │  :7443    │  │  :7900   │  │ (后端) :4321 │   │
│  └──────────┘  └──────────┘  └──────┬───────┘   │
│                                      │           │
│                                PostgreSQL        │
│                                (共享 api7ee)      │
└──────────────────────────────────────┼───────────┘
                                       │ portal.url + portal.token
                                       │
┌──────────────────────────────────────┼───────────┐
│  developer-portal-fe chart (新建)     │           │
│  ┌──────────────────┐                │           │
│  │ Developer Portal  │◄──────────────┘           │
│  │ FE (Next.js)     │                            │
│  │  :3001           │                            │
│  └────────┬─────────┘                            │
│           │                                      │
│     PostgreSQL                                   │
│     (独立,用于 Better Auth 用户管理)               │
└──────────────────────────────────────────────────┘

关键区分

  • Portal API 后端(已有 chart)和 Developer Portal FE 前端(本 chart)使用不同的 PostgreSQL 数据库
  • FE 通过 portal.url + portal.token 连接后端 Portal API
  • FE 有自己的用户认证系统(Better Auth),数据存储在自己的 PostgreSQL 中

3. 应用运行时画像

3.1 Docker 镜像信息

属性
镜像 api7/api7-ee-developer-portal-fe
最新版本 v0.5.7
架构 linux/amd64, linux/arm64 (~85-86 MB)
基础镜像 Node.js 22 Alpine
容器端口 3001
配置文件路径 /app/apps/site/config.yaml
入口 ./docker-entrypoint.shnode apps/site/server.js

3.2 启动流程

docker-entrypoint.sh
  └─ preflight.js       # 验证数据库连通性 + Portal API 可用性
      └─ node apps/site/server.js   # 启动 Next.js 服务

3.3 Health Check

探针类型 路径 端口 协议
Liveness /healthz 3001 HTTP
Readiness /healthz 3001 HTTP

3.4 环境变量

变量 必需 说明
NODE_ENV 设为 production
PORT 服务端口(默认 3001)
HOSTNAME 监听地址(默认 0.0.0.0)
NODE_TLS_REJECT_UNAUTHORIZED 仅自签名证书场景 设为 0 跳过 TLS 验证
PORTAL_URL API7 Portal API endpoint
PORTAL_TOKEN 从 Provider Portal 生成的 Token

3.5 配置文件 Schema

config.yaml 支持 ${VAR}${VAR:default} 环境变量模板语法

完整 schema(来自 apps/site/config.yaml.example):

# 必需 - Portal API 连接
portal:
  url: ${PORTAL_URL:http://provider-portal.api.local}
  token: ${PORTAL_TOKEN:}

# 必需 - 数据库
db:
  url: ""                              # PostgreSQL 连接字符串
  # pool:                              # 可选连接池配置
  #   max: 20
  #   min: 0
  #   idleTimeout: 30000
  # ssl: false

# 必需 - 认证
auth:
  secret: ""                           # 至少 32 字符
  # session:
  #   expiresIn: 604800               # 7 天(秒)
  #   updateAge: 86400                # 1 天
  # emailAndPassword:
  #   enabled: true
  # socialProviders:                  # GitHub, Google 等

# 可选 - 应用设置
app:
  name: "Developer Portal"
  baseURL: "http://localhost:3001"
  trustedOrigins:
    - "*"

3.6 依赖

依赖 版本 用途
PostgreSQL 15+ 用户/组织数据存储(通过 Drizzle ORM)
API7 Portal API - 后端 REST API(端口 4321)

4. Docker Compose → Helm Chart 映射

Docker Compose 组件 Helm Chart 资源 说明
developer-portal service Deployment + Service + Ingress 镜像 api7/api7-ee-developer-portal-fe:v0.5.7
postgres service 子依赖 (bitnami/postgresql) 或外部连接 可选内置 PostgreSQL
config.yaml 挂载 ConfigMap(非敏感)+ Secret(敏感值通过环境变量注入) 挂载到 /app/apps/site/config.yaml
ports: "80:3001" Service port 80 → containerPort 3001
NODE_TLS_REJECT_UNAUTHORIZED env env in Deployment spec
volumes: postgres_data PVC(通过 postgresql subchart 管理)

5. Chart 设计

5.1 Chart 元数据

# charts/developer-portal-fe/Chart.yaml
apiVersion: v2
name: developer-portal-fe
description: A Helm chart for API7 Developer Portal Frontend
type: application
version: 0.1.0
appVersion: "0.5.7"
maintainers:
  - name: API7
    email: support@api7.ai
    url: https://api7.ai
dependencies:
  - name: postgresql
    condition: postgresql.builtin
    version: "12.12.10"
    repository: "https://charts.bitnami.com/bitnami"

5.2 values.yaml 结构

# ============================================================
# 应用配置
# ============================================================
developerPortal:
  replicaCount: 1
  image:
    repository: api7/api7-ee-developer-portal-fe
    pullPolicy: IfNotPresent
    tag: "v0.5.7"

  resources: {}
  extraEnvVars: []
  extraVolumes: []
  extraVolumeMounts: []
  podLabels: {}
  podAnnotations: {}
  topologySpreadConstraints: []

  # 针对自签名证书的 Portal API(仅开发环境使用)
  tlsRejectUnauthorized: true  # 设 false 则 NODE_TLS_REJECT_UNAUTHORIZED=0

  livenessProbe:
    initialDelaySeconds: 30
    periodSeconds: 10
    failureThreshold: 10
  readinessProbe:
    initialDelaySeconds: 10
    periodSeconds: 5
    failureThreshold: 3

# ============================================================
# Portal API 连接配置
# ============================================================
portal:
  # Portal API 的 endpoint(即 api7 chart 中部署的 developer portal 后端)
  url: "https://api7-developer-portal:4321"
  # 从 Provider Portal 生成的 Token(明文,优先级低于 existingSecret)
  token: ""
  # 引用已有 Secret(生产环境推荐)
  existingSecret: ""
  existingSecretKey: "portal-token"

# ============================================================
# 数据库配置
# ============================================================
db:
  # PostgreSQL 连接字符串
  url: "postgres://portal:portal123@developer-portal-fe-postgresql:5432/portal"
  # 引用已有 Secret(生产环境推荐)
  existingSecret: ""
  existingSecretKey: "db-url"

# ============================================================
# Auth 配置
# ============================================================
auth:
  # Better Auth secret key(至少 32 字符,可用 openssl rand -base64 32 生成)
  secret: ""
  existingSecret: ""
  existingSecretKey: "auth-secret"

# ============================================================
# 应用 URL 配置
# ============================================================
app:
  baseURL: "http://localhost"
  trustedOrigins:
    - "http://localhost"

# ============================================================
# Service 配置
# ============================================================
service:
  type: ClusterIP
  port: 80
  containerPort: 3001
  annotations: {}

# ============================================================
# Ingress 配置
# ============================================================
ingress:
  enabled: false
  className: ""
  annotations: {}
  hosts:
    - host: developer-portal.local
      paths:
        - path: /
          pathType: ImplementationSpecific
  tls: []

# ============================================================
# 内置 PostgreSQL
# ============================================================
postgresql:
  builtin: true
  fullnameOverride: "developer-portal-fe-postgresql"
  image:
    registry: docker.io
    repository: postgres
    tag: "16"
  auth:
    username: portal
    password: portal123
    database: portal
  primary:
    persistence:
      size: 10Gi
    service:
      ports:
        postgresql: 5432

# ============================================================
# 通用配置
# ============================================================
imagePullSecret: ""
nameOverride: ""
fullnameOverride: ""

serviceAccount:
  create: true
  annotations: {}
  name: ""

nodeSelector: {}
tolerations: []
affinity: {}

5.3 Templates 清单

文件 说明
_helpers.tpl 名称、标签、selector 等 helper 函数,遵循现有 chart 风格
configmap.yaml 生成 config.yaml(敏感字段使用 ${ENV_VAR} 占位符)
secret.yaml 包含 portal.tokenauth.secretdb.url(支持 existingSecret 时跳过创建)
deployment.yaml Developer Portal FE Deployment
service.yaml ClusterIP/NodePort/LoadBalancer Service
ingress.yaml 可选 Ingress
serviceaccount.yaml 可选 ServiceAccount
NOTES.txt 安装后提示信息

5.4 敏感数据策略

config.yaml 支持 ${VAR} 环境变量模板语法,因此采用以下策略:

  1. ConfigMap 中的 config.yaml 使用环境变量占位符:
# ConfigMap 中的 config.yaml
portal:
  url: {{ .Values.portal.url }}
  token: ${PORTAL_TOKEN}
db:
  url: ${DB_URL}
auth:
  secret: ${AUTH_SECRET}
app:
  baseURL: {{ .Values.app.baseURL }}
  trustedOrigins:
    {{- toYaml .Values.app.trustedOrigins | nindent 4 }}
  1. Secret 存储实际敏感值(PORTAL_TOKENDB_URLAUTH_SECRET
  2. Deployment 通过 envFrom.secretRef 将 Secret 挂载为环境变量
  3. 支持 existingSecret 引用外部管理的 Secret(Vault、Sealed Secrets 等)

5.5 Deployment 关键设计

containers:
  - name: developer-portal-fe
    image: "{{ image }}"
    ports:
      - containerPort: 3001
        name: http
        protocol: TCP
    env:
      - name: NODE_ENV
        value: "production"
      - name: PORT
        value: "3001"
      - name: HOSTNAME
        value: "0.0.0.0"
      - name: NODE_TLS_REJECT_UNAUTHORIZED
        value: "{{ if .Values.developerPortal.tlsRejectUnauthorized }}1{{ else }}0{{ end }}"
      - name: PORTAL_TOKEN
        valueFrom:
          secretKeyRef:
            name: {{ secret name }}
            key: portal-token
      - name: DB_URL
        valueFrom:
          secretKeyRef:
            name: {{ secret name }}
            key: db-url
      - name: AUTH_SECRET
        valueFrom:
          secretKeyRef:
            name: {{ secret name }}
            key: auth-secret
    volumeMounts:
      - name: config
        mountPath: /app/apps/site/config.yaml
        subPath: config.yaml
    livenessProbe:
      httpGet:
        path: /healthz
        port: http
      initialDelaySeconds: 30
      periodSeconds: 10
      failureThreshold: 10
    readinessProbe:
      httpGet:
        path: /healthz
        port: http
      initialDelaySeconds: 10
      periodSeconds: 5
      failureThreshold: 3
volumes:
  - name: config
    configMap:
      name: {{ fullname }}-config

6. 安全考虑

项目 策略
Portal Token 存储在 Kubernetes Secret 中,支持 existingSecret 引用外部管理的 Secret
Auth Secret 同上
DB Password 通过 db.url 连接字符串中包含,整个 URL 存储在 Secret
TLS 支持 Ingress TLS 终结;支持 NODE_TLS_REJECT_UNAUTHORIZED 配置(仅开发环境)
PostgreSQL 生产环境建议设 postgresql.builtin: false 使用外部托管数据库

7. 目录结构

charts/developer-portal-fe/
├── .helmignore
├── Chart.yaml
├── charts/                        # postgresql subchart(helm dependency update 生成)
├── README.md
├── templates/
│   ├── _helpers.tpl
│   ├── configmap.yaml
│   ├── deployment.yaml
│   ├── ingress.yaml
│   ├── NOTES.txt
│   ├── secret.yaml
│   ├── service.yaml
│   └── serviceaccount.yaml
└── values.yaml

8. 实现步骤

  1. 创建 charts/developer-portal-fe/ 目录结构
  2. 编写 Chart.yamlvalues.yaml
  3. 编写 _helpers.tpl(参考现有 chart 的 helper 模式)
  4. 编写 configmap.yaml(config.yaml 使用环境变量占位符)
  5. 编写 secret.yaml(portal token, auth secret, db url;支持 existingSecret)
  6. 编写 deployment.yaml
  7. 编写 service.yaml
  8. 编写 ingress.yaml
  9. 编写 serviceaccount.yaml
  10. 编写 NOTES.txt
  11. 编写 .helmignore
  12. helm lint + helm template 验证
  13. 编写 README.md
  14. 提交 PR 到 https://github.com/api7/api7-helm-chart

9. 已有参考资源

资源 路径/链接 用途
现有 api7 chart 的 developer-portal 模板 charts/api7/templates/developer-portal-*.yaml 参考模板风格和 helper 函数
boilerplate 仓库的 K8s 示例 dev-tools/devportal.yaml (GitHub) 参考 ConfigMap + Deployment 结构
Docker Compose 部署文档 getting-started 需求来源
config.yaml.example apps/site/config.yaml.example (GitHub) 完整配置 schema

10. 决策记录

决策点 决策 理由
Chart 独立 vs 集成到 umbrella chart 独立 chart FE 和后端是不同的应用,有独立的数据库和生命周期
敏感数据注入方式 环境变量 + config.yaml 占位符 应用原生支持 ${VAR} 语法,无需额外工具
PostgreSQL 依赖 可选内置 (bitnami subchart) 开发/测试用内置,生产环境用外部数据库
Chart 版本策略 独立版本(从 0.1.0 开始) appVersion 跟随 Docker 镜像 tag
PostgreSQL 版本 16(跟随官方文档 Docker Compose 示例) 文档示例使用 postgres:16

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions