飞牛 NAS Docker、Jenkins 与 k3d/K8s 一体化技术方案

说明:本文为脱敏版技术方案。项目名、仓库地址、端口、目录、域名、内网地址、主机名和密钥路径均使用通用占位符,落地时请替换为自己的实际环境。

1. 方案摘要

本方案面向小型私有化部署场景,目标是在飞牛 NAS 上把 Docker、Jenkins、前端静态发布和后端 API 容器发布整合成一套可持续迭代的标准流程。

  • 飞牛 NAS 作为内网计算与数据承载节点。
  • Docker 承载 Jenkins Controller、Jenkins Agent、本地 Registry、Nginx、数据库、对象存储等基础容器。
  • 后端 API 迁入 NAS 本机的 k3d/K3s 集群,由 Jenkins 构建镜像并滚动发布。
  • 前端 Web 与 Playground 暂时继续走 Nginx 静态目录发布。
  • 公网入口由云服务器中转节点承接,家庭 NAS 不直接暴露 80/443。

这是一套“先稳定、再演进”的方案:先把后端 API 标准化接入 K8s,让发布、回滚、密钥注入、运行状态观测具备统一入口;后续再逐步把前端、Ingress、监控和备份纳入同一套平台能力。

2. 建设目标

2.1 业务目标

  • 形成后端 API 从代码提交到 NAS K8s 上线的标准流水线。
  • 保持现有公网访问方式基本不变,降低切换风险。
  • 保留前端现有 Nginx 静态发布模式,避免一次性迁移范围过大。
  • 让发布失败可回滚、运行状态可排查、生产环境变量不进入 Git。
  • 让未来新增服务可以复用同一套命名、目录、端口、镜像和 Jenkins 流水线规范。

2.2 技术目标

  • Jenkins 只负责 CI/CD 编排,不直接保存真实生产配置。
  • Jenkins Agent 具备 Node.js、pnpm、Docker CLI、kubectl 等构建发布能力。
  • Docker 本地 Registry 固定在 NAS,减少发布时对公网镜像仓库的依赖。
  • K8s 运行态使用 Deployment + Service,默认支持滚动更新和 rollout undo
  • 生产环境变量从 Agent 私有文件生成 K8s Secret,做到 Git 与真实配置隔离。
  • 所有一次性初始化动作脚本化,减少手工步骤漂移。

3. 总体架构

整体链路可以拆成四层:公网入口层、NAS Docker 控制层、NAS K8s 运行层和应用层。

开发者 / Git push
  -> Git 仓库 [GIT_REPO]
  -> Jenkins Controller
  -> Jenkins Agent
  -> pnpm install / lint / test / build
  -> docker build 业务镜像
  -> NAS 本地 Registry
  -> kubectl apply / set image / rollout status
  -> k3d/K3s 集群
  -> 后端 API Pod
  -> NAS API 端口

前端 Web / Playground
  -> Jenkins 构建静态产物
  -> Nginx 静态目录
  -> NAS 前端端口

公网访问
  -> 云服务器中转节点
  -> VPN 或内网转发链路
  -> NAS 服务端口

3.1 分层职责

层级承载对象职责
公网入口层云服务器中转节点、反向代理、VPN 隧道公网 TLS、域名入口、转发到 NAS
NAS Docker 控制层Jenkins、Agent、Registry、Nginx、数据库、对象存储构建、发布、基础服务和静态资源
NAS K8s 运行层k3d/K3s后端 API 工作负载、滚动更新、回滚
应用层API、Web、Playground业务接口、前台展示、可视化编辑器

3.2 为什么采用 k3d/K3s

  • NAS 已经以 Docker 为主要运行环境,k3d 可以直接复用 Docker,不需要额外虚拟机。
  • K3s 轻量,适合家庭 NAS 或小型私有化部署。
  • k3d 可以把集群 API、NodePort、Registry 标准化在 Docker 网络内。
  • 对现有 Docker 服务影响较小,可以先迁移后端 API,后续再扩展其他服务。

4. 命名与资源规范

公开方案中使用通用命名。实际落地时建议固定命名,避免 Jenkins 参数、K8s manifest、Nginx 配置和运维脚本之间出现漂移。

对象示例命名
Jenkins Agent 节点app-node-agent
Jenkins Agent 镜像app-jenkins-agent:node22
k3d 集群app-nas
K8s namespaceapp-prod
本地 Registry[REGISTRY_HOST]:[REGISTRY_PORT]
API 镜像[REGISTRY_HOST]:[REGISTRY_PORT]/backend-api:<tag>
API Deploymentbackend-api
API env Secretbackend-api-env

5. 端口与目录规范

5.1 端口规范

服务NAS 端口容器/K8s 端口说明
API[API_HOST_PORT][API_CONTAINER_PORT]由 k3d loadbalancer 映射到 NodePort
API NodePort[API_NODE_PORT][API_CONTAINER_PORT]K8s Service NodePort
Web[WEB_HOST_PORT][WEB_CONTAINER_PORT]Nginx 静态服务
Playground[PLAYGROUND_HOST_PORT][PLAYGROUND_CONTAINER_PORT]Nginx 静态服务

5.2 目录规范

路径用途
[DATA_ROOT]/app-k8sK8s 标准化根目录
[DATA_ROOT]/app-k8s/registry本地 Registry 数据
[DATA_ROOT]/app-k8s/kubeconfighost 与 Agent kubeconfig
[AGENT_WORKDIR]/env/backend-api/.env.productionAgent 内 API 生产环境变量
[AGENT_WORKDIR]/kubeconfig/app-nas.jenkins.yamlAgent 内 kubeconfig

6. Jenkins 流水线设计

6.1 发布目标

DEPLOY_TARGET行为
k8s标准模式,构建镜像、推送本地 Registry、滚动更新 K8s
docker兼容旧模式,构建镜像后用 docker run 替换旧容器
none只做 CI,不构建或发布镜像
标准生产发布参数:

DEPLOY_TARGET=k8s
BUILD_DOCKER_IMAGE=true
PUSH_DOCKER_IMAGE=true
DOCKER_REGISTRY=[REGISTRY_HOST]:[REGISTRY_PORT]
IMAGE_NAME=backend-api
CONTAINER_ENV_FILE=[AGENT_WORKDIR]/env/backend-api/.env.production
KUBE_CONFIG_FILE=[AGENT_WORKDIR]/kubeconfig/app-nas.jenkins.yaml
K8S_MANIFEST_FILE=k8s/prod/api.yaml
K8S_NAMESPACE=app-prod
K8S_DEPLOYMENT=backend-api
K8S_CONTAINER=api
K8S_ENV_SECRET=backend-api-env

6.2 流水线阶段

Checkout
  -> Prepare
  -> Install
  -> Lint
  -> Test
  -> Build
  -> Docker Build
  -> Docker Push
  -> K8s Deploy
  -> Archive Artifacts

6.3 镜像标签策略

默认镜像标签建议使用分支名加 Jenkins 构建号,便于排查和回滚:

[REGISTRY_HOST]:[REGISTRY_PORT]/backend-api:main-28
[REGISTRY_HOST]:[REGISTRY_PORT]/backend-api:latest
  • 分支名需要经过 Docker tag 兼容化处理。
  • PR 构建不发布到 K8s。
  • main、master、release/* 默认允许发布。
  • latest 只作为 manifest 默认镜像和人工排查辅助,真实发布以构建 tag 为准。

7. K8s 运行态设计

7.1 Deployment

replicas: 1
strategy: RollingUpdate
maxSurge: 1
maxUnavailable: 0
revisionHistoryLimit: 5

单机 NAS 场景默认使用单副本。未来如果 API 无状态化、数据库连接和上传存储都稳定后,可以扩展到两个或更多副本。

7.2 Service

type: NodePort
port: [API_CONTAINER_PORT]
targetPort: [API_CONTAINER_PORT]
nodePort: [API_NODE_PORT]

k3d 创建集群时将 NAS 宿主机端口映射到 NodePort。这样外部仍然访问原 API 端口,不需要修改云服务器侧转发规则。

7.3 探针与资源限制

当前可以先使用 TCP 探针,保证容器端口已监听。后续建议新增 /health 之类的 HTTP 健康检查接口,再把探针改为 HTTP GET。

readinessProbe: tcpSocket [API_CONTAINER_PORT]
livenessProbe: tcpSocket [API_CONTAINER_PORT]

requests:
  cpu: 100m
  memory: 256Mi
limits:
  cpu: 1000m
  memory: 768Mi

8. 配置与密钥设计

仓库只提交 .env.example。真实生产配置放在 Jenkins Agent 私有路径中,并通过流水线生成 K8s Secret。

[AGENT_WORKDIR]/env/backend-api/.env.production

kubectl -n app-prod create secret generic backend-api-env \
  --from-env-file=[AGENT_WORKDIR]/env/backend-api/.env.production \
  --dry-run=client -o yaml | kubectl apply -f -

这种方式可以让环境变量变更不进入 Git,同时 Secret 与 Deployment 更新在同一条流水线里完成。需要注意的是,Kubernetes 原生 Secret 默认只是 base64 编码,不等于加密。单机可信环境短期可接受,长期建议接入 SOPS、SealedSecret 或外部 Secret 管理。

9. 初始化与切换方案

9.1 安全初始化

.\ci\fnos-k8s\run-remote-bootstrap.ps1
  • 安装或确认 k3d。
  • 安装或确认 kubectl。
  • 创建标准数据目录。
  • 创建本地 Registry。
  • 如果 API 端口已被旧容器占用,则停止在集群创建前。

9.2 正式切换

.\ci\fnos-k8s\run-remote-bootstrap.ps1 -Cutover
  1. 停止旧后端 API Docker 容器。
  2. 创建 k3d 集群,并映射 NAS API 端口到 K8s NodePort。
  3. 创建生产 namespace。
  4. 复制 kubeconfig 到 Jenkins Agent。
  5. 从 Agent env 文件创建 K8s Secret。
  6. 由 Jenkins 或手动 kubectl 部署 API。

9.3 网络问题处理

NAS 拉取 GitHub、Docker Hub、Kubernetes 官方二进制可能较慢。建议把基础二进制和关键镜像提前缓存,业务镜像优先推送到 NAS 本地 Registry。

  • k3d 和 kubectl 可以由本机下载后通过 scp 上传到 NAS。
  • K3s sandbox 镜像建议在 bootstrap 中主动拉取并导入集群。
  • 业务镜像发布时推送本地 Registry,避免每次发布都依赖公网镜像仓库。

10. 日常发布 SOP

  1. 开发者提交代码到发布分支。
  2. Jenkins 多分支流水线拉取最新 Jenkinsfile。
  3. Jenkins 执行 install、lint、test、build。
  4. Jenkins 构建业务镜像并推送 NAS 本地 Registry。
  5. Jenkins 从 Agent 私有 env 文件重建 K8s Secret。
  6. Jenkins 更新 Deployment 镜像并等待 rollout 成功。
  7. 运维人员验证 API、前端入口和核心业务接口。
常用验证:

kubectl --kubeconfig [HOST_KUBECONFIG] -n app-prod get deploy,pod,svc -o wide
curl -sS -i http://127.0.0.1:[API_HOST_PORT]/

Agent 内验证:

docker exec app-node-agent sh -lc \
  'kubectl --kubeconfig [AGENT_KUBECONFIG] -n app-prod get deploy,pod,svc'

11. 回滚方案

11.1 K8s 标准回滚

kubectl --kubeconfig [HOST_KUBECONFIG] \
  -n app-prod rollout history deployment/backend-api

kubectl --kubeconfig [HOST_KUBECONFIG] \
  -n app-prod rollout undo deployment/backend-api

kubectl --kubeconfig [HOST_KUBECONFIG] \
  -n app-prod rollout status deployment/backend-api --timeout=180s

11.2 指定镜像回滚

kubectl --kubeconfig [HOST_KUBECONFIG] \
  -n app-prod set image deployment/backend-api \
  api=[REGISTRY_HOST]:[REGISTRY_PORT]/backend-api:[TAG]

11.3 退回旧 Docker 模式

仅在 K8s 集群不可用且短期无法恢复时使用。退回 Docker 模式需要先释放 NAS API 端口,再用旧 Docker 参数启动后端容器。该方式会绕开 K8s 的 Deployment 回滚能力,只建议作为应急方案。

12. 运维与排障

查看服务状态:
kubectl --kubeconfig [HOST_KUBECONFIG] -n app-prod get all
docker ps --format '{{.Names}} {{.Status}} {{.Ports}}'

查看 API 日志:
kubectl --kubeconfig [HOST_KUBECONFIG] \
  -n app-prod logs -l app=backend-api --tail=200

查看事件:
kubectl --kubeconfig [HOST_KUBECONFIG] \
  -n app-prod get events --sort-by=.lastTimestamp
问题现象处理
Jenkins 参数缓存旧值Registry 参数为空导致发布失败Jenkinsfile 运行时 fallback 到本地 Registry
Agent 缺少 kubectl部署阶段找不到 kubectl重建 Agent 镜像或把 kubectl 注入当前容器
sandbox 镜像拉取失败Pod 卡在 ContainerCreating提前拉取并导入 K3s sandbox 镜像
Secret 缺失Pod 启动失败或 env 不完整确认 Agent env 文件存在后重跑 Jenkins
默认镜像不可拉ImagePullBackOff确保 latest 或目标 tag 已推送到本地 Registry

13. 安全边界

  • 家庭 NAS 不直接暴露 80/443。
  • 公网入口由云服务器中转节点承接,NAS 通过内网隧道或转发链路提供服务。
  • Jenkins Agent 通过 Docker socket 控制 NAS Docker,仅放在可信内网和可信 Jenkins 任务中使用。
  • 真实生产 env 不进入 Git。
  • kubeconfig 只放在 NAS 和 Agent 私有路径。
风险说明当前策略后续优化
Docker socket 挂载Agent 拥有 NAS Docker 控制权仅用于可信内网构建发布拆出专用构建节点或 rootless buildkit
K8s Secret 非加密原生 Secret 默认不是强加密单机可信环境短期接受引入 SOPS 或 SealedSecret
Registry 无鉴权本地 Registry 主要供 NAS 与 k3d 使用限制在本机和 Docker 网络增加 registry auth 或网络隔离
单机集群NAS 故障会影响服务通过备份和冷恢复降低风险建立异地备份或备用节点

14. 备份与恢复建议

对象路径或来源
Registry 数据[DATA_ROOT]/app-k8s/registry
kubeconfig[DATA_ROOT]/app-k8s/kubeconfig
生产 env[AGENT_WORKDIR]/env
Jenkins 配置Jenkins Controller volume
数据库数据数据库 volume
对象存储数据对象存储 volume
  1. 恢复 Docker、Jenkins、Agent、Registry。
  2. 恢复标准 K8s 数据目录。
  3. 执行 bootstrap 脚本重新创建或修复 k3d 集群。
  4. 用本地 Registry 中的镜像恢复 API Deployment。
  5. 验证 API、Web、Playground 三类入口。

15. 后续演进路线

15.1 巩固后端 K8s 发布

  • 给后端新增 HTTP 健康检查接口。
  • 将 K8s 探针从 TCP 改为 HTTP。
  • 给 Jenkins 增加发布后 smoke test。
  • 定期清理本地 Registry 旧镜像。
  • 给 bootstrap 增加更清晰的日志和幂等检查。

15.2 前端、Ingress 与观测

  • Web 和 Playground 继续保留 Nginx 静态部署,发布产物纳入版本化 release 目录。
  • 评估是否将 Nginx 也迁入 K8s。
  • 引入 Traefik 或 Nginx Ingress,统一管理 API、Web、Playground。
  • 增加基础监控:Pod 状态、重启次数、磁盘、内存、Registry 空间。
  • 用 SOPS 或 SealedSecret 管理 K8s Secret。

16. 验收标准

验收项标准
Jenkins 构建发布分支可完成 lint/test/build/docker/k8s deploy
K8s 运行后端 API Deployment 为 1/1
端口访问NAS API 端口可访问到后端 API
回滚能力rollout history 可看到发布记录,rollout undo 可执行
配置隔离真实生产 env 不进入 Git
Agent 能力Agent 内可执行 node、pnpm、docker、kubectl
本地 Registry可 push/pull API 镜像
文档完整性SOP、技术方案、bootstrap 脚本均在仓库内

17. 核心命令速查

查看集群:
kubectl --kubeconfig [HOST_KUBECONFIG] get nodes

查看 API:
kubectl --kubeconfig [HOST_KUBECONFIG] -n app-prod get deploy,pod,svc -o wide

查看日志:
kubectl --kubeconfig [HOST_KUBECONFIG] -n app-prod logs -l app=backend-api --tail=200

手动部署指定镜像:
kubectl --kubeconfig [HOST_KUBECONFIG] -n app-prod \
  set image deployment/backend-api \
  api=[REGISTRY_HOST]:[REGISTRY_PORT]/backend-api:[TAG]

回滚:
kubectl --kubeconfig [HOST_KUBECONFIG] -n app-prod \
  rollout undo deployment/backend-api

这套方案适合以 NAS 为核心的小型私有化部署。它不是为了把所有组件一次性“云原生化”,而是先把最容易产生发布风险的后端 API 纳入 K8s 标准发布链路,再逐步扩展到前端、Ingress、监控、备份和密钥治理。这样既保留了 Docker 在 NAS 上的简单直接,也获得了 K8s 在发布、回滚和运行态管理上的稳定收益。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇