引言:一个实习生的工程化觉醒
2024年7月8日,我开始了在前端开发领域的实习生涯。加入了一家致力于云产品服务创新的开发公司,很快发现公司在工程化方面存在诸多不完善之处------项目缺乏统一的CI/CD工作流,团队协作时各种奇怪问题频发,代码规范执行也不够严格。这成为了我接触前端工程化的契机,也是我职业生涯中第一次系统性地搭建CI/CD流水线。
起初,这个任务对我来说既陌生又枯燥。和大多数刚入行的开发者一样,我的关注点一直局限在业务代码开发上,对工程化知之甚少。但当Leader给出"一周内完成所有配置"的要求时,我不得不快速进入状态,啃 了两天的GitLab CI/CD pipeline 熟悉了配置相关的文档,包括每一个配置对象的作用以及使用都理解了一遍。同时通过博客也做了很多了解。开启了这段充满挑战的研究之路。
一、CI/CD基础认知
1.1 什么是CI/CD?
CI(持续集成,Continuous Integration)是指开发人员频繁地将代码变更合并到共享主干(通常每天多次),每次合并都会触发自动化构建和测试流程。
CD 持续交付(Continuous Delivery)和持续部署(Continuous Deployment),前者确保代码可以随时安全地部署到生产环境,后者则自动将变更部署到生产环境。
1.2 为什么需要CI/CD?
在传统开发模式中,我常遇到以下问题:
- "在我机器上是好的"------环境差异导致的问题
- 代码合并冲突频发
- 质量问题到项目后期才暴露
- 手动部署容易出错
CI/CD通过自动化解决了这些问题,带来了以下优势:
- 快速反馈:代码提交后立即获得构建和测试结果
- 质量保障:通过自动化测试和代码检查保证代码质量
- 降低风险:小批量频繁集成减少大规模冲突风险
- 提高效率:自动化流程解放开发者生产力
二、GitLab CI/CD核心概念
2.1 Pipeline基础结构
GitLab CI/CD的核心是.gitlab-ci.yml
配置文件,它定义了整个流水线的结构和行为。一个典型的Pipeline包含:
yaml
stages:
- verify # 前置检查阶段
- package # 构建阶段
- release # 部署阶段
job1:
stage: verify
script:
- echo "运行前置检查"
job2:
stage: package
script:
- echo "运行构建"
2.2 Runner与执行环境
Runner是执行Pipeline作业的代理,支持多种执行环境:
- Shell Runner:直接在主机上执行
- Docker Runner:在容器中执行(推荐)
- Kubernetes Runner:在K8s集群中执行(适合大规模部署)
我们选择了Kubernetes Runner(腾讯云Serverless集群),因为它提供了良好的隔离性和可扩展性。
三、代码提交阶段的规范化
3.1 Git Hook与Husky
Git Hook是Git在特定事件(如提交、推送)发生时自动运行的脚本。我们使用Husky来更便捷地管理Git Hook。
配置步骤:
- 安装Husky:
css
npm install --save-dev husky
- 在package.json中添加prepare脚本:
json
{
"scripts": {
"prepare": "husky install"
}
}
3.2 预提交检查(Pre-commit)
我们在.husky目录下创建pre-commit钩子,确保每次提交前都通过代码检查和测试:
bash
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run lint # 代码风格检查
npm run test # 单元测试
3.3 提交信息规范(Commitlint)
统一的提交信息格式让项目历史更清晰,也为自动化处理提供基础。我们使用commitlint来强制执行规范:
- 安装依赖:
scss
npm install --save-dev @commitlint/config-conventional @commitlint/cli
- 配置commitlint.config.js:
java
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'revert', 'build', 'chore', 'ci', 'perf'],
],
'type-case': [2, 'always', 'lowerCase'],
'type-empty': [2, 'never'],
'subject-full-stop': [2, 'never', '.'],
},
};
- 创建commit-msg钩子:
bash
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx commitlint --edit "$1"
- 设置执行权限:
bash
chmod 755 .husky/commit-msg
这样配置后,不符合规范的提交信息会被拒绝,例如:
bash
⧗ input: chore123: test
✖ type must be one of [feat, fix, docs, style, refactor, test, revert, build, ci, perf] [type-enum]
规范提交:
sql
git commit -m "feat: 添加提交信息"
四、代码合并阶段的自动化检查
4.1 代码质量报告集成
GitLab支持基于Code Climate规范的代码质量报告。我们配置了ESLint和Stylelint生成符合规范的报告:
- 在package.json中添加脚本:
css
{
"scripts": {
"lint:script:ci": "eslint --ext .tsx,.ts --format gitlab ./src",
"lint:style:ci": "stylelint src/*.{css,less} src/**/*.{css,less} --custom-formatter=node_modules/stylelint-formatter-gitlab"
},
"devDependencies": {
"eslint-formatter-gitlab": "3.0.0",
"stylelint-formatter-gitlab": "1.0.1"
}
}
- 配置.gitlab-ci.yml:
yaml
stages:
- verify
- package
- release
lint-job:
stage: verify
allow_failure: false
image: XXX
variables:
ESLINT_CODE_QUALITY_REPORT: gl-codequality-script.json
STYLELINT_CODE_QUALITY_REPORT: gl-codequality-style.json
script:
- npm i
- npm run lint:script:ci & lint:style:ci
- npx deepmerge-cli gl-codequality-script.json gl-codequality-style.json > gl-codequality.json
artifacts:
name: "$CI_JOB_NAME-$CI_JOB_STAGE-$CI_COMMIT_SHORT_SHA-$CI_COMMIT_TIMESTAMP"
when: always
reports:
codequality: gl-codequality.json
only:
- merge_requests
- main
- tags
tags:
- k8s
sonarqube-check:
stage: verify
allow_failure: false
image:
name: XXX
entrypoint: [""]
variables:
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar"
GIT_DEPTH: "0"
cache:
key: "${CI_JOB_NAME}"
paths:
- .sonar/cache
script:
- sonar-scanner
only:
- merge_requests
- main
- tags
tags:
- k8s
关键点说明:
verify
是特殊阶段,会在其他阶段前运行- 同时运行了检查任务和合并报告任务
artifacts:reports:codequality
将报告上传到GitLab,在MR界面进行展示
4.2 单元测试与覆盖率
配置了Jest测试框架,并生成测试报告和覆盖率数据:
- 安装依赖:
css
npm install jest-junit --save-dev
- 配置测试脚本:
less
{
"scripts": {
"test:ci": "tsdx test --ci --reporters=default --reporters=jest-junit --coverage --coverage-reporters=cobertura --coverage-reporters=text --coverage-reporters=text-summary"
}
}
- 配置 .gitlab-ci.yml:
yaml
unit-test-job:
script:
- npm run test:ci
artifacts:
reports:
junit: junit.xml
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
coverage: /Statements\s*:\s*(\d+.?\d*)%.*/
4.3 安全扫描
GitLab提供了内置的安全扫描功能,我们启用了以下检查:
yaml
sast-job:
stage: test
script:
- echo "运行SAST扫描..."
artifacts:
reports:
sast: gl-sast-report.json
secret-detection-job:
stage: test
script:
- echo "运行泄密检测..."
artifacts:
reports:
secret_detection: gl-secret-detection-report.json
五、构建与部署自动化
5.1 多环境构建策略
为不同环境配置了不同的构建策略:
bash
build-job:
stage: package
allow_failure: false
image: XXX
script:
- npm i
- npm run build
- echo $IMAGE_NAME:$IMAGE_TAG
- docker -v
- docker build --rm --no-cache -t $IMAGE_NAME:$IMAGE_TAG `pwd`
- docker push $IMAGE_NAME:$IMAGE_TAG
only:
- tags
tags:
- k8s
5.2 自动化部署
部署配置根据环境有所不同:
yaml
deploy-job:
stage: release
allow_failure: false
image: XXX
script:
- sed -i "s/xxx/${IMAGE_TAG}/g" .kube/serverless.yml
- export KUBECONFIG=`pwd`/.kube/config
- kubectl delete -f .kube/serverless.yml || true
- kubectl apply -f .kube/serverless.yml
only:
- tags
tags:
- k8s
environment:
name: dev
url: $APP_DOMAIN
六、经验总结与最佳实践
6.1 实施过程中的挑战
- 基础分支问题:当目标分支(如master)没有运行过代码质量检查时,MR会比较失败。解决方案是确保主分支至少运行一次完整的Pipeline。
- 缓存问题:在K8s环境中,缓存路径必须使用相对路径,否则不同Runner实例间无法共享缓存。
- 并行任务协调 :使用
&
和wait
实现并行任务时,需要注意任务间的资源竞争。
6.2 推荐的最佳实践
- 渐进式采用:从最基本的lint和test开始,逐步添加更复杂的检查。
- 失败快速:将最重要的检查放在前面,尽早发现问题。
- 可视化反馈:充分利用GitLab的报告功能,让问题一目了然。
- 文档化:记录此次的CI/CD搭建指南,降低后续的学习成本。
七、未来规划
- 研究自动化回滚,当监控发现问题时自动回滚到上一个稳定版本。
- 探索cicd 配置如何集成可复用的工具,避免每个项目需要自动化测试时都做重复的配置。
结语
从对CI/CD一无所知到最后完整的搭建了工作流,现在回头看,这段经历真的让我成长不少,既艰难又充满成就感。深刻认识到工程化对团队开发效率的重要性。一个好的CI/CD系统就像交通信号灯,虽然建设时需要投入,但一旦运行起来,就能让整个开发流程有序且高效。
好了,我的分享就到这里啦! 目前加入了新公司,带我的导师一直鼓励我多总结,将自己的产出留痕,以便于感知自己的收获,并且通过发布文章,分享自己的经历也能和更多人交流学习,开发之路永远需要保持开放的心态。
所以今天就把之前搭建CI/CD的过程整理一下,既是对自己的复盘,也希望本文能帮到在探索前端工程化或者有同样需求的小伙伴噢~