Skip to content

GitLab 配置 Jenkins 实现自动化部署

配置 Jenkins

新建任务

image.png

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

image.png

此处默认即可

image.png

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

image.png

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

image.png

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

image.png

环境部分,需要配置k8s

https://192.168.30.70:6443

image.png

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

image.png

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

image.png

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

image.png

下方这个脚本只需要修改最上方的环境变量 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发送构建状态

image.png

完成后保存即可

配置GitLab

去掉默认流水线配置,保存更改 image.png

配置webhooks

image.png

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

image.png

保存后测试

前端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