小型开发团队这样工作才最爽:代码管理、自动部署、服务器监控、远程运维一套工作流全搞定
本文以 Ubuntu 24.04 LTS 为基础环境,使用 GitLab、Jenkins、Docker、Prometheus、Node Exporter 与 cpolar,搭建一套适合小型开发团队的代码管理、自动部署、服务器监控和远程运维工作流。
本版采用“实景场景图 + 技术信息图”交替排版:实景图展示痛点和使用结果,技术图解释部署结构与关键配置。涉及命令与参数时请以正文为准。
一个五六人的小型开发团队,项目不多时通常不会投入太多精力建设流程。代码可以通过聊天软件传递,测试版本打包后放进共享文件夹,程序上线时由某位开发人员登录服务器手动替换文件。只要团队成员彼此熟悉,这种方式看起来简单、直接,也不会立即暴露出太多问题。
当项目数量、成员数量和发布频率逐渐增加后,原来的办法就会开始失效。不同开发人员手里保存着不同版本的代码,测试环境与正式环境经常不一致;每次发布都需要重复登录服务器、复制文件和重启服务,任何一步遗漏都可能造成线上异常;程序上线后又缺少统一监控,往往要等到客户反馈页面打不开,团队才知道服务器早已出现问题。即使代码仓库、部署平台和监控页面都搭建好了,成员出差或居家办公时仍可能因为局域网限制而无法使用。
本文将这几个问题串成一条完整工作流:GitLab负责代码和版本管理,Jenkins负责自动构建与部署,Docker负责承载示例应用,Prometheus与Node Exporter负责服务器基础监控,最后使用cpolar解决异地访问和公网Webhook触发问题。流程跑通后,开发人员只需提交代码,后续构建、部署、监控和远程处理便能沿着固定路径完成。

一、部署前先规划服务器资源与端口
将GitLab、Jenkins、Docker构建任务和Prometheus部署在同一台服务器上时,测试环境最低可以从4核CPU、8GB内存起步,但内存会比较紧张,建议同时配置Swap。准备长期运行时,更适合使用4—8核CPU、16GB内存和120GB以上SSD空间。GitLab仓库、Docker镜像、Jenkins构建记录和Prometheus时序数据都会持续增长,因此磁盘容量不宜只按照刚安装时的占用量估算。
本文采用以下端口规划。正式部署前应确认这些端口没有被其他程序占用,并根据实际网络环境调整服务器防火墙。
| 服务 | 本地端口 | 作用 |
|---|---|---|
| GitLab Web | 8929 | 代码仓库与项目管理 |
| GitLab SSH | 2424 | SSH方式拉取与推送代码 |
| Jenkins | 8080 | 自动构建与部署 |
| 示例网站 | 8088 | 验证自动部署结果 |
| Prometheus | 9090 | 服务器指标查询 |
| Node Exporter | 9100 | 采集Linux主机指标 |
| cpolar Web UI | 9200 | 管理公网隧道 |

先更新系统并安装基础工具:
sudo apt update
sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg git vim wget
二、从Docker官方软件源安装Docker Engine
Ubuntu软件仓库提供的docker.io可以用于简单测试,但为了方便后续升级并与Docker官方文档保持一致,本文使用Docker官方APT仓库安装Docker Engine和Compose插件。若服务器曾经安装过发行版提供的Docker软件包,先清理可能产生冲突的旧包:
for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do
sudo apt-get remove -y "$pkg" 2>/dev/null || true
done
添加Docker官方签名密钥和软件源:
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
安装Docker Engine、Buildx和Compose插件:
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
为了让当前登录用户可以直接执行Docker命令,可以将其加入docker用户组:
sudo usermod -aG docker "$USER"
newgrp docker
验证安装结果:
docker --version
docker compose version
docker run --rm hello-world
需要注意的是,加入docker用户组相当于授予较高的宿主机权限,只应给可信任的运维和开发账号使用。
三、使用GitLab解决代码散落和版本混乱

小型团队最早经常通过压缩包传递代码,文件名可能逐渐变成“最终版”“最终版2”“最终版-今天修改”。成员增加后,这种方式很快就会出现代码相互覆盖、修改记录无法追踪和旧版本无法恢复的问题。GitLab的作用,是把项目代码、分支、提交记录和成员权限统一放入一套私有平台。
3.1 创建GitLab目录
sudo mkdir -p /srv/gitlab
sudo chown -R "$USER":"$USER" /srv/gitlab
cd /srv/gitlab
3.2 编写Docker Compose配置
创建compose.yml:
services:
gitlab:
image: gitlab/gitlab-ce:latest
container_name: gitlab
restart: unless-stopped
hostname: gitlab.local
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://192.168.1.50:8929'
gitlab_rails['gitlab_shell_ssh_port'] = 2424
ports:
- "8929:8929"
- "2424:22"
volumes:
- "./config:/etc/gitlab"
- "./logs:/var/log/gitlab"
- "./data:/var/opt/gitlab"
shm_size: "256m"
将192.168.1.50替换为服务器自己的局域网IP。示例使用latest便于实验,正式环境建议在验证后固定明确的GitLab版本标签,并在升级前备份config、logs和data目录。

启动GitLab:
docker compose up -d
docker logs -f gitlab
GitLab第一次启动需要初始化数据库和内部组件,耗时通常明显长于普通容器。初始化完成后访问:
http://服务器局域网IP:8929
查看初始管理员密码:
docker exec -it gitlab grep "Password:" /etc/gitlab/initial_root_password
默认管理员用户名为root。首次登录后应立即修改密码,并为团队建立独立Group、Project和成员账号,不要让所有成员共用管理员账号。初始密码文件不会永久保留,因此应在首次启动后及时完成登录。
3.3 创建并推送测试项目
在开发电脑上配置Git身份:
git config --global user.name "developer"
git config --global user.email "developer@example.com"
进入项目目录后执行:
git init
git add .
git commit -m "initial commit"
git branch -M main
git remote add origin http://服务器IP:8929/团队名称/项目名称.git
git push -u origin main
GitLab页面中能够看到代码与提交记录后,说明私有仓库已经可以正常工作。代码管理问题解决后,下一步是把手动登录服务器发布程序的过程变成固定流水线。
四、准备一个安全的示例网站项目
为了验证Jenkins自动部署,可以准备一个简单的Nginx静态页面。项目目录如下:
team-demo/
├── index.html
├── Dockerfile
├── .dockerignore
└── Jenkinsfile
index.html示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>团队自动部署测试</title>
</head>
<body>
<h1>代码已经通过 Jenkins 自动部署成功</h1>
</body>
</html>
Dockerfile只复制真正需要发布的网页文件,避免将Git仓库元数据和流水线配置暴露到Nginx目录:
FROM nginx:alpine
COPY index.html /usr/share/nginx/html/index.html
创建.dockerignore:
.git
.gitignore
Jenkinsfile
Dockerfile
五、安装Jenkins并赋予构建权限

Jenkins负责把拉取代码、构建镜像和启动容器等重复操作固化为流水线。本文使用Jenkins官方Debian软件源安装LTS版本,并使用Java 21作为运行环境。
5.1 安装Java 21
sudo apt update
sudo apt install -y fontconfig openjdk-21-jre
java -version
5.2 添加Jenkins LTS软件源
sudo wget -O /etc/apt/keyrings/jenkins-keyring.asc https://pkg.jenkins.io/debian-stable/jenkins.io-2026.key
echo "deb [signed-by=/etc/apt/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian-stable binary/" | sudo tee /etc/apt/sources.list.d/jenkins.list > /dev/null
安装并启动Jenkins:
sudo apt update
sudo apt install -y jenkins
sudo systemctl enable --now jenkins
sudo systemctl status jenkins
浏览器访问:
http://服务器局域网IP:8080
查看初始化密码:
sudo cat /var/lib/jenkins/secrets/initialAdminPassword
完成初始化后安装推荐插件,并确认已安装Git、Pipeline、GitLab和Credentials Binding等常用插件。
5.3 让Jenkins能够调用Docker
sudo usermod -aG docker jenkins
sudo systemctl restart jenkins
验证权限:
sudo -u jenkins docker ps
如果仍然提示权限不足,可以重启服务器后再次测试。让Jenkins访问Docker套接字意味着其拥有较高宿主机权限,因此正式生产环境更适合使用独立构建节点、受限Runner或隔离构建环境。
六、编写不会重复检出代码的Jenkins流水线
Declarative Pipeline默认可能自动检出一次代码,如果流水线中又显式执行checkout scm,就会产生重复操作。下面通过skipDefaultCheckout(true)关闭默认检出,同时使用disableConcurrentBuilds()避免两个构建同时争抢同一个容器名称和端口。
项目根目录中的Jenkinsfile如下:
pipeline {
agent any
options {
skipDefaultCheckout(true)
disableConcurrentBuilds()
timestamps()
}
stages {
stage('拉取代码') {
steps {
checkout scm
}
}
stage('构建镜像') {
steps {
sh 'docker build --pull -t team-demo:${BUILD_NUMBER} .'
}
}
stage('部署应用') {
steps {
sh '''
docker rm -f team-demo || true
docker run -d --name team-demo --restart unless-stopped -p 8088:80 team-demo:${BUILD_NUMBER}
'''
}
}
}
post {
success {
echo '项目构建与部署成功'
}
failure {
echo '构建失败,请检查控制台日志'
}
}
}

提交项目文件:
git add .
git commit -m "add Jenkins pipeline"
git push
在Jenkins中新建“流水线”任务,流水线定义选择Pipeline script from SCM,SCM选择Git并填写GitLab项目地址。私有仓库应在Jenkins凭据管理中保存GitLab用户名与Personal Access Token,然后在任务中选择对应凭据。
分支填写:
*/main
脚本路径填写:
Jenkinsfile
保存后点击“立即构建”。构建成功后访问:
http://服务器局域网IP:8088
如果页面显示测试内容,说明代码拉取、镜像构建和容器部署已经跑通。
七、配置GitLab Webhook自动触发Jenkins
手动点击“立即构建”只能证明流水线可用,真正顺畅的流程应当由代码提交自动触发。安装GitLab插件后,在Jenkins任务的“构建触发器”中勾选GitLab Push事件触发选项,并记录页面生成的Webhook URL和Secret Token。

GitLab与Jenkins处在同一局域网时,可以先使用:
http://服务器局域网IP:8080/project/team-demo
进入GitLab项目的Settings → Webhooks,填写URL与Secret Token并勾选Push Events。如果自建GitLab默认阻止Webhook访问局域网地址,需要用管理员账号进入:
Admin Area
→ Settings
→ Network
→ Outbound requests
开启允许Webhook和集成访问本地网络的选项。
如果GitLab位于外部网络,或者需要长期从公网稳定触发Jenkins,则应在cpolar中为Jenkins保留固定HTTP地址,并将该地址配置为Webhook URL。随机地址发生变化后,GitLab中的Webhook也必须同步修改,因此不适合长期自动化流程。
修改index.html后推送代码:
git add .
git commit -m "update homepage"
git push
GitLab应自动通知Jenkins,Jenkins随后拉取最新代码、构建新镜像并替换示例容器。
八、使用Prometheus与Node Exporter监控服务器

本文的监控范围是Linux服务器的CPU、内存、磁盘和网络等基础状态,并不等同于完整的应用可用性监控。若要进一步确认8088端口的网页是否能正常访问,可以继续增加Blackbox Exporter;若要观察Docker容器资源,可以增加cAdvisor。
8.1 创建配置文件
sudo mkdir -p /srv/monitor
sudo chown -R "$USER":"$USER" /srv/monitor
cd /srv/monitor
创建prometheus.yml:
global:
scrape_interval: 15s
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["127.0.0.1:9090"]
- job_name: "node-exporter"
static_configs:
- targets: ["127.0.0.1:9100"]
8.2 使用宿主机网络运行监控组件
创建compose.yml:
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
restart: unless-stopped
network_mode: host
volumes:
- "./prometheus.yml:/etc/prometheus/prometheus.yml:ro"
- "prometheus-data:/prometheus"
command:
- "--config.file=/etc/prometheus/prometheus.yml"
- "--storage.tsdb.path=/prometheus"
node-exporter:
image: quay.io/prometheus/node-exporter:latest
container_name: node-exporter
restart: unless-stopped
network_mode: host
pid: host
command:
- "--path.rootfs=/host"
volumes:
- "/:/host:ro,rslave"
volumes:
prometheus-data:
启动并检查状态:
docker compose up -d
docker ps
访问:
http://服务器局域网IP:9090
http://服务器局域网IP:9100/metrics
在Prometheus的Status → Targets页面中,Prometheus和Node Exporter目标都应显示UP。

8.3 使用更直观的PromQL查询
目标在线状态:
up
整机CPU使用率:
100 * (
1 - avg by (instance) (
rate(node_cpu_seconds_total{mode="idle"}[5m])
)
)
内存使用率:
100 * (
1 -
node_memory_MemAvailable_bytes
/
node_memory_MemTotal_bytes
)
根目录磁盘使用率:
100 * (
1 -
node_filesystem_avail_bytes{
mountpoint="/",
fstype!~"tmpfs|overlay"
}
/
node_filesystem_size_bytes{
mountpoint="/",
fstype!~"tmpfs|overlay"
}
)
九、使用cpolar解决公网访问与远程Webhook问题

当GitLab、Jenkins和Prometheus都能在局域网中运行后,最后一个问题是异地成员无法访问。cpolar可以为本地HTTP或TCP服务建立公网入口,使成员在公司外部访问代码仓库、部署平台和监控页面,同时也能为Jenkins提供稳定的公网Webhook地址。
9.1 安装cpolar
sudo curl https://get.cpolar.sh | sh
检查并启动服务:
cpolar version
sudo systemctl enable --now cpolar
sudo systemctl status cpolar
浏览器访问:
http://服务器局域网IP:9200
使用cpolar账号登录Web UI。
9.2 建议创建的隧道
| 隧道 | 协议 | 本地地址 | 建议公网类型 | 用途 |
|---|---|---|---|---|
| GitLab Web | HTTP | 8929 | 固定二级子域名 | 远程访问代码仓库 |
| GitLab SSH | TCP | 2424 | 固定TCP地址 | SSH方式拉取和推送 |
| Jenkins | HTTP | 8080 | 固定二级子域名 | 管理平台与Webhook |
| Prometheus | HTTP | 9090 | 临时或受保护地址 | 远程排查服务器状态 |

固定HTTP二级子域名和固定TCP地址涉及相应套餐,免费套餐提供的随机地址可能发生变化。Jenkins Webhook需要长期稳定地址,因此更适合使用固定二级子域名。
9.3 GitLab公网地址的两种使用方式
如果只是临时从外网查看GitLab页面,可以保留原来的局域网external_url,直接把8929端口映射到公网,但GitLab页面显示的部分克隆链接仍可能是局域网地址。
如果准备把固定cpolar地址作为GitLab主要入口,可以将GitLab配置改为:
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://你的固定子域名.cpolar.top'
nginx['listen_port'] = 8929
nginx['listen_https'] = false
gitlab_rails['gitlab_shell_ssh_port'] = 2424
更新后重新创建容器:
cd /srv/gitlab
docker compose up -d
这里由cpolar在公网侧提供HTTPS,GitLab容器内部仍通过HTTP监听8929端口。若需要公网SSH克隆,还应创建TCP隧道,并根据cpolar提供的公网主机和端口连接。
9.4 Jenkins公网Webhook
为Jenkins创建固定HTTP隧道后,在Jenkins中进入:
Manage Jenkins
→ System
→ Jenkins Location
将Jenkins URL修改为固定公网地址,再把新的Webhook地址填写到GitLab项目中并执行测试Push。
9.5 Prometheus公网安全
Prometheus默认不适合长期匿名暴露在公网。更安全的做法包括增加Basic Auth反向代理、设置访问白名单,或者只在临时排查问题时开启隧道。Jenkins同样应关闭匿名权限,并使用明确的认证与授权策略。
十、完整流程测试
完成配置后,可以按照以下顺序进行验收:开发人员在本地修改index.html并推送到GitLab;GitLab收到Push事件后,通过Webhook触发Jenkins;Jenkins自动拉取代码、构建镜像并替换8088端口上的示例容器;随后在Prometheus中确认Node Exporter仍然处于UP状态,并检查CPU、内存与磁盘指标;最后断开公司Wi-Fi,使用手机流量访问GitLab、Jenkins和经过保护的Prometheus公网地址。
当这条链路能够连续跑通时,团队的工作方式便从“群里传代码、手动登录发布、客户反馈后排查”,变成了“提交代码、自动构建、自动部署、持续监控、随时远程处理”。
十一、常见问题
GitLab启动很久仍无法访问
GitLab首次启动会初始化多个内部组件。先查看日志:
docker logs -f gitlab
再检查内存和容器状态:
free -h
docker ps -a
如果服务器只有8GB内存,建议配置Swap,并尽量避免同时运行大量Jenkins构建任务。
Jenkins无法执行Docker命令
groups jenkins
sudo -u jenkins docker ps
若jenkins不在docker组中,重新添加并重启服务:
sudo usermod -aG docker jenkins
sudo systemctl restart jenkins
Jenkins无法拉取私有GitLab项目
先在服务器终端使用相同仓库地址和凭据执行一次git clone,确认网络、用户名和Personal Access Token正常,再回到Jenkins检查Credentials与分支配置。
GitLab Webhook测试失败
同一局域网内使用私有地址时,应检查GitLab是否允许Webhook访问本地网络;跨网络或外部GitLab触发时,应检查cpolar隧道是否在线、地址是否变化,以及Jenkins任务是否开启对应的Push触发器。
Prometheus中的Node Exporter显示DOWN
先访问:
http://服务器IP:9100/metrics
如果无法打开,检查Node Exporter容器和9100端口;如果页面可打开,再检查prometheus.yml中的目标地址,以及Prometheus容器是否确实使用了宿主机网络。
十二、部署验收清单
- GitLab能够正常登录、创建Group和Project并推送代码;
- 团队成员使用独立账号,不共用
root管理员; - Jenkins能够从GitLab拉取私有项目;
- Jenkins流水线不会重复检出代码;
- 同一任务不会发生并发部署冲突;
- Docker镜像只包含需要发布的网页文件;
- GitLab Push事件能够自动触发Jenkins;
- Prometheus中的目标均显示
UP; - CPU、内存和磁盘使用率查询正常;
- cpolar固定地址能够稳定访问GitLab和Jenkins;
- Prometheus公网访问已增加保护,或只在排查时临时开启;
- GitLab、Jenkins与Prometheus数据均纳入备份计划。
十三、真正的爽点,是开发人员只需要专心提交代码
这套工作流真正带来的变化,并不是服务器上多安装了几个软件,而是每个环节终于有了明确职责。GitLab负责代码、版本和权限,Jenkins负责把构建与发布动作自动执行,Prometheus与Node Exporter负责持续观察服务器状态,cpolar则让团队在公司之外仍然能够访问这些工具。
以前一次上线,需要先在群里确认谁手中的代码最新,再由某个人打包、登录服务器、替换文件并重启服务;程序出现问题后,团队还要临时连接服务器逐项排查。现在开发人员完成修改后只需提交代码,系统就会沿着既定流程完成构建和部署;服务器是否健康,可以通过监控指标快速确认;即使成员不在办公室,仍然能够进入GitLab、Jenkins和监控平台处理问题。
对于小型开发团队来说,这才是自动化工作流最实际的价值:它不一定让每一项工作完全无人参与,却能把最容易出错、不断重复的操作变成稳定流程,让团队把更多时间用于开发产品,而不是反复处理版本、发布和远程访问问题。
完整教程可参考
-
CentOS 7环境下的GitLab部署与公网访问参考:
https://www.cpolar.com/blog/centos7-private-gitlab-cpolar-internal-network-penetration-to-achieve-public-network-access-tutorial -
Jenkins自动部署与cpolar公网触发:
https://www.cpolar.com/blog/jenkins-automatic-deployment-in-practice-combining-cpolar-to-achieve-public-network-triggering -
Prometheus、Node Exporter与Alertmanager监控告警:
https://www.cpolar.com/blog/say-goodbye-to-downtime-build-a-server-monitoring-and-alarm-system-from-scratch-even-beginners-can-learn-it -
Node Exporter与cpolar远程监控:
https://www.cpolar.com/blog/no-public-ip-address-required-remote-monitoring-of-server-status-is-achieved-by-using-node_exporter-and-cpolar -
cpolar安装与配置文档:
https://www.cpolar.com/docs
技术校对依据
-
Docker Engine on Ubuntu:
https://docs.docker.com/engine/install/ubuntu/ -
GitLab Docker安装与配置:
https://docs.gitlab.com/install/docker/installation/
https://docs.gitlab.com/install/docker/configuration/ -
Jenkins Linux安装:
https://www.jenkins.io/doc/book/installing/linux/ -
Prometheus与Node Exporter:
https://prometheus.io/docs/guides/node-exporter/
https://prometheus.io/docs/guides/basic-auth/
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)