【基于 RHEL 9.3 的 K8s + GitLab 全自动化部署环境搭建第三篇】

基于CI/CD+K8s部署Java项目(复用现有环境,零额外搭建)

前言:前面我们已经搭建好了 Harbor 私有镜像仓库、 K8s 1.35.3 集群、 GitLab 代码仓库、 GitLab Runner 全套基础环境,今天就复用这套环境,手把手教大家部署Java项目(SpringBoot),实现「代码提交→自动编译→镜像构建→推送Harbor→部署K8s」全流程自动化,和前端项目部署逻辑对齐,新手也能一步到位,完全还原企业Java项目容器化发布场景!

**一、科普:**Java 项目 CI/CD 和前端有啥区别?

很多新手会疑惑,同样是部署到K8s,Java项目和前端项目的CI/CD流程为啥不一样?核心差异就在于「编译打包」环节------

  • 前端项目:纯静态文件(HTML/CSS/JS),无需编译,直接打包成Nginx镜像即可;
  • Java项目(SpringBoot):需要先通过 Maven/Gradle 编译源代码、打包成WAR/JAR包,再封装到Docker镜像(需依赖JDK运行环境),最后部署到K8s。

本次教程的核心亮点:全程镜像化 + 复用现有环境,无需在Runner节点额外部署复杂依赖,通过Docker封装Java运行环境,避免版本冲突,同时沿用之前的GitLab CI/CD流水线逻辑,降低学习成本。

二、前置环境说明

在开始前,请确认以下环境已正常运行(前面教程已部署完成),无需额外操作:

  1. Harbor私有仓库:地址 192.168.223.200,项目 k8s-project,账号 admin/Harbor12345;
  1. K8s集群:1主2从,所有节点处于Ready状态,Flannel网络插件正常运行;
  1. GitLab:地址 192.168.223.23,已创建root管理员账号,可正常创建项目;
  1. GitLab Runner:已注册并绑定 shared 标签,以root权限运行,可正常访问K8s集群。

|------------------------------------------------------------|
| 提示:若之前环境未部署完成,可先回顾前面的Harbor、K8s、GitLab部署教程,确保所有组件正常运行后再继续。 |

**三、核心准备:**Maven+JDK 环境配置( Master+Runner 节点)

Java项目编译需要JDK和Maven,我们在Master节点(本地测试)和GitLab Runner节点(流水线执行)都安装,避免编译报错,推荐版本:JDK 11 + Maven 3.9.6(版本兼容,稳定无坑)。

3.1****安装 JDK 11 (全局生效)

  1. 上传 jdk-11_linux-x64_bin.tar.gz 到节点的 /root 目录,执行解压并重命名:

    cd /root
    tar -zxf jdk-11_linux-x64_bin.tar.gz
    mv jdk-11 jdk11

  2. 配置全局环境变量(永久生效):

    cat > /etc/profile.d/jdk.sh << 'EOF'
    export JAVA_HOME=/root/jdk11
    export PATH=JAVA_HOME/bin:PATH
    export CLASSPATH=.:$JAVA_HOME/lib
    EOF

  3. 生效并验证安装:

    source /etc/profile.d/jdk.sh
    java -version # 输出JDK 11版本即成功

3.2****安装 Maven 3.9.6 (适配 JDK 11

  1. 下载Maven安装包(官方源,稳定可用):

    cd /root
    wget https://archive.apache.org/dist/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz

  2. 解压并重命名,方便后续配置:

    tar -zxf apache-maven-3.9.6-bin.tar.gz
    mv apache-maven-3.9.6 maven

  3. 配置全局环境变量:

    cat > /etc/profile.d/maven.sh << 'EOF'
    export MAVEN_HOME=/root/maven
    export PATH=MAVEN_HOME/bin:PATH
    EOF
    source /etc/profile.d/maven.sh

  4. 验证安装,并配置Maven阿里云镜像加速(解决编译慢、依赖拉取超时问题):

    mvn -version # 输出Maven 3.9.6版本即成功

    配置阿里云镜像

    vim /root/maven/conf/settings.xml

在 <mirrors> 标签内添加如下镜像(替换默认中央仓库):

复制代码
<mirror>
    <id>aliyunmaven</id>
    <mirrorOf>central</mirrorOf>
    <url>https://maven.aliyun.com/repository/public/</url>
</mirror>

四、实操步骤:部署****Java 项目

本次我们部署一个最简SpringBoot Web项目,全程分为「创建项目目录→编写核心文件→配置CI/CD→推送触发部署→验证结果」5步,所有命令均经过实测,可直接复制执行。

4.1****第一步:创建 Java 项目目录( Master 节点)

回到部署根目录,创建Java项目专属目录,和前端项目同级,方便管理:

复制代码
cd /root/k8s/deploy
mkdir java-demo
cd java-demo

4.2****第二步:编写 4 个核心文件(直接复制,无需修改)

这4个文件是Java项目部署的核心,分别对应「源代码、Maven配置、Docker镜像、K8s部署」,全程复制即可,无需手动编写。

1. Java****源代码( SpringBoot 最简 Web 项目)

创建SpringBoot的Controller和启动类,实现一个简单的接口,用于后续验证部署结果:

复制代码
# 创建源代码目录结构
mkdir -p src/main/java/com/demo

# 编写HelloController(接口层)
cat > src/main/java/com/demo/HelloController.java <<EOF
package com.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/")
    public String hello() {
        return "Java-Demo 部署成功!K8s + GitLab CI/CD 正常运行!";
    }
}
EOF

# 编写DemoApplication(启动类,适配WAR包)
cat > src/main/java/com/demo/DemoApplication.java <<EOF
package com.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class DemoApplication extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(DemoApplication.class);
    }
}
EOF

2. Maven****配置文件( pom.xml

固定JDK版本、SpringBoot依赖、打包方式(WAR包),适配Tomcat运行环境,避免版本兼容问题:

复制代码
cat > pom.xml <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.demo</groupId>
    <artifactId>java-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!-- 固定为war包,适配Tomcat -->
    <packaging>war</packaging>

    <!-- 统一JDK 11编译版本,避免版本不兼容 -->
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <!-- SpringBoot父依赖(2.7.15适配JDK 11 + Tomcat 9) -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.15</version>
        <relativePath/>
    </parent>

    <dependencies>
        <!-- Web核心依赖,排除内置Tomcat(用外部Tomcat) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- Tomcat 9适配的Servlet API(固定版本) -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <!-- 固定WAR包名称为ROOT,避免访问路径加项目名 -->
        <finalName>ROOT</finalName><plugins>
            <!-- SpringBoot打包插件(固定) -->
           <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.7.15</version>
            </plugin>
        </plugins>
    </build>
</project>
EOF

3. Dockerfile**(镜像化编译** + 运行)

基于Tomcat+JDK11镜像,封装Java项目,先加载本地镜像并推送至Harbor,避免Runner拉取镜像超时:

复制代码
# 加载本地Tomcat+JDK11镜像(提前准备好离线包)
docker load -i tomcat-9.0-jdk11.tar
# 给镜像打标签,适配Harbor仓库地址
docker tag tomcat:9.0-jdk11 192.168.223.200/k8s-project/tomcat:9.0-jdk11
# 推送镜像到Harbor私有仓库
docker push 192.168.223.200/k8s-project/tomcat:9.0-jdk11

# 编写Dockerfile
cat > Dockerfile <<EOF
FROM 192.168.223.200/k8s-project/tomcat:9.0-jdk11
WORKDIR /usr/local/tomcat
RUN rm -rf webapps/*
COPY target/ROOT.war webapps/ROOT.war
EXPOSE 8080
CMD ["catalina.sh", "run"]
EOF

4. K8s****部署文件( java.yaml

定义Deployment(部署)和Service(暴露端口),采用NodePort类型,方便外部访问,端口使用30084(避免和前端30083冲突):

复制代码
cat > java.yaml <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: java-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: java-demo
  template:
    metadata:
      labels:
        app: java-demo
    spec:
      containers:
      - name: java-demo
        image: $IMAGE
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: java-demo-svc
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 8080
    nodePort: 30084
  selector:
    app: java-demo
EOF

4.3第三步:本地测试编译(可选,验证环境)

在Master节点执行编译命令,验证Maven+JDK环境是否正常,同时生成WAR包,避免后续流水线编译报错:

复制代码
cd /root/k8s/deploy/java-demo
mvn clean package -DskipTests  # 跳过测试,快速编译
# 编译成功后,会在target目录生成ROOT.war文件
ls target/ROOT.war  # 能看到文件即成功

4.4****第四步:编写 GitLab CI/CD 配置( .gitlab-ci.yml

沿用前端项目的流水线逻辑,定义「build(编译+构建镜像)、push(推送镜像)、deploy(部署K8s)」三个阶段,直接复制即可:

复制代码
vim .gitlab-ci.yml
cat > .gitlab-ci.yml <<EOF
stages:
  - build
  - push
  - deploy

variables:
  HARBOR_REGISTRY: "192.168.223.200"
  HARBOR_PROJECT: "k8s-project"
  IMAGE_NAME: "java-demo"
  TAG: "$CI_COMMIT_SHORT_SHA"
  NAMESPACE: "default"

build:
  stage: build
  tags:
    - shared
  script:
    - echo "=== 开始编译打包Java项目 ==="
    - mvn clean package -DskipTests
    - echo "=== 编译完成,开始构建Docker镜像 ==="
    - docker build -t ${HARBOR_REGISTRY}/${HARBOR_PROJECT}/${IMAGE_NAME}:${TAG} .
    - docker tag ${HARBOR_REGISTRY}/${HARBOR_PROJECT}/${IMAGE_NAME}:${TAG} ${HARBOR_REGISTRY}/${HARBOR_PROJECT}/${IMAGE_NAME}:latest

push:
  stage: push
  tags:
    - shared
  script:
    - echo "=== 登录Harbor,推送镜像 ==="
    - docker login ${HARBOR_REGISTRY} -u admin -p Harbor12345
    - docker push ${HARBOR_REGISTRY}/${HARBOR_PROJECT}/${IMAGE_NAME}:${TAG}
    - docker push ${HARBOR_REGISTRY}/${HARBOR_PROJECT}/${IMAGE_NAME}:latest

deploy:
  stage: deploy
  tags:
    - shared
  script:
    - echo "=== 开始部署Java项目到K8s集群 ==="
    - export IMAGE=${HARBOR_REGISTRY}/${HARBOR_PROJECT}/${IMAGE_NAME}:${TAG}
    - envsubst '$IMAGE' < java.yaml > java-deploy.yaml
    - kubectl apply -f java-deploy.yaml
    - kubectl rollout status deployment java-demo -n ${NAMESPACE} --timeout=120s
    - rm -f java-deploy.yaml
    - echo "=== 部署成功,查看Pod状态 ==="
    - kubectl get pods -n ${NAMESPACE}
EOF

4.5****第五步:推送到 GitLab 仓库,触发自动部署

初始化Git仓库,将所有文件推送到GitLab,自动触发CI/CD流水线,全程无需手动干预:

复制代码
# 配置Git全局信息(首次执行)
git config --global user.name "Administrator"
git config --global user.email "gitlab_admin_f440b6@example.com"

# 初始化Git仓库
git init --initial-branch=main

# 添加所有文件
git add .

# 提交代码
git commit -m "Initial commit: Java项目初始化,适配CI/CD+K8s部署"

# 关联GitLab远程仓库(替换为你的GitLab项目地址)
git remote add origin http://192.168.223.23/root/java-demo.git

# 推送代码,触发自动部署
git push --set-upstream origin main

五、验证部署结果

5.1****查看 GitLab CI/CD 流水线

打开GitLab → 进入java-demo项目 → 左侧菜单「CI/CD → Pipelines」,查看 build、push、deploy 三个阶段,全部显示绿色对勾 ✅,说明流水线执行成功。

5.2查看 K8s Pod Service 状态

在K8s Master节点执行命令,查看Pod是否正常运行、Service是否成功暴露端口:

复制代码
# 查看Java项目Pod状态(Running即正常)
kubectl get pods -n default | grep java-demo
# 正常输出示例:java-demo-7f98d7c6b4-2xqzk   1/1     Running   0          30s

# 查看Service状态(NodePort为30084即正常)
kubectl get svc -n default | grep java-demo
# 正常输出示例:java-demo-svc   NodePort    10.102.158.78   <none>        8080:30084/TCP   1min

5.3****浏览器访问 Java 项目

打开浏览器,输入地址:http://任意K8s节点IP:30084,看到如下内容,说明部署成功:

Java-Demo 部署成功! K8s + GitLab CI/CD 正常运行!

六、常见问题排查(新手必看)

  1. 问题 1 Maven 编译报错 " 依赖拉取失败 "
  • 原因:Maven镜像未配置或配置错误,无法拉取SpringBoot依赖;
  • 解决:重新配置settings.xml中的阿里云镜像,确保标签格式正确,重启Maven(source /etc/profile.d/maven.sh)。
  1. 问题 2 K8s Pod "ImagePullBackOff"
  • 原因:K8s节点未配置Harbor为可信仓库,无法拉取镜像;
  • 解决:在所有K8s节点执行以下命令,重启Docker后重新登录Harbor:
    echo '{ "insecure-registries": "192.168.223.200" }' > /etc/docker/daemon.json
    systemctl restart docker
    docker login 192.168.223.200 -u admin -p Harbor12345
  1. 问题 3 :流水线 deploy 阶段报错 "kubectl: command not found"
  • 原因:GitLab Runner节点未安装kubectl,无法操作K8s集群;
  • 解决:在Runner节点配置K8s YUM源,安装kubectl,同时拷贝Master节点的~/.kube/config文件,确保权限正常。
  1. 问题 4 :端口冲突
  • 原因:30084端口已被其他服务占用;
  • 解决:修改java.yaml中的nodePort,替换为未被占用的端口(范围30000-32767),重新推送代码触发部署。

七、总结

本次教程复用了已有的Harbor、K8s、GitLab、GitLab Runner环境,实现了Java项目的全流程自动化部署,核心亮点的是「镜像化编译+复用流水线逻辑」,避免了重复搭建环境的麻烦。

整个流程的核心逻辑:代码提交 →Maven 编译打包 →Docker 构建镜像 推送 Harbor→K8s 部署,和前端项目部署流程高度对齐,掌握后可无缝迁移到真实企业Java项目(微服务、单体项目均可)。

通过这套架构,我们真正实现了"一次搭建,多项目复用",开发者只需专注于代码开发,提交代码后即可自动完成部署,极大提升了开发效率,也贴合企业容器化、自动化的生产需求。

后续可在此基础上扩展:添加测试阶段、实现蓝绿部署、集成Helm管理K8s资源,让整个CI/CD流程更贴合企业生产场景!

相关推荐
SelectDB1 天前
Litefuse 开源并推出单进程轻量模式,25 秒就能跑起来的 Agent 可观测与评估平台
运维·后端·自动化运维
XIAOHEZIcode2 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户0328472220703 天前
如何搭建本地yum源(上)
运维
大树886 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠6 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质6 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
Inhand陈工6 天前
基于台达PLC与映翰通IG502的智慧水产养殖精准投喂与远程运维解决方案
运维·人工智能·物联网·阿里云·信息与通信
酣大智6 天前
ARP代理--工作原理
运维·网络·arp·arp代理
shushangyun_6 天前
2026年快消品B2B系统推荐:支持终端门店订货、促销政策自动化的工具?
java·运维·网络·数据库·人工智能·spring·自动化
施努卡机器视觉6 天前
SNK施努卡侧滑门锁上滑轮总成自动化装配线,从零件到组件,全流程精密制造方案
运维·自动化·制造