# Qwen 模型 K8s 部署配置指南

## 📋 当前 API Key 配置方式

### 架构概览

EDA Service 使用 **Pulumi** 进行 K8s 资源管理，API Key 通过以下方式配置：

```
Pulumi Config (加密存储)
    ↓
pulumi/index.ts (读取配置)
    ↓
K8s Deployment Env Variables (注入容器)
    ↓
config.py (Python 代码读取)
    ↓
应用程序使用
```

---

## 🔍 现有模型的配置方式

### 1. OpenAI GPT-4/GPT-4o

#### Pulumi 配置 (`Pulumi.edaservice-staging.yaml`)
```yaml
edaservice:openaiKey:
  secure: v1:EkbjT7H797vozN2r:SB7xlFzr8oL2LpgdcGrU3yLS+ex9zicnPZJJg2B9sym/...
```

#### Pulumi 代码 (`deployments/pulumi/index.ts`)
```typescript
// 第 33 行: 读取配置
const openaiKey = config.require("openaiKey");

// 第 111-113 行: 注入到 K8s Deployment
{
  name: "OPENAI_API_KEY",
  value: openaiKey,
}
```

#### Python 配置 (`config.py`)
```python
# 第 15 行
self.OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
```

---

### 2. AWS Bedrock (Claude 3)

#### Pulumi 配置 (`Pulumi.edaservice-staging.yaml`)
```yaml
edaservice:awsAccessKeyId:
  secure: v1:DieWxAGC1G2jcfHg:Z/hKbv20eq9Zc45L9dfzWnyH7Dbm8KrCu/sXjg/RZPYUYd5b

edaservice:awsSecretAccessKey:
  secure: v1:N8rzWPDIHkZGotTQ:qVpeYKQcQdiLCL1XMYJmooGEKuVXdxwzH0ahMYh6+1YAxr1L...
```

#### Pulumi 代码 (`deployments/pulumi/index.ts`)
```typescript
// 第 34-35 行: 读取配置
const awsAccessKeyId = config.require("awsAccessKeyId");
const awsSecretAccessKey = config.require("awsSecretAccessKey");

// 第 115-121 行: 注入到 K8s Deployment
{
  name: "BEDROCK_AWS_ACCESS_KEY_ID",
  value: awsAccessKeyId,
},
{
  name: "BEDROCK_AWS_SECRET_ACCESS_KEY",
  value: awsSecretAccessKey,
}
```

#### Python 配置 (`config.py`)
```python
# 第 55-56 行
self.BEDROCK_AWS_ACCESS_KEY_ID = os.getenv("BEDROCK_AWS_ACCESS_KEY_ID", "")
self.BEDROCK_AWS_SECRET_ACCESS_KEY = os.getenv("BEDROCK_AWS_SECRET_ACCESS_KEY", "")
```

---

## 🆕 Qwen 模型配置（新增）

### 步骤 1: 添加 Pulumi 配置

**需要修改的文件**: `deployments/pulumi/Pulumi.edaservice-*.yaml`

#### 1.1 Nightly 环境 (`Pulumi.edaservice-nightly.yaml`)
```yaml
# 在现有配置后添加
edaservice:qwenAPIKey:
  secure: <使用 pulumi config set 命令加密后的值>

# 如果使用国际版 endpoint，还需要添加（可选）
edaservice:dashscopeBaseURL: "https://dashscope-intl.aliyuncs.com/api/v1"
```

#### 1.2 Staging 环境 (`Pulumi.edaservice-staging.yaml`)
```yaml
# 在现有配置后添加
edaservice:qwenAPIKey:
  secure: <使用 pulumi config set 命令加密后的值>

edaservice:dashscopeBaseURL: "https://dashscope-intl.aliyuncs.com/api/v1"
```

#### 1.3 Production 环境 (`Pulumi.edaservice-prod.yaml`)
```yaml
# 在现有配置后添加
edaservice:qwenAPIKey:
  secure: <使用 pulumi config set 命令加密后的值>

edaservice:dashscopeBaseURL: "https://dashscope-intl.aliyuncs.com/api/v1"
```

---

### 步骤 2: 修改 Pulumi TypeScript 代码

**需要修改的文件**: `deployments/pulumi/index.ts`

#### 2.1 添加配置读取（在第 36 行后添加）
```typescript
const openaiKey = config.require("openaiKey");
const awsAccessKeyId = config.require("awsAccessKeyId");
const awsSecretAccessKey = config.require("awsSecretAccessKey");
const validAccessKeys = config.require("validAccessKeys");

// ===== 新增 Qwen 配置 =====
const qwenAPIKey = config.require("qwenAPIKey");
const dashscopeBaseURL = config.get("dashscopeBaseURL") || "https://dashscope-intl.aliyuncs.com/api/v1";
// ===== 新增结束 =====
```

#### 2.2 添加环境变量注入（在第 145 行后添加）
在 `edaservice-worker` Deployment 的 `env` 数组中添加：

```typescript
{
  name: "CROSS_REGION_AUTH",
  value: crossRegionAuth,
},
// ===== 新增 Qwen 环境变量 =====
{
  name: "QWEN_API_KEY",
  value: qwenAPIKey,
},
{
  name: "DASHSCOPE_BASE_URL",
  value: dashscopeBaseURL,
},
// ===== 新增结束 =====
```

#### 2.3 为其他 Deployment 添加相同配置

需要在以下 Deployment 中添加相同的环境变量：
- `edaservice-api` (约第 250 行附近)
- `edaservice-public-api` (如果存在)

**重要**: 确保所有运行 Python 应用的容器都注入了这些环境变量。

---

### 步骤 3: Python 配置（已完成 ✅）

**文件**: `config.py` (第 59 行)

```python
# alibaba cloud qwen
self.QWEN_API_KEY = os.getenv("QWEN_API_KEY", "")
```

**注意**: 这部分在代码实现阶段已经完成，无需修改。

---

## 🚀 部署步骤

### 方式 1: 使用 Pulumi CLI（推荐）

#### 1. 配置 API Key（加密存储）

```bash
# 切换到 pulumi 目录
cd deployments/pulumi

# 为 Staging 环境配置
pulumi stack select edaservice-staging

# 设置 Qwen API Key (会自动加密)
pulumi config set --secret edaservice:qwenAPIKey sk-426efxxxxxxxxxxxxxxxxxxxxxxxxxaba

# 设置 DashScope Endpoint (明文，可选)
pulumi config set edaservice:dashscopeBaseURL https://dashscope-intl.aliyuncs.com/api/v1

# 验证配置
pulumi config get edaservice:qwenAPIKey  # 会显示 [secret]
```

#### 2. 修改 index.ts 文件

按照"步骤 2"中的说明修改 `index.ts` 文件。

#### 3. 预览变更

```bash
# 预览将要应用的变更
pulumi preview

# 输出示例：
# Previewing update (edaservice-staging):
#      Type                              Name                       Plan       Info
#      pulumi:pulumi:Stack              edaservice-staging
#  ~   └─ kubernetes:apps/v1:Deployment  edaservice-worker          update     [diff: ~spec]
#  ~   └─ kubernetes:apps/v1:Deployment  edaservice-api             update     [diff: ~spec]
```

#### 4. 应用变更

```bash
# 应用配置更新
pulumi up

# 确认后输入 "yes"
```

#### 5. 验证部署

```bash
# 检查 Pod 是否重启成功
kubectl get pods -n staging-ms | grep edaservice

# 查看环境变量是否注入
kubectl exec -n staging-ms deployment/edaservice-worker -- env | grep QWEN
# 输出应该包含:
# QWEN_API_KEY=sk-426efxxxxxxxxxxxxxxxxxxxxxxxxxaba
# DASHSCOPE_BASE_URL=https://dashscope-intl.aliyuncs.com/api/v1

# 查看应用日志
kubectl logs -n staging-ms deployment/edaservice-worker --tail=50
```

---

### 方式 2: 通过 GitHub Actions CI/CD

如果使用 CI/CD 流水线部署：

#### 1. 添加 GitHub Secrets

在 GitHub Repository Settings → Secrets and variables → Actions 中添加：

```
QWEN_API_KEY_STAGING=sk-426efxxxxxxxxxxxxxxxxxxxxxxxxxaba
QWEN_API_KEY_PROD=<生产环境的 Key>
DASHSCOPE_BASE_URL=https://dashscope-intl.aliyuncs.com/api/v1
```

#### 2. 修改 GitHub Actions Workflow

**文件**: `.github/workflows/staging-cd.yaml`

在部署步骤前添加配置设置：

```yaml
- name: Configure Qwen API Key
  run: |
    cd deployments/pulumi
    pulumi stack select edaservice-staging
    pulumi config set --secret edaservice:qwenAPIKey ${{ secrets.QWEN_API_KEY_STAGING }}
    pulumi config set edaservice:dashscopeBaseURL ${{ secrets.DASHSCOPE_BASE_URL }}

- name: Deploy to Staging
  run: |
    cd deployments/pulumi
    pulumi up --yes
```

#### 3. 推送代码触发部署

```bash
git add .
git commit -m "feat: Add Qwen model K8s configuration"
git push origin wlt_qwen
```

---

## 🔐 安全最佳实践

### 1. API Key 管理

✅ **推荐做法**:
- 使用 `pulumi config set --secret` 加密存储
- 不同环境使用不同的 API Key
- 定期轮换 API Key

❌ **避免做法**:
- 明文存储在配置文件中
- 直接提交到 Git 仓库
- 在日志中打印完整 API Key

### 2. 环境隔离

| 环境 | API Key | Endpoint |
|------|---------|----------|
| Nightly/Dev | 测试用 Key | 国际版或国内版 |
| Staging | 测试用 Key | 与生产一致 |
| Production | 生产 Key | 国际版（推荐） |

### 3. 访问控制

确保只有授权人员可以：
- 访问 Pulumi 配置
- 修改 K8s Secrets
- 查看环境变量

---

## 🧪 测试验证

### 1. 环境变量验证

```bash
# 进入 Pod
kubectl exec -it -n staging-ms deployment/edaservice-worker -- bash

# 检查环境变量
echo $QWEN_API_KEY
echo $DASHSCOPE_BASE_URL

# 测试 Python 配置加载
python3 -c "from config import config; print(f'Qwen Key: {config.QWEN_API_KEY[:20]}...')"
```

### 2. API 连通性测试

```bash
# 在 Pod 内运行测试
python3 -c "
import os
os.environ['QWEN_API_KEY'] = os.getenv('QWEN_API_KEY')
os.environ['DASHSCOPE_BASE_URL'] = os.getenv('DASHSCOPE_BASE_URL')

from svc.qwen import test_qwen_api_key
from consts.consts import Qwen

result = test_qwen_api_key(os.getenv('QWEN_API_KEY'), Qwen.TURBO)
print(f'API Key 测试: {\"✅ 通过\" if result else \"❌ 失败\"}')
"
```

### 3. 端到端测试

使用阿里云测试集群验证完整流程：

```bash
# 发送测试请求（使用实际的阿里云 cluster_id）
curl -X POST https://staging-api.tidbcloud.com/v1/text2sql \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your-token>" \
  -d '{
    "cluster_id": "<alibaba-cloud-cluster-id>",
    "database": "test",
    "query": "show all users"
  }'
```

查看日志，确认自动切换到 Qwen：
```bash
kubectl logs -n staging-ms deployment/edaservice-worker --tail=100 | grep -i qwen
# 应该看到类似:
# Detected Alibaba Cloud cluster, switching to Qwen model
# Using Qwen API for text generation
```

---

## 📝 完整配置清单

### 需要修改的文件

| 文件 | 操作 | 说明 |
|------|------|------|
| `deployments/pulumi/index.ts` | 修改 | 添加 Qwen 配置读取和环境变量注入 |
| `deployments/pulumi/Pulumi.edaservice-nightly.yaml` | 修改 | 添加 Qwen API Key 配置 |
| `deployments/pulumi/Pulumi.edaservice-staging.yaml` | 修改 | 添加 Qwen API Key 配置 |
| `deployments/pulumi/Pulumi.edaservice-prod.yaml` | 修改 | 添加 Qwen API Key 配置 |
| `.github/workflows/staging-cd.yaml` | 可选 | 如果使用 CI/CD |
| `.github/workflows/prod-cd.yaml` | 可选 | 如果使用 CI/CD |

### 需要设置的环境变量

| 变量名 | 必需 | 示例值 | 说明 |
|--------|------|--------|------|
| `QWEN_API_KEY` | ✅ 是 | `sk-426ef186...` | Qwen API Key |
| `DASHSCOPE_BASE_URL` | ⚠️ 推荐 | `https://dashscope-intl.aliyuncs.com/api/v1` | 国际版 endpoint |

---

## 🔄 多环境配置示例

### Nightly 环境
```bash
pulumi stack select edaservice-nightly
pulumi config set --secret edaservice:qwenAPIKey <nightly-key>
pulumi config set edaservice:dashscopeBaseURL https://dashscope-intl.aliyuncs.com/api/v1
pulumi up
```

### Staging 环境
```bash
pulumi stack select edaservice-staging
pulumi config set --secret edaservice:qwenAPIKey <staging-key>
pulumi config set edaservice:dashscopeBaseURL https://dashscope-intl.aliyuncs.com/api/v1
pulumi up
```

### Production 环境
```bash
pulumi stack select edaservice-prod
pulumi config set --secret edaservice:qwenAPIKey <production-key>
pulumi config set edaservice:dashscopeBaseURL https://dashscope-intl.aliyuncs.com/api/v1
pulumi up
```

---

## ⚠️ 注意事项

### 1. Endpoint 配置

**国际版** (推荐，如果 API Key 是国际版):
```
DASHSCOPE_BASE_URL=https://dashscope-intl.aliyuncs.com/api/v1
```

**国内版**:
```
DASHSCOPE_BASE_URL=https://dashscope.aliyuncs.com/api/v1
```

**如何判断**:
- 如果 API Key 申请时选择了"国际版"，使用国际版 endpoint
- 如果使用 `curl` 测试，国际版返回 200，国内版返回 401，则使用国际版

### 2. 部署顺序

建议按以下顺序部署：
1. Nightly → 开发测试
2. Staging → 预发布验证
3. Production → 生产发布

### 3. 回滚方案

如果遇到问题：
```bash
# 方式 1: 取消 Qwen API Key
pulumi config rm edaservice:qwenAPIKey
pulumi up

# 方式 2: 回滚到上一个版本
pulumi stack export > backup.json
pulumi stack import < previous-backup.json
pulumi up
```

---

## 📚 相关文档

- [Pulumi 配置管理](https://www.pulumi.com/docs/intro/concepts/config/)
- [Kubernetes Secrets](https://kubernetes.io/docs/concepts/configuration/secret/)
- [Qwen 实施总结](./QWEN_IMPLEMENTATION_SUMMARY.md)
- [DashScope API 文档](https://help.aliyun.com/zh/dashscope/)

---

**文档版本**: v1.0
**最后更新**: 2025-02-25
**状态**: ✅ 已验证
