小型开发团队这样工作才最爽:代码管理、自动部署、服务器监控、远程运维一套工作流全搞定

本文以 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 Web8929代码仓库与项目管理
GitLab SSH2424SSH方式拉取与推送代码
Jenkins8080自动构建与部署
示例网站8088验证自动部署结果
Prometheus9090服务器指标查询
Node Exporter9100采集Linux主机指标
cpolar Web UI9200管理公网隧道

先更新系统并安装基础工具:

sudoaptupdatesudoaptupgrade-ysudoaptinstall-yca-certificatescurlgnupggitvimwget

二、从Docker官方软件源安装Docker Engine

Ubuntu软件仓库提供的docker.io可以用于简单测试,但为了方便后续升级并与Docker官方文档保持一致,本文使用Docker官方APT仓库安装Docker Engine和Compose插件。若服务器曾经安装过发行版提供的Docker软件包,先清理可能产生冲突的旧包:

forpkgindocker.io docker-docdocker-composedocker-compose-v2 podman-docker containerd runc;dosudoapt-getremove-y"$pkg"2>/dev/null||truedone

添加Docker官方签名密钥和软件源:

sudoinstall-m0755-d/etc/apt/keyringssudocurl-fsSLhttps://download.docker.com/linux/ubuntu/gpg-o/etc/apt/keyrings/docker.ascsudochmoda+r /etc/apt/keyrings/docker.ascecho"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"|sudotee/etc/apt/sources.list.d/docker.list>/dev/null

安装Docker Engine、Buildx和Compose插件:

sudoaptupdatesudoaptinstall-ydocker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginsudosystemctlenable--nowdocker

为了让当前登录用户可以直接执行Docker命令,可以将其加入docker用户组:

sudousermod-aGdocker"$USER"newgrpdocker

验证安装结果:

docker--versiondockercompose versiondockerrun--rmhello-world

需要注意的是,加入docker用户组相当于授予较高的宿主机权限,只应给可信任的运维和开发账号使用。

三、使用GitLab解决代码散落和版本混乱

小型团队最早经常通过压缩包传递代码,文件名可能逐渐变成“最终版”“最终版2”“最终版-今天修改”。成员增加后,这种方式很快就会出现代码相互覆盖、修改记录无法追踪和旧版本无法恢复的问题。GitLab的作用,是把项目代码、分支、提交记录和成员权限统一放入一套私有平台。

3.1 创建GitLab目录

sudomkdir-p/srv/gitlabsudochown-R"$USER":"$USER"/srv/gitlabcd/srv/gitlab

3.2 编写Docker Compose配置

创建compose.yml

services:gitlab:image:gitlab/gitlab-ce:latestcontainer_name:gitlabrestart:unless-stoppedhostname:gitlab.localenvironment:GITLAB_OMNIBUS_CONFIG:|external_url 'http://192.168.1.50:8929' gitlab_rails['gitlab_shell_ssh_port'] = 2424ports:-"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版本标签,并在升级前备份configlogsdata目录。

启动GitLab:

dockercompose up-ddockerlogs-fgitlab

GitLab第一次启动需要初始化数据库和内部组件,耗时通常明显长于普通容器。初始化完成后访问:

http://服务器局域网IP:8929

查看初始管理员密码:

dockerexec-itgitlabgrep"Password:"/etc/gitlab/initial_root_password

默认管理员用户名为root。首次登录后应立即修改密码,并为团队建立独立Group、Project和成员账号,不要让所有成员共用管理员账号。初始密码文件不会永久保留,因此应在首次启动后及时完成登录。

3.3 创建并推送测试项目

在开发电脑上配置Git身份:

gitconfig--globaluser.name"developer"gitconfig--globaluser.email"developer@example.com"

进入项目目录后执行:

gitinitgitadd.gitcommit-m"initial commit"gitbranch-Mmaingitremoteaddorigin http://服务器IP:8929/团队名称/项目名称.gitgitpush-uorigin main

GitLab页面中能够看到代码与提交记录后,说明私有仓库已经可以正常工作。代码管理问题解决后,下一步是把手动登录服务器发布程序的过程变成固定流水线。

四、准备一个安全的示例网站项目

为了验证Jenkins自动部署,可以准备一个简单的Nginx静态页面。项目目录如下:

team-demo/ ├── index.html ├── Dockerfile ├── .dockerignore └── Jenkinsfile

index.html示例:

<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="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

sudoaptupdatesudoaptinstall-yfontconfig openjdk-21-jrejava-version

5.2 添加Jenkins LTS软件源

sudowget-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/"|sudotee/etc/apt/sources.list.d/jenkins.list>/dev/null

安装并启动Jenkins:

sudoaptupdatesudoaptinstall-yjenkinssudosystemctlenable--nowjenkinssudosystemctl status jenkins

浏览器访问:

http://服务器局域网IP:8080

查看初始化密码:

sudocat/var/lib/jenkins/secrets/initialAdminPassword

完成初始化后安装推荐插件,并确认已安装Git、Pipeline、GitLab和Credentials Binding等常用插件。

5.3 让Jenkins能够调用Docker

sudousermod-aGdockerjenkinssudosystemctl restart jenkins

验证权限:

sudo-ujenkinsdockerps

如果仍然提示权限不足,可以重启服务器后再次测试。让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'构建失败,请检查控制台日志'}}}

提交项目文件:

gitadd.gitcommit-m"add Jenkins pipeline"gitpush

在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后推送代码:

gitadd.gitcommit-m"update homepage"gitpush

GitLab应自动通知Jenkins,Jenkins随后拉取最新代码、构建新镜像并替换示例容器。

八、使用Prometheus与Node Exporter监控服务器

本文的监控范围是Linux服务器的CPU、内存、磁盘和网络等基础状态,并不等同于完整的应用可用性监控。若要进一步确认8088端口的网页是否能正常访问,可以继续增加Blackbox Exporter;若要观察Docker容器资源,可以增加cAdvisor。

8.1 创建配置文件

sudomkdir-p/srv/monitorsudochown-R"$USER":"$USER"/srv/monitorcd/srv/monitor

创建prometheus.yml

global:scrape_interval:15sscrape_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:latestcontainer_name:prometheusrestart:unless-stoppednetwork_mode:hostvolumes:-"./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:latestcontainer_name:node-exporterrestart:unless-stoppednetwork_mode:hostpid:hostcommand:-"--path.rootfs=/host"volumes:-"/:/host:ro,rslave"volumes:prometheus-data:

启动并检查状态:

dockercompose up-ddockerps

访问:

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

sudocurlhttps://get.cpolar.sh|sh

检查并启动服务:

cpolar versionsudosystemctlenable--nowcpolarsudosystemctl status cpolar

浏览器访问:

http://服务器局域网IP:9200

使用cpolar账号登录Web UI。

9.2 建议创建的隧道

隧道协议本地地址建议公网类型用途
GitLab WebHTTP8929固定二级子域名远程访问代码仓库
GitLab SSHTCP2424固定TCP地址SSH方式拉取和推送
JenkinsHTTP8080固定二级子域名管理平台与Webhook
PrometheusHTTP9090临时或受保护地址远程排查服务器状态

固定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/gitlabdockercompose 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首次启动会初始化多个内部组件。先查看日志:

dockerlogs-fgitlab

再检查内存和容器状态:

free-hdockerps-a

如果服务器只有8GB内存,建议配置Swap,并尽量避免同时运行大量Jenkins构建任务。

Jenkins无法执行Docker命令

groupsjenkinssudo-ujenkinsdockerps

jenkins不在docker组中,重新添加并重启服务:

sudousermod-aGdockerjenkinssudosystemctl 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/