第三章 持续集成基础:CI/CD概念解析、Jenkins安装与配置、GitLab CI Runner注册、第一个嵌入式CI流水线搭建
3.1 CI/CD到底是什么?别被概念吓到
说实话,我刚入行那会儿,听到CI/CD这几个字母就觉得高大上。后来做嵌入式项目踩了不少坑,才真正理解它的价值。
CI,全称是持续集成。说白了,就是让开发人员频繁地把代码合并到主干。我以前带的一个团队,大家各写各的,两周才合一次代码。结果呢?合并那天简直是灾难,冲突多到让人崩溃。CI就是要解决这个问题——每次提交代码,自动编译、自动测试,有问题立刻发现。
CD有两个意思:持续交付和持续部署。持续交付是说,代码随时可以发布到生产环境。持续部署更激进,代码通过测试后自动部署。我个人习惯在嵌入式项目里做到持续交付就够了,毕竟硬件环境复杂,全自动部署风险不小。
核心要点:
- CI:频繁合并代码 + 自动构建测试
- CD:持续交付(随时可发布)或持续部署(自动发布)
- 嵌入式场景:CI是刚需,CD看项目成熟度
3.2 Jenkins安装与配置——我踩过的坑
Jenkins是我用得最多的CI工具。为什么选它?插件生态丰富,社区活跃,而且免费。嗯,这里要注意,Jenkins对Java环境有依赖,版本别搞错了。
安装步骤(以Ubuntu 20.04为例)
# 1. 安装Java 11(Jenkins 2.346.x需要)
sudo apt update
sudo apt install openjdk-11-jdk -y
# 2. 添加Jenkins仓库
wget -q -O - https://pkg.jenkins.io/debian-stable/jenkins.io.key | sudo apt-key add -
sudo sh -c 'echo deb https://pkg.jenkins.io/debian-stable binary/ > /etc/apt/sources.list.d/jenkins.list'
# 3. 安装Jenkins
sudo apt update
sudo apt install jenkins -y
# 4. 启动并设置开机自启
sudo systemctl start jenkins
sudo systemctl enable jenkins
安装完成后,访问 http://你的IP:8080。第一次登录需要初始密码,位置在 /var/lib/jenkins/secrets/initialAdminPassword。
我曾经踩过的坑:
- Java版本不匹配:Jenkins 2.346要求Java 11,用Java 8会报错
- 防火墙没开8080端口:折腾了半天才发现是网络问题
- 磁盘空间不足:Jenkins默认把构建产物放/var/lib/jenkins,记得监控磁盘
基础配置
登录后,我建议先做这几件事:
- 安装推荐插件:选择「安装推荐的插件」,省心
- 创建管理员用户:别用默认的admin账号,不安全
- 配置全局工具:在「系统管理 → 全局工具配置」里添加Git、CMake、交叉编译工具链
- 配置邮件通知:构建失败时能收到邮件提醒
3.3 GitLab CI Runner注册——让嵌入式编译跑起来
GitLab自带的CI功能其实很强大。Runner是执行任务的工作节点。我习惯在嵌入式开发板上直接注册Runner,这样编译出来的二进制文件就是目标架构的。
注册Runner的步骤
# 1. 安装GitLab Runner(以ARM架构为例)
sudo curl -L --output /usr/local/bin/gitlab-runner \
https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-arm
sudo chmod +x /usr/local/bin/gitlab-runner
# 2. 注册Runner
sudo gitlab-runner register
# 3. 按提示输入:
# - GitLab实例URL(比如 https://gitlab.com/)
# - 注册令牌(在项目Settings → CI/CD → Runners里找)
# - Runner描述(比如 "stm32-build-runner")
# - 标签(比如 "stm32, arm")
# - 执行器(选 "shell" 最直接)
我的经验:
- 嵌入式项目建议用shell执行器,简单直接
- Runner标签要起好名字,方便在.gitlab-ci.yml里指定
- 如果编译环境复杂,可以用Docker执行器,但ARM架构的Docker镜像需要自己构建
3.4 第一个嵌入式CI流水线——从零到一
好了,理论讲完了,咱们动手写一个真正的嵌入式CI流水线。以STM32项目为例,用GitLab CI实现自动编译。
项目结构
my_stm32_project/
├── .gitlab-ci.yml # CI配置文件
├── src/
│ └── main.c
├── inc/
│ └── main.h
├── Makefile
└── README.md
编写.gitlab-ci.yml
stages:
- build
- test
build-stm32:
stage: build
tags:
- stm32
script:
- make clean
- make all
artifacts:
paths:
- build/*.hex
- build/*.bin
expire_in: 1 week
test-stm32:
stage: test
tags:
- stm32
script:
- echo "运行单元测试..."
- make test
only:
- master
- develop
你想想看,这个流水线做了什么?
- 每次提交代码,自动触发build任务
- 编译生成的hex和bin文件作为产物保存
- 只有master和develop分支才运行测试
- 测试失败会发邮件通知
Makefile示例(简化版)
CC = arm-none-eabi-gcc
CFLAGS = -mcpu=cortex-m4 -mthumb -O2
TARGET = build/firmware.elf
all: $(TARGET)
$(TARGET): src/main.c
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -rf build/*
test:
@echo "Running tests..."
# 这里可以调用Ceedling或Unity测试框架
避坑指南:
- Makefile里的路径要写对,尤其是交叉编译工具链的路径
- GitLab CI的artifacts要设置过期时间,不然磁盘会爆
- tags要和Runner注册时填的标签一致,否则流水线找不到Runner
3.5 总结与思考
这一章我们走通了嵌入式CI/CD的完整链路。从概念到工具安装,再到第一个流水线跑起来。我个人觉得,最难的不是技术本身,而是养成「每次提交都跑CI」的习惯。
我记得有个项目,团队一开始嫌麻烦,觉得手动编译也挺快。结果有一次,有人改了头文件没通知大家,导致三个人同时编译失败。从那以后,CI就成了团队的铁律。
下一章,我们会深入嵌入式自动化测试框架,聊聊怎么用Ceedling和Unity做单元测试。到时候你会发现,CI和测试结合起来,才是真正的生产力。
课后练习:
- 在自己的开发机上安装Jenkins,配置一个简单的嵌入式编译任务
- 注册一个GitLab Runner,用shell执行器跑通第一个流水线
- 尝试在.gitlab-ci.yml里添加代码静态检查步骤