Files
qiming/qiming-rcoder/make/k8s.mk
2026-06-01 13:54:52 +08:00

234 lines
10 KiB
Makefile
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ============================================================================
# K8s 开发/部署 Makefile (Kustomize)
# ============================================================================
IMAGE ?= rcoder:test-k8s
K8S_IMAGE_REGISTRY ?= nuwax-docker-images-registry.cn-hangzhou.cr.aliyuncs.com/dev/rcoder:latest
KUSTOMIZE_DIR ?= k8s/manifests
ROLLOUT_TIMEOUT ?= 180s
# Namespace 按 overlay 推导
K8S_NAMESPACE_DEV := nuwax-rcoder-dev
K8S_NAMESPACE_PROD := nuwax-rcoder-prod
# 本地 k3s 同步配置make dev-build-k8s 构建后自动 import 到本地 k3s
SUDO ?= sudo
K3S_CTR ?= $(SUDO) k3s ctr
K3S_NAMESPACE ?= k8s.io
# 设为 1 跳过本地 k3s import例如机器没装 k3s 或不想 import
SKIP_K3S_IMPORT ?= 0
# 设为 1 跳过 build 后自动 rollout restart
SKIP_ROLLOUT_RESTART ?= 0
# ============================================================================
# 镜像构建
# ============================================================================
dev-build-k8s: docker-build-master-base
@echo "☸️ 构建 K8s 镜像..."
@echo "📍 镜像名称: $(IMAGE)"
@echo "⏳ 这可能需要较长时间(包含 Rust 编译)..."
@docker build -f docker/rcoder-master/Dockerfile -t $(IMAGE) --build-arg CARGO_FLAGS="--features kubernetes" .
@echo "✅ K8s 镜像构建完成!"
@echo ""
@echo "📤 推送镜像到阿里云仓库..."
@docker tag $(IMAGE) $(K8S_IMAGE_REGISTRY)
@skopeo copy docker-daemon:$(K8S_IMAGE_REGISTRY) docker://$(K8S_IMAGE_REGISTRY)
@echo "✅ 镜像已推送到 $(K8S_IMAGE_REGISTRY)"
@$(MAKE) -s --no-print-directory _k8s-import-image
@$(MAKE) -s --no-print-directory _k8s-rollout-restart
@echo ""
@echo "💡 下一步: make dev-up-k8s 启动 K8s 开发模式 (镜像已就位)"
# 内部 target: 把刚构建的镜像直接导入本地 k3s containerd, 跳过 registry 网络往返
# 使用 docker save | k3s ctr image import, 完全离线
_k8s-import-image:
@if [ "$(SKIP_K3S_IMPORT)" = "1" ]; then \
echo ""; echo "⏭ 跳过 k3s 本地 import (SKIP_K3S_IMPORT=1)"; exit 0; \
fi
@if ! command -v k3s >/dev/null 2>&1; then \
echo ""; echo "⚠️ 未检测到 k3s (本机非 k3s 节点), 跳过本地 import"; \
echo " 远程 registry 已更新, 其他集群仍可正常拉取"; exit 0; \
fi
@echo ""
@echo "📥 导入镜像到本地 k3s containerd (跳过 registry 网络往返)..."
@echo " 方式: docker save | k3s ctr image import"
@docker save $(K8S_IMAGE_REGISTRY) | $(K3S_CTR) -n $(K3S_NAMESPACE) image import - >/dev/null
@echo "✅ 镜像已 import 到本地 k3s 节点 ($(K3S_NAMESPACE) namespace)"
# 内部 target: 重启已部署的 rcoder Deployment 使其拉取/使用新 image
# imagePullPolicy 是 IfNotPresent, 节点上已经是新 image, restart 后即生效
_k8s-rollout-restart:
@if [ "$(SKIP_ROLLOUT_RESTART)" = "1" ]; then \
echo "⏭ 跳过 rollout restart (SKIP_ROLLOUT_RESTART=1)"; exit 0; \
fi
@if ! command -v kubectl >/dev/null 2>&1; then exit 0; fi
@echo ""
@echo "🔄 重启已部署的 rcoder Deployment (使新镜像生效)..."
@for ns in $(K8S_NAMESPACE_DEV) $(K8S_NAMESPACE_PROD); do \
if kubectl get deploy rcoder -n $$ns >/dev/null 2>&1; then \
kubectl rollout restart deploy/rcoder -n $$ns >/dev/null && \
echo "$$ns: rollout restart 已触发"; \
else \
echo " - $$ns: deploy 不存在, 跳过"; \
fi; \
done
# ============================================================================
# 开发模式快捷命令 (默认指向 dev overlay)
# ============================================================================
# 启动 K8s 开发模式(使用 Kustomize dev overlay
dev-up-k8s:
@echo "☸️ 启动 K8s 开发模式 (overlays/dev -> $(K8S_NAMESPACE_DEV))..."
@echo ""
@echo "[1/4] 检查 JuiceFS CSI Driver..."
@kubectl rollout status daemonset/juicefs-csi-driver-node -n kube-system --timeout=120s 2>/dev/null || \
(echo "⚠️ JuiceFS CSI 未部署,请先执行: helm install juicefs-csi-driver juicefs/juicefs-csi-driver --namespace kube-system" && exit 1)
@echo ""
@echo "[2/4] 部署 dev overlay..."
@kubectl apply -k $(KUSTOMIZE_DIR)/overlays/dev
@echo ""
@echo "[3/4] 等待存储层就绪..."
@kubectl wait --for=condition=ready pod -l app=postgresql -n $(K8S_NAMESPACE_DEV) --timeout=180s 2>/dev/null || echo "⚠️ PostgreSQL 等待超时,继续..."
@kubectl wait --for=condition=ready pod -l app=minio -n $(K8S_NAMESPACE_DEV) --timeout=180s 2>/dev/null || echo "⚠️ MinIO 等待超时,继续..."
@kubectl wait --for=condition=complete job/minio-init -n $(K8S_NAMESPACE_DEV) --timeout=120s 2>/dev/null || echo "⚠️ MinIO 初始化等待超时,继续..."
@echo ""
@echo "[4/4] 等待 RCoder 就绪..."
@kubectl rollout status deploy/rcoder -n $(K8S_NAMESPACE_DEV) --timeout=$(ROLLOUT_TIMEOUT)
@echo ""
@echo "📋 K8s 部署状态:"
@kubectl get pods -n $(K8S_NAMESPACE_DEV)
@echo ""
@kubectl get pvc -n $(K8S_NAMESPACE_DEV)
@echo ""
@kubectl get storageclass | grep juice || true
@echo ""
@echo "💡 查看日志: make dev-logs-k8s"
# 重启 K8s 开发模式(重新构建镜像+部署)
dev-restart-k8s: dev-build-k8s
@echo "☸️ 重启 K8s 开发模式..."
@kubectl apply -k $(KUSTOMIZE_DIR)/overlays/dev
@kubectl delete pods -n $(K8S_NAMESPACE_DEV) -l app=rcoder --ignore-not-found
@kubectl rollout status deploy/rcoder -n $(K8S_NAMESPACE_DEV) --timeout=$(ROLLOUT_TIMEOUT)
@echo "✅ K8s 部署已重启!"
@kubectl get pods -n $(K8S_NAMESPACE_DEV)
# 停止 K8s 开发模式
dev-down-k8s:
@echo "☸️ 停止 K8s 开发模式..."
@kubectl delete -k $(KUSTOMIZE_DIR)/overlays/dev --ignore-not-found
@echo "✅ K8s 开发栈已从集群移除"
# 查看 K8s 开发模式日志
dev-logs-k8s:
@echo "☸️ 查看 K8s 开发模式日志..."
@kubectl logs -n $(K8S_NAMESPACE_DEV) -l app=rcoder -f
# ============================================================================
# 多环境部署命令
# ============================================================================
# 部署开发环境
deploy-dev:
@echo "☸️ 部署开发环境..."
@kubectl apply -k $(KUSTOMIZE_DIR)/overlays/dev
@kubectl rollout status deploy/rcoder -n $(K8S_NAMESPACE_DEV) --timeout=$(ROLLOUT_TIMEOUT)
@echo "✅ 开发环境部署完成!"
# 部署生产环境
deploy-prod:
@echo "☸️ 部署生产环境..."
@kubectl apply -k $(KUSTOMIZE_DIR)/overlays/prod
@kubectl rollout status deploy/rcoder -n $(K8S_NAMESPACE_PROD) --timeout=$(ROLLOUT_TIMEOUT)
@echo "✅ 生产环境部署完成!"
# 清理指定环境
undeploy-dev:
@echo "☸️ 清理开发环境..."
@kubectl delete -k $(KUSTOMIZE_DIR)/overlays/dev --ignore-not-found
undeploy-prod:
@echo "☸️ 清理生产环境..."
@kubectl delete -k $(KUSTOMIZE_DIR)/overlays/prod --ignore-not-found
# 验证 Kustomize 配置(构建不部署)
kustomize-build:
@echo "☸️ 验证 Kustomize 配置..."
@echo "=== Base ==="
@kubectl kustomize $(KUSTOMIZE_DIR)/base >/dev/null && echo " ✓"
@echo "=== Dev Overlay ==="
@kubectl kustomize $(KUSTOMIZE_DIR)/overlays/dev >/dev/null && echo " ✓"
@echo "=== Prod Overlay ==="
@kubectl kustomize $(KUSTOMIZE_DIR)/overlays/prod >/dev/null && echo " ✓"
# ============================================================================
# 本地 K8s 测试 (OrbStack / k3d / kind)
# ============================================================================
K8S_LOCAL_NAMESPACE := rcoder-local
K8S_LOCAL_IMAGE ?= rcoder-local:latest
K8S_LOCAL_AGENT_IMAGE ?= rcoder-agent-runner-local:latest
# 构建本地 K8s 测试镜像(不推送到远程仓库)
dev-build-k8s-local:
@echo "🔨 构建本地 K8s 测试镜像..."
@echo "📦 [1/2] 构建 rcoder (features=kubernetes)..."
@docker build -f docker/rcoder-master/Dockerfile -t $(K8S_LOCAL_IMAGE) --build-arg CARGO_FLAGS="--features kubernetes" .
@echo "📦 [2/2] 构建 agent-runner..."
@echo " 步骤 1: 在 Docker 中编译 agent_runner 二进制..."
@docker build -f docker/rcoder-agent-runner/Dockerfile.build -t rcoder-agent-runner-build-local .
@mkdir -p docker/rcoder-agent-runner/bin
@docker create --name build-container-local rcoder-agent-runner-build-local 2>/dev/null || true
@docker cp build-container-local:/build/target/release/agent_runner docker/rcoder-agent-runner/bin/agent_runner
@docker rm build-container-local
@docker rmi rcoder-agent-runner-build-local
@echo " 步骤 2: 构建最终 agent-runner 镜像..."
@cd docker/rcoder-agent-runner && docker build -f Dockerfile --build-arg INSTALL_EBPF_TOOLS=false -t $(K8S_LOCAL_AGENT_IMAGE) .
@echo "✅ 本地镜像构建完成!"
@docker images | grep -E "rcoder-local|rcoder-agent-runner-local"
# 启动本地 K8s 测试OrbStack 自动共享 Docker 镜像,无需手动 import
dev-up-k8s-local:
@echo "☸️ 启动本地 K8s 测试 ($(K8S_LOCAL_NAMESPACE))..."
@kubectl apply -k $(KUSTOMIZE_DIR)/overlays/local
@echo ""
@echo "🔄 重启 Pod 使新镜像生效..."
@kubectl delete pods -n $(K8S_LOCAL_NAMESPACE) -l app=rcoder --ignore-not-found
@echo ""
@echo "⏳ 等待 RCoder 就绪..."
@kubectl rollout status deploy/rcoder -n $(K8S_LOCAL_NAMESPACE) --timeout=$(ROLLOUT_TIMEOUT)
@echo ""
@echo "📋 部署状态:"
@kubectl get pods -n $(K8S_LOCAL_NAMESPACE)
@kubectl get pvc -n $(K8S_LOCAL_NAMESPACE)
@echo ""
@echo "💡 访问: http://localhost:30087"
@echo "💡 日志: make dev-logs-k8s-local"
# 重启本地 K8s 测试
dev-restart-k8s-local:
@echo "☸️ 重启本地 K8s 测试..."
@kubectl delete pods -n $(K8S_LOCAL_NAMESPACE) -l app=rcoder --ignore-not-found
@kubectl rollout status deploy/rcoder -n $(K8S_LOCAL_NAMESPACE) --timeout=$(ROLLOUT_TIMEOUT)
@echo "✅ 已重启!"
# 停止本地 K8s 测试
dev-down-k8s-local:
@echo "☸️ 停止本地 K8s 测试..."
@kubectl delete -k $(KUSTOMIZE_DIR)/overlays/local --ignore-not-found
@echo "✅ 已清理"
# 查看本地 K8s 测试日志
dev-logs-k8s-local:
@kubectl logs -n $(K8S_LOCAL_NAMESPACE) -l app=rcoder -f --tail=100
# 一键构建+部署(本地 K8s 测试)
dev-local-k8s: dev-build-k8s-local dev-up-k8s-local
@echo "🎉 本地 K8s 测试环境已就绪!"