Appearance
GitLab 配置 Jenkins 实现自动化部署
配置 Jenkins
新建任务

填写任务名称,选择自由风格

此处默认即可

源码管理输入git仓库地址,选择认证信息。如仓库主分支为main,需要手动添加分支

触发器部分配置如下,提前复制地址到剪贴板。

点击下发的高级按钮,点击Generate生成token,将token复制到剪贴板

环境部分,需要配置k8s
https://192.168.30.70:6443

然后同样在环境部分,选择安装自定义工具,选择kubectl

构建步骤部分,点击增加构建步骤,选择 执行 shell

写进去,要注意工作空间名称与第一步任务名称一致。

下方这个脚本只需要修改最上方的环境变量 IMAGE_NAME 即可。(前端项目需要额外修改targetPort变量,指定为80端口)
shell
# 定义变量
REGISTRY="192.168.30.12/aritime"
IMAGE_NAME="whweb"
FULL_IMAGE_NAME="$REGISTRY/$IMAGE_NAME"
NAMESPACE="apps"
APP_PORT=9014
APP_IP="192.168.30.65"
# 1. 登录 Harbor (建议使用 --password-stdin 更安全)
echo "Harbor12345" | docker login $REGISTRY -u admin --password-stdin
# 2. 构建并推送
export DOCKER_BUILDKIT=1
docker build -t $FULL_IMAGE_NAME:$BUILD_NUMBER .
docker tag $FULL_IMAGE_NAME:$BUILD_NUMBER $FULL_IMAGE_NAME:latest
docker push $FULL_IMAGE_NAME:$BUILD_NUMBER
docker push $FULL_IMAGE_NAME:latest
echo "开始部署到 K8s 集群..."
# 3. 部署到 K8s
# 注意:插件会自动处理 kubectl 的权限,这里直接运行即可
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: $IMAGE_NAME
namespace: $NAMESPACE
spec:
replicas: 1
# 滚动更新策略:保证在更新时先启动新容器,再停止旧容器
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: $IMAGE_NAME
template:
metadata:
labels:
app: $IMAGE_NAME
spec:
imagePullSecrets:
- name: harbor-aritime-secret
containers:
- name: $IMAGE_NAME
image: $FULL_IMAGE_NAME:$BUILD_NUMBER
ports:
- containerPort: $APP_PORT
# 强制 Nacos 注册这个 IP
env:
- name: SPRING_CLOUD_NACOS_DISCOVERY_IP
value: "$APP_IP"
---
apiVersion: v1
kind: Service
metadata:
name: ${IMAGE_NAME}-svc
namespace: $NAMESPACE
annotations:
metallb.universe.tf/allow-shared-ip: "share-65"
spec:
type: LoadBalancer
loadBalancerIP: $APP_IP
selector:
app: $IMAGE_NAME
ports:
- protocol: TCP
port: $APP_PORT
targetPort: $APP_PORT
EOF
# 4. 验证部署状态
echo "正在等待 K8s 滚动更新完成..."
# rollout status 会持续追踪直到容器启动成功
kubectl rollout status deployment/$IMAGE_NAME -n $NAMESPACE --timeout=90s
if [ $? -eq 0 ]; then
echo "------------------------------------------------"
echo "项目 $IMAGE_NAME 部署成功!"
echo "------------------------------------------------"
else
echo "部署失败,请检查 Kuboard 中的 Pod 日志!"
kubectl get pods -n $NAMESPACE | grep $IMAGE_NAME
exit 1
fi
# 5. 清理本地过期镜像(只保留最近的,防止 Jenkins 宿主机磁盘爆满)
docker image prune -f多个项目分容器部署。
将command写在脚本里 command: ["java", "-jar", "krweb.jar"] 并去掉Dockerfile里的端口号和运行命令CMD部分(Dockerfile里的运行命令会被自动化部署脚本覆盖) 两个容器本质上还是一样的镜像,只是运行时指定的命令不同,运行不同的jar包。
shell
# 定义变量
REGISTRY="192.168.30.12/aritime"
IMAGE_NAME="kr"
FULL_IMAGE_NAME="$REGISTRY/$IMAGE_NAME"
NAMESPACE="apps"
APP_PORT=9011
APP_IP="192.168.30.65"
# 1. 登录 Harbor
echo "Harbor12345" | docker login $REGISTRY -u admin --password-stdin
# 2. 构建并推送 (构建一次,包含两个 JAR)
export DOCKER_BUILDKIT=1
docker build -t $FULL_IMAGE_NAME:$BUILD_NUMBER .
docker tag $FULL_IMAGE_NAME:$BUILD_NUMBER $FULL_IMAGE_NAME:latest
docker push $FULL_IMAGE_NAME:$BUILD_NUMBER
docker push $FULL_IMAGE_NAME:latest
echo "开始部署到 K8s 集群..."
# 3. 部署到 K8s (单 Pod 双容器模式)
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: $IMAGE_NAME
namespace: $NAMESPACE
spec:
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: $IMAGE_NAME
template:
metadata:
labels:
app: $IMAGE_NAME
spec:
imagePullSecrets:
- name: harbor-aritime-secret
containers:
# --- 容器 1: krweb ---
- name: krweb
image: $FULL_IMAGE_NAME:$BUILD_NUMBER
command: ["java", "-jar", "krweb.jar"]
env:
- name: SPRING_CLOUD_NACOS_DISCOVERY_IP
value: "$APP_IP"
ports:
- containerPort: $APP_PORT
# --- 容器 2: krMsgHandle ---
- name: krmsg
image: $FULL_IMAGE_NAME:$BUILD_NUMBER
command: ["java", "-jar", "krMsgHandle.jar"]
env:
- name: SPRING_CLOUD_NACOS_DISCOVERY_IP
value: "$APP_IP"
---
apiVersion: v1
kind: Service
metadata:
name: ${IMAGE_NAME}-svc
namespace: $NAMESPACE
annotations:
metallb.universe.tf/allow-shared-ip: "share-65"
spec:
type: LoadBalancer
loadBalancerIP: $APP_IP
selector:
app: $IMAGE_NAME
ports:
- name: web-port
protocol: TCP
port: $APP_PORT
targetPort: $APP_PORT
EOF
# 4. 验证部署状态
echo "正在等待 K8s 滚动更新完成..."
kubectl rollout status deployment/$IMAGE_NAME -n $NAMESPACE --timeout=90s
if [ $? -eq 0 ]; then
echo "------------------------------------------------"
echo "项目 $IMAGE_NAME 部署成功!"
echo "访问地址: http://$APP_IP:$APP_PORT (Web)"
echo "访问地址: http://$APP_IP:$MSG_PORT (Msg)"
echo "------------------------------------------------"
else
echo "部署失败,请检查 Kuboard 中的 Pod 日志!"
kubectl get pods -n $NAMESPACE | grep $IMAGE_NAME
exit 1
fi
# 5. 清理本地过期镜像
docker image prune -f最后是配置给gitlab发送构建状态

完成后保存即可
配置GitLab
去掉默认流水线配置,保存更改 
配置webhooks

输入剪贴板里保存的地址和token,选择推送事件,main分支

保存后测试
前端Dockerfile
dockerfile
FROM node:22-alpine as builder
WORKDIR /app
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
npm install --legacy-peer-deps
COPY . .
RUN npm run build
FROM nginx:stable-alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]后端Dockerfile
shell
# 第一阶段:Maven构建
FROM maven:3.9.6-eclipse-temurin-21 AS builder
WORKDIR /build
RUN mkdir -p /root/.m2 && \
echo '<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd"><mirrors><mirror><id>aliyunmaven</id><mirrorOf>*</mirrorOf><name>aliyun</name><url>https://maven.aliyun.com/repository/public</url></mirror></mirrors></settings>' > /root/.m2/settings.xml
# 复制lib依赖
COPY lib ./lib
COPY pom.xml .
COPY lpweb/pom.xml lpweb/
# 下载依赖(利用缓存)
RUN --mount=type=cache,target=/root/.m2 \
mvn dependency:go-offline -pl lpweb -am || true
# 复制源码
COPY lpweb/src lpweb/src
# 构建两个模块
RUN --mount=type=cache,target=/root/.m2 \
mvn clean package -DskipTests -pl lpweb -am
# 第二阶段:运行镜像
FROM eclipse-temurin:21-jre
LABEL maintainer="airtime"
LABEL description="坯库docker"
WORKDIR /opt/app
# 复制两个jar包
COPY --from=builder /build/lpweb/target/lpweb-1.0.jar ./lpweb.jar
ENV SPRING_PROFILES_ACTIVE=test
EXPOSE 9015
CMD java -jar lpweb.jar & wait