【基于 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流程更贴合企业生产场景!

相关推荐
日取其半万世不竭1 小时前
Mattermost 自建团队协作平台:开源的 Slack 替代品
运维
云游牧者1 小时前
K8S灰度发布与蓝绿部署实战指南-CSDN博客
运维·云原生·容器·kubernetes·发布策略
南境十里·墨染春水1 小时前
linux学习进展 libevent
linux·运维·学习
kanyun1231 小时前
在Docker容器中运行Docker:Docker-in-Docker(DinD)全面指南
运维·docker·容器
Agent产品评测局1 小时前
国产vs海外AI Agent方案,制造业场景适配性横评:2026年企业级自动化选型全景观察
运维·人工智能·ai·chatgpt·自动化
落日流年1 小时前
欧拉操作系统部署OceanBase集群
运维·oceanbase
开开心心就好1 小时前
直接减少蓝光辐射的专业护眼工具
linux·运维·服务器·智能手机·excel·java-rabbitmq·sdkman
唔662 小时前
Android在局域网中搭建 MQTT服务器 协议V3.1.1
android·运维·服务器
Shadow(⊙o⊙)2 小时前
进程分析—从操作系统到Linux内核深入
linux·运维·服务器·开发语言·网络·c++·后端