- 基本任务: 实现单体系统的CI/CD流水线构建与测试
在本地搭建CI/CD流水线,实现软件工程基础课程系统代码到本地K8S环境的持续集成与部署(Docker Desktop自带),最低要求利用包管理工具进行本地单元测试、项目构建、容器化和本地部署,也推荐容器化搭建本地流水线如Jenkins,有具体要求如下:- 确保每个函数至少存在正反两个单元测试用例,构建时自动进行测试
- 前端、后端与数据库单独容器化
- 容器化后自动部署到本地K8S环境中
- 运行之后用测试工具进行集成测试(用例级别) 注:可用Postman直接集成测试后端,也可使用GUI测试工具进行前段的集成测试
- 原料检查(单元测试):确保每个零件(函数)都是合格的。
- 产品打包(容器化):把检查好的零件(代码)分别打包进三个标准化的“集装箱”(Docker 容器)里,分别是前端、后端和数据库。
- 自动化物流(CI/CD 流水线):有一条传送带(Jenkins 或 GitHub Actions),自动完成检查、打包的工作。
- 部署上架(部署到 K8S):用一台智能吊车(Kubernetes),把三个“集装箱”精准地放到商场货架(本地 K8S 环境)上,并让它们之间能互相找到。
- 最终质检(集成测试):商场经理(你)用工具(Postman)测试整个商品是否工作正常。
下面我们来详细走通每一个环节。
第一步:准备工作(安装必要的软件)
工欲善其事,必先利其器。你需要先在本地电脑上安装好以下软件:
- Docker Desktop:这是核心。它不仅能帮你构建和运行容器,还自带了我们需要用的本地 Kubernetes 集群。
- 安装后务必:打开 Docker Desktop,进入
Settings -> Kubernetes,勾选Enable Kubernetes,然后点击Apply & Restart。这会花点时间,耐心等待它变成绿色的Kubernetes is running。
- 安装后务必:打开 Docker Desktop,进入
- Git:用于代码版本管理。
- JDK 和 Maven/Gradle:因为你的是 Spring Boot 项目,需要 Java 环境和构建工具。
- (可选但推荐)Jenkins:如果你想体验“容器化搭建本地流水线”,可以安装 Jenkins。最简单的方式就是通过 Docker 来运行它:
docker run -p 8080:8080 -p 50000:50000 jenkins/jenkins:lts。安装好后,访问http://localhost:8080进行初始设置。
第二步:原料检查 - 编写单元测试
目标:确保每个函数至少有正反(正确输入和错误输入)两个测试用例,并且构建时能自动运行。
-
怎么做:
- 在你的 Spring Boot 后端项目中,找到
src/test/java目录。这里就是放所有测试代码的地方。 - 通常你会为
src/main/java里的每个主要类(如UserService,OrderController)创建一个对应的测试类(如UserServiceTest,OrderControllerTest)。 - 使用 JUnit 和 Mockito(Spring Boot 已经默认集成了)来写测试。
- 正面用例:输入正确的参数,验证输出是否是你期望的结果。
- 反面用例:输入错误的参数(如一个不存在的用户ID),验证程序是否如你预期的那样抛出了异常或返回了错误信息。
- 在你的 Spring Boot 后端项目中,找到
-
通俗理解:就像你写了一个加法函数
add(int a, int b)。正面用例是add(1, 2),你期望结果是3。反面用例是add(null, 2),你期望它抛出一个“参数不能为空”的异常。 -
检查:在项目根目录下运行
mvn test或./gradlew test,如果所有测试都通过,说明这一步成功了。
第三步:产品打包 - 编写 Dockerfile 容器化
目标:为前端、后端、数据库分别编写 Dockerfile 文件,把它们做成独立的镜像。
-
后端(Spring Boot)的 Dockerfile:
# 使用一个轻量级的 Java 基础镜像 FROM openjdk:17-jdk-slim # 在容器内部创建一个目录来存放你的应用 WORKDIR /app # 将Maven构建好的jar包复制到容器内 # 假设你的jar包名叫 `myapp-0.0.1-SNAPSHOT.jar` COPY target/myapp-0.0.1-SNAPSHOT.jar app.jar # 告诉Docker容器运行时需要暴露的端口(和你的Spring Boot应用端口一致) EXPOSE 8080 # 启动应用的命令 ENTRYPOINT ["java", "-jar", "app.jar"] -
数据库(MySQL)的 Dockerfile:
- 通常数据库我们直接使用官方镜像,不需要自己写很复杂的 Dockerfile。但为了数据持久化,我们需要一些配置。
FROM mysql:8.0 # 设置数据库环境变量(密码、库名等) ENV MYSQL_ROOT_PASSWORD=my-secret-pw ENV MYSQL_DATABASE=mydatabase # 将你本地的数据库初始化脚本复制到容器中 COPY ./init.sql /docker-entrypoint-initdb.d/- 你需要一个
init.sql文件来创建表、插入初始数据。
-
前端(React/Vue)的 Dockerfile:
# 构建阶段:使用Node.js镜像来编译前端代码 FROM node:lts-alpine as build-stage WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build # 生产阶段:使用Nginx来提供编译好的静态文件 FROM nginx:stable-alpine COPY /app/dist /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
- 通俗理解:
Dockerfile就是一个说明书,告诉 Docker 如何把你的代码、环境、命令一步步组合成一个完整的、可运行的“集装箱”(镜像)。
第四步:自动化物流 - 构建 CI/CD 流水线
这里有两个主流选择,任选其一即可:
方案A:使用 Jenkins(容器化流水线)
- 启动 Jenkins 容器。
- 访问
localhost:8080,安装推荐的插件。 - 创建一个新的任务(Job),选择“流水线(Pipeline)”。
- 在你的代码仓库根目录创建一个
Jenkinsfile文件。这个文件定义了流水线的所有步骤。 - Jenkinsfile 核心步骤:
pipeline { agent any stages { stage('Build') { steps { // 1. 拉取代码 git 'https://github.com/your-name/your-repo.git' // 2. 运行单元测试并打包 sh 'mvn clean package' } } stage('Build Docker Images') { steps { // 3. 根据Dockerfile构建镜像 sh 'docker build -t my-backend-app ./backend' sh 'docker build -t my-frontend-app ./frontend' // ...数据库镜像 } } stage('Deploy to K8S') { steps { // 4. 应用K8S配置文件,部署到集群 sh 'kubectl apply -f k8s-deployment.yaml' } } } } - 在 Jenkins 任务中配置好这个
Jenkinsfile的路径,然后点击“构建”。你就会看到流水线自动运行了!
方案B:使用 GitHub Actions(更简单,直接集成在GitHub中)
-
在代码仓库根目录创建
.github/workflows/ci-cd.yml文件。 -
配置文件核心内容:
name: CI/CD Pipeline on: [push] # 当你推送代码时触发 jobs: build-and-deploy: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up JDK uses: actions/setup-java@v3 with: java-version: '17' - name: Run Unit Tests and Build run: mvn clean package # 这一步完成了单元测试和构建 - name: Build Docker images run: | docker build -t my-backend-app ./backend docker build -t my-frontend-app ./frontend - name: Deploy to K8S run: | kubectl apply -f k8s-deployment.yaml
- 通俗理解:
Jenkinsfile或.github/workflows/ci-cd.yml就是给自动化流水线看的工序清单,它严格规定了先做什么、后做什么。
第五步:部署上架 - 编写 K8S 配置文件
目标:编写一个 k8s-deployment.yaml 文件,告诉 Kubernetes 如何运行你的三个容器。
这个文件通常包含Deployment(定义如何运行Pod)和Service(定义如何访问Pod)两种资源。
# 后端应用的Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend-deployment
spec:
replicas: 1
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: my-backend-app # 和你docker build时起的名字一致
ports:
- containerPort: 8080
---
# 后端应用的Service,让前端和外部能访问到它
apiVersion: v1
kind: Service
metadata:
name: backend-service
spec:
selector:
app: backend
ports:
- protocol: TCP
port: 8080
targetPort: 8080
type: ClusterIP
---
# 前端应用的Deployment和Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend-deployment
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: my-frontend-app
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: frontend-service
spec:
selector:
app: frontend
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer # 对外暴露前端服务,这样你才能在浏览器访问
---
# 数据库的Deployment和Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-deployment
spec:
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
ports:
- containerPort: 3306
---
apiVersion: v1
kind: Service
metadata:
name: mysql-service
spec:
selector:
app: mysql
ports:
- protocol: TCP
port: 3306
targetPort: 3306
type: ClusterIP
通俗理解:这个 YAML 文件就是给智能吊车(Kubernetes) 的施工图纸,告诉它:
- 每个应用(前端、后端、数据库)需要各吊起一个集装箱(
replicas: 1)。 - 集装箱内部的服务在哪个端口运行(
containerPort)。 - 如何给这些集装箱贴标签(
app: backend)以便互相发现。 - 如何给它们分配内部电话(ClusterIP Service)或对外招牌(LoadBalancer Service)。
第六步:最终质检 - 集成测试
目标:等 K8S 把所有容器都运行起来后,进行测试。
- 检查Pod状态:在终端运行
kubectl get pods,查看所有 Pod 是否是Running状态。 - 找到前端访问地址:运行
kubectl get service frontend-service,Docker Desktop 的 K8S 会把LoadBalancer类型的 Service 映射到localhost。你就能用http://localhost访问前端了。 - 用 Postman 测试后端:
- 首先,需要让 Postman 能访问到后端 Service。可以临时将后端 Service 的类型也改为
LoadBalancer,或者使用端口转发:kubectl port-forward service/backend-service 8080:8080。 - 然后就可以在 Postman 里访问
http://localhost:8080/api/your-endpoint来测试所有后端 API 接口了。
- 首先,需要让 Postman 能访问到后端 Service。可以临时将后端 Service 的类型也改为
- 编写自动化集成测试:在 Postman 里,你可以把多个测试请求组织成一个 Collection,并为之编写测试脚本(例如,检查HTTP状态码是否为200),然后使用 Postman Runner 或 Newman 命令行工具来自动化运行这个集合。这样就可以实现“用例级别的集成测试”。
总结与行动路线
别再看了,动手做吧!遵循这个顺序:
- 本地手动测试:先别管容器和K8S,确保你的代码本地
mvn test能过,本地能跑起来。 - 容器化:分别写好三个应用的
Dockerfile,并确保能用docker build/docker run单独运行它们。 - 编写K8S图纸:写
k8s-deployment.yaml,用kubectl apply -f手动部署,确保能在K8S里跑通。 - 自动化:最后再搭建 Jenkins 或配置 GitHub Actions,把前几步的手动命令填到流水线配置里。
遇到问题随时查文档(你提供的链接非常棒!)或搜索错误信息,99%的问题都有人遇到过。祝你成功!