第三章 持续集成基础: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,记得监控磁盘

基础配置

登录后,我建议先做这几件事:

  1. 安装推荐插件:选择「安装推荐的插件」,省心
  2. 创建管理员用户:别用默认的admin账号,不安全
  3. 配置全局工具:在「系统管理 → 全局工具配置」里添加Git、CMake、交叉编译工具链
  4. 配置邮件通知:构建失败时能收到邮件提醒

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和测试结合起来,才是真正的生产力。

课后练习:

  1. 在自己的开发机上安装Jenkins,配置一个简单的嵌入式编译任务
  2. 注册一个GitLab Runner,用shell执行器跑通第一个流水线
  3. 尝试在.gitlab-ci.yml里添加代码静态检查步骤