在中大型工业研发团队中,手工上线极易引发配置遗漏、版本错乱、人为操作失误等线上风险,而物联网服务直接对接现场采集终端,故障会直接影响设备数据采集、告警上报。本文围绕Jenkins+GitLab联合 CI/CD 架构,阐述 CI 持续集成、CD 持续交付与持续部署的技术原理,完整讲解 Webhook 联动、流水线定义、容器镜像构建推送、Kubernetes 滚动发布整套实现;结合工业物联网平台业务案例,给出生产级 Jenkinsfile 配置,梳理常见故障根因与排错方案,同时对比 GitLab‑CI 原生流水线的适用场景,为工业类 DevOps 流水线落地提供可复用的技术方案。
传统交付模式中,开发提交代码至 GitLab 仓库,运维人员登录跳板机,手动完成代码拉取、编译打包、文件上传、服务重启整套操作。该模式高度依赖人工,极易出现配置文件缺失、环境参数写错、Jar 包版本错误等问题。
某工业物联网设备接入服务曾因上线时遗漏采集通道的 MQTT 连接参数配置,导致上百台现场传感器断连、采集数据丢失,引发车间监控大屏无数据,事故推动团队全面转向自动化 CI/CD 体系,选择GitLab 负责代码托管,Webhook 事件驱动 Jenkins 执行流水线的组合方案,既复用 GitLab 代码仓库能力,又借助 Jenkins 丰富插件生态完成复杂构建、测试、镜像构建、K8s 部署能力,实现从代码提交到上线的全链路自动化。
CI/CD 核心目标:把编译、单元测试、代码质量扫描、镜像构建、应用发布全部自动化,尽早暴露代码缺陷,消除人为操作带来的故障。
.gitlab‑ci.yml定义 Job,无需额外部署服务,适合小团队轻量场景。采用GitLab Webhook 驱动 Jenkins的经典架构,完整链路如下:
优势:代码变更源头在 GitLab,调度能力交给 Jenkins;兼顾代码管理能力与复杂定制化流水线能力。
生产环境建议使用 LTS 长期支持版本,使用 Docker 容器快速拉起 Jenkins、GitLab 服务。
# Jenkins LTS部署,挂载docker.sock,允许流水线内部构建docker镜像
docker run -d --name jenkins \
-p 8080:8080 -p 50000:50000 \
-v jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
jenkins/jenkins:lts
# GitLab CE私有化部署
docker run -d --name gitlab \
-p 443:443 -p 80:80 -p 22:22 \
-v gitlab_config:/etc/gitlab \
-v gitlab_logs:/var/log/gitlab \
-v gitlab_data:/var/opt/gitlab \
gitlab/gitlab-ce:latestUser Settings → Access Tokens,勾选api权限,生成 Token 妥善保存,用于 Jenkins 调用 GitLab API 回写流水线状态。GitLab Plugin;进入Manage Jenkins → Configure System → GitLab,填入 GitLab 访问地址,凭证选择GitLab API Token填入上一步生成 Token,点击Test Connection验证连通性。Settings → Webhooks:http://your‑jenkins‑url/gitlab‑webhook/Push events,配置分支过滤仅触发main分支,避免其他分支频繁触发构建。⚠️重点注意:GitLab 服务端需要网络可达 Jenkins 地址,内网环境切勿填写
localhost,否则 Webhook 请求会访问 GitLab 自身,直接触发失败。
针对工业物联网采集微服务,流水线包含:拉取代码、Maven 编译打包、单元测试、SonarQube 质量门禁、Docker 镜像构建推送、K8s 测试环境部署、冒烟测试;生产环境设置人工确认卡点,实现持续交付。
pipeline {
agent any
options {
timestamps()
buildDiscarder(logRotator(numToKeepStr: '20')) // 限制构建历史保存数量
}
environment {
DOCKER_REGISTRY = "harbor.example.com"
PROJECT_NAME = "iot-collector-service"
KUBECONFIG = credentials('k8s‑kubeconfig')
SONAR_TOKEN = credentials('sonar‑token')
// 使用git短commit作为镜像标签,便于版本追溯
GIT_COMMIT_SHORT = sh(returnStdout:true, script:'git rev‑parse --short HEAD').trim()
}
stages {
stage('拉取代码') {
steps {
git(
url: 'http://gitlab.example.com/iot-platform/iot-collector-service.git',
branch: 'main',
credentialsId: 'gitlab‑ssh‑credentials'
)
}
}
stage('编译构建') {
steps {
sh 'mvn clean package -DskipTests'
}
post {
success {
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
}
stage('单元测试') {
steps {
sh 'mvn test'
}
post {
always {
junit 'target/surefire‑reports/*.xml'
publishCoverage adapters: [jacocoAdapter('target/site/jacoco/jacoco.xml')], sourceFileResolver: sourceFiles('STORE_LAST_BUILD')
}
}
}
stage('代码质量检查‑SonarQube') {
steps {
sh '''mvn sonar:sonar \
‑Dsonar.projectKey=${PROJECT_NAME} \
‑Dsonar.host.url=http://sonarqube.example.com \
‑Dsonar.login=${SONAR_TOKEN}'''
}
}
stage('构建推送Docker镜像') {
steps {
script {
def imageName = "${DOCKER_REGISTRY}/${PROJECT_NAME}:${GIT_COMMIT_SHORT}"
sh "docker build -t ${imageName} ."
sh "docker push ${imageName}"
}
}
}
stage('部署‑测试环境K8s滚动更新') {
steps {
sh "kubectl set image deployment/${PROJECT_NAME} ${PROJECT_NAME}=${DOCKER_REGISTRY}/${PROJECT_NAME}:${GIT_COMMIT_SHORT} -n test"
sh "kubectl rollout status deployment/${PROJECT_NAME} -n test"
}
}
stage('冒烟测试') {
steps {
sh 'curl -X POST http://test.example.com/api/health-check'
}
}
stage('人工确认‑发布生产环境') {
input {
message: "确认发布生产环境采集服务?"
ok: "确认发布"
}
steps {
sh "kubectl set image deployment/${PROJECT_NAME} ${PROJECT_NAME}=${DOCKER_REGISTRY}/${PROJECT_NAME}:${GIT_COMMIT_SHORT} -n prod"
sh "kubectl rollout status deployment/${PROJECT_NAME} -n prod"
}
}
}
post {
success {
echo "流水线执行成功"
sh '''curl -X POST https://qyapi.weixin.qq.com/cgi‑bin/webhook/send?key=xxx \
‑d '{"msgtype":"text","text":{"content":"IoT采集服务部署成功,镜像版本:${GIT_COMMIT_SHORT}"}}' '''
}
failure {
echo "流水线执行失败,请排查日志"
sh '''curl -X POST https://qyapi.weixin.qq.com/cgi‑bin/webhook/send?key=xxx \
‑d '{"msgtype":"text","text":{"content":"IoT采集服务流水线执行失败,请查看Jenkins日志!"}}' '''
}
}
}.gitlab‑ci.yml)小团队无需维护 Jenkins,可以直接使用 GitLab 内置 Runner,下面为简化示例。
stages:
- build
- test
- deploy
build_job:
stage: build
image: maven:3.8‑openjdk‑17
script:
- mvn clean package -DskipTests
artifacts:
paths:
- target/*.jar
test_job:
stage: test
image: maven:3.8‑openjdk‑17
script:
- mvn test
artifacts:
reports:
junit: target/surefire‑reports/*.xml
deploy_job:
stage: deploy
image: bitnami/kubectl:latest
script:
- kubectl set image deployment/iot-collector-service iot-collector-service=harbor.example.com/iot-collector-service:${CI_PIPELINE_ID} -n prod
only:
- main选型建议:
x509: certificate signed by unknown authoritydocker push报证书不信任。/etc/docker/daemon.json{
"insecure‑registries": ["harbor.example.com"]
}修改完成重启 Docker 服务。
kubectl set image提示没有部署权限。edit角色 RoleBinding,赋予 Jenkins 账号对应命名空间部署权限。apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins‑sa
namespace: test
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: jenkins‑rolebinding
namespace: test
subjects:
‑ kind: ServiceAccount
name: jenkins‑sa
namespace: test
roleRef:
kind: Role
name: edit
apiGroup: rbac.authorization.k8s.io@SpringBootTest加载完整 Spring 上下文,测试用例内部模拟设备连接存在死锁。@MockBean做单元 Mock,减少 MQTT、Modbus 模拟客户端长连接,避免完整启动采集上下文,缩短测试耗时。Jenkins+GitLab CI/CD 架构解决了传统手工上线的人为失误、交付效率低下问题,实现从代码提交、质量校验、制品构建到 K8s 部署的全链路自动化。对于工业物联网这类对接大量现场终端的系统,稳定、可追溯的发布流程尤为关键。但 CI/CD 只是 DevOps 体系一环,还需要配套监控告警、日志体系、故障回滚方案,形成完整研发运维闭环。
选型上不要盲目追求工具堆砌,小团队优先 GitLab CI 降低维护负担;业务复杂、多工具链场景引入 Jenkins,依据业务规模选择最合适的方案,以解决团队实际痛点为目标。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。