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

RCoder K8s 部署配置

本目录提供 三种部署方式,按场景选择:

场景 方式 入口
日常开发 / 在线环境 Kustomize deploy-dev.sh / deploy-prod.sh
参数化部署 / 对外交付 Helm (双栈并存) helm install ... k8s/helm/rcoder
政企客户 / 完全断网 离线 Bundle make k8s-offline-bundleinstall.sh

另外还有可选的 本地镜像加速register2/),面向多节点 k3s / 频繁构建场景,详见下文"本地镜像加速"一节。

目录结构

k8s/
├── manifests/                    # Kustomize manifests (日常开发 + 在线部署)
│   ├── base/                    # 基础配置 (不可直接部署, 需走 overlay)
│   │   ├── storage/             # postgresql / minio / juicefs-init / juicefs-pvc
│   │   └── rcoder/              # rcoder Deployment/Service/NetworkPolicy/PDB/SA+ClusterRole
│   └── overlays/
│       ├── dev/                 # 开发环境 (nuwax-rcoder-dev, NodePort 30080)
│       └── prod/                # 生产环境 (nuwax-rcoder-prod, NodePort 30081)
│
├── helm/                         # Helm chart (对外交付 + 离线部署源)
│   └── rcoder/
│       ├── Chart.yaml
│       ├── values.yaml           # 默认值 (共享)
│       ├── values-dev.yaml       # dev 覆盖
│       ├── values-prod.yaml      # prod 覆盖
│       ├── values-offline.yaml   # 离线 registry 覆盖
│       └── templates/            # K8s 模板
│
├── offline/                      # 离线 bundle 素材
│   ├── images.txt                # 镜像清单 (单一数据源)
│   ├── install.sh                # 离线安装脚本 (direct / registry 双模式)
│   ├── rewrite-registry.sh       # 重打 tag + 推送私有 registry
│   └── README.md                 # 交付给政企客户的部署手册
│
├── register2/                    # 本地私有镜像仓库 (docker compose)
│   ├── docker-compose.yml        # registry:2 容器 + 数据卷
│   └── README.md                 # 作 k3s mirror / 离线 push 目标的用法
│
├── deploy-dev.sh                 # [在线] Kustomize 开发环境一键部署
├── deploy-prod.sh                # [在线] Kustomize 生产环境一键部署 (含占位符密码守卫)
├── undeploy.sh                   # [在线] 清理部署 (ENV=dev|prod)
│
├── scripts/                      # 辅助脚本
│   ├── deploy-juicefs.sh         # 仅部署存储层 (ENV=dev|prod)
│   ├── test-chat.sh              # 功能冒烟测试 (NAMESPACE 可覆盖)
│   ├── install-k3s-registry-mirrors-cn.sh  # K3s 节点镜像加速配置 (支持 REGISTRY_HOST)
│   └── k3s-registries-cn.yaml    # 镜像加速配置模板
│
└── README.md

dev 和 prod 可以并存于同一个集群:

  • 集群级资源StorageClass / ClusterRoleBinding命名独立juicefs-sc-dev / juicefs-sc-prodrcoder-pods-crb-dev / rcoder-pods-crb-prod
  • NodePort 错开dev=30080 / prod=30081
  • ClusterRole rcoder-pods-clusterrole 是唯一共享的集群级资源(两个 overlay 写入完全一致,幂等)

快速开始

开发环境

# 首次完整部署(含 Longhorn、JuiceFS CSI、open-iscsi 检查)
./k8s/deploy-dev.sh

# 常用
kubectl apply -k k8s/manifests/overlays/dev     # 部署/更新
kubectl delete -k k8s/manifests/overlays/dev    # 删除
kubectl get all -n nuwax-rcoder-dev             # 查看状态
k8s/scripts/test-chat.sh                        # 冒烟测试

生产环境

重要:首次部署前必须替换 k8s/manifests/overlays/prod/credentials.yamljuicefs-secret.yaml 里的 CHANGE-ME-BEFORE-DEPLOY 占位符;deploy-prod.sh 有守卫检查,发现占位符会拒绝部署。若使用 SealedSecret / ExternalSecret 在集群外注入,设置 FORCE_PROD_DEPLOY=1 跳过。

# 首次完整部署
./k8s/deploy-prod.sh

# 跳过占位符检查(仅当通过外部密钥注入方案时)
FORCE_PROD_DEPLOY=1 ./k8s/deploy-prod.sh

# 常用
kubectl apply -k k8s/manifests/overlays/prod
kubectl get all -n nuwax-rcoder-prod
NAMESPACE=nuwax-rcoder-prod k8s/scripts/test-chat.sh

清理

ENV=dev  ./k8s/undeploy.sh      # 清理 dev
ENV=prod ./k8s/undeploy.sh      # 清理 prod

Makefile 快捷命令

在项目根目录执行:

# 镜像
make dev-build-k8s             # 构建并推送 K8s 镜像 (含 k3s 本地 import + rollout restart)

# 部署/清理(默认走 overlay
make deploy-dev                # kubectl apply -k overlays/dev
make deploy-prod               # kubectl apply -k overlays/prod
make undeploy-dev              # 清理 dev
make undeploy-prod             # 清理 prod

# 开发闭环
make dev-up-k8s                # 部署 dev
make dev-restart-k8s           # 重新构建镜像 + 重部署 dev
make dev-down-k8s              # 清理 dev
make dev-logs-k8s              # 跟随 rcoder 日志

# 本地验证(不部署)
make kustomize-build           # 分别 build base / dev / prod

# 离线部署 (政企内网)
make k8s-offline-bundle        # 打包完整离线包 (images + helm + manifests)
make k8s-offline-import BUNDLE=<tgz> INSTALL_ARGS="--mode=direct --env=dev"
make k8s-offline-images-list   # 打印所有离线依赖镜像清单
make k8s-offline-clean         # 清理构建产物

Helm 部署 (参数化 / 对外交付)

Helm chart 与 Kustomize 双栈并存、长期维护。修改 manifests/base/*.yaml 时请同步更新 helm/rcoder/templates/* 对应模板。

# dev (本地或在线环境)
helm install rcoder-dev k8s/helm/rcoder \
    --namespace nuwax-rcoder-dev --create-namespace \
    -f k8s/helm/rcoder/values-dev.yaml

# 同集群已有 Kustomize 部署的话, 加 --set rcoder.clusterRole.create=false
# (避免 Helm 尝试接管 Kustomize 已创建的 ClusterRole)
helm install rcoder-helm-test k8s/helm/rcoder \
    --namespace nuwax-rcoder-helm-test --create-namespace \
    -f k8s/helm/rcoder/values-dev.yaml \
    --set rcoder.service.nodePort=30082 \
    --set juicefs.storageClass.name=juicefs-sc-helm-test \
    --set rcoder.clusterRole.create=false

# prod (密码通过 --set 或 external secret 注入)
helm install rcoder-prod k8s/helm/rcoder \
    --namespace nuwax-rcoder-prod --create-namespace \
    -f k8s/helm/rcoder/values-prod.yaml \
    --set credentials.postgresql.password=<real> \
    --set credentials.minio.rootPassword=<real>

# 升级
helm upgrade rcoder-dev k8s/helm/rcoder -f k8s/helm/rcoder/values-dev.yaml

# 卸载
helm uninstall rcoder-dev --namespace nuwax-rcoder-dev

渲染对比 (开发调试)

helm template rcoder-dev k8s/helm/rcoder -f k8s/helm/rcoder/values-dev.yaml > /tmp/helm-dev.yaml
kubectl kustomize k8s/manifests/overlays/dev > /tmp/kustomize-dev.yaml
diff <(grep -E 'image:|nodePort:|storageClassName:' /tmp/helm-dev.yaml | sort -u) \
     <(grep -E 'image:|nodePort:|storageClassName:' /tmp/kustomize-dev.yaml | sort -u)

集群级资源命名

Helm 为每个 release 自动生成独立的集群级资源名:

资源 dev release (rcoder-dev) prod release (rcoder-prod)
StorageClass juicefs-sc-dev (显式 override) juicefs-sc-prod (显式 override)
ClusterRoleBinding rcoder-dev-pods-crb (自动) rcoder-prod-pods-crb (自动)
ClusterRole rcoder-pods-clusterrole (共享, resource-policy: keep)

离线部署 (政企内网, 完全断网)

当客户内网无公网访问时,使用 Bundle 模式在有网的构建机打包所有镜像、helm charts、manifests产出单个 tar.gz;离线机器上解压运行 install.sh 完成部署。

构建 bundle (有网构建机)

# 拉取所有镜像 + 打包 helm charts + 下载 Longhorn/JuiceFS CSI manifest + 压缩
make k8s-offline-bundle

# 输出: dist/rcoder-offline-<version>-<arch>.tar.gz (约 1.7-2 GB, 共 27 个镜像)
ls -lh dist/rcoder-offline-*.tar.gz

# 查看镜像清单
make k8s-offline-images-list

离线机器部署

# 方式 1: 用 make 一键跑完
make k8s-offline-import BUNDLE=/path/to/rcoder-offline-xxx.tar.gz \
    INSTALL_ARGS="--mode=direct --env=dev"

# 方式 2: 手工解压 + 跑 install.sh
tar xzf rcoder-offline-xxx.tar.gz -C /opt/rcoder-offline
cd /opt/rcoder-offline
sudo bash install.sh --mode=direct --env=dev

两种导入模式

模式 镜像落盘方式 适用场景
--mode=direct ctr image import 到节点 containerd 单节点 / 小集群 / 无私有 registry
--mode=registry docker load + re-tag + push 多节点 / 已有 Harbor/Nexus / 客户自建 registry

详见 offline/README.md(客户交付文档)。


本地镜像加速(多节点 / 频繁构建场景)

当本地 k3s 有多个节点,或者你频繁 push 测试镜像又不想每次走公网时,启用 register2/ 作本地 registry mirror所有节点直接拉局域网镜像千兆

架构

  k3s/containerd (所有节点)
        │
        ├── (1) http://<你的机器>:5000  ← register2 (本目录, 私有推送)
        ├── (2) http://<你的机器>:5002  ← registry-cache (可选 pull-through)
        ├── (3) https://docker.m.daocloud.io / ...  ← 公网 cn mirror 回退
        └── (4) 默认源 (docker.io / registry.k8s.io) 兜底

containerd 按顺序尝试 endpoint命中200即返回失败404/超时)自动回退下一个。

启动本地 registry

cd k8s/register2
docker compose up -d
# 验证:
curl -s http://<你的机器>:5000/v2/_catalog

一键配置 k3s 节点

# 在每个 k3s 节点上执行 (REGISTRY_HOST 按实际填)
sudo REGISTRY_HOST=192.168.32.228:5000 \
    k8s/scripts/install-k3s-registry-mirrors-cn.sh

# 多个 registry 串联 (比如同时有 registry2 和 pull-through cache)
sudo REGISTRY_HOST=192.168.32.228:5000,192.168.32.228:5002 \
    k8s/scripts/install-k3s-registry-mirrors-cn.sh

脚本会:

  • 备份现有 /etc/rancher/k3s/registries.yaml
  • 写入包含本地 registry + 公网 cn mirror 回退的完整配置(含 registry.k8s.io/ghcr.io/quay.io 全套)
  • 自动加 "自指 mirror" + insecure_skip_verify 允许 crictl pull <host>/foo 走 plain HTTP
  • 自动 systemctl restart k3sk3s-agent
  • crictl pull docker.io/rancher/mirrored-pause:3.6 验证

本机 docker daemon 配置(允许 push 到 HTTP registry

sudo tee /etc/docker/daemon.json <<EOF
{
  "insecure-registries": ["192.168.32.228:5000"]
}
EOF
sudo systemctl restart docker

详见 register2/README.md

与离线 bundle 的联动

配好本地 registry 后,在本机就能测通 bundle 的 registry 模式

tar xzf dist/rcoder-offline-*.tar.gz -C /tmp/offline-test
cd /tmp/offline-test
docker load -i images/all-images.tar
bash rewrite-registry.sh \
    --registry 192.168.32.228:5000/rcoder \
    --thirdparty-registry 192.168.32.228:5000/thirdparty \
    --images-file images/images.txt
# 之后 helm install 时 k3s 自动从 192.168.32.228:5000 拉

存储架构

┌─────────────────────────────────────────────────────────────┐
│                     Kubernetes 集群                          │
│  ┌──────────────────────────────────────────────────────┐  │
│  │            JuiceFS CSI Driver (kube-system)           │  │
│  └──────────────────────────────────────────────────────┘  │
│                            ↓                                │
│  ┌────────────────┐    ┌────────────────┐                   │
│  │ rcoder 主服务   │    │ Agent Runner   │                   │
│  │ (Deployment)   │    │ (动态创建 Pod) │                    │
│  └────────┬───────┘    └────────┬───────┘                   │
│           └──────────┬───────────┘                          │
│                      ↓                                      │
│              ┌──────────────┐                               │
│              │ JuiceFS 卷   │  ← ReadWriteMany 共享         │
│              └───────┬──────┘                               │
└──────────────────────┼──────────────────────────────────────┘
                       ↓
┌───────────────────────────────────────────────────────────────┐
│  MinIO (S3)    ← JuiceFS 数据存储per-namespace             │
│  PostgreSQL    ← JuiceFS 元数据存储per-namespace           │
└───────────────────────────────────────────────────────────────┘

每个 namespace 独立拥有 PostgreSQL 和 MinIO 实例metadata 和 object 存储互不干扰。


环境要求

  • Kubernetes 1.14+(本仓库在 K3s 1.34.x 上测试)
  • kubectl 已配置 kubeconfig
  • helm 3.x用于首次安装 JuiceFS CSI Driver + Helm 部署路径)
  • Longhorn 存储(为 PostgreSQL / MinIO 提供 PVdeploy-*.sh 会自动安装)
  • open-iscsiLonghorn 依赖;deploy-*.sh 会自动安装)
  • docker(仅在有网构建机 make k8s-offline-bundle 或本地 push 到 register2 时需要)

国内节点建议先配置 k3s 镜像加速(纯公网 cn mirror 版):

sudo k8s/scripts/install-k3s-registry-mirrors-cn.sh

有本地 registry 时用 REGISTRY_HOST=...(见 "本地镜像加速" 一节)。


故障排查

# Pod 状态
kubectl get pods -n nuwax-rcoder-dev   # 或 -prod / -helm-test / <your-ns>

# 事件
kubectl get events -n nuwax-rcoder-dev --sort-by='.lastTimestamp'

# RCoder 日志
kubectl logs -n nuwax-rcoder-dev -l app=rcoder --tail=200 -f

# PVC 绑定情况
kubectl get pvc -n nuwax-rcoder-dev
kubectl describe pvc rcoder-workspace -n nuwax-rcoder-dev

# StorageClass
kubectl get sc

# 镜像加速是否生效 (与 kubelet 同链路验证, 不要用 k3s ctr images pull)
sudo crictl --runtime-endpoint unix:///run/k3s/containerd/containerd.sock \
    pull docker.io/rancher/mirrored-pause:3.6

# 本地 registry 命中情况
curl -s http://192.168.32.228:5000/v2/_catalog
curl -s http://192.168.32.228:5002/v2/_catalog   # pull-through 缓存

历史说明

此前版本曾提供 k8s/helm/rcoder/ Helm chart 作为另一条部署路径;2025 年后改为 Kustomize + Helm 双栈并存

  • Kustomize 用于开发和已有部署,保持轻量;
  • Helm 用于参数化对外交付和离线 bundle
  • 两者共享同一份 K8s 资源定义(修改时需同步)。