一个最小可运行的演示。默认走 local-k3s(纯本地、无 registry):本机 docker build → 平台自动 kubectl set-image 滚动更新,全程在 UI 里点 Build / Pipeline 即可,不需要手动敲 kubectl 或 make。
examples/hello-cicd/
├── main.go # 零依赖 Go HTTP 服务(读 PORT / APP_VERSION 环境变量)
├── go.mod # 独立 module,不干扰主工程
├── Dockerfile # 多阶段构建(golang:1.22 → alpine)
├── .dockerignore
├── k8s/deployment.yaml # Deployment + Service(imagePullPolicy: IfNotPresent,占位 hello-cicd:local)
└── project.json # 交给 cicdkit 的项目定义(snake_case,method=local-k3s)
scripts/
└── import-to-k3s.sh # 备用逃生舱:手动把平台最新本地镜像导入 k3s containerd
- 本机
docker在跑(构建镜像)、kubectl能连上 k3s(平台用kubectl --kubeconfig <...>操作集群)。 deploy.kubeconfig留空时读取服务启动时的KUBECONFIG/ 默认~/.kube/config。OrbStack 用户无需任何设置——默认 contextorbstack就在~/.kube/config里。- 关键:镜像对集群可见。两种方式(平台按
deploy.k3s_import_cmd决定):- OrbStack:docker 构建的镜像会被 Kubernetes 自动共享,无需导入。示例
k3s_import_cmd留空即可。 - 纯 k3s(非 OrbStack):docker 与 k3s 的 containerd 不互通,需把
k3s_import_cmd设为"k3s ctr images import -"(或带sudo),平台会在每次部署时docker save | k3s ctr import。
- OrbStack:docker 构建的镜像会被 Kubernetes 自动共享,无需导入。示例
make dev # 后端 :8080 + 前端 :5173
make example # 把 project.json 导入运行中的服务
# 或手动 POST:
curl -X POST http://localhost:8080/api/projects -H 'Content-Type: application/json' \
--data-binary @examples/hello-cicd/project.json浏览器打开 http://localhost:8080 看到 hello-cicd 卡片。
- 点卡片上的 Build → 平台在本机
docker build出hello-cicd:<时间戳>镜像(不推送任何仓库)。 - 点 Pipeline(或 Deploy)→ 平台按
local-k3s执行:- 若
k3s_import_cmd非空,先把镜像docker save | <导入命令>导入 k3s(OrbStack 留空则跳过); - 若目标 Deployment 不存在且配了
manifest_path,先kubectl apply -f <清单>建好资源; kubectl set-image deployment/hello-cicd hello-cicd=hello-cicd:<时间戳> -n default --wait --timeout 120s滚动更新。
- 若
也就是说首次部署也无需手动 apply、无需手动导入——UI 点一下就闭环。 点开运行记录里的日志可实时看到这几步的输出。
kubectl -n default get pods -l app=hello-cicd
kubectl -n default port-forward svc/hello-cicd 8080:80
curl localhost:8080 # -> Hello from hello-cicd (version 1.0.0)| 环境 | k3s_import_cmd |
镜像导入 | 说明 |
|---|---|---|---|
| OrbStack(本机默认) | ""(留空) |
不需要 | docker 镜像自动对 k8s 可见 |
| 纯 k3s(物理机/VM) | "k3s ctr images import -" |
平台自动做 | 需 k3s 在 PATH;若需 root 用 "sudo k3s ctr images import -" |
切换只需改 project.json 的 deploy.k3s_import_cmd 后重新导入(编辑项目 → 保存)。
若要走「构建→推送→k3s 拉取」的标准云原生流程,把 project.json 改成:
"build": {
"image_repo": "docker.io/<你的用户名>/hello-cicd",
"tag_strategy": "timestamp",
"push": true,
"registry": { "server": "https://registry-1.docker.io", "username": "<用户名>", "password": "<密码或 token>" },
"build_args": { "APP_VERSION": "1.0.0" }
}k8s/deployment.yaml 的 image 改成对应仓库地址(imagePullPolicy: IfNotPresent 或 Always)。此模式把 deploy.method 改回 kubectl-set-image 或 local-k3s 均可(local-k3s 的导入步骤因 k3s_import_cmd 为空会自动跳过),直接点 Pipeline。
deploy.method 支持:
local-k3s(示例默认)— 纯本地闭环:可选导入镜像 + 自动建 Deployment(若缺失)+set-image。UI 一步到位。kubectl-apply— 用manifest_path指向一份清单做声明式发布(镜像 tag 静态,不随构建自动更新)。"deploy": { "method": "kubectl-apply", "manifest_path": "examples/hello-cicd/k8s/deployment.yaml", "namespace": "default", "wait": true, "timeout": "120s" }
kubectl-set-image— 把刚构建的镜像更新到已存在的 Deployment(不含自动建资源)。helm— 填release_name+chart_path,并设helm_set_image: true让平台把新镜像写进image(或helm_image_key自定义 key)。
tag_strategy 默认 timestamp(每次构建打 20060102-150405 时间戳 tag,平台自动生成,UI 直接点)。manual 需触发时显式传 tag;git-sha 在 build context 内执行 git rev-parse --short HEAD(是 git 仓库才生效,否则回退 timestamp)。
scripts/import-to-k3s.sh 是独立的手动导入脚本:读取「最近一次成功构建」的 tag,把对应镜像 docker save | k3s ctr import 进 k3s。make k3s-import 等价调用它。仅在你想绕开平台的自动导入、或调试镜像可见性时使用。
examples/hello-node/ 与 hello-cicd 功能与流程完全等价,只是换成 Node.js,用来验证平台对解释型语言的闭环同样跑得通。两个示例可同时导入同一台平台、各自独立发布到本地 k3s 或腾讯云。
examples/hello-node/
├── server.js # 零依赖 Node.js HTTP 服务(读 PORT / APP_VERSION 环境变量)
├── package.json # 无外部依赖,无需 npm install
├── Dockerfile # 单阶段 node:24-alpine(当前 Active LTS,支持至 2028-04),非 root(node 用户)运行
├── .dockerignore
├── k8s/deployment.yaml # Deployment + Service(imagePullPolicy: IfNotPresent,占位 hello-node:local)
└── project.json # 交给 cicdkit 的项目定义(snake_case,method=local-k3s)
与 Go 版的唯一实质差异在镜像构建阶段:
- 没有编译步骤。
Dockerfile直接从node:24-alpine(当前 Active LTS,安全支持到 2028-04)起,只COPY package.json server.js;APP_VERSION同样通过build_args→ARG→ENV注入。若要加依赖,在COPY前补COPY package*.json ./ && RUN npm install --omit=dev即可。 - 以非 root 运行:
node:alpine镜像自带node用户,Dockerfile末尾USER node,比 Go 版更省一步(Go 版要adduser)。
其余完全一致:local-k3s(纯本地无 registry)/ ssh 腾讯云直传、kubectl apply -f 每次幂等、探针按部署方式选 URL、NodePort Service 带 app: hello-node 标签。导入与触发命令把路径换成 node 版即可:
curl -X POST http://localhost:8080/api/projects -H 'Content-Type: application/json' \
--data-binary @examples/hello-node/project.json
# 腾讯云裸机版(ssh 免仓库直传;JSON 不含任何真实主机信息,连接方式全部来自项目根 .env 的 CICD_SSH_*)
curl -X POST http://localhost:8080/api/projects -H 'Content-Type: application/json' \
--data-binary @examples/hello-node/project-tencent-cloud.json验证(本地 k3s):
kubectl -n default get pods -l app=hello-node
kubectl -n default port-forward svc/hello-node 8080:80
curl localhost:8080 # -> Hello from hello-node (version 1.0.0)examples/hello-java/ 与 hello-cicd 流程等价,但刻意不含 Dockerfile 与 k8s 清单——用来验证平台的「生成缺失文件」功能:导入后点一下,由平台按 java-maven 检测自动生成多阶段 Dockerfile 与 Deployment+Service。
examples/hello-java/
├── pom.xml # <finalName>app</finalName>,对齐生成模板的 /app/app.jar
├── src/main/java/com/example/HelloApp.java # 零依赖 JDK HttpServer,读 PORT/APP_VERSION
├── .dockerignore
└── project.json # 指向尚不存在的 Dockerfile / k8s 路径(触发生成)
导入并触发生成:
# 1. 启动平台(后端 :8080 + 前端 :5173)
make dev
# 2. 导入示例(此时还没有 Dockerfile / k8s 清单)
curl -X POST http://localhost:8080/api/projects -H 'Content-Type: application/json' \
--data-binary @examples/hello-java/project.json
# 3. 在卡片上点「生成缺失文件」→ 预览 java-maven 多阶段 Dockerfile + Deployment/Service → 确认确认后 examples/hello-java/Dockerfile(maven:3.9-eclipse-temurin-21 → eclipse-temurin:21-jre,java -jar /app/app.jar)与 examples/hello-java/k8s/deployment.yaml 即被写入;project.json 里原本指向的缺失路径现在指向真实文件,项目立即可走 Build → Pipeline 闭环。
想顺手验证 Gradle 分支:把
pom.xml换成build.gradle(plugins { id 'java' },jar 任务产出build/libs/*.jar),「生成缺失文件」会改为生成gradle:8-jdk21多阶段模板。
⚠️ java -jar要求 jar 带Main-Class清单项。普通 Maven 工程要在pom.xml的maven-jar-plugin里声明<mainClass>com.example.HelloApp</mainClass>(本示例已配),否则镜像能跑起来却CrashLoopBackOff: no main manifest attribute, in /app/app.jar。Spring Boot 工程靠spring-boot-maven-plugin的 repackage 自动获得可执行 jar,无需额外配置。
单元用例见 internal/generate/generate_test.go 的 TestPlanAndApplyJava(覆盖 maven / gradle 两条检测路径)。
这五个示例与 hello-node(以及 hello-cicd / hello-java)流程完全等价——每个都是一个能被 cicdkit Build → Pipeline 的最小 HTTP 服务,仅语言不同,用来验证平台对多种语言的构建 / 发布 / 探针闭环都跑得通。可同时导入同一台平台、各自独立发布到本地 k3s。
| 示例 | 语言 | 构建方式 | 容器内端口 | 备注 |
|---|---|---|---|---|
| hello-rust | Rust 1.85 | 多阶段(rust:slim 编译 → debian 运行) | 8080 | 零依赖,仅标准库 std::net |
| hello-ruby | Ruby 3.3 | 单阶段(ruby:alpine) | 8080 | 零依赖,仅标准库 socket |
| hello-php | PHP 8.3 | 单阶段(php:*-apache) | 80 | Apache 自动服务 index.php |
| hello-dotnet | .NET 8 | 多阶段(SDK 编译 → runtime 运行) | 8080 | 零依赖 HttpListener,无 ASP.NET Core |
| hello-python | Python 3.12 | 单阶段(python:slim) | 8080 | 零依赖,仅标准库 http.server |
注意 PHP 容器内 Apache 监听 80,故其
k8s/deployment.yaml的targetPort与ssh_run_args都是8080:80(其它语言为8080:8080)。
导入(任选其一,其余路径同理):
curl -X POST http://localhost:8080/api/projects -H 'Content-Type: application/json' \
--data-binary @examples/hello-rust/project.json
# 其余:hello-ruby / hello-php / hello-dotnet / hello-python本地直跑(不依赖 Docker / k8s):
# Rust(需先 cargo build)
cd examples/hello-rust && cargo run
# Ruby(PORT=9090 ruby ... 可改端口)
ruby examples/hello-ruby/server.rb
# PHP(本机 php 内置服务器;或丢进 Apache 的 DocumentRoot)
php -S 0.0.0.0:8080 examples/hello-php/index.php
# .NET
cd examples/hello-dotnet && dotnet run
# Python(PORT=9090 python3 ... 可改端口)
python3 examples/hello-python/server.py验证(本地 k3s,以 hello-rust 为例,其余替换名字):
kubectl -n default get pods -l app=hello-rust
kubectl -n default port-forward svc/hello-rust 8080:80
curl localhost:8080 # -> Hello from hello-rust (version 1.0.0)