OneDev通过CICD上线项目
近期在开发项目的时候,发现一个问题就是服务器的 CPU 时不时的飙的老高,内存占用也很大。于是将服务器升级为 4 核 8GB 内存,但是在部署项目的时候还是时不时的出现问题。
因为我的服务器上安装了将近 15 个 docker 容器,以及 15 个网站,对应的还有一些备份计划。于是我将系统的备份以及快照分布在七牛上了。这样也会降低内存风险。
因为使用的数据库,没有使用远程数据,所以数据的内存以及备份也会放在服务器,这样同样也会增加内存风险。
于是我在不动备份数据,以及不增加成本的情况下,将一些占用 cpu 高的容器优化整理如下:
- gitea 容器
- jenkins 容器
于是,我在我将二者合一替换为oneDev容器。oneDev容器支持 git 自托管,CICD 等功能。这样一个容器就可以替换掉 gitea 容器以及 jenkins 容器了。
接下来我将整理总结一下oneDev容器的使用经验。
安装
首先我使用的1panel面板来安装oneDev容器。
如果发现应用商店中没有对应的容器,那么有一个方法可以使用脚本文件进行应用商店应用的扩展。脚本如下:
# 更新三方应用库
git clone -b localApps https://github.com/okxlin/appstore /opt/1panel/resource/apps/local/appstore-localApps
cp -rf /opt/1panel/resource/apps/local/appstore-localApps/apps/* /opt/1panel/resource/apps/local/
rm -rf /opt/1panel/resource/apps/local/appsatore-localApps
echo 'ok'之后更新之后,就可以在应用商店中看到oneDev容器了。 之前我想打算使用gitlab的,只是因为gitlab的容器比较大,占用的内存比较多,而oneDev容器占用的内存比较少。
可以使用域名代理访问oneDev容器。
使用
如图所示,这是我现在的oneDev容器的使用界面。
刚开始使用的时候,我也研究了一下,这款软件不错,还可以设置中英文语言。总体功能还算齐全。
当然可以自己创建项目,同时也支持远程仓库的导入。导入完成后,可以使用配置进行 CICD 的配置。文件名为:.onedev-buildspec.yml,这个文件类似于github的actions文件, 如下图:

这里有一个配置:
version: 43
jobs:
- name: 打包部署
steps:
- type: UseTemplateStep
name: checkout code
templateName: 代码签出
condition: SUCCESSFUL
optional: false
- type: UseTemplateStep
name: generate package checksum
templateName: 生成软件包校验
condition: SUCCESSFUL
optional: false
- type: UseTemplateStep
name: set up npm cache
templateName: 生成缓存
condition: SUCCESSFUL
optional: false
- type: UseTemplateStep
name: set up npm cache
templateName: 构建版本
condition: SUCCESSFUL
optional: false
- type: UseTemplateStep
name: build & upload
templateName: 上传构建产物
condition: SUCCESSFUL
optional: false
- type: UseTemplateStep
name: product
templateName: 生成制品
condition: SUCCESSFUL
optional: false
- type: UseTemplateStep
name: deploy
templateName: 部署
condition: SUCCESSFUL
optional: false
triggers:
- type: BranchUpdateTrigger
branches: master
userMatch: anyone
retryCondition: never
maxRetries: 3
retryDelay: 30
timeout: 14400
stepTemplates:
- name: 代码签出
steps:
- type: CheckoutStep
name: checkout code
cloneCredential:
type: DefaultCredential
withLfs: false
withSubmodules: false
condition: SUCCESSFUL
optional: false
- name: 生成软件包校验
steps:
- type: GenerateChecksumStep
name: generate package checksum
files: package-lock.json yarn.lock pnpm-lock.yaml
targetFile: checksum
condition: SUCCESSFUL
optional: false
- name: 生成缓存
steps:
- type: SetupCacheStep
name: set up npm cache
key: node_modules_@file:checksum@
loadKeys:
- node_modules
paths:
- node_modules
uploadStrategy: UPLOAD_IF_NOT_HIT
condition: SUCCESSFUL
optional: false
- name: 构建版本
steps:
- type: SetBuildVersionStep
name: set build version
buildVersion: "@script:builtin:node:determine-project-version@"
condition: SUCCESSFUL
optional: false
- name: 上传构建产物
steps:
- type: CommandStep
name: build & upload
runInContainer: true
image: node
interpreter:
type: DefaultInterpreter
commands: |
set -e
echo "📦 开始进行构建..."
# 构建
npm install -g pnpm
pnpm install
pnpm run build
echo "✅ 构建完成..."
echo "🌾 开始进行同步ssh..."
# 同步ssh
mkdir -p ~/.ssh
chmod 700 ~/.ssh
# 使用 printf 或 echo -e 来写入私钥,避免 heredoc 问题
printf '%s\n' '@secret:ssh@' > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
# 验证私钥格式
if ssh-keygen -l -f ~/.ssh/id_rsa > /dev/null 2>&1; then
echo "✅ 私钥格式验证通过"
else
echo "❌ 私钥格式错误"
exit 1
fi
ssh-keyscan -H 你的服务器IP >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
echo "✅ ssh同步完成..."
echo "⏫ 开始上传构建产物..."
CACHE_DIR="/opt/build_cache_apps/plugin-functional-helpers"
ssh -o StrictHostKeyChecking=no -o BatchMode=yes 你的用户名@你的服务器IP "mkdir -p $CACHE_DIR"
scp -o StrictHostKeyChecking=no -o BatchMode=yes -r dist/* 你的用户名@你的服务器IP:$CACHE_DIR/
echo "✅ 构建产物上传完成..."
useTTY: true
condition: SUCCESSFUL
optional: false
- name: 生成制品
steps:
- type: PublishArtifactStep
name: Products
sourcePath: dist
artifacts: "**"
condition: SUCCESSFUL
optional: false
- name: 部署
steps:
- type: SSHCommandStep
name: deploy
remoteMachine: 你的服务器IP
userName: root
privateKeySecret: ssh
commands: |
echo "🪤 开始进行项目部署..."
# 临时的构建产物目录
CACHE_DIR="/opt/build_cache_apps"
# 容器名
CONTAINER_NAME="openresty"
# 目标路径
CONTAINER_PATH="/www/sites"
# 在容器中创建目录并复制文件
# docker exec $CONTAINER_NAME mkdir -p $CONTAINER_PATH
docker cp $CACHE_DIR/. $CONTAINER_NAME:$CONTAINER_PATH
echo "✅ 项目「plugin-functional-helpers」部署完成"
echo "🧹 正在清理缓存..."
rm -rf $CACHE_DIR
echo "✅ 缓存已清除"
condition: SUCCESSFUL
optional: false密钥的生成
其中的 ssh 密钥是用来进行服务器之间的 ssh 连接的,需要在服务器上生成一个密钥对,将公钥配置到服务器上,私钥配置到 onedev 中。如图: 
服务器 ssh 中执行:
# 生成密钥对
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
# 复制公钥到服务器
ssh-copy-id 你的用户名@你的服务器IP
# 如果 ssh-copy-id 失败,手动复制公钥
cat ~/.ssh/id_rsa.pub | ssh 你的用户名@你的服务器IP "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
# 完成之后,可以查看服务器 ~/.ssh/authorized_keys 文件是否包含了你的公钥
cat ~/.ssh/authorized_keys
# 这一行解释:
# 这行命令将本地的 dist 目录下的所有文件递归复制到服务器的 $CACHE_DIR 目录下。
# -o StrictHostKeyChecking=no 选项禁用主机密钥检查,这在第一次连接未知主机时很有用。
# -o BatchMode=yes 选项启用批量模式,这在脚本中执行时很有用,避免交互式提示。
scp -o StrictHostKeyChecking=no -o BatchMode=yes -r dist/* 你的用户名@你的服务器IP:$CACHE_DIR/完成之后,可以在图中的这个地方查看: 
这样有个好处就是:之前都是先将代码上传到 git 托管上,然后在通过 jenkins 进行发布,现在是直接在 onedev 上进行发布,省去了中间的步骤,当然可以设置代码合并策略,比如合并到主分支后触发发布。具体其他的可以自行研究。