日期:2026-09-15 | 对象:DevOps 工程师 | 范围:内部试点与测试环境(不含外部 SIT / PROD、不含公网入口)| 依据:《公司 AI 网关方案》§4 多环境、《Skill 中心 · SkillHub 整合评估》
0. 一页结论
- 形态:一台阿里云 ECS(4 vCPU / 16 GiB)用 Docker Compose 跑 agentgateway v1.5.0 与 SkillHub v0.2.20(server / web / scanner 三个容器);PostgreSQL、Redis、对象存储不装在机器上,分别用阿里云 RDS PostgreSQL 16、Tair(Redis 7 兼容)、OSS。
- 入口:只有内网。两个内网域名(网关 API、SkillHub Web)都指向 ECS 内网 IP,TLS 在 agentgateway 终止,443 端口只对办公网 / VPN 网段开放;SkillHub Web 只经网关按主机名转发,不直接暴露。
- 身份:阶段 1 用 agentgateway 管理界面签发的个人 Key(模型与 MCP 同一把 Key)+ SkillHub 首登管理员与本地账号;阶段 2 再加 Keycloak(AI IdP,飞书登录)并让 SkillHub 走 OIDC。阶段 2 的容器与路由已在部署包里以叠加文件给出。
- 与正式环境的关系:这是公司版方案"内部 1 套"的试点前身。配置文件、策略格式、镜像版本与后续落生产主集群命名空间的形态一致,试点验收后可平迁。
- DevOps 可直接开工的材料:§1 部署图、§2 资源清单、§3 网络与安全组、§4 部署包(
deploy/internal-test/:compose.yaml、compose.idp.yaml、gateway/config.yaml.tmpl、.env.example、render.sh)、§5 实施步骤与验收命令。需要业务侧先给的 5 个输入见 §6。
1. 部署图
读图要点:
- 左列是使用方,全部来自办公网或 VPN;四类流量汇聚到网关 443,运维走堡垒机 SSH 与管理界面 15000。
- 中间是阿里云 VPC。上方虚线框是那台 ECS 与其上的五个容器(Keycloak 为阶段 2);下方虚线框是托管中间件,二者之间是 VPC 内网,中间件只放行 ECS 内网 IP。
- 右列是出站目标:模型厂商与 MCP server 由网关经 NAT 访问,厂商 Key 只在网关;镜像仓库用公司 ACR 转存;飞书开放平台只在阶段 2 由 Keycloak 访问。
- 颜色:蓝 = 开源或云服务直接复用;青 = 需要配置或增强(Keycloak 联邦);灰 = 存量或范围外。本环境没有新开发组件。
2. 资源清单(阿里云)
| # | 资源 | 规格建议 | 数量 | 用途 | 说明 |
|---|---|---|---|---|---|
| 1 | ECS | ecs.g8i.xlarge(4 vCPU / 16 GiB);系统盘 ESSD 100 GiB;Alibaba Cloud Linux 3 或 Ubuntu 24.04;只分配内网 IP |
1 | 跑全部容器 | 官网目录价 502.32 元/月(2026-09-14)。不装 Keycloak 与 scanner 时可降到 ecs.c8i.xlarge(4 vCPU / 8 GiB,391.39 元/月)。倚天 c8y 系列便宜约 35%,但需拉 arm64 镜像(SkillHub 有多架构镜像,agentgateway 需确认) |
| 2 | RDS PostgreSQL | 16 版本,基础版 2 vCPU / 4 GiB,ESSD 50 GiB,内网地址 | 1 实例 3 库 | agentgateway(Key、预算、请求日志)、skillhub(技能库)、keycloak(阶段 2) |
三库三账号,各自只有本库权限;白名单只放 ECS 内网 IP;自动备份保留 7 天 |
| 3 | Tair(Redis 7 兼容) | 社区版 1 GiB 标准版(主从),内网地址,开密码 | 1 | SkillHub 会话与分布式锁 | 白名单只放 ECS 内网 IP;不开公网 |
| 4 | OSS | 标准存储,私有读写,同地域,开版本控制 | 1 Bucket | SkillHub 技能包 | RAM 子账号 AK,策略只授该 Bucket;服务端走内网 endpoint,浏览器下载链接走公网 endpoint |
| 5 | NAT 网关 | 存量或新建,绑定 ECS 所在交换机 | 1 | ECS 出站到模型厂商、公网 MCP、镜像仓库 | ECS 不绑 EIP;若出站要走代理,改网关的 provider baseUrl 或系统代理 |
| 6 | 内网 DNS(PrivateZone) | A 记录 → ECS 内网 IP | 2 条(阶段 2 加 1 条) | ai-gw-test.<内网域>、skills-test.<内网域>、idp-test.<内网域> |
域名由业务侧定,见 §6 |
| 7 | TLS 证书 | 一张证书含三个 SAN;公司内部 CA 签发,或公有 CA 用 DNS 验证签发 | 1 | 网关 443 | 内部 CA 时开发机需信任根证书;证书放 /opt/ai-gateway/certs/ |
| 8 | 容器镜像仓库(ACR) | 个人版或企业版,命名空间 ai-gateway |
1 | 转存 cr.agentgateway.dev 与 ghcr.io/iflytek 的镜像 |
避免 ECS 直接拉境外仓库不稳定;镜像与版本锁定见 §4.1 |
| 9 | 云监控 + SLS(可选) | ECS / RDS 基础监控免费;SLS 一个 Logstore,Logtail 采容器 stdout | — | 告警到飞书群;日志集中查 | 阶段 1 可只用 docker compose logs |
3. 网络与安全组
| 方向 | 端口 | 来源 / 目标 | 用途 | 备注 |
|---|---|---|---|---|
| 入站 | 443/TCP | 办公网与 VPN 网段 | agentgateway 统一入口(模型 API、MCP、SkillHub Web) | TLS 在网关终止;SkillHub 与阶段 2 的 Keycloak 按主机名转发 |
| 入站 | 15000/TCP | 运维 IP / 堡垒机 | agentgateway 管理界面(创建 Key、看日志、改预算) | 界面无鉴权,必须限源;后续可用网关自身 ui.policies 加认证 |
| 入站 | 22/TCP | 堡垒机 | SSH | 密钥登录,禁密码 |
| 入站 | 其他 | — | — | 全部拒绝;容器端口 18080 / 18081 / 15020 / 15021 / 18180 / 19000 只绑 127.0.0.1 |
| 出站 | 5432 / 6379 | RDS / Tair 内网地址 | 数据库与缓存 | RDS / Tair 白名单放 ECS 内网 IP |
| 出站 | 443 | OSS 内网 endpoint | 技能包读写 | oss-<region>-internal.aliyuncs.com |
| 出站 | 443 | 模型厂商、公网 MCP、镜像仓库、存量代理 | 经 NAT | 厂商 Key 只在网关配置文件 |
| 容器网络 | — | 10.207.0.0/24 |
Compose 默认网络 | 避开 Docker 默认地址池与公司 172.x 内网重叠 |
域名与路由(同一张证书、同一个 443):
| 主机名 | 网关路由 | 后端 | 鉴权 |
|---|---|---|---|
ai-gw-test.<内网域> |
/v1/*(模型,OpenAI / Anthropic 兼容)、/mcp/<name>(MCP) |
模型厂商 / 存量代理;登记的 MCP server | 个人 Key(Authorization: Bearer),模型与 MCP 同一把 |
skills-test.<内网域> |
/(主机名匹配) |
skillhub-web:80 → skillhub-server:8080 |
SkillHub 自身登录(首登管理员、本地账号;阶段 2 OIDC) |
idp-test.<内网域>(阶段 2) |
/(主机名匹配) |
keycloak:8080 |
Keycloak 自身 |
4. 部署包与配置
部署包在本目录 deploy/internal-test/,放到 ECS 的 /opt/ai-gateway/:
/opt/ai-gateway/
├── compose.yaml # agentgateway + skillhub-server + skillhub-web + skill-scanner
├── compose.idp.yaml # 阶段 2 叠加:keycloak + SkillHub OIDC 环境变量
├── .env # 由 .env.example 复制并填写;chmod 600;不入库
├── render.sh # 用 .env 渲染 gateway/config.yaml 并重启网关
├── gateway/
│ ├── config.yaml.tmpl # agentgateway 配置模板(入库)
│ └── config.yaml # 渲染产物(含口令;0600;属主 65532;不入库)
└── certs/
├── fullchain.pem # SAN:ai-gw-test / skills-test / idp-test
└── privkey.pem # 0600;属主 65532
4.1 镜像与版本锁定
| 组件 | 镜像 | 版本 | 说明 |
|---|---|---|---|
| agentgateway | cr.agentgateway.dev/agentgateway |
v1.5.0 |
无 shell 的最小镜像,以 uid 65532 运行;配置与证书文件属主要改为 65532 |
| SkillHub Server | ghcr.io/iflytek/skillhub-server |
v0.2.20 |
Java 21;Flyway 启动时自动建表 |
| SkillHub Web | ghcr.io/iflytek/skillhub-web |
v0.2.20 |
nginx,/api/*、/oauth2/*、/.well-known/* 反代到 server |
| skill-scanner | ghcr.io/iflytek/skillhub-scanner |
v0.2.20 |
可选;发布技能时做规则 / 行为扫描,AI 扫描可经网关调模型 |
| Keycloak(阶段 2) | quay.io/keycloak/keycloak |
26.7.3 |
与 POC 同版本;start 生产模式,数据库用 RDS |
转存到公司 ACR 后,把 .env 里的 AGW_IMAGE、SKILLHUB_*_IMAGE、KC_IMAGE 改成 ACR 地址;升级只改版本号,并按 §5.7 回滚。
4.2 Compose(compose.yaml)
要点:PostgreSQL / Redis 不在本机,全部指向 RDS / Tair;OSS 需要显式传 SKILLHUB_STORAGE_S3_DISABLE_CHUNKED_ENCODING=true(阿里云 OSS 不接受 aws-chunked 编码,上游发布模板没有透传这个变量);SkillHub Web 只经网关访问,所以 SKILLHUB_TRUST_FORWARDED_PROTO=true 且网关在该路由上覆写 X-Forwarded-Proto;每个容器有 CPU / 内存上限与日志滚动。
name: ai-gateway-test
x-common: &common
restart: unless-stopped
logging: { driver: json-file, options: { max-size: "50m", max-file: "5" } }
services:
agentgateway:
<<: *common
image: ${AGW_IMAGE:-cr.agentgateway.dev/agentgateway:v1.5.0}
command: ["-f", "/config/config.yaml"]
environment: { RUST_LOG: "${AGW_LOG_LEVEL:-info}" }
volumes: ["./gateway:/config:ro", "./certs:/certs:ro"]
ports: ["443:3000", "15000:15000", "127.0.0.1:15020:15020", "127.0.0.1:15021:15021"]
deploy: { resources: { limits: { cpus: "2", memory: 1G } } }
skillhub-server:
<<: *common
image: ${SKILLHUB_SERVER_IMAGE:-ghcr.io/iflytek/skillhub-server}:${SKILLHUB_VERSION:-v0.2.20}
environment:
SPRING_PROFILES_ACTIVE: docker
JAVA_TOOL_OPTIONS: -XX:MaxRAMPercentage=70 -Duser.timezone=Asia/Shanghai
SPRING_DATASOURCE_URL: jdbc:postgresql://${RDS_HOST}:${RDS_PORT:-5432}/skillhub
SPRING_DATASOURCE_USERNAME: ${SKILLHUB_DB_USER:-skillhub}
SPRING_DATASOURCE_PASSWORD: ${SKILLHUB_DB_PASSWORD:?required}
SPRING_DATA_REDIS_HOST: ${TAIR_HOST:?required}
SPRING_DATA_REDIS_PORT: ${TAIR_PORT:-6379}
SPRING_DATA_REDIS_PASSWORD: ${TAIR_PASSWORD:-}
SKILLHUB_PUBLIC_BASE_URL: https://${SKILLS_HOST:?required}
SESSION_COOKIE_SECURE: "true"
SKILLHUB_DOWNLOAD_ANON_COOKIE_SECRET: ${SKILLHUB_DOWNLOAD_ANON_COOKIE_SECRET:?required}
SKILLHUB_STORAGE_PROVIDER: s3
SKILLHUB_STORAGE_S3_ENDPOINT: https://oss-${ALIYUN_REGION:?required}-internal.aliyuncs.com
SKILLHUB_STORAGE_S3_PUBLIC_ENDPOINT: https://oss-${ALIYUN_REGION}.aliyuncs.com
SKILLHUB_STORAGE_S3_BUCKET: ${OSS_BUCKET:?required}
SKILLHUB_STORAGE_S3_ACCESS_KEY: ${OSS_ACCESS_KEY:?required}
SKILLHUB_STORAGE_S3_SECRET_KEY: ${OSS_SECRET_KEY:?required}
SKILLHUB_STORAGE_S3_REGION: ${ALIYUN_REGION}
SKILLHUB_STORAGE_S3_FORCE_PATH_STYLE: "false"
SKILLHUB_STORAGE_S3_DISABLE_CHUNKED_ENCODING: "true"
SKILLHUB_SECURITY_SCANNER_ENABLED: ${SKILLHUB_SECURITY_SCANNER_ENABLED:-true}
SKILLHUB_SECURITY_SCANNER_URL: http://skill-scanner:8000
SKILLHUB_SECURITY_SCANNER_MODE: upload
SKILLHUB_BUILTIN_SKILLS_ENABLED: "false"
SKILLHUB_LOG_FORMAT: json
BOOTSTRAP_ADMIN_ENABLED: ${BOOTSTRAP_ADMIN_ENABLED:-true}
BOOTSTRAP_ADMIN_USERNAME: ${BOOTSTRAP_ADMIN_USERNAME:-admin}
BOOTSTRAP_ADMIN_PASSWORD: ${BOOTSTRAP_ADMIN_PASSWORD:?required}
BOOTSTRAP_ADMIN_EMAIL: ${BOOTSTRAP_ADMIN_EMAIL:?required}
ports: ["127.0.0.1:18081:8080"]
depends_on: { skill-scanner: { condition: service_healthy } }
deploy: { resources: { limits: { cpus: "2", memory: 3G } } }
healthcheck: { test: ["CMD", "wget", "-qO-", "http://localhost:8080/actuator/health"], interval: 15s, timeout: 5s, retries: 12, start_period: 90s }
skillhub-web:
<<: *common
image: ${SKILLHUB_WEB_IMAGE:-ghcr.io/iflytek/skillhub-web}:${SKILLHUB_VERSION:-v0.2.20}
environment:
SKILLHUB_API_UPSTREAM: http://skillhub-server:8080
SKILLHUB_PUBLIC_BASE_URL: https://${SKILLS_HOST}
SKILLHUB_TRUST_FORWARDED_PROTO: "true"
ports: ["127.0.0.1:18080:80"]
depends_on: { skillhub-server: { condition: service_healthy } }
deploy: { resources: { limits: { cpus: "0.5", memory: 256M } } }
healthcheck: { test: ["CMD", "wget", "-qO-", "http://127.0.0.1/nginx-health"], interval: 15s, timeout: 5s, retries: 12 }
skill-scanner:
<<: *common
image: ${SKILLHUB_SCANNER_IMAGE:-ghcr.io/iflytek/skillhub-scanner}:${SKILLHUB_VERSION:-v0.2.20}
environment:
SKILL_SCANNER_LLM_API_KEY: ${SCANNER_LLM_API_KEY:-}
SKILL_SCANNER_LLM_BASE_URL: ${SCANNER_LLM_BASE_URL:-}
SKILL_SCANNER_LLM_MODEL: ${SCANNER_LLM_MODEL:-}
SKILLHUB_SCANNER_MAX_CONCURRENT_SCANS: "1"
deploy: { resources: { limits: { cpus: "1", memory: 1500M } } }
healthcheck: { test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8000/health"], interval: 15s, timeout: 5s, retries: 10 }
networks:
default: { ipam: { config: [{ subnet: 10.207.0.0/24 }] } }
完整文件(含注释与阶段 2 的 compose.idp.yaml)见部署包。
4.3 agentgateway 配置模板(gateway/config.yaml.tmpl)
要点:config.database.url 指向 RDS,storage.mode: hybrid 让管理界面创建的 Key、预算、模型白名单落库;请求日志入库只存元数据(不存提示词);gateways.default 在 3000 端口终止 TLS(宿主发布为 443);llm 段是模型入口并强制个人 Key;/mcp/context7 是验证"同一把 Key 接 MCP"的公网试点路由;skills-test 主机名转发到 SkillHub Web。
config:
adminAddr: 0.0.0.0:15000
statsAddr: 0.0.0.0:15020
readinessAddr: 0.0.0.0:15021
database:
url: postgresql://${AGW_DB_USER}:${AGW_DB_PASSWORD}@${RDS_HOST}:${RDS_PORT}/agentgateway
maxConnections: 5
storage:
mode: hybrid
logging:
format: json
database:
llm: metadata
gateways:
default:
port: 3000
tls: { cert: /certs/fullchain.pem, key: /certs/privkey.pem, minTlsVersion: "1.2" }
llm:
gateways: [default]
policies:
apiKey: { mode: strict, keys: [] } # Key 在管理界面创建(hybrid 落 RDS);也可写 keyHash: sha256:<hex>
localRateLimit:
- { type: requests, maxTokens: 300, tokensPerFill: 300, fillInterval: 60s }
providers:
- name: bailian
provider: openAI
params: { baseUrl: https://dashscope.aliyuncs.com/compatible-mode/v1, apiKey: "${BAILIAN_API_KEY}" }
- name: newapi
provider: openAI
params: { baseUrl: "${NEWAPI_BASE_URL}", apiKey: "${NEWAPI_API_KEY}" }
models:
- { name: coding-default, provider: { reference: bailian }, params: { model: "${BAILIAN_CODING_MODEL}" } }
- { name: chat-default, provider: { reference: newapi }, params: { model: "${NEWAPI_DEFAULT_MODEL}" } }
routes:
- name: mcp-context7
matches: [{ path: { exact: /mcp/context7 } }]
policies:
apiKey: { mode: strict, keys: [] }
cors: { allowOrigins: ['*'], allowHeaders: ['*'], exposeHeaders: [Mcp-Session-Id, Mcp-Protocol-Version] }
backends:
- mcp: { targets: [{ name: context7, mcp: { host: https://mcp.context7.com/mcp } }] }
- name: skillhub-web
hostnames: ["${SKILLS_HOST}"]
matches: [{ path: { pathPrefix: / } }]
policies:
requestHeaderModifier: { set: { X-Forwarded-Proto: https, X-Forwarded-Host: "${SKILLS_HOST}" } }
backends:
- host: skillhub-web:80
两处待试点第一天实测的字段(05 §2.4 已注明以 v1.5.0 文档为准):管理界面创建的 Key 是否自动被 apiKey 策略接受(否则改为在模板里写 keyHash);就绪端点路径(按 /healthz/ready 试)。
4.4 .env 变量(只列名字,值不进文档)
| 组 | 变量 | 说明 |
|---|---|---|
| 域名 | GW_HOST、SKILLS_HOST、IDP_HOST |
三个内网域名 |
| 地域与镜像 | ALIYUN_REGION、AGW_IMAGE、SKILLHUB_VERSION、SKILLHUB_SERVER_IMAGE、SKILLHUB_WEB_IMAGE、SKILLHUB_SCANNER_IMAGE、KC_IMAGE |
转存 ACR 后改地址 |
| RDS | RDS_HOST、RDS_PORT、AGW_DB_USER/PASSWORD、SKILLHUB_DB_USER/PASSWORD、KC_DB_USER/PASSWORD |
三库三账号 |
| Tair | TAIR_HOST、TAIR_PORT、TAIR_PASSWORD、TAIR_DATABASE |
|
| OSS | OSS_BUCKET、OSS_ACCESS_KEY、OSS_SECRET_KEY |
RAM 子账号 |
| SkillHub | SKILLHUB_DOWNLOAD_ANON_COOKIE_SECRET(openssl rand -hex 32)、BOOTSTRAP_ADMIN_*、SKILLHUB_SECURITY_SCANNER_ENABLED、SCANNER_LLM_* |
|
| 模型 | BAILIAN_API_KEY、BAILIAN_CODING_MODEL、NEWAPI_BASE_URL、NEWAPI_API_KEY、NEWAPI_DEFAULT_MODEL |
只出现在 .env 与渲染后的网关配置 |
| 阶段 2 | KC_ADMIN_USER/PASSWORD、KC_REALM、SKILLHUB_OIDC_CLIENT_ID/SECRET |
4.5 容器资源与 ECS 容量
| 容器 | CPU 上限 | 内存上限 | 依据 |
|---|---|---|---|
| agentgateway | 2 | 1 GiB | POC 实测空载 14 MiB、压测 30 MiB 以内;上限留给日志与连接 |
| skillhub-server | 2 | 3 GiB | Java 21,MaxRAMPercentage=70 |
| skillhub-web | 0.5 | 256 MiB | nginx |
| skill-scanner | 1 | 1.5 GiB | Python,扫描时峰值 |
| keycloak(阶段 2) | 2 | 2 GiB | POC 实测稳态 0.8 GiB |
| 合计 | 7.5 | 7.8 GiB | 16 GiB 机型留有余量;8 GiB 机型需去掉 Keycloak 与 scanner |
5. 实施步骤与验收
5.1 开通资源(云平台)
- 按 §2 开通 ECS、RDS、Tair、OSS;RDS 建三个库与三个账号(
agentgateway/skillhub/keycloak),各库 owner 为对应账号;Tair 开密码;OSS 建私有 Bucket 与 RAM 子账号(策略只授该 Bucket 的oss:GetObject / PutObject / DeleteObject / ListObjects)。 - RDS、Tair 白名单加 ECS 内网 IP;确认 ECS 所在交换机有 NAT 出站。
- PrivateZone 加两条 A 记录(阶段 2 加第三条);签发含三个 SAN 的证书。
- 安全组按 §3 配置。
5.2 ECS 初始化
# Docker Engine 27+ 与 compose 插件(>= 2.24);时区;目录
sudo timedatectl set-timezone Asia/Shanghai
sudo mkdir -p /opt/ai-gateway && sudo chown $USER /opt/ai-gateway
# 镜像转存到 ACR(在有境外访问的机器上执行一次;<acr> 为公司 ACR 地址)
for i in cr.agentgateway.dev/agentgateway:v1.5.0 ghcr.io/iflytek/skillhub-server:v0.2.20 ghcr.io/iflytek/skillhub-web:v0.2.20 ghcr.io/iflytek/skillhub-scanner:v0.2.20; do
docker pull $i && docker tag $i <acr>/ai-gateway/${i##*/} && docker push <acr>/ai-gateway/${i##*/}; done
5.3 落配置并启动
cd /opt/ai-gateway # 放入部署包内容
cp .env.example .env && chmod 600 .env && vi .env # 填 §4.4 的值;镜像改为 ACR 地址
cp /path/to/fullchain.pem certs/ && cp /path/to/privkey.pem certs/
./render.sh # 渲染 gateway/config.yaml,修正属主为 65532
docker compose config -q # 语法与变量检查(缺必填变量会直接报错)
docker compose up -d && docker compose ps
5.4 健康检查
curl -s http://127.0.0.1:15021/healthz/ready # 网关就绪
curl -s http://127.0.0.1:15020/metrics | head -3 # 指标
curl -s http://127.0.0.1:18081/actuator/health # SkillHub server:{"status":"UP"}
curl -s http://127.0.0.1:18080/nginx-health # SkillHub web
docker compose logs --since 10m agentgateway | grep -i -E 'error|reload' # 配置装载无错误
5.5 初始化
- 运维 IP 打开
http://<ECS 内网 IP>:15000,在管理界面创建第一把个人 Key(填元数据:用户、部门;设日 / 月预算),记录 Key。 - 打开
https://skills-test.<内网域>,用首登管理员登录并立即改密;创建第一个命名空间(如platform),关闭公开注册或开启准入审批。 - 在 SkillHub 管理界面把发布审核策略设为"必须审核",扫描失败不批准(SkillHub 默认不阻断,靠审核兜底)。
- 用一个示例技能(
SKILL.md+ 目录)走一遍:CI 或本机skillhub publish→ 扫描 → 审核通过 → 发布。
5.6 验收命令(开发者视角)
KEY=<管理界面创建的个人 Key>; GW=https://ai-gw-test.<内网域>
curl -s $GW/v1/models -H "Authorization: Bearer $KEY" # 列出别名
curl -s $GW/v1/chat/completions -H "Authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{"model":"coding-default","messages":[{"role":"user","content":"ping"}]}' # 经百炼返回
curl -s -o /dev/null -w '%{http_code}\n' $GW/v1/models # 无 Key → 401
# Claude Code / Codex 接入
export ANTHROPIC_BASE_URL=$GW ANTHROPIC_AUTH_TOKEN=$KEY # Claude Code(/v1/messages 由网关转换)
export OPENAI_BASE_URL=$GW/v1 OPENAI_API_KEY=$KEY # Codex / 其他 OpenAI 兼容工具
claude mcp add --transport http context7 $GW/mcp/context7 --header "Authorization: Bearer $KEY" # 同一把 Key 接 MCP
# SkillHub CLI(npm 包 @astron-team/skillhub)
npx @astron-team/skillhub login --server https://skills-test.<内网域> --token <SkillHub 令牌>
npx @astron-team/skillhub install <命名空间>/<技能> --agent claude # 装到 ~/.claude/skills
# 管理界面"日志"页应能看到上述请求的模型、token 与费用;RDS agentgateway 库有请求日志表
验收通过标准:三条模型请求(有 Key、无 Key、超预算)行为正确;Claude Code 与 Codex 各完成一次对话;MCP tools/list 经网关成功;一个技能完成发布并被 CLI 安装到 Claude Code;重启 ECS 后所有容器自动拉起且 Key 仍有效(落库验证)。
5.7 运维约定
- 备份:RDS 自动备份 7 天;OSS 版本控制;
/opt/ai-gateway整目录纳入 ECS 快照或每日打包到 OSS(含.env,按密文处理)。 - 升级:改
.env里的版本号 →docker compose pull→docker compose up -d;回滚改回版本号再up -d。SkillHub 升级前看上游变更说明(Flyway 迁移不可逆)。 - 改网关配置:改
gateway/config.yaml.tmpl→./render.sh(含重启)。管理界面里的改动落在 RDS,不会写回文件。 - 日志:容器 stdout 滚动 50 MB × 5;接 SLS 时用 Logtail 采 Docker 标准输出。
- 口令轮换:厂商 Key、数据库口令、OSS AK 每季度轮换,只改
.env后./render.sh && docker compose up -d。
6. 需要业务侧先给的输入
| # | 输入 | 默认假设 |
|---|---|---|
| 1 | 地域与 VPC(与生产主集群同 VPC,还是独立 VPC 打通) | 同地域同 VPC |
| 2 | 三个内网域名与证书方式(内部 CA / 公有 CA) | ai-gw-test、skills-test、idp-test + 公司内部 CA |
| 3 | 办公网 / VPN 出口网段与运维 IP | 由网络组提供 |
| 4 | 模型出口:百炼账号 Key 与存量代理地址;是否还要火山方舟 | 百炼 + 存量代理 |
| 5 | 阶段 2 时间:是否在试点第一周就上 Keycloak 与飞书登录 | 试点第 2 周 |
7. 风险与对冲
| 风险 | 对冲 |
|---|---|
| 单机无高可用;ECS 故障即中断 | 试点可接受;配置全在 RDS 与 /opt/ai-gateway,新 ECS 30 分钟内重建;正式环境按公司版方案落 K8s |
| 管理界面无鉴权 | 安全组只放运维 IP;第二步用网关 ui.policies 加 basicAuth 或 OIDC |
| 境外镜像仓库拉取不稳定 | ACR 转存并锁版本 |
| SkillHub 扫描失败默认不阻断发布 | 审核规则设为不批准;CI 侧再扫一道 |
| 阿里云 OSS 与 S3 细节差异(分块编码、路径风格) | 已在 compose 固定 DISABLE_CHUNKED_ENCODING=true、FORCE_PATH_STYLE=false;上线前上传一个 20 MB 技能包验证 |
| agentgateway v1.5.0 的 Key 落库与策略衔接细节 | 试点第一天实测;不通则改为文件内 keyHash |