You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将NodeJS/Express REST API接入K8s自定义资源并关联部署、成为API端点?

将NodeJS/Express API集成到Kubernetes API并关联自定义资源

核心思路

要把你的Express API变成Kubernetes API的一部分,核心是利用**Kubernetes聚合层(Aggregation Layer)**扩展API,同时通过自定义资源定义(CRD)+ 控制器实现CR与应用部署的关联。以下是分步实现方案:


1. 确认集群已启用聚合层

Kubernetes聚合层默认可能未开启,需检查kube-apiserver的启动参数:

  • 确保存在--enable-aggregator-routing=true
  • 确认kube-apiserver有权限访问集群内服务(默认配置通常满足,若有问题需调整RBAC规则)

2. 改造Express API适配Kubernetes规范

你的API需要遵循Kubernetes的API格式,同时处理K8s的身份认证:

2.1 遵循K8s API响应格式

所有返回的资源需包含kind、apiVersion、metadata、spec、status字段,示例结构:

// GET /apis/myapp.example.com/v1/myapps/{name} 返回示例
res.json({
  kind: "MyApp",
  apiVersion: "myapp.example.com/v1",
  metadata: {
    name: "demo-app",
    namespace: "default",
    uid: "xxxx-xxxx-xxxx"
  },
  spec: {
    image: "node:18-alpine",
    replicas: 2,
    port: 3000
  },
  status: {
    readyReplicas: 2,
    phase: "Running"
  }
});

2.2 处理Kubernetes身份认证

K8s API要求请求携带Bearer Token,需在Express中解析并验证Token:

const express = require('express');
const { KubeConfig, TokenReview } = require('@kubernetes/client-node');

const app = express();
app.use(express.json());

// Token验证中间件
async function authenticate(req, res, next) {
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).send('Missing or invalid authorization header');
  }

  const token = authHeader.split(' ')[1];
  const kc = new KubeConfig();
  kc.loadFromDefault();
  const k8sApi = kc.makeApiClient(TokenReview);

  try {
    const review = await k8sApi.createTokenReview({ spec: { token } });
    if (review.body.status.authenticated) {
      req.user = review.body.status.user;
      next();
    } else {
      res.status(401).send('Invalid token');
    }
  } catch (err) {
    res.status(500).send('Failed to verify token');
  }
}

// 给API路由应用认证中间件
app.use('/apis/myapp.example.com/v1', authenticate);

// 实现CRUD路由
app.get('/apis/myapp.example.com/v1/myapps', (req, res) => {
  res.json({
    kind: "MyAppList",
    apiVersion: "myapp.example.com/v1",
    items: []
  });
});

// POST/PUT/DELETE路由逻辑类似,此处省略

3. 部署Express API到Kubernetes

3.1 编写Deployment和Service YAML

# myapp-api-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-api
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp-api
  template:
    metadata:
      labels:
        app: myapp-api
    spec:
      serviceAccountName: myapp-api-sa
      containers:
      - name: myapp-api
        image: your-nodejs-image:latest # 替换为你的镜像地址
        ports:
        - containerPort: 3000

---
# myapp-api-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-api
  namespace: default
spec:
  selector:
    app: myapp-api
  ports:
  - port: 443
    targetPort: 3000

3.2 创建ServiceAccount及权限

给API服务账号分配调用TokenReview的权限:

# myapp-api-sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: myapp-api-sa
  namespace: default

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: myapp-api-clusterrole
rules:
- apiGroups: ["authentication.k8s.io"]
  resources: ["tokenreviews"]
  verbs: ["create"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: myapp-api-binding
subjects:
- kind: ServiceAccount
  name: myapp-api-sa
  namespace: default
roleRef:
  kind: ClusterRole
  name: myapp-api-clusterrole
  apiGroup: rbac.authorization.k8s.io

4. 注册API到Kubernetes聚合层

创建APIService资源,告知K8s你的API位置:

# myapp-api-service-registration.yaml
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
  name: v1.myapp.example.com
spec:
  group: myapp.example.com
  version: v1
  service:
    name: myapp-api
    namespace: default
  groupPriorityMinimum: 1000
  versionPriority: 10

5. 关联CR与应用部署(实现控制器逻辑)

用NodeJS编写控制器,监听CR变化,自动创建/更新应用部署:

5.1 定义CRD

# myapp-crd.yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: myapps.myapp.example.com
spec:
  group: myapp.example.com
  versions:
  - name: v1
    served: true
    storage: true
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              image:
                type: string
              replicas:
                type: integer
              port:
                type: integer
          status:
            type: object
            properties:
              readyReplicas:
                type: integer
              phase:
                type: string
  scope: Namespaced
  names:
    plural: myapps
    singular: myapp
    kind: MyApp
    shortNames:
    - ma

5.2 NodeJS控制器代码示例

const { KubeConfig, AppsV1Api, CustomObjectsApi, Watch } = require('@kubernetes/client-node');

const kc = new KubeConfig();
kc.loadFromDefault();
const appsApi = kc.makeApiClient(AppsV1Api);
const customApi = kc.makeApiClient(CustomObjectsApi);

// 监听MyApp CR的变化
async function watchMyApps() {
  const watch = new Watch(kc);
  await watch.watch(
    '/apis/myapp.example.com/v1/namespaces/default/myapps',
    {},
    (type, obj) => {
      switch (type) {
        case 'ADDED':
          createDeployment(obj);
          break;
        case 'MODIFIED':
          updateDeployment(obj);
          break;
        case 'DELETED':
          deleteDeployment(obj);
          break;
      }
    },
    (err) => {
      console.error('Watch error:', err);
      setTimeout(watchMyApps, 5000); // 出错后重试
    }
  );
}

// 根据CR创建Deployment
async function createDeployment(myApp) {
  const deploymentName = `myapp-${myApp.metadata.name}`;
  try {
    await appsApi.createNamespacedDeployment('default', {
      metadata: { name: deploymentName, labels: { app: deploymentName } },
      spec: {
        replicas: myApp.spec.replicas,
        selector: { matchLabels: { app: deploymentName } },
        template: {
          metadata: { labels: { app: deploymentName } },
          spec: {
            containers: [{
              name: 'app-container',
              image: myApp.spec.image,
              ports: [{ containerPort: myApp.spec.port }]
            }]
          }
        }
      }
    });
    // 更新CR状态
    await customApi.patchNamespacedCustomObject(
      'myapp.example.com', 'v1', 'default', 'myapps', myApp.metadata.name,
      [{ op: 'replace', path: '/status', value: { phase: 'Running', readyReplicas: myApp.spec.replicas } }]
    );
  } catch (err) {
    console.error('Failed to create deployment:', err);
  }
}

// 更新/删除Deployment逻辑类似,此处省略

// 启动监听
watchMyApps();

验证

部署所有资源后,可通过Kubectl直接访问你的API:

kubectl get myapps
# 创建一个MyApp CR实例
kubectl create -f - <<EOF
apiVersion: myapp.example.com/v1
kind: MyApp
metadata:
  name: demo
spec:
  image: node:18-alpine
  replicas: 2
  port: 3000
EOF
# 检查是否自动创建了对应Deployment
kubectl get deployments

内容的提问来源于stack exchange,提问作者Lady Sonia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 02:25:42