dns解析问题解决
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
# Agent Manager ARM64 构建和部署指南
|
||||
|
||||
本文档说明如何在 ARM64 架构的 AKS 集群上构建和部署 Agent Manager 项目。
|
||||
|
||||
## 前置要求
|
||||
|
||||
1. **Docker** (支持 buildx)
|
||||
2. **kubectl** (已配置连接到 AKS 集群)
|
||||
3. **Azure CLI** (已登录)
|
||||
4. **Azure Container Registry (ACR)** 访问权限
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 方法 1: 使用快速构建脚本(推荐)
|
||||
|
||||
```bash
|
||||
# 一键构建并部署
|
||||
./build-and-deploy-arm64.sh
|
||||
```
|
||||
|
||||
### 方法 2: 使用完整部署脚本
|
||||
|
||||
```bash
|
||||
# 构建镜像并部署
|
||||
./scripts/deploy-to-k8s-arm64.sh
|
||||
|
||||
# 或跳过构建,仅部署
|
||||
./scripts/deploy-to-k8s-arm64.sh --skip-build
|
||||
```
|
||||
|
||||
## 详细步骤
|
||||
|
||||
### 1. 配置 Docker Buildx
|
||||
|
||||
确保 Docker Buildx 已启用并配置:
|
||||
|
||||
```bash
|
||||
# 检查 buildx
|
||||
docker buildx version
|
||||
|
||||
# 创建 ARM64 builder(如果不存在)
|
||||
docker buildx create --name arm64-builder --use --driver docker-container
|
||||
docker buildx inspect --bootstrap
|
||||
```
|
||||
|
||||
### 2. 登录 Azure Container Registry
|
||||
|
||||
```bash
|
||||
ACR_NAME="agnettaiji"
|
||||
az acr login --name ${ACR_NAME}
|
||||
```
|
||||
|
||||
### 3. 构建 ARM64 镜像
|
||||
|
||||
```bash
|
||||
ACR_NAME="agnettaiji"
|
||||
IMAGE_NAME="agent-manager"
|
||||
IMAGE_TAG="latest-arm64"
|
||||
FULL_IMAGE_NAME="${ACR_NAME}.azurecr.io/${IMAGE_NAME}:${IMAGE_TAG}"
|
||||
|
||||
docker buildx build \
|
||||
--platform linux/arm64 \
|
||||
-f Dockerfile \
|
||||
-t ${FULL_IMAGE_NAME} \
|
||||
--push \
|
||||
.
|
||||
```
|
||||
|
||||
### 4. 部署到 Kubernetes
|
||||
|
||||
确保 AKS 集群中有 ARM64 节点:
|
||||
|
||||
```bash
|
||||
# 检查节点架构
|
||||
kubectl get nodes -o wide
|
||||
|
||||
# 查看节点标签
|
||||
kubectl get nodes --show-labels | grep arch
|
||||
```
|
||||
|
||||
部署应用:
|
||||
|
||||
```bash
|
||||
# 创建命名空间(如果不存在)
|
||||
kubectl apply -f k8s/agent-manager-namespace.yaml
|
||||
|
||||
# 创建 ACR Secret(用于拉取镜像)
|
||||
ACR_NAME="agnettaiji"
|
||||
ACR_USERNAME=$(az acr credential show --name ${ACR_NAME} --query username -o tsv)
|
||||
ACR_PASSWORD=$(az acr credential show --name ${ACR_NAME} --query passwords[0].value -o tsv)
|
||||
|
||||
kubectl create secret docker-registry acr-secret \
|
||||
--namespace=agent-manager \
|
||||
--docker-server=${ACR_NAME}.azurecr.io \
|
||||
--docker-username=${ACR_USERNAME} \
|
||||
--docker-password=${ACR_PASSWORD} \
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
|
||||
# 部署应用
|
||||
kubectl apply -f k8s/agent-manager-deployment.yaml
|
||||
kubectl apply -f k8s/agent-manager-service.yaml
|
||||
```
|
||||
|
||||
### 5. 验证部署
|
||||
|
||||
```bash
|
||||
# 查看 Pod 状态
|
||||
kubectl get pods -n agent-manager -o wide
|
||||
|
||||
# 查看 Pod 详细信息(确认调度到 ARM64 节点)
|
||||
kubectl describe pod -n agent-manager -l app=agent-manager
|
||||
|
||||
# 查看日志
|
||||
kubectl logs -n agent-manager -l app=agent-manager -f
|
||||
|
||||
# 查看服务
|
||||
kubectl get svc -n agent-manager
|
||||
```
|
||||
|
||||
## 配置说明
|
||||
|
||||
### 镜像配置
|
||||
|
||||
- **镜像仓库**: `agnettaiji.azurecr.io`
|
||||
- **镜像名称**: `agent-manager`
|
||||
- **ARM64 标签**: `latest-arm64`
|
||||
|
||||
### 节点选择器
|
||||
|
||||
部署配置中已设置节点选择器,确保 Pod 调度到 ARM64 节点:
|
||||
|
||||
```yaml
|
||||
nodeSelector:
|
||||
kubernetes.io/arch: arm64
|
||||
```
|
||||
|
||||
### 资源限制
|
||||
|
||||
默认资源配置:
|
||||
- **请求**: CPU 200m, 内存 256Mi
|
||||
- **限制**: CPU 500m, 内存 512Mi
|
||||
|
||||
可根据需要调整 `k8s/agent-manager-deployment.yaml` 中的资源配置。
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 问题 1: 镜像拉取失败
|
||||
|
||||
**症状**: Pod 状态为 `ImagePullBackOff`
|
||||
|
||||
**解决**:
|
||||
1. 检查 ACR Secret 是否正确创建
|
||||
2. 确认 ACR 已附加到 AKS: `az aks update --name <aks-name> --resource-group <rg> --attach-acr <acr-name>`
|
||||
3. 检查镜像标签是否正确
|
||||
|
||||
### 问题 2: Pod 无法调度
|
||||
|
||||
**症状**: Pod 状态为 `Pending`
|
||||
|
||||
**解决**:
|
||||
1. 检查集群中是否有 ARM64 节点: `kubectl get nodes -l kubernetes.io/arch=arm64`
|
||||
2. 检查节点选择器配置是否正确
|
||||
3. 如果节点有污点,需要配置相应的容忍度
|
||||
|
||||
### 问题 3: 构建失败
|
||||
|
||||
**症状**: `docker buildx build` 失败
|
||||
|
||||
**解决**:
|
||||
1. 确保 Docker Buildx 已正确安装和配置
|
||||
2. 检查网络连接(推送镜像需要)
|
||||
3. 确认 ACR 登录状态: `az acr login --name <acr-name>`
|
||||
|
||||
## 更新部署
|
||||
|
||||
更新镜像后,需要重启 Pod 以使用新镜像:
|
||||
|
||||
```bash
|
||||
# 方法 1: 删除 Pod(Deployment 会自动创建新的)
|
||||
kubectl delete pod -n agent-manager -l app=agent-manager
|
||||
|
||||
# 方法 2: 滚动更新
|
||||
kubectl rollout restart deployment/agent-manager -n agent-manager
|
||||
|
||||
# 方法 3: 更新镜像标签
|
||||
kubectl set image deployment/agent-manager \
|
||||
agent-manager=agnettaiji.azurecr.io/agent-manager:latest-arm64 \
|
||||
-n agent-manager
|
||||
```
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `Dockerfile` - Docker 镜像构建文件
|
||||
- `k8s/agent-manager-deployment.yaml` - Kubernetes 部署配置
|
||||
- `k8s/agent-manager-service.yaml` - Kubernetes 服务配置
|
||||
- `scripts/deploy-to-k8s-arm64.sh` - 完整部署脚本
|
||||
- `build-and-deploy-arm64.sh` - 快速构建和部署脚本
|
||||
|
||||
|
||||
+4
-1
@@ -1,10 +1,13 @@
|
||||
# 支持多架构构建(包括 ARM64)
|
||||
# 使用 buildx 构建: docker buildx build --platform linux/arm64 -t <image> .
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# 安装系统依赖
|
||||
# 安装系统依赖(包括 openssl 用于生成自签名证书)
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
openssl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# 复制应用代码
|
||||
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
# OPENCLAW AKS 部署 HTTPS 配置指南
|
||||
|
||||
## 概述
|
||||
|
||||
本指南说明如何为 OPENCLAW 平台 agent 在 AKS 上配置 HTTPS 访问,使用自签名证书解决只有 DNS 域名但没有正式证书的问题。
|
||||
|
||||
## 前置条件
|
||||
|
||||
1. 已部署 OPENCLAW 到 AKS
|
||||
2. 已安装 nginx-ingress-controller
|
||||
3. 有域名指向 AKS Ingress IP
|
||||
4. 已安装 `kubectl` 和 `openssl`
|
||||
|
||||
## 解决方案:使用自签名证书
|
||||
|
||||
### 步骤 1: 生成自签名证书
|
||||
|
||||
使用提供的脚本生成自签名证书:
|
||||
|
||||
```bash
|
||||
# 给脚本添加执行权限
|
||||
chmod +x generate-self-signed-cert.sh
|
||||
|
||||
# 运行脚本生成证书(替换为你的实际域名)
|
||||
./generate-self-signed-cert.sh openclaw.yourdomain.com openclaw openclaw-tls
|
||||
```
|
||||
|
||||
**参数说明:**
|
||||
- 第一个参数:你的域名(例如:`openclaw.example.com`)
|
||||
- 第二个参数:Kubernetes 命名空间(默认:`openclaw`)
|
||||
- 第三个参数:Kubernetes Secret 名称(默认:`openclaw-tls`)
|
||||
|
||||
### 步骤 2: 更新部署配置
|
||||
|
||||
确保 `deploay.yaml` 中的 Ingress 配置已包含 TLS 部分(已更新):
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
tls:
|
||||
- hosts:
|
||||
- openclaw.yourdomain.com # 你的域名
|
||||
secretName: openclaw-tls # Secret 名称
|
||||
rules:
|
||||
- host: openclaw.yourdomain.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: openclaw
|
||||
port:
|
||||
number: 18789
|
||||
```
|
||||
|
||||
### 步骤 3: 应用配置
|
||||
|
||||
```bash
|
||||
# 应用更新后的配置
|
||||
kubectl apply -f deploay.yaml
|
||||
|
||||
# 验证 Ingress 配置
|
||||
kubectl get ingress -n openclaw
|
||||
|
||||
# 查看证书 Secret
|
||||
kubectl get secret openclaw-tls -n openclaw
|
||||
```
|
||||
|
||||
### 步骤 4: 配置 DNS
|
||||
|
||||
确保你的域名指向 AKS Ingress 的外部 IP:
|
||||
|
||||
```bash
|
||||
# 获取 Ingress IP
|
||||
kubectl get ingress -n openclaw
|
||||
|
||||
# 在 DNS 提供商处添加 A 记录:
|
||||
# openclaw.yourdomain.com -> <INGRESS_IP>
|
||||
```
|
||||
|
||||
### 步骤 5: 访问测试
|
||||
|
||||
1. 在浏览器中访问:`https://openclaw.yourdomain.com`
|
||||
2. 浏览器会显示安全警告(这是正常的,因为使用的是自签名证书)
|
||||
3. 点击"高级" -> "继续访问"(Chrome)或"接受风险并继续"(Firefox)
|
||||
4. 之后即可正常访问 OPENCLAW UI
|
||||
|
||||
## 手动生成证书(可选)
|
||||
|
||||
如果脚本无法使用,可以手动生成:
|
||||
|
||||
```bash
|
||||
# 1. 生成私钥
|
||||
openssl genrsa -out tls.key 2048
|
||||
|
||||
# 2. 生成证书签名请求
|
||||
openssl req -new -key tls.key -out tls.csr \
|
||||
-subj "/C=CN/ST=Beijing/L=Beijing/O=OpenClaw/CN=openclaw.yourdomain.com"
|
||||
|
||||
# 3. 生成自签名证书(包含 SAN)
|
||||
openssl x509 -req -days 365 -in tls.csr -signkey tls.key \
|
||||
-out tls.crt \
|
||||
-extensions v3_req \
|
||||
-extfile <(cat <<EOF
|
||||
[req]
|
||||
distinguished_name = req_distinguished_name
|
||||
req_extensions = v3_req
|
||||
|
||||
[v3_req]
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
DNS.1 = openclaw.yourdomain.com
|
||||
DNS.2 = *.openclaw.yourdomain.com
|
||||
DNS.3 = localhost
|
||||
IP.1 = 127.0.0.1
|
||||
EOF
|
||||
)
|
||||
|
||||
# 4. 创建 Kubernetes Secret
|
||||
kubectl create secret tls openclaw-tls \
|
||||
--cert=tls.crt \
|
||||
--key=tls.key \
|
||||
--namespace=openclaw
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
### 自签名证书的限制
|
||||
|
||||
1. **浏览器警告**:所有浏览器都会显示安全警告,需要用户手动接受
|
||||
2. **有效期**:默认证书有效期为 365 天,到期后需要重新生成
|
||||
3. **不适用于生产环境**:自签名证书不适合生产环境,仅用于开发/测试
|
||||
|
||||
### 生产环境建议
|
||||
|
||||
对于生产环境,建议使用:
|
||||
|
||||
1. **Let's Encrypt**(免费,自动续期)
|
||||
```bash
|
||||
# 安装 cert-manager
|
||||
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
|
||||
|
||||
# 配置 ClusterIssuer
|
||||
# 然后 Ingress 添加注解:
|
||||
# cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
```
|
||||
|
||||
2. **Azure Key Vault**(Azure 托管证书)
|
||||
|
||||
3. **购买商业证书**
|
||||
|
||||
### 更新证书
|
||||
|
||||
证书到期后,重新生成并更新:
|
||||
|
||||
```bash
|
||||
# 重新生成证书
|
||||
./generate-self-signed-cert.sh openclaw.yourdomain.com openclaw openclaw-tls
|
||||
|
||||
# 重启 Ingress Controller(如果需要)
|
||||
kubectl rollout restart deployment -n ingress-nginx ingress-nginx-controller
|
||||
```
|
||||
|
||||
## 故障排查
|
||||
|
||||
### 问题 1: 证书 Secret 不存在
|
||||
|
||||
```bash
|
||||
# 检查 Secret
|
||||
kubectl get secret openclaw-tls -n openclaw
|
||||
|
||||
# 如果不存在,重新创建
|
||||
./generate-self-signed-cert.sh <your-domain> openclaw openclaw-tls
|
||||
```
|
||||
|
||||
### 问题 2: Ingress 无法访问
|
||||
|
||||
```bash
|
||||
# 检查 Ingress 状态
|
||||
kubectl describe ingress openclaw -n openclaw
|
||||
|
||||
# 检查 Ingress Controller
|
||||
kubectl get pods -n ingress-nginx
|
||||
|
||||
# 检查 Service
|
||||
kubectl get svc openclaw -n openclaw
|
||||
```
|
||||
|
||||
### 问题 3: HTTPS 连接失败
|
||||
|
||||
```bash
|
||||
# 检查证书是否正确加载
|
||||
kubectl get ingress openclaw -n openclaw -o yaml | grep -A 5 tls
|
||||
|
||||
# 检查 Ingress Controller 日志
|
||||
kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
使用自签名证书可以快速解决 OPENCLAW 在 AKS 上需要 HTTPS 访问的问题。虽然会有浏览器警告,但对于开发和测试环境已经足够。生产环境建议使用 Let's Encrypt 或商业证书。
|
||||
|
||||
|
||||
@@ -390,18 +390,33 @@ async def create_agent(request: CreateAgentRequest, db: Session = Depends(get_db
|
||||
)
|
||||
|
||||
# 步骤3: 获取服务端口
|
||||
service_port = k8s_manager.TEMPLATE_PORTS.get(request.template)
|
||||
# OpenClaw 使用 18789 端口(沙箱镜像会自动启用)
|
||||
if request.template == "openclaw":
|
||||
service_port = 18789
|
||||
else:
|
||||
service_port = k8s_manager.TEMPLATE_PORTS.get(request.template)
|
||||
|
||||
# 步骤4: 创建 LoadBalancer Service(AKS 会自动分配外网 IP)
|
||||
# 步骤4: 创建 Service(OpenClaw 已在 create_openclaw_deployment 中自动创建 Service 和 Ingress)
|
||||
service_info = None
|
||||
dns_info = None
|
||||
|
||||
if service_port:
|
||||
# OpenClaw 使用 Ingress + HTTPS,不需要 LoadBalancer Service
|
||||
if request.template == "openclaw":
|
||||
logger.info("OpenClaw 使用 Ingress + HTTPS,跳过 LoadBalancer Service 创建")
|
||||
# Service 和 Ingress 已在 create_openclaw_deployment 中自动创建
|
||||
# 从 result 中获取访问信息
|
||||
if "access_info" in result:
|
||||
service_info = {
|
||||
"name": f"{request.name}-service",
|
||||
"type": "ClusterIP",
|
||||
"note": "OpenClaw 使用 Ingress + HTTPS 访问"
|
||||
}
|
||||
elif service_port:
|
||||
try:
|
||||
import time
|
||||
time.sleep(2) # 等待Pod启动
|
||||
|
||||
# 创建 LoadBalancer Service
|
||||
# 创建 LoadBalancer Service(非 OpenClaw 模板)
|
||||
service_info = temp_manager.create_service(
|
||||
service_name=f"{request.name}-service",
|
||||
namespace=agent_namespace,
|
||||
@@ -465,11 +480,17 @@ async def create_agent(request: CreateAgentRequest, db: Session = Depends(get_db
|
||||
"labels": pod.metadata.labels
|
||||
}
|
||||
|
||||
# 添加 LoadBalancer Service 信息到响应
|
||||
if service_info:
|
||||
# 添加 Service 信息到响应
|
||||
# OpenClaw 的访问信息已在 create_openclaw_deployment 中设置
|
||||
if request.template == "openclaw":
|
||||
# OpenClaw 使用 Ingress + HTTPS,访问信息已在 result 中
|
||||
if "access_info" in result and result["access_info"].get("https_url"):
|
||||
logger.info(f" - HTTPS 访问: {result['access_info']['https_url']}")
|
||||
logger.info(f" - 注意: 使用自签名证书,浏览器会显示安全警告")
|
||||
elif service_info:
|
||||
result["service_info"] = service_info
|
||||
|
||||
# 构建访问信息
|
||||
# 构建访问信息(非 OpenClaw 模板)
|
||||
external_ip = service_info.get("external_ip")
|
||||
|
||||
if external_ip:
|
||||
@@ -625,6 +646,34 @@ async def delete_agent(agent_name: str, db: Session = Depends(get_db)):
|
||||
except Exception as e:
|
||||
logger.warning(f"删除 DNS 记录失败(可忽略): {str(e)}")
|
||||
|
||||
# 检查是否是 OpenClaw 类型的 Agent
|
||||
is_openclaw = False
|
||||
if db_agent and db_agent.agent_framework:
|
||||
# 从数据库记录判断
|
||||
pass
|
||||
|
||||
# 通过命名空间中的资源判断是否为 OpenClaw
|
||||
try:
|
||||
computed_ns = f"agent-{agent_name}".lower().strip('-')[:63]
|
||||
temp_manager = K8sManager(namespace=computed_ns, kubeconfig_path=KUBECONFIG_PATH)
|
||||
# 尝试查找 OpenClaw 特有的资源
|
||||
try:
|
||||
temp_manager.v1.read_namespaced_config_map(name=f"{agent_name}-config", namespace=computed_ns)
|
||||
is_openclaw = True
|
||||
logger.info(f"检测到 OpenClaw Agent: {agent_name}")
|
||||
except:
|
||||
pass
|
||||
except:
|
||||
pass
|
||||
|
||||
# 如果是 OpenClaw,先清理其特有资源
|
||||
if is_openclaw:
|
||||
try:
|
||||
logger.info(f"清理 OpenClaw 专用资源...")
|
||||
temp_manager.delete_openclaw_deployment(agent_name)
|
||||
except Exception as e:
|
||||
logger.warning(f"清理 OpenClaw 资源失败(可忽略): {e}")
|
||||
|
||||
# 步骤2: 删除 Agent 的独立命名空间(会自动删除Pod、Service等所有资源)
|
||||
result = k8s_manager.delete_agent_namespace(agent_name=agent_name)
|
||||
# region agent log
|
||||
|
||||
Executable
+79
@@ -0,0 +1,79 @@
|
||||
#!/bin/bash
|
||||
|
||||
##############################################################################
|
||||
# Agent Manager - 快速构建和部署脚本 (ARM64)
|
||||
# 用途: 一键构建 ARM64 Docker 镜像并部署到 AKS
|
||||
##############################################################################
|
||||
|
||||
set -e
|
||||
|
||||
# 颜色输出
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
# 配置变量
|
||||
ACR_NAME="agnettaiji"
|
||||
IMAGE_NAME="agent-manager"
|
||||
IMAGE_TAG="latest-arm64"
|
||||
FULL_IMAGE_NAME="${ACR_NAME}.azurecr.io/${IMAGE_NAME}:${IMAGE_TAG}"
|
||||
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE} Agent Manager ARM64 构建和部署${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
|
||||
# 检查必要工具
|
||||
echo -e "\n${GREEN}检查工具...${NC}"
|
||||
command -v docker >/dev/null 2>&1 || { echo "需要安装 Docker"; exit 1; }
|
||||
command -v kubectl >/dev/null 2>&1 || { echo "需要安装 kubectl"; exit 1; }
|
||||
command -v az >/dev/null 2>&1 || { echo "需要安装 Azure CLI"; exit 1; }
|
||||
|
||||
# 登录 ACR
|
||||
echo -e "\n${GREEN}登录 Azure Container Registry...${NC}"
|
||||
az acr login --name ${ACR_NAME}
|
||||
|
||||
# 设置 buildx
|
||||
echo -e "\n${GREEN}配置 Docker Buildx...${NC}"
|
||||
BUILDER_NAME="arm64-builder"
|
||||
if ! docker buildx inspect ${BUILDER_NAME} &> /dev/null; then
|
||||
echo "创建 buildx builder: ${BUILDER_NAME}"
|
||||
docker buildx create --name ${BUILDER_NAME} --use --driver docker-container
|
||||
docker buildx inspect --bootstrap
|
||||
else
|
||||
docker buildx use ${BUILDER_NAME}
|
||||
fi
|
||||
|
||||
# 构建并推送镜像
|
||||
echo -e "\n${GREEN}构建 ARM64 镜像...${NC}"
|
||||
docker buildx build \
|
||||
--platform linux/arm64 \
|
||||
-f Dockerfile \
|
||||
-t ${FULL_IMAGE_NAME} \
|
||||
--push \
|
||||
.
|
||||
|
||||
echo -e "\n${GREEN}✅ 镜像构建完成: ${FULL_IMAGE_NAME}${NC}"
|
||||
|
||||
# 部署到 Kubernetes
|
||||
echo -e "\n${GREEN}部署到 Kubernetes...${NC}"
|
||||
echo -e "${YELLOW}使用脚本: scripts/deploy-to-k8s-arm64.sh --skip-build${NC}"
|
||||
echo -e "${YELLOW}或手动运行: kubectl apply -f k8s/agent-manager-deployment.yaml${NC}"
|
||||
|
||||
# 询问是否立即部署
|
||||
read -p "是否立即部署到 Kubernetes? [y/N] " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
if [ -f "scripts/deploy-to-k8s-arm64.sh" ]; then
|
||||
bash scripts/deploy-to-k8s-arm64.sh --skip-build
|
||||
else
|
||||
echo -e "${YELLOW}部署脚本不存在,请手动部署:${NC}"
|
||||
echo "kubectl apply -f k8s/agent-manager-deployment.yaml"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "\n${GREEN}========================================${NC}"
|
||||
echo -e "${GREEN} 完成!${NC}"
|
||||
echo -e "${GREEN}========================================${NC}"
|
||||
|
||||
|
||||
+446
@@ -0,0 +1,446 @@
|
||||
# OpenClaw AKS 部署文件
|
||||
# 包含沙箱功能 (DinD 模式)
|
||||
#
|
||||
# 部署步骤:
|
||||
# 1. 先将 ACR 附加到 AKS: az aks update --name <aks> --resource-group <rg> --attach-acr openclawacr
|
||||
# 2. 部署: kubectl apply -f openclaw-deploy.yaml
|
||||
# 3. 查看状态: kubectl get pods -n openclaw
|
||||
# 4. 查看日志: kubectl logs -n openclaw -l app=openclaw -c gateway -f
|
||||
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: openclaw
|
||||
|
||||
---
|
||||
# Secret: 存储敏感信息
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: openclaw-secrets
|
||||
namespace: openclaw
|
||||
type: Opaque
|
||||
stringData:
|
||||
# Gateway 认证令牌
|
||||
OPENCLAW_GATEWAY_TOKEN: "07f99167450cffe6c236a3da36ac3c029f708bee54d742820b523b990d3ba0d4"
|
||||
|
||||
# LiteLLM API Key
|
||||
LITELLM_API_KEY: "sk-litellm-taiji-prod-8f3a9b2c4d5e6f7g"
|
||||
|
||||
# 飞书配置
|
||||
FEISHU_APP_ID: "cli_a90af793703a9bcc"
|
||||
FEISHU_APP_SECRET: "16Df1ByGy5frbdj7Vm5azbLOSBcprbaw"
|
||||
|
||||
# Telegram Bot Token
|
||||
TELEGRAM_BOT_TOKEN: "8550418255:AAF50xr0MvNwZ4lqpW5PI5tZQ9uRZymKWvc"
|
||||
|
||||
# Gateway Auth Token (Web UI 用)
|
||||
GATEWAY_AUTH_TOKEN: "6b8c483a5495fa1a0babe425504fcbf0633bb1ca8e8ed0fa0a89dfa30267636a"
|
||||
|
||||
---
|
||||
# ConfigMap: OpenClaw 配置文件
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: openclaw-config
|
||||
namespace: openclaw
|
||||
data:
|
||||
openclaw.json: |
|
||||
{
|
||||
"meta": {
|
||||
"lastTouchedVersion": "2026.1.30"
|
||||
},
|
||||
"models": {
|
||||
"providers": {
|
||||
"litellm": {
|
||||
"baseUrl": "https://litellm.graystone-fb459c5d.southeastasia.azurecontainerapps.io/v1",
|
||||
"apiKey": "${LITELLM_API_KEY}",
|
||||
"api": "openai-completions",
|
||||
"models": [
|
||||
{
|
||||
"id": "taiji/gemini-2.5-flash",
|
||||
"name": "Gemini 2.5 Flash",
|
||||
"reasoning": false,
|
||||
"input": ["text"],
|
||||
"cost": { "input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0 },
|
||||
"contextWindow": 1000000,
|
||||
"maxTokens": 8192
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"model": {
|
||||
"primary": "litellm/taiji/gemini-2.5-flash"
|
||||
},
|
||||
"models": {
|
||||
"litellm/taiji/gemini-2.5-flash": {
|
||||
"alias": "gemini-2.5-flash"
|
||||
}
|
||||
},
|
||||
"workspace": "/home/node/.openclaw/workspace",
|
||||
"compaction": { "mode": "safeguard" },
|
||||
"maxConcurrent": 4,
|
||||
"subagents": { "maxConcurrent": 8 },
|
||||
"sandbox": {
|
||||
"mode": "all",
|
||||
"workspaceAccess": "rw",
|
||||
"scope": "agent",
|
||||
"docker": {
|
||||
"image": "openclawacr.azurecr.io/openclaw-sandbox:arm64",
|
||||
"network": "bridge"
|
||||
},
|
||||
"browser": {
|
||||
"enabled": true,
|
||||
"image": "openclawacr.azurecr.io/openclaw-sandbox-browser:arm64"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"messages": {
|
||||
"ackReactionScope": "group-mentions"
|
||||
},
|
||||
"commands": {
|
||||
"native": "auto",
|
||||
"nativeSkills": "auto"
|
||||
},
|
||||
"channels": {
|
||||
"telegram": {
|
||||
"enabled": true,
|
||||
"dmPolicy": "pairing",
|
||||
"botToken": "${TELEGRAM_BOT_TOKEN}",
|
||||
"groupPolicy": "allowlist",
|
||||
"streamMode": "partial"
|
||||
},
|
||||
"feishu": {
|
||||
"appId": "${FEISHU_APP_ID}",
|
||||
"appSecret": "${FEISHU_APP_SECRET}",
|
||||
"enabled": true,
|
||||
"connectionMode": "websocket",
|
||||
"dmPolicy": "open",
|
||||
"groupPolicy": "open"
|
||||
}
|
||||
},
|
||||
"gateway": {
|
||||
"port": 18789,
|
||||
"mode": "local",
|
||||
"bind": "lan",
|
||||
"auth": {
|
||||
"mode": "token",
|
||||
"token": "${GATEWAY_AUTH_TOKEN}"
|
||||
},
|
||||
"http": {
|
||||
"endpoints": {
|
||||
"chatCompletions": { "enabled": true }
|
||||
}
|
||||
}
|
||||
},
|
||||
"plugins": {
|
||||
"entries": {
|
||||
"telegram": { "enabled": true },
|
||||
"feishu": { "enabled": true }
|
||||
},
|
||||
"installs": {
|
||||
"feishu": {
|
||||
"source": "npm",
|
||||
"spec": "@m1heng-clawd/feishu",
|
||||
"installPath": "/home/node/.openclaw/extensions/feishu",
|
||||
"version": "0.1.6"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tools": {
|
||||
"sandbox": {
|
||||
"tools": {
|
||||
"allow": [
|
||||
"exec", "process", "read", "write", "edit", "browser",
|
||||
"sessions_list", "sessions_history", "sessions_send", "sessions_spawn", "session_status"
|
||||
],
|
||||
"deny": ["canvas", "nodes", "cron", "discord", "gateway"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
---
|
||||
# PersistentVolumeClaim: 存储 workspace 和配置数据
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: openclaw-data
|
||||
namespace: openclaw
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: managed-csi # Azure AKS 默认存储类
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
|
||||
---
|
||||
# Deployment: OpenClaw Gateway + DinD Sidecar
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: openclaw
|
||||
namespace: openclaw
|
||||
labels:
|
||||
app: openclaw
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: openclaw
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: openclaw
|
||||
spec:
|
||||
# 初始化容器:准备配置文件 + 安装飞书插件
|
||||
initContainers:
|
||||
# 第一步:使用 OpenClaw 镜像安装飞书插件
|
||||
- name: plugin-install
|
||||
image: openclawacr.azurecr.io/openclaw:arm64
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
echo "=== Installing Feishu plugin ==="
|
||||
cd /home/node
|
||||
|
||||
# 创建必要目录
|
||||
mkdir -p /data/extensions /data/workspace /data/sandboxes
|
||||
|
||||
# 安装飞书插件到持久化目录
|
||||
if [ ! -d "/data/extensions/feishu/node_modules" ]; then
|
||||
echo "Installing @m1heng-clawd/feishu plugin..."
|
||||
npm pack @m1heng-clawd/feishu --pack-destination /tmp
|
||||
mkdir -p /data/extensions/feishu
|
||||
tar -xzf /tmp/m1heng-clawd-feishu-*.tgz -C /data/extensions/feishu --strip-components=1
|
||||
cd /data/extensions/feishu && npm install --production
|
||||
echo "Plugin installed successfully"
|
||||
else
|
||||
echo "Plugin already installed, skipping..."
|
||||
fi
|
||||
|
||||
ls -la /data/extensions/feishu/
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data
|
||||
|
||||
# 第二步:准备配置文件(替换环境变量)
|
||||
- name: config-init
|
||||
image: busybox:1.36
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
# 复制配置文件并替换环境变量占位符
|
||||
cp /config-template/openclaw.json /config/openclaw.json
|
||||
sed -i "s|\${LITELLM_API_KEY}|$LITELLM_API_KEY|g" /config/openclaw.json
|
||||
sed -i "s|\${FEISHU_APP_ID}|$FEISHU_APP_ID|g" /config/openclaw.json
|
||||
sed -i "s|\${FEISHU_APP_SECRET}|$FEISHU_APP_SECRET|g" /config/openclaw.json
|
||||
sed -i "s|\${TELEGRAM_BOT_TOKEN}|$TELEGRAM_BOT_TOKEN|g" /config/openclaw.json
|
||||
sed -i "s|\${GATEWAY_AUTH_TOKEN}|$GATEWAY_AUTH_TOKEN|g" /config/openclaw.json
|
||||
|
||||
echo "Config initialized successfully"
|
||||
cat /config/openclaw.json
|
||||
env:
|
||||
- name: LITELLM_API_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openclaw-secrets
|
||||
key: LITELLM_API_KEY
|
||||
- name: FEISHU_APP_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openclaw-secrets
|
||||
key: FEISHU_APP_ID
|
||||
- name: FEISHU_APP_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openclaw-secrets
|
||||
key: FEISHU_APP_SECRET
|
||||
- name: TELEGRAM_BOT_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openclaw-secrets
|
||||
key: TELEGRAM_BOT_TOKEN
|
||||
- name: GATEWAY_AUTH_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openclaw-secrets
|
||||
key: GATEWAY_AUTH_TOKEN
|
||||
volumeMounts:
|
||||
- name: config-template
|
||||
mountPath: /config-template
|
||||
- name: config
|
||||
mountPath: /config
|
||||
- name: data
|
||||
mountPath: /data
|
||||
|
||||
containers:
|
||||
# ========== Gateway 容器 ==========
|
||||
- name: gateway
|
||||
image: openclawacr.azurecr.io/openclaw:arm64
|
||||
ports:
|
||||
- containerPort: 18789
|
||||
name: http
|
||||
- containerPort: 18790
|
||||
name: bridge
|
||||
env:
|
||||
- name: HOME
|
||||
value: "/home/node"
|
||||
- name: TERM
|
||||
value: "xterm-256color"
|
||||
- name: OPENCLAW_GATEWAY_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: openclaw-secrets
|
||||
key: OPENCLAW_GATEWAY_TOKEN
|
||||
# Docker 连接到 DinD sidecar
|
||||
- name: DOCKER_HOST
|
||||
value: "tcp://localhost:2375"
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /home/node/.openclaw/openclaw.json
|
||||
subPath: openclaw.json
|
||||
- name: data
|
||||
mountPath: /home/node/.openclaw/workspace
|
||||
subPath: workspace
|
||||
- name: data
|
||||
mountPath: /home/node/.openclaw/sandboxes
|
||||
subPath: sandboxes
|
||||
- name: data
|
||||
mountPath: /home/node/.openclaw/extensions
|
||||
subPath: extensions
|
||||
command:
|
||||
- node
|
||||
- dist/index.js
|
||||
- gateway
|
||||
- --bind
|
||||
- lan
|
||||
- --port
|
||||
- "18789"
|
||||
resources:
|
||||
requests:
|
||||
memory: "512Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "2Gi"
|
||||
cpu: "2000m"
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 18789
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 18789
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 30
|
||||
|
||||
# ========== DinD Sidecar (用于沙箱) ==========
|
||||
- name: dind
|
||||
image: docker:24-dind
|
||||
securityContext:
|
||||
privileged: true # DinD 需要特权模式
|
||||
env:
|
||||
- name: DOCKER_TLS_CERTDIR
|
||||
value: "" # 禁用 TLS,内部通信
|
||||
ports:
|
||||
- containerPort: 2375
|
||||
name: docker
|
||||
volumeMounts:
|
||||
- name: docker-storage
|
||||
mountPath: /var/lib/docker
|
||||
- name: data
|
||||
mountPath: /home/node/.openclaw/workspace
|
||||
subPath: workspace
|
||||
- name: data
|
||||
mountPath: /home/node/.openclaw/sandboxes
|
||||
subPath: sandboxes
|
||||
resources:
|
||||
requests:
|
||||
memory: "512Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "4Gi"
|
||||
cpu: "2000m"
|
||||
|
||||
volumes:
|
||||
- name: config-template
|
||||
configMap:
|
||||
name: openclaw-config
|
||||
- name: config
|
||||
emptyDir: {}
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: openclaw-data
|
||||
- name: docker-storage
|
||||
emptyDir: {}
|
||||
|
||||
---
|
||||
# Service: 暴露 Gateway 端口
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: openclaw
|
||||
namespace: openclaw
|
||||
spec:
|
||||
selector:
|
||||
app: openclaw
|
||||
ports:
|
||||
- name: http
|
||||
port: 18789
|
||||
targetPort: 18789
|
||||
- name: bridge
|
||||
port: 18790
|
||||
targetPort: 18790
|
||||
type: ClusterIP
|
||||
|
||||
---
|
||||
# Ingress: 外部访问 (可选,需要 Ingress Controller)
|
||||
# 如果使用 Azure Application Gateway 或 nginx-ingress
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: openclaw
|
||||
namespace: openclaw
|
||||
annotations:
|
||||
# 如果使用 nginx-ingress:
|
||||
# kubernetes.io/ingress.class: nginx
|
||||
# nginx.ingress.kubernetes.io/websocket-services: openclaw
|
||||
|
||||
# 如果使用 Azure Application Gateway:
|
||||
# kubernetes.io/ingress.class: azure/application-gateway
|
||||
kubernetes.io/ingress.class: nginx
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/websocket-services: "openclaw"
|
||||
# 启用 HTTPS 重定向(可选,如果希望强制 HTTPS)
|
||||
# nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
spec:
|
||||
# TLS 配置:使用自签名证书
|
||||
# 使用前需要先运行: ./generate-self-signed-cert.sh <your-domain> openclaw openclaw-tls
|
||||
tls:
|
||||
- hosts:
|
||||
- openclaw.yourdomain.com # ← 修改为你的域名
|
||||
secretName: openclaw-tls # ← 对应 Kubernetes Secret 名称
|
||||
rules:
|
||||
- host: openclaw.yourdomain.com # ← 修改为你的域名
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: openclaw
|
||||
port:
|
||||
number: 18789
|
||||
|
||||
Executable
+90
@@ -0,0 +1,90 @@
|
||||
#!/bin/bash
|
||||
# 生成自签名证书脚本
|
||||
# 用于 OPENCLAW AKS 部署的 HTTPS 访问
|
||||
|
||||
set -e
|
||||
|
||||
# 配置变量
|
||||
DOMAIN="${1:-openclaw.yourdomain.com}" # 从命令行参数获取域名,默认为 openclaw.yourdomain.com
|
||||
NAMESPACE="${2:-openclaw}" # Kubernetes 命名空间
|
||||
SECRET_NAME="${3:-openclaw-tls}" # Kubernetes Secret 名称
|
||||
CERT_DIR="./certs"
|
||||
DAYS_VALID=365 # 证书有效期(天)
|
||||
|
||||
echo "=========================================="
|
||||
echo "生成自签名证书 for OPENCLAW"
|
||||
echo "=========================================="
|
||||
echo "域名: $DOMAIN"
|
||||
echo "命名空间: $NAMESPACE"
|
||||
echo "Secret 名称: $SECRET_NAME"
|
||||
echo "=========================================="
|
||||
|
||||
# 创建证书目录
|
||||
mkdir -p "$CERT_DIR"
|
||||
|
||||
# 生成私钥
|
||||
echo "1. 生成私钥..."
|
||||
openssl genrsa -out "$CERT_DIR/tls.key" 2048
|
||||
|
||||
# 生成证书签名请求 (CSR)
|
||||
echo "2. 生成证书签名请求..."
|
||||
openssl req -new -key "$CERT_DIR/tls.key" -out "$CERT_DIR/tls.csr" \
|
||||
-subj "/C=CN/ST=Beijing/L=Beijing/O=OpenClaw/CN=$DOMAIN"
|
||||
|
||||
# 生成自签名证书
|
||||
echo "3. 生成自签名证书..."
|
||||
openssl x509 -req -days $DAYS_VALID -in "$CERT_DIR/tls.csr" -signkey "$CERT_DIR/tls.key" \
|
||||
-out "$CERT_DIR/tls.crt" \
|
||||
-extensions v3_req \
|
||||
-extfile <(cat <<EOF
|
||||
[req]
|
||||
distinguished_name = req_distinguished_name
|
||||
req_extensions = v3_req
|
||||
|
||||
[v3_req]
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
DNS.1 = $DOMAIN
|
||||
DNS.2 = *.$DOMAIN
|
||||
DNS.3 = localhost
|
||||
IP.1 = 127.0.0.1
|
||||
EOF
|
||||
)
|
||||
|
||||
# 清理 CSR 文件
|
||||
rm -f "$CERT_DIR/tls.csr"
|
||||
|
||||
echo "4. 证书生成完成!"
|
||||
echo ""
|
||||
echo "证书文件:"
|
||||
echo " - 私钥: $CERT_DIR/tls.key"
|
||||
echo " - 证书: $CERT_DIR/tls.crt"
|
||||
echo ""
|
||||
|
||||
# 创建 Kubernetes Secret
|
||||
echo "5. 创建 Kubernetes Secret..."
|
||||
kubectl create secret tls "$SECRET_NAME" \
|
||||
--cert="$CERT_DIR/tls.crt" \
|
||||
--key="$CERT_DIR/tls.key" \
|
||||
--namespace="$NAMESPACE" \
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "✅ 完成!"
|
||||
echo "=========================================="
|
||||
echo "Secret '$SECRET_NAME' 已创建在命名空间 '$NAMESPACE' 中"
|
||||
echo ""
|
||||
echo "下一步:"
|
||||
echo "1. 更新 deploay.yaml 中的 Ingress 配置,添加 TLS 部分"
|
||||
echo "2. 将域名 '$DOMAIN' 指向你的 AKS Ingress IP"
|
||||
echo "3. 访问 https://$DOMAIN (浏览器会显示安全警告,这是正常的)"
|
||||
echo ""
|
||||
echo "注意:自签名证书会在浏览器中显示安全警告,"
|
||||
echo " 需要手动接受证书才能访问。"
|
||||
echo "=========================================="
|
||||
|
||||
|
||||
@@ -8,5 +8,5 @@ data:
|
||||
DATABASE_URL: "postgresql://taiji:By%40123456.@taijipda.postgres.database.azure.com:5432/taijiagnet"
|
||||
# Azure DNS 配置(如果需要)
|
||||
AZURE_DNS_ZONE: "taijiagnet.com"
|
||||
AZURE_SUBSCRIPTION_ID: "your-subscription-id"
|
||||
AZURE_RESOURCE_GROUP: "your-resource-group"
|
||||
AZURE_SUBSCRIPTION_ID: "45d7a360-af09-40fc-9afc-56dc475245ec"
|
||||
AZURE_RESOURCE_GROUP: "taiji-ai-v0"
|
||||
|
||||
@@ -18,20 +18,20 @@ spec:
|
||||
# 使用专用的 ServiceAccount
|
||||
serviceAccountName: agent-manager
|
||||
|
||||
# ARM 架构节点选择器
|
||||
# ARM 架构节点选择器(确保 Pod 调度到 ARM64 节点)
|
||||
nodeSelector:
|
||||
kubernetes.io/arch: arm64
|
||||
|
||||
# 容忍度(如果需要)
|
||||
tolerations:
|
||||
- key: "kubernetes.io/arch"
|
||||
operator: "Equal"
|
||||
value: "arm64"
|
||||
effect: "NoSchedule"
|
||||
# 容忍度(如果 ARM64 节点有污点,取消注释以下配置)
|
||||
# tolerations:
|
||||
# - key: "kubernetes.io/arch"
|
||||
# operator: "Equal"
|
||||
# value: "arm64"
|
||||
# effect: "NoSchedule"
|
||||
|
||||
containers:
|
||||
- name: agent-manager
|
||||
image: agnettaiji.azurecr.io/ai-agents/agent-manager:latest
|
||||
image: agnettaiji.azurecr.io/agent-manager:latest-arm64
|
||||
imagePullPolicy: Always
|
||||
|
||||
ports:
|
||||
|
||||
@@ -4,7 +4,7 @@ metadata:
|
||||
name: agent-manager-role
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources: ["namespaces", "pods", "services", "configmaps", "secrets"]
|
||||
resources: ["namespaces", "pods", "services", "configmaps", "secrets", "persistentvolumeclaims"]
|
||||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
||||
- apiGroups: ["apps"]
|
||||
resources: ["deployments", "replicasets"]
|
||||
|
||||
+1068
-26
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,124 @@
|
||||
# NSG 规则检查结果
|
||||
|
||||
## 检查时间
|
||||
2026-02-03
|
||||
|
||||
## NSG 规则详情
|
||||
|
||||
### 自定义规则(优先级从高到低)
|
||||
|
||||
1. **优先级 500**: `k8s-azure-lb_allow_IPv4_d39272f7f57ed937951650d93992ad77`
|
||||
- 访问: Allow
|
||||
- 协议: Tcp
|
||||
- 源地址: Internet
|
||||
- 目标端口: 80
|
||||
- 目标地址: 所有
|
||||
|
||||
2. **优先级 501**: `k8s-azure-lb_allow_IPv4_556f7044ec033071ec0dfcf7cd85bc93`
|
||||
- 访问: Allow
|
||||
- 协议: Tcp
|
||||
- 源地址: Internet
|
||||
- 目标端口: 80, 443
|
||||
- 目标地址: 40.65.173.54
|
||||
|
||||
### 默认规则
|
||||
|
||||
- **优先级 65000**: AllowVnetInBound - 允许 VNet 内部流量
|
||||
- **优先级 65001**: AllowAzureLoadBalancerInBound - 允许 Azure LoadBalancer 流量
|
||||
- **优先级 65500**: DenyAllInBound - 拒绝所有其他入站流量(但会被优先级更高的规则覆盖)
|
||||
|
||||
## 规则分析
|
||||
|
||||
✅ **NSG 规则配置正确**
|
||||
- 没有更高优先级的 Deny 规则
|
||||
- 规则 500 和 501 都允许从 Internet 访问 80/443 端口
|
||||
- 规则优先级顺序正确(500 < 501 < 65000 < 65500)
|
||||
|
||||
## LoadBalancer 配置
|
||||
|
||||
### 健康检查探针
|
||||
- **HTTP 探针**: `a2eecfe068cbe4c1b936d6b0880bee0b-TCP-80`
|
||||
- 协议: Http
|
||||
- 端口: 32519 (NodePort)
|
||||
- 间隔: 5 秒
|
||||
- 探测次数: 2
|
||||
- 状态: Succeeded ✅
|
||||
|
||||
- **HTTPS 探针**: `a2eecfe068cbe4c1b936d6b0880bee0b-TCP-443`
|
||||
- 协议: Https
|
||||
- 端口: 31651 (NodePort)
|
||||
- 间隔: 5 秒
|
||||
- 探测次数: 2
|
||||
- 状态: Succeeded ✅
|
||||
|
||||
### 后端池
|
||||
- 后端池名称: `kubernetes`
|
||||
- Endpoints: `10.224.0.37`, `10.224.0.66` (Ingress Controller Pods)
|
||||
|
||||
## 测试结果
|
||||
|
||||
### ✅ 成功的测试
|
||||
- 从集群内部访问 `40.65.173.54:80` → 返回 308 重定向 ✅
|
||||
- 从集群内部访问 `40.65.173.54:443` → TLS 握手成功 ✅
|
||||
|
||||
### ❌ 失败的测试
|
||||
- 从外部网络访问 `40.65.173.54:80` → 连接超时 ❌
|
||||
- 从外部网络访问 `40.65.173.54:443` → 连接超时 ❌
|
||||
- 从外部网络访问 `test-openclaw-dns.taijiagnet.com` → 连接超时 ❌
|
||||
|
||||
## 问题分析
|
||||
|
||||
虽然 NSG 规则配置正确,但外部访问仍然超时。可能的原因:
|
||||
|
||||
1. **NSG 规则生效延迟**
|
||||
- Azure NSG 规则可能需要几分钟才能完全生效
|
||||
- 建议等待 5-10 分钟后再次测试
|
||||
|
||||
2. **外部网络到 Azure 的路径问题**
|
||||
- 可能是 ISP 或网络运营商的限制
|
||||
- 可能是地理位置或网络路由问题
|
||||
- 建议从不同网络环境测试
|
||||
|
||||
3. **Azure 平台层面的限制**
|
||||
- 可能有订阅级别的网络策略
|
||||
- 可能有资源组级别的限制
|
||||
- 需要检查 Azure Policy
|
||||
|
||||
4. **LoadBalancer 配置问题**
|
||||
- 虽然健康检查显示 Succeeded,但可能后端实例状态异常
|
||||
- 需要在 Azure Portal 中检查 LoadBalancer 的详细状态
|
||||
|
||||
## 建议操作
|
||||
|
||||
1. **等待规则生效**
|
||||
- 等待 5-10 分钟让 NSG 规则完全生效
|
||||
- 然后再次测试
|
||||
|
||||
2. **检查 LoadBalancer 状态**
|
||||
- 在 Azure Portal 中打开 LoadBalancer `kubernetes`
|
||||
- 检查"后端池"中的实例状态
|
||||
- 检查"健康探测"的详细状态
|
||||
|
||||
3. **从不同网络测试**
|
||||
- 使用手机热点
|
||||
- 使用其他网络环境
|
||||
- 排除本地网络问题
|
||||
|
||||
4. **检查 Azure Policy**
|
||||
- 在 Azure Portal 中检查订阅的网络策略
|
||||
- 检查资源组的网络策略
|
||||
|
||||
5. **联系 Azure 支持**
|
||||
- 如果问题持续,建议打开 Azure 支持请求
|
||||
- 提供 LoadBalancer 和 NSG 的详细信息
|
||||
|
||||
## 结论
|
||||
|
||||
NSG 规则配置**完全正确**,没有阻止访问的规则。问题可能在于:
|
||||
- 规则生效延迟
|
||||
- 外部网络到 Azure 的连接问题
|
||||
- Azure 平台层面的其他限制
|
||||
|
||||
建议等待几分钟后再次测试,或从不同网络环境测试。
|
||||
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
# OpenClaw Pod 访问问题诊断报告
|
||||
|
||||
## 问题描述
|
||||
域名 `test-openclaw-dns.taijiagnet.com` 无法访问
|
||||
|
||||
## 诊断结果
|
||||
|
||||
### ✅ 正常的部分
|
||||
|
||||
1. **Pod 状态正常**
|
||||
- Pod: `test-openclaw-dns-6c457fc9c8-p5pg5`
|
||||
- 命名空间: `agent-test-openclaw-dns`
|
||||
- 状态: `Running (2/2)` - 两个容器(gateway 和 dind)都在运行
|
||||
- 容器就绪状态: `true true` - 两个容器都已就绪
|
||||
|
||||
2. **Pod 内部服务正常**
|
||||
- 从 Pod 内部访问 `http://localhost:18789/health` 返回正常 HTML 响应
|
||||
- 从 Pod 内部访问 Service `http://test-openclaw-dns-service:18789/health` 也正常
|
||||
|
||||
3. **Service 配置正确**
|
||||
- Service: `test-openclaw-dns-service`
|
||||
- 类型: `ClusterIP`
|
||||
- 端口: `18789/TCP`
|
||||
- Endpoints: `10.224.0.8:18789` ✅ 正确指向 Pod
|
||||
|
||||
4. **Ingress 配置正确**
|
||||
- Ingress: `test-openclaw-dns-ingress`
|
||||
- 域名: `test-openclaw-dns.taijiagnet.com`
|
||||
- Backend: `test-openclaw-dns-service:18789 (10.224.0.8:18789)` ✅
|
||||
- TLS: 已配置自签名证书
|
||||
- Ingress IP: `40.65.173.54`
|
||||
|
||||
5. **DNS 解析正常**
|
||||
- `test-openclaw-dns.taijiagnet.com` 正确解析到 `40.65.173.54`
|
||||
- DNS 记录与 Ingress IP 一致
|
||||
|
||||
6. **Ingress Controller 运行正常**
|
||||
- Ingress Controller Pods: 2 个都在运行
|
||||
- Service: `ingress-nginx-controller` (LoadBalancer)
|
||||
- LoadBalancer IP: `40.65.173.54`
|
||||
- 端口映射: `80:32519/TCP, 443:31651/TCP`
|
||||
|
||||
### ❌ 问题所在
|
||||
|
||||
**外部网络访问被阻止**
|
||||
|
||||
从集群内部测试:
|
||||
- ✅ Pod 内部访问正常
|
||||
- ✅ Service 访问正常
|
||||
- ❌ 外部访问 `40.65.173.54:80` 超时
|
||||
- ❌ 外部访问 `40.65.173.54:443` 超时
|
||||
|
||||
**根本原因:Azure 网络安全组(NSG)或防火墙规则阻止了 80/443 端口**
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 方案 1: 检查并更新 Azure 网络安全组(推荐)
|
||||
|
||||
1. 在 Azure Portal 中找到 AKS 集群的资源组
|
||||
2. 找到与 LoadBalancer IP `40.65.173.54` 关联的网络安全组(NSG)
|
||||
3. 添加入站规则:
|
||||
- **端口 80 (HTTP)**: 允许来自 `*` 的流量
|
||||
- **端口 443 (HTTPS)**: 允许来自 `*` 的流量
|
||||
|
||||
### 方案 2: 使用 Azure CLI 检查 NSG 规则
|
||||
|
||||
```bash
|
||||
# 查找 LoadBalancer 关联的 NSG
|
||||
az network lb list --query "[?frontendIpConfigurations[0].publicIpAddress=='40.65.173.54']" -o table
|
||||
|
||||
# 查找并更新 NSG 规则
|
||||
az network nsg rule list --nsg-name <nsg-name> --resource-group <rg-name> -o table
|
||||
az network nsg rule create \
|
||||
--resource-group <rg-name> \
|
||||
--nsg-name <nsg-name> \
|
||||
--name AllowHTTP \
|
||||
--priority 100 \
|
||||
--direction Inbound \
|
||||
--access Allow \
|
||||
--protocol Tcp \
|
||||
--destination-port-ranges 80
|
||||
|
||||
az network nsg rule create \
|
||||
--resource-group <rg-name> \
|
||||
--nsg-name <nsg-name> \
|
||||
--name AllowHTTPS \
|
||||
--priority 101 \
|
||||
--direction Inbound \
|
||||
--access Allow \
|
||||
--protocol Tcp \
|
||||
--destination-port-ranges 443
|
||||
```
|
||||
|
||||
### 方案 3: 检查 AKS 节点池的 NSG
|
||||
|
||||
```bash
|
||||
# 查找节点池的 NSG
|
||||
az aks show --name <aks-cluster-name> --resource-group <rg-name> --query "agentPoolProfiles[0].vnetSubnetId" -o tsv
|
||||
|
||||
# 然后查找该子网的 NSG 并更新规则
|
||||
```
|
||||
|
||||
## 其他发现
|
||||
|
||||
### 配置版本警告(非关键)
|
||||
- 日志显示: `Config was last written by a newer OpenClaw (2026.2.3); current version is 2026.1.30`
|
||||
- 这是配置版本不匹配的警告,不影响功能,但建议更新镜像版本
|
||||
|
||||
### Readiness Probe 早期失败(已恢复)
|
||||
- 在 Pod 启动初期有 readiness probe 失败
|
||||
- 现在已经恢复正常,容器状态为 `ready`
|
||||
|
||||
## 验证步骤
|
||||
|
||||
修复 NSG 规则后,验证访问:
|
||||
|
||||
```bash
|
||||
# 测试 HTTP 访问
|
||||
curl -v http://test-openclaw-dns.taijiagnet.com/health
|
||||
|
||||
# 测试 HTTPS 访问(忽略自签名证书警告)
|
||||
curl -k -v https://test-openclaw-dns.taijiagnet.com/health
|
||||
```
|
||||
|
||||
## 重要发现
|
||||
|
||||
### ✅ 从集群内部访问成功
|
||||
|
||||
从 Kubernetes 集群内部测试访问 `40.65.173.54:80` **成功**,返回了 308 重定向响应。这说明:
|
||||
- LoadBalancer 配置正确 ✅
|
||||
- Ingress Controller 工作正常 ✅
|
||||
- 路由规则正确 ✅
|
||||
- NSG 规则对集群内部生效 ✅
|
||||
|
||||
### ❌ 从外部网络访问失败
|
||||
|
||||
从外部网络访问 `40.65.173.54:80` 和 `443` 端口超时。这说明问题在于:
|
||||
- **外部网络到 Azure LoadBalancer 的路径被阻止**
|
||||
|
||||
## 总结
|
||||
|
||||
**问题类型**: 外部网络到 Azure 的网络连接问题
|
||||
|
||||
**已确认正常的部分**:
|
||||
- ✅ DNS 绑定正常(DNS 解析正确)
|
||||
- ✅ Pod 正常运行(2/2 容器就绪)
|
||||
- ✅ Ingress 配置正确(路由规则正确)
|
||||
- ✅ Service 配置正确(Endpoints 正确)
|
||||
- ✅ NSG 规则已配置(允许 80/443 端口)
|
||||
- ✅ LoadBalancer 配置正确(从集群内部访问成功)
|
||||
|
||||
**问题所在**:
|
||||
- ❌ 外部网络无法连接到 Azure LoadBalancer IP `40.65.173.54`
|
||||
|
||||
**可能的原因**:
|
||||
1. **NSG 规则可能只对集群内部生效**
|
||||
- 虽然规则显示 `sourceAddressPrefix: Internet`,但可能实际只允许集群内部访问
|
||||
- 需要检查是否有其他限制
|
||||
|
||||
2. **Azure 订阅或资源组级别的网络策略**
|
||||
- 可能有订阅级别的网络限制
|
||||
- 可能有资源组的网络策略
|
||||
|
||||
3. **外部网络到 Azure 的路径问题**
|
||||
- 可能是 ISP 或网络运营商的问题
|
||||
- 可能是地理位置限制
|
||||
|
||||
4. **LoadBalancer 的源地址限制**
|
||||
- 虽然检查显示 `loadBalancerSourceRanges` 为空,但可能在其他地方有限制
|
||||
|
||||
**建议操作**:
|
||||
1. ✅ 已确认 NSG 规则存在(优先级 501,允许 Internet 访问 80/443)
|
||||
2. ⏳ 检查是否有更高优先级的 Deny 规则
|
||||
3. ⏳ 在 Azure Portal 中检查 LoadBalancer 的详细配置
|
||||
4. ⏳ 尝试从不同的外部网络测试(排除本地网络问题)
|
||||
5. ⏳ 联系 Azure 支持检查是否有平台级别的限制
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
# OpenClaw 网络访问问题详细检查报告
|
||||
|
||||
## 检查时间
|
||||
2026-02-03
|
||||
|
||||
## 检查结果
|
||||
|
||||
### ✅ 已确认正常的部分
|
||||
|
||||
1. **NSG 规则已配置**
|
||||
- 规则名称: `k8s-azure-lb_allow_IPv4_556f7044ec033071ec0dfcf7cd85bc93`
|
||||
- 优先级: 501
|
||||
- 访问: Allow
|
||||
- 协议: Tcp
|
||||
- 源地址: Internet
|
||||
- 目标端口: 80, 443
|
||||
- 目标地址: 40.65.173.54 ✅
|
||||
|
||||
2. **LoadBalancer 配置正常**
|
||||
- Public IP: `40.65.173.54`
|
||||
- SKU: Standard
|
||||
- 状态: Succeeded
|
||||
- Zones: 1, 2, 3
|
||||
|
||||
3. **Ingress Controller 运行正常**
|
||||
- Pods: 2 个都在运行
|
||||
- 监听端口: 80, 443 ✅
|
||||
- Service Endpoints: 正常
|
||||
|
||||
4. **Kubernetes 资源正常**
|
||||
- Pod: Running (2/2)
|
||||
- Service: Endpoints 正确
|
||||
- Ingress: 配置正确,已同步
|
||||
|
||||
### ❌ 问题现象
|
||||
|
||||
从外部网络访问 `40.65.173.54:80` 和 `443` 端口超时
|
||||
|
||||
### 可能的原因
|
||||
|
||||
虽然 NSG 规则已配置,但可能存在以下情况:
|
||||
|
||||
1. **规则优先级问题**
|
||||
- 可能有更高优先级的 Deny 规则覆盖了 Allow 规则
|
||||
- 需要检查所有 Inbound 规则的优先级顺序
|
||||
|
||||
2. **网络路由问题**
|
||||
- 可能有路由表规则影响流量
|
||||
- 需要检查 VNet 的路由配置
|
||||
|
||||
3. **LoadBalancer 健康检查问题**
|
||||
- LoadBalancer 可能认为后端不健康
|
||||
- 需要检查 LoadBalancer 的健康检查配置
|
||||
|
||||
4. **Azure 平台层面的限制**
|
||||
- 可能有订阅级别的网络策略
|
||||
- 可能有其他安全策略影响
|
||||
|
||||
## 建议的排查步骤
|
||||
|
||||
### 步骤 1: 检查所有 NSG 规则的优先级
|
||||
|
||||
```bash
|
||||
az network nsg rule list \
|
||||
--nsg-name aks-agentpool-50066007-nsg \
|
||||
--resource-group mc_taiji-ai-pda_taiji-ai-pda_southeastasia \
|
||||
--query "[?direction=='Inbound'].{name:name, priority:priority, access:access, destinationPortRanges:destinationPortRanges}" \
|
||||
-o table
|
||||
```
|
||||
|
||||
**重要**: 检查是否有优先级 < 501 的 Deny 规则
|
||||
|
||||
### 步骤 2: 检查 LoadBalancer 健康检查
|
||||
|
||||
在 Azure Portal 中:
|
||||
1. 找到 LoadBalancer: `kubernetes`
|
||||
2. 检查健康探测(Health Probes)状态
|
||||
3. 检查后端池(Backend Pools)中的实例状态
|
||||
|
||||
### 步骤 3: 检查 VNet 路由表
|
||||
|
||||
```bash
|
||||
az network route-table list --query "[].{name:name, resourceGroup:resourceGroup}" -o table
|
||||
```
|
||||
|
||||
### 步骤 4: 从 Azure 内部测试
|
||||
|
||||
尝试从 Azure 内部的另一个资源(如另一个 VM 或 Container Instance)测试访问
|
||||
|
||||
### 步骤 5: 检查 Azure 订阅的网络限制
|
||||
|
||||
在 Azure Portal 中检查:
|
||||
- 订阅的网络策略
|
||||
- 资源组的网络策略
|
||||
- 是否有 Azure Policy 限制网络访问
|
||||
|
||||
## 临时解决方案
|
||||
|
||||
如果急需访问,可以考虑:
|
||||
|
||||
1. **使用 NodePort 直接访问**
|
||||
```bash
|
||||
# 获取 NodePort
|
||||
kubectl get svc -n ingress-nginx ingress-nginx-controller
|
||||
# 然后通过节点的公网 IP + NodePort 访问
|
||||
```
|
||||
|
||||
2. **使用 kubectl port-forward**
|
||||
```bash
|
||||
kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller 8080:80
|
||||
# 然后访问 http://localhost:8080
|
||||
```
|
||||
|
||||
3. **检查是否有其他 LoadBalancer**
|
||||
- 可能需要在 Azure Portal 中检查是否有多个 LoadBalancer
|
||||
- 确认使用的是正确的 LoadBalancer
|
||||
|
||||
## 下一步行动
|
||||
|
||||
1. ✅ 已确认 NSG 规则存在
|
||||
2. ⏳ 需要检查规则优先级顺序
|
||||
3. ⏳ 需要检查 LoadBalancer 健康检查状态
|
||||
4. ⏳ 需要从 Azure 内部测试访问
|
||||
5. ⏳ 需要检查是否有其他网络限制
|
||||
|
||||
## 联系信息
|
||||
|
||||
如果问题持续,建议:
|
||||
1. 在 Azure Portal 中打开支持请求
|
||||
2. 提供 LoadBalancer 和 NSG 的详细信息
|
||||
3. 说明已配置的 NSG 规则但仍然无法访问
|
||||
|
||||
|
||||
@@ -86,20 +86,31 @@ build_image() {
|
||||
|
||||
echo "镜像名称: ${FULL_IMAGE_NAME}"
|
||||
|
||||
# 使用 buildx 支持多架构构建
|
||||
# 检查并设置 buildx
|
||||
if ! docker buildx version &> /dev/null; then
|
||||
print_warning "docker buildx 未启用,尝试启用..."
|
||||
docker buildx create --use
|
||||
print_error "docker buildx 未安装,请先安装 Docker Buildx"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 构建镜像
|
||||
# 创建并使用 buildx builder(如果不存在)
|
||||
BUILDER_NAME="arm64-builder"
|
||||
if ! docker buildx inspect ${BUILDER_NAME} &> /dev/null; then
|
||||
print_step "创建 buildx builder: ${BUILDER_NAME}"
|
||||
docker buildx create --name ${BUILDER_NAME} --use --driver docker-container
|
||||
docker buildx inspect --bootstrap
|
||||
else
|
||||
docker buildx use ${BUILDER_NAME}
|
||||
fi
|
||||
|
||||
# 构建 ARM64 镜像并推送到 ACR
|
||||
print_step "开始构建 ARM64 镜像..."
|
||||
if docker buildx build \
|
||||
--platform linux/arm64 \
|
||||
-f Dockerfile.arm64 \
|
||||
-f Dockerfile \
|
||||
-t ${FULL_IMAGE_NAME} \
|
||||
--push \
|
||||
.; then
|
||||
print_success "镜像构建并推送成功"
|
||||
print_success "ARM64 镜像构建并推送成功: ${FULL_IMAGE_NAME}"
|
||||
else
|
||||
print_error "镜像构建失败"
|
||||
exit 1
|
||||
|
||||
Reference in New Issue
Block a user