在现代 DevOps 流程中,实现从代码提交到服务上线的自动化部署已经成为一种标准操作。而我们今天要介绍的是如何使用 OneDev 配合 Portainer 打造一个轻量、中文友好、丝滑的 CI/CD 工作流。

OneDev 自带中文界面、支持 Git 仓库和 CI/CD 管道,而且内置 Docker Registry,几乎可以零门槛搭建自己的 DevOps 平台。结合 Portainer 强大的 Docker Stack 管理能力,我们可以轻松实现如下流程:

Git 推送代码 → OneDev 构建镜像 → 推送至本地 Registry → 调用 Portainer API 更新部署


📦 准备工作

1. 在 Git 项目根目录中添加以下两个文件:

Dockerfile:用于构建应用镜像

# 以 Node.js 为例
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN npm install && npm run build
CMD ["npm", "start"]
Docker

docker-compose.yml:用于部署 Stack 到 Portainer

version: '3.8'
services:
  app:
    image: localhost:5000/my-app:latest
    restart: always
    ports:
      - "8080:3000"
YAML

🛠 配置 OneDev 的构建工作流

步骤一:创建 CD 工作流

打开 OneDev 项目,点击左侧「代码」菜单,代码顶部有"通过 添加 .onedev-buildspec.yml 启用构建支持", 点击"添加"

  1. Checkout Code

  2. Docker Image / Build Image

  3. Execute Commands

容器可以选择urlimages/curl:latest 用来CURL请求API.
命令行中添加安装jq来方便处理json字符串

apk add --no-cache jq
SQL

部署:

设置要部署到portainer的stack_name. endpointdId

portainer_url为portainer的域名

@secret:portainer_token@ 中的"portainer_token"为构建设置的变量名称

stack_name="test"
endpoint=5 
portainer_url="https://test.uqoo.cc"

# 安装 jq(仅 Alpine 可用)
apk add --no-cache jq

# 获取 stack_id
get_stack_id() {
  curl -s -H "X-API-KEY: @secret:portainer_token@" "${portainer_url}/api/stacks" |
    jq ".[] | select(.Name==\"${stack_name}\") | .Id"
}

# 更新 stack
update_stack() {
  local local_stack_id=$1
  echo "update stack: ${local_stack_id}"

  # 将 compose 文件转为 JSON 字符串
  content=$(jq -Rs . < docker-compose.yml)

  # 构造 JSON 并发送
  curl -X PUT -H "Content-Type: application/json" \
       -H "X-API-KEY: @secret:portainer_token@" \
       -d '{"prune": true, "pullImage": true, "stackFileContent": '"${content}"'}' \
       "${portainer_url}/api/stacks/${local_stack_id}?endpointId=${endpoint}"
}

# 创建 stack
create_stack() {
  curl -X POST "${portainer_url}/api/stacks/create/standalone/file?endpointId=${endpoint}" \
       -H "X-API-KEY: @secret:portainer_token@" \
       -F "Name=${stack_name}" \
       -F "file=@@docker-compose.yml"
}

# 判断是否存在 stack
stack_id=$(get_stack_id)

if [ -n "$stack_id" ]; then
  echo "update stack."
  update_stack "$stack_id"
else
  echo "create new stack."
  create_stack
fi
Bash

步骤二:设置变量(建议使用 OneDev 的 Secret 功能)

  • PORTAINER_TOKEN:Portainer API 的访问令牌

  • DOCKER_REGISTRY:默认是 localhost:5000,你也可以指定其他私有 Registry 地址


📡 配置 Portainer

  1. 登录 Portainer 后台

  2. 确保已开启 API 功能(启用认证)

  3. 创建 Access Token,用于 OneDev 调用


✅ 整体流程图

         开发者提交代码
                 ↓
           OneDev Git 仓库
                 ↓
        OneDev CD 工作流触发
                 ↓
         构建镜像 + 推送到本地 Registry
                 ↓
         调用 Portainer API 更新 Stack
                 ↓
           应用服务丝滑上线 ✨
Plain text

🎯 总结

使用 OneDev + Portainer,可以不依赖 GitHub Actions、Jenkins、Harbor 等复杂平台,在本地就能搭建出一个完整、高效、中文友好的 CI/CD 环境。尤其适合中小团队或内网部署需求。


因时间有限省略了比较简单CI流程,仅描述难度较高的CD

portainer api的官方网站. 当前文章所使用的api的版本为2.27.6

https://app.swaggerhub.com/apis/portainer/portainer-ce/2.27.6#/stacks/StackUpdate