2、DevOps基础:CI/CD流水线概念、版本控制(Git),自动化构建与部署

好,咱们进入正题。这一章聊的是DevOps最核心的骨架——CI/CD流水线。说白了,就是让代码从你本地跑到生产环境的那条路。我见过太多团队,代码写得很漂亮,但上线全靠手搓,结果每次发布都像在拆弹。嗯,咱们今天就把这条路铺平。

2.1 CI/CD流水线:从代码到交付的自动化高速公路

先说说CI/CD到底是什么。CI,持续集成,意思是开发人员频繁地把代码合并到主干,每次合并都自动跑构建和测试。CD,持续交付/持续部署,意思是每次通过测试的代码,都能自动部署到目标环境。

我个人习惯把流水线想象成一条传送带。你放上去一个代码提交,传送带自动帮你编译、测试、打包、部署。中间任何一环出问题,传送带就停下来报警。我在项目中遇到过最典型的场景:一个团队每天手动部署,上线前发现少了个配置文件,结果回滚花了两个小时。后来上了流水线,这种低级错误再也没出现过。

核心要点:CI/CD不是工具,是流程。工具只是帮你把流程自动化。

2.2 版本控制(Git):一切自动化的基石

没有版本控制,CI/CD就是空中楼阁。Git是目前的事实标准,没有之一。你想想看,如果代码都靠U盘拷贝,那还谈什么自动化?

2.4.1 Git工作流:选对姿势很重要

我见过最混乱的Git用法,就是所有人都在master上直接提交。那场面,简直像菜市场。我个人推荐两种主流工作流:

  • GitFlow:适合有固定发布周期的项目。有master、develop、feature、release、hotfix分支,结构清晰但稍显复杂。
  • Trunk-Based Development:适合追求快速迭代的团队。所有人在主干上开发,通过特性开关控制功能发布。我在做硬件在环测试时,经常用这种方式,因为测试环境需要快速同步最新代码。

我的建议:如果你的团队小于10人,用Trunk-Based Development就够了。分支太多反而增加管理成本。

2.4.2 提交规范:让流水线读懂你的意图

为什么提交规范重要?因为CI/CD流水线需要根据提交信息决定触发什么操作。比如,提交信息里带[skip ci],流水线就不跑。我曾经见过一个团队,提交信息全是"fix bug"、"update",结果想回滚都找不到对应版本。

推荐使用Conventional Commits规范:

feat: 添加硬件在环测试接口
fix: 修复GPIO读取超时问题
docs: 更新API文档
chore: 升级依赖库版本

这样流水线就能根据前缀自动判断:feat触发完整测试,docs只触发文档构建,效率高很多。

2.3 自动化构建:把代码变成可运行的产物

构建,就是把源代码变成可执行文件、镜像或者部署包。在硬件在环测试场景里,构建尤其重要,因为你可能需要交叉编译——在x86机器上编译出ARM架构的程序。

2.3.1 构建工具选型

语言/场景 推荐工具 我的经验
Java Maven / Gradle Maven稳定,Gradle灵活
Python Poetry / Pipenv Poetry的依赖解析更靠谱
C/C++(嵌入式) CMake + Make 交叉编译必须用CMake
容器化 Docker 硬件在环测试强烈推荐

避坑指南:我曾经在构建脚本里写死了绝对路径,结果换到CI服务器上全崩了。记住,所有路径都要用相对路径或者环境变量。

2.3.2 构建脚本示例

一个典型的Docker构建脚本,用于硬件在环测试环境:

# Dockerfile
FROM ubuntu:22.04 AS builder
WORKDIR /app
COPY . .
RUN apt-get update && apt-get install -y gcc-arm-none-eabi cmake
RUN cmake -B build -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
RUN cmake --build build

FROM ubuntu:22.04 AS runtime
COPY --from=builder /app/build/firmware.bin /firmware/
CMD ["/firmware/firmware.bin"]

这个例子展示了多阶段构建。第一阶段编译,第二阶段只放产物。这样最终镜像小很多,部署也快。

2.4 自动化部署:把产物送到该去的地方

部署,就是把构建好的产物放到目标环境里运行。对于硬件在环测试,目标环境可能是真实的硬件设备,也可能是仿真器。

2.4.1 部署策略

  • 蓝绿部署:同时维护两套环境,切换流量。适合不能中断的服务。
  • 滚动更新:逐个替换实例。适合集群部署。
  • 金丝雀发布:先让一小部分用户用新版本,没问题再全量。我在项目中用这个策略测试固件更新,先刷一台设备,观察半小时再刷全部。

2.4.2 部署到硬件设备

硬件在环测试的部署和普通软件不一样。你不能直接SSH上去装包,通常需要通过特定接口刷写固件。举个例子:

# 部署脚本示例
#!/bin/bash
# 通过JTAG接口刷写固件到STM32设备
openocd -f interface/stlink.cfg \
        -f target/stm32f4x.cfg \
        -c "program build/firmware.hex verify reset exit"

嗯,这里要注意,刷写固件前一定要确认设备连接正常。我曾经因为USB线接触不良,刷写到一半断连,设备直接变砖。后来我加了前置检查:

# 检查设备是否在线
if ! openocd -f interface/stlink.cfg -c "init; exit" 2>/dev/null; then
    echo "设备未连接,请检查JTAG线缆"
    exit 1
fi

关键原则:自动化部署要幂等。也就是说,不管跑多少次,结果都一样。如果部署到一半失败了,重跑一次应该能恢复。

2.5 完整的CI/CD流水线示例

最后,咱们看一个完整的流水线配置。以GitLab CI为例:

stages:
  - build
  - test
  - deploy

build-job:
  stage: build
  script:
    - cmake -B build -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
    - cmake --build build
  artifacts:
    paths:
      - build/firmware.bin

test-job:
  stage: test
  script:
    - python3 run_hil_tests.py --firmware build/firmware.bin
  dependencies:
    - build-job

deploy-job:
  stage: deploy
  script:
    - ./flash_device.sh build/firmware.bin
  dependencies:
    - build-job
  only:
    - master

这个流水线做了三件事:构建固件、在硬件在环平台上跑测试、通过测试后部署到设备。注意,只有master分支的提交才会触发部署,这是为了防止把开发中的代码刷到生产设备上。

好了,这一章的内容就这些。记住,CI/CD流水线不是一蹴而就的,需要根据团队和项目的实际情况不断调整。下一章咱们聊聊硬件在环测试平台的具体搭建,到时候会用到今天讲的这些自动化知识。