好的,各位观众,欢迎来到今天的“C++ CI/CD:让你的代码飞起来”讲座!我是今天的讲师,今天我们要聊聊如何让你的C++项目摆脱手动部署的苦海,拥抱自动化,变得高效又可靠。
为什么我们需要CI/CD?
想象一下,你辛辛苦苦写了几个月的C++代码,终于完成了某个激动人心的功能。你信心满满地把代码提交到仓库,然后…
- 手动构建: “嗯,我要打开Visual Studio/CMake/Makefile,手动编译一下…” (内心OS: 编译时间怎么这么长?!)
- 手动测试: “编译完了,我要手动跑一下单元测试,集成测试…” (内心OS: 测试用例又挂了几个,又要debug…)
- 手动部署: “测试通过了,我要把可执行文件/库拷贝到服务器上,重启服务…” (内心OS: 别出错了,别出错了…)
这个过程是不是很熟悉?是不是很痛苦?而且很容易出错,效率低下。
CI/CD 就是来解决这些问题的。它可以自动化构建、测试和部署流程,减少人为错误,提高开发效率,让你可以专注于写代码,而不是折腾部署。
CI/CD 的基本概念
- CI (Continuous Integration,持续集成): 指的是频繁地(最好每天)将代码集成到共享仓库中。每次集成都会触发自动构建和测试,以便尽早发现集成错误。
- CD (Continuous Delivery/Continuous Deployment,持续交付/持续部署): 指的是将代码变更自动地构建、测试并准备好发布到生产环境。持续交付意味着你需要手动批准部署,而持续部署意味着代码变更会自动发布到生产环境。
CI/CD 的流程
一个典型的 CI/CD 流程大致如下:
- 代码提交: 开发者将代码提交到代码仓库(例如 GitHub、GitLab、Bitbucket)。
- 触发构建: 代码仓库会触发 CI/CD 系统开始构建。
- 构建: CI/CD 系统会从代码仓库拉取代码,编译、链接,生成可执行文件或者库。
- 测试: CI/CD 系统会运行各种测试,包括单元测试、集成测试、系统测试等。
- 代码分析: CI/CD 系统会进行代码静态分析,检查代码质量、安全漏洞等。
- 打包: CI/CD 系统会将构建好的程序打包成可部署的格式(例如 Docker 镜像、tarball)。
- 部署: CI/CD 系统会将打包好的程序部署到测试环境、预发布环境或者生产环境。
- 监控: CI/CD 系统会监控部署后的程序,确保其正常运行。
CI/CD 工具选择
市面上有很多 CI/CD 工具可供选择,例如:
- Jenkins: 开源、灵活、可定制性强,但配置较为复杂。
- GitLab CI: GitLab 内置的 CI/CD 系统,与 GitLab 集成紧密,配置简单。
- GitHub Actions: GitHub 内置的 CI/CD 系统,与 GitHub 集成紧密,使用方便。
- Travis CI: 简单易用,与 GitHub 集成紧密,但免费额度有限。
- CircleCI: 功能强大,支持多种语言和平台,但价格较高。
- Azure DevOps: 微软提供的 CI/CD 服务,与 Azure 云平台集成紧密。
选择哪个工具取决于你的项目需求、团队规模和预算。
C++ 项目 CI/CD 实战
下面我们以一个简单的 C++ 项目为例,演示如何使用 GitLab CI 进行 CI/CD。
1. 项目结构
我们的项目非常简单,包含以下文件:
main.cpp
:主程序文件add.h
:加法函数头文件add.cpp
:加法函数实现文件test.cpp
:单元测试文件CMakeLists.txt
:CMake 构建文件
// main.cpp
#include <iostream>
#include "add.h"
int main() {
std::cout << "1 + 2 = " << add(1, 2) << std::endl;
return 0;
}
// add.h
#ifndef ADD_H
#define ADD_H
int add(int a, int b);
#endif
// add.cpp
#include "add.h"
int add(int a, int b) {
return a + b;
}
// test.cpp
#include "gtest/gtest.h"
#include "add.h"
TEST(AddTest, PositiveNumbers) {
ASSERT_EQ(add(1, 2), 3);
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
// CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(cpp_ci_cd)
set(CMAKE_CXX_STANDARD 14)
# Add GoogleTest
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG release-1.10.0
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
add_executable(cpp_ci_cd main.cpp add.cpp)
enable_testing()
add_executable(test test.cpp add.cpp)
target_link_libraries(test gtest_main)
include(GoogleTest)
gtest_discover_tests(test)
2. GitLab CI 配置 (.gitlab-ci.yml)
在项目根目录下创建一个名为 .gitlab-ci.yml
的文件,这是 GitLab CI 的配置文件。
stages:
- build
- test
- deploy
build:
stage: build
image: ubuntu:latest # 使用 Ubuntu 镜像
before_script:
- apt-get update -y
- apt-get install -y cmake g++ # 安装构建工具
script:
- mkdir build
- cd build
- cmake ..
- make # 构建项目
artifacts:
paths:
- build/cpp_ci_cd # 上传构建产物
test:
stage: test
image: ubuntu:latest
before_script:
- apt-get update -y
- apt-get install -y cmake g++ libgtest-dev # 安装测试工具
script:
- mkdir build
- cd build
- cmake ..
- make
- ./test # 运行测试
dependencies:
- build
deploy:
stage: deploy
image: ubuntu:latest
before_script:
- apt-get update -y
- apt-get install -y openssh-client # 安装 ssh 客户端
script:
- echo "Deploying to server..."
- apt-get install -y zip #安装zip压缩工具
- cd build
- zip -r cpp_ci_cd.zip cpp_ci_cd # 压缩文件
- sshpass -p "your_password" scp cpp_ci_cd.zip your_user@your_server:/path/to/deploy/ # 使用 sshpass 传输文件 替换为你的密码,用户名,服务器地址
- ssh your_user@your_server "unzip /path/to/deploy/cpp_ci_cd.zip -d /path/to/deploy/" # 使用 ssh 解压文件
- ssh your_user@your_server "chmod +x /path/to/deploy/cpp_ci_cd" # 添加执行权限
- ssh your_user@your_server "nohup /path/to/deploy/cpp_ci_cd &" # 后台运行程序
dependencies:
- build
only:
- main # 只在 main 分支上部署
.gitlab-ci.yml
文件详解
stages
: 定义 CI/CD 的阶段,例如build
、test
、deploy
。build
: 定义构建阶段的配置。stage
:指定阶段为build
。image
:指定使用的 Docker 镜像,这里使用ubuntu:latest
。before_script
:在执行script
之前执行的脚本,这里安装了构建工具cmake
和g++
。script
:构建脚本,包括创建构建目录、使用 CMake 生成 Makefile、使用 make 构建项目。artifacts
:定义构建产物,这里上传了构建好的可执行文件build/cpp_ci_cd
。
test
: 定义测试阶段的配置。stage
:指定阶段为test
。image
:指定使用的 Docker 镜像,这里使用ubuntu:latest
。before_script
:在执行script
之前执行的脚本,这里安装了测试工具cmake
、g++
和libgtest-dev
。script
:测试脚本,包括创建构建目录、使用 CMake 生成 Makefile、使用 make 构建项目、运行测试。dependencies
:指定依赖的阶段,这里依赖build
阶段,表示只有build
阶段成功后才会执行test
阶段。
deploy
: 定义部署阶段的配置。stage
:指定阶段为deploy
。image
:指定使用的 Docker 镜像,这里使用ubuntu:latest
。before_script
:在执行script
之前执行的脚本,这里安装了openssh-client
。script
:部署脚本,这里使用scp
将构建好的可执行文件拷贝到远程服务器,并重启服务。(请注意,这里使用了sshpass
,这在生产环境中是不安全的,应该使用 SSH 密钥进行身份验证。)dependencies
:指定依赖的阶段,这里依赖build
阶段,表示只有build
阶段成功后才会执行deploy
阶段。only
:指定只在main
分支上执行部署。
3. 配置 GitLab Runner
要让 GitLab CI 运行你的 CI/CD 流程,你需要配置 GitLab Runner。 GitLab Runner 是一个独立的应用程序,它负责执行 .gitlab-ci.yml
中定义的任务。
- 安装 GitLab Runner: 按照 GitLab 官方文档安装 GitLab Runner。
- 注册 GitLab Runner: 使用
gitlab-runner register
命令注册 GitLab Runner,你需要提供 GitLab 实例 URL 和注册令牌。注册令牌可以在 GitLab 项目的 "Settings" -> "CI/CD" -> "Runners" 中找到。 - 配置 Runner 执行器: 在注册 GitLab Runner 时,你需要选择一个执行器。常用的执行器有
shell
、docker
、kubernetes
等。这里我们选择shell
执行器。
4. 提交代码并观察 CI/CD 流程
将你的代码提交到 GitLab 仓库,GitLab CI 会自动触发 CI/CD 流程。你可以在 GitLab 项目的 "CI/CD" -> "Pipelines" 中查看 CI/CD 流程的执行状态。
一些优化建议
- 使用 Docker 镜像: 使用 Docker 镜像可以确保构建环境的一致性,避免因为环境差异导致的问题。
- 缓存依赖: 使用缓存可以加速构建过程,例如缓存 apt 包、Maven 依赖等。
- 并行构建: 将构建任务分解成多个并行任务,可以缩短构建时间。
- 使用 SSH 密钥: 使用 SSH 密钥进行身份验证,避免在脚本中硬编码密码。
- 自动化测试: 编写完善的自动化测试用例,确保代码质量。
- 监控和告警: 监控 CI/CD 流程的执行状态,及时发现和解决问题。
C++ 项目 CI/CD 的一些挑战
- 构建时间长: C++ 项目的编译时间通常比较长,可以使用缓存、并行构建等技术来优化构建时间。
- 依赖管理: C++ 项目的依赖管理比较复杂,可以使用 Conan、vcpkg 等包管理工具来简化依赖管理。
- 跨平台构建: C++ 项目需要支持多个平台,可以使用 CMake 等构建工具来生成不同平台的构建文件。
- 测试框架: 选择合适的 C++ 测试框架,例如 Google Test、Catch2 等。
总结
CI/CD 可以极大地提高 C++ 项目的开发效率和代码质量。虽然配置 CI/CD 流程需要一些时间和精力,但它可以带来长期的回报。希望今天的讲座能帮助你入门 C++ CI/CD,让你的代码飞起来!
代码示例补充说明
- 关于
sshpass
的安全问题: 我必须再次强调,在deploy
阶段使用sshpass
只是为了演示方便。在生产环境中,绝对不能 直接在脚本中硬编码密码。更安全的方法是使用 SSH 密钥进行身份验证。你可以生成 SSH 密钥对,并将公钥添加到服务器的~/.ssh/authorized_keys
文件中。然后,在 GitLab CI 中配置私钥,用于 SSH 连接。 - 关于部署策略:
deploy
阶段的部署策略非常简单,只是将可执行文件拷贝到服务器并重启服务。在实际项目中,你可能需要更复杂的部署策略,例如蓝绿部署、滚动更新等。 - 关于错误处理: 示例中的
.gitlab-ci.yml
文件没有包含完善的错误处理机制。在实际项目中,你应该添加错误处理逻辑,例如在构建、测试或部署失败时发送告警。
表格总结常用命令及解释
命令 | 解释 |
---|---|
apt-get update -y |
更新 apt 包索引。-y 选项表示自动确认所有提示。 |
apt-get install -y <package> |
安装指定的软件包。-y 选项表示自动确认所有提示。 |
cmake .. |
在构建目录中运行 CMake,生成构建文件(例如 Makefile)。.. 表示 CMakeLists.txt 文件位于上一级目录。 |
make |
使用 Makefile 构建项目。 |
./test |
运行可执行文件 test ,执行单元测试。 |
sshpass -p "password" scp ... |
使用 sshpass 工具,通过 SSH 协议拷贝文件。-p "password" 选项指定 SSH 密码。请注意,在生产环境中不建议使用 sshpass ,应该使用 SSH 密钥。 |
ssh user@server "command" |
通过 SSH 协议连接到远程服务器,并执行指定的命令。 |
unzip file.zip -d /path/to/extract |
解压 zip 文件到指定的目录。 |
chmod +x /path/to/executable |
为指定的可执行文件添加执行权限。 |
nohup /path/to/executable & |
在后台运行指定的可执行文件。nohup 命令可以防止程序在终端关闭后退出。& 符号表示将程序放入后台运行。 |
zip -r cpp_ci_cd.zip cpp_ci_cd |
压缩文件,-r 表示递归压缩目录. |
Q&A 环节
现在是提问环节,大家有什么问题可以提出来,我会尽力解答。
谢谢大家!