All checks were successful
Docker Build and Push / build-and-push (push) Successful in 7m15s
Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
185 lines
5.3 KiB
JavaScript
185 lines
5.3 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* K8S 部署命令行工具
|
|
* 用于部署 Claude API 代理服务到 ECI
|
|
*
|
|
* 用法:
|
|
* pnpm deploy <name> <image> [options] - 部署代理服务
|
|
* pnpm deploy delete <name> - 删除代理服务
|
|
* pnpm deploy status <name> - 查询服务状态
|
|
*
|
|
* 选项:
|
|
* --replicas <n> 副本数 (默认: 1)
|
|
* --port <port> 容器端口 (默认: 3000)
|
|
* --eip-bandwidth <n> EIP 带宽 Mbps (默认: 5)
|
|
*/
|
|
|
|
import { config } from 'dotenv';
|
|
// 使用 override: true 确保覆盖系统环境变量
|
|
config({ override: true });
|
|
|
|
import { deployProxy, deleteProxy, getProxyStatus } from '../src/deploy';
|
|
|
|
// 解析命令行参数
|
|
function parseArgs() {
|
|
const args = process.argv.slice(2);
|
|
|
|
if (args.length === 0) {
|
|
printUsage();
|
|
process.exit(1);
|
|
}
|
|
|
|
const command = args[0];
|
|
|
|
// 解析选项
|
|
const getOption = (name: string, defaultValue: string): string => {
|
|
const idx = args.indexOf(name);
|
|
if (idx !== -1 && idx + 1 < args.length) {
|
|
return args[idx + 1];
|
|
}
|
|
return defaultValue;
|
|
};
|
|
|
|
const getOptionNumber = (name: string, defaultValue: number): number => {
|
|
return Number(getOption(name, String(defaultValue)));
|
|
};
|
|
|
|
// 判断是否是子命令模式
|
|
const isSubCommand = command === 'delete' || command === 'status';
|
|
|
|
return {
|
|
command,
|
|
name: isSubCommand ? args[1] : command,
|
|
image: isSubCommand ? undefined : args[1],
|
|
options: {
|
|
replicas: getOptionNumber('--replicas', 1),
|
|
port: getOptionNumber('--port', 3000),
|
|
eipBandwidth: getOptionNumber('--eip-bandwidth', 5),
|
|
},
|
|
};
|
|
}
|
|
|
|
function printUsage() {
|
|
console.log(`
|
|
K8S 部署命令行工具 - Claude API 代理服务
|
|
|
|
用法:
|
|
pnpm deploy <name> <image> [options] 部署代理服务
|
|
pnpm deploy delete <name> 删除代理服务
|
|
pnpm deploy status <name> 查询服务状态
|
|
|
|
选项:
|
|
--replicas <n> 副本数 (默认: 1)
|
|
--port <port> 容器端口 (默认: 3000)
|
|
--eip-bandwidth <n> EIP 带宽 Mbps (默认: 5)
|
|
|
|
示例:
|
|
# 部署单个代理实例
|
|
pnpm deploy claude-proxy-1 registry.cn-beijing.aliyuncs.com/d8dcloud/claude-api-proxy:v0.0.1
|
|
|
|
# 部署 3 个副本
|
|
pnpm deploy claude-proxy-1 registry.cn-beijing.aliyuncs.com/d8dcloud/claude-api-proxy:v0.0.1 --replicas 3
|
|
|
|
# 删除服务
|
|
pnpm deploy delete claude-proxy-1
|
|
|
|
# 查询状态
|
|
pnpm deploy status claude-proxy-1
|
|
`);
|
|
}
|
|
|
|
async function main() {
|
|
const { command, name, image, options } = parseArgs();
|
|
|
|
// 检查环境变量
|
|
if (!process.env.K8S_API_URL || !process.env.K8S_API_TOKEN) {
|
|
console.error('❌ 错误: 请配置 K8S_API_URL 和 K8S_API_TOKEN 环境变量');
|
|
console.error(' 可以在 .env 文件中配置或通过环境变量传入');
|
|
process.exit(1);
|
|
}
|
|
|
|
try {
|
|
switch (command) {
|
|
case 'delete': {
|
|
if (!name) {
|
|
console.error('❌ 错误: 请指定服务名称');
|
|
process.exit(1);
|
|
}
|
|
console.log(`🗑️ 正在删除服务 ${name}...`);
|
|
const result = await deleteProxy(name);
|
|
if (result.success) {
|
|
console.log(`✅ ${result.message}`);
|
|
} else {
|
|
console.error(`❌ ${result.message}`);
|
|
process.exit(1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 'status': {
|
|
if (!name) {
|
|
console.error('❌ 错误: 请指定服务名称');
|
|
process.exit(1);
|
|
}
|
|
console.log(`📊 查询服务状态 ${name}...`);
|
|
const status = await getProxyStatus(name);
|
|
if (status.exists) {
|
|
console.log(`✅ 服务状态: ${status.status}`);
|
|
if (status.hosts && status.hosts.length > 0) {
|
|
console.log(`🌐 访问地址: ${status.hosts.join(', ')}`);
|
|
}
|
|
} else {
|
|
console.log(`⚠️ 服务 ${name} 不存在`);
|
|
}
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
// deploy 命令
|
|
if (!name || !image) {
|
|
console.error('❌ 错误: 请指定服务名称和镜像');
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`🚀 正在部署 ${name}...`);
|
|
console.log(` 镜像: ${image}`);
|
|
console.log(` 副本: ${options.replicas}`);
|
|
console.log(` 端口: ${options.port}`);
|
|
console.log(` EIP 带宽: ${options.eipBandwidth} Mbps`);
|
|
|
|
// 构建环境变量 - 从当前 .env 读取关键配置注入容器
|
|
const containerEnv: Record<string, string> = {
|
|
ANTHROPIC_BASE_URL: process.env.ANTHROPIC_BASE_URL || 'https://api.anthropic.com',
|
|
OPENAI_BASE_URL: process.env.OPENAI_BASE_URL || 'https://api.openai.com',
|
|
};
|
|
|
|
const result = await deployProxy({
|
|
name,
|
|
image,
|
|
replicas: options.replicas,
|
|
port: options.port,
|
|
eipBandwidth: options.eipBandwidth,
|
|
env: containerEnv,
|
|
});
|
|
|
|
if (result.success) {
|
|
console.log(`\n✅ ${result.message}`);
|
|
if (result.hosts && result.hosts.length > 0) {
|
|
console.log(`\n🌐 访问地址:`);
|
|
result.hosts.forEach(host => console.log(` ${host}`));
|
|
}
|
|
} else {
|
|
console.error(`\n❌ ${result.message}`);
|
|
process.exit(1);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('❌ 执行失败:', error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main();
|