基于GitLab CI/CD + Kubernetes的自动化部署平台搭建

一、系统架构

主机名 IP地址 角色 软件
harbor 172.25.254.200 harbor docker,harbor
k8s-master 172.25.254.20 master kubeadm, kubelet, kubectl, etcd,api-server,controller-manager,scheduler
k8s-node 1 172.25.254.21 node 1 kubelet,kube-proxy,docker
k8s-node 2 172.25.254.22 node 2 kubelet,kube-proxy,docker
gitlab-server 172.25.254.23 server docker, gitlab
gitlab-runner 172.25.254.24 runner docker, gitlab-runner

二、初始化环境(所有主机)

2.1 关闭防火墙和SELinux

复制代码
# 关闭防火墙
[root@harbor ~]# systemctl stop firewalld
[root@harbor ~]# systemctl disable firewalld

# 关闭SELinux
[root@harbor ~]# setenforce 0
[root@harbor ~]# sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config

2.2 配置本地YUM源

复制代码
# 挂载光盘
[root@harbor ~]# mount /dev/sr0   /mnt

# 创建本地yum源
[root@harbor ~]# cat > /etc/yum.repos.d/local.repo << 'EOF'
[base01]
name=base
baseurl=/mnt/BaseOS
enable=1
gpgcheck=0
[base02]
name=app
baseurl=/mnt/AppStream
enable=1
gpgcheck=0
EOF

# 安装工具依赖
[root@harbor ~]# yum install vim net-tools  tree  zip   git  -y

2.3 配置主机名

复制代码
[root@harbor ~]# cat >> /etc/hosts << 'EOF'
172.25.254.20 k8s-master  master
172.25.254.21 k8s-node1   node1
172.25.254.22 k8s-node2   node2
EOF

2.4 关闭swap

复制代码
[root@harbor ~]# sed '/swap/s/^/#/g' -i /etc/fstab
[root@harbor ~]# swapoff -a
[root@harbor ~]# swapon  -s  #没有显示才是对的

2.5 内核参数配置(缺失会导致CRI通信失败)

复制代码
# 添加内核参数
[root@harbor ~]# cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF

# 生效参数
[root@harbor ~]# sysctl --system

# 加载 br_netfilter 模块
[root@harbor ~]# modprobe br_netfilter
[root@harbor ~]# modprobe vxlan
[root@harbor ~]# echo "br_netfilter" >> /etc/modules-load.d/k8s.conf
[root@harbor ~]# echo "vxlan" >> /etc/modules-load.d/k8s.conf
[root@harbor ~]# lsmod | grep br_netfilter  # 有输出则正确

2.6 部署Docker

复制代码
# 安装依赖
[root@harbor ~]# yum install -y yum-utils device-mapper-persistent-data lvm2

# 添加Docker阿里云镜像源
[root@harbor ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 安装Docker(指定版本)
[root@harbor ~]# yum install -y docker-ce

# 启动Docker
[root@harbor ~]# systemctl enable docker
[root@harbor ~]# systemctl start docker

2.7 配置Docker阿里云镜像加速器

复制代码
# 创建docker配置目录
[root@harbor ~]# mkdir -p /etc/docker

# 配置镜像加速器
[root@harbor ~]# cat > /etc/docker/daemon.json << 'EOF'
{
  "registry-mirrors": [
    "https://docker.1ms.run",
    "https://p1umdw8d.mirror.aliyuncs.com",
    "https://docker.xuanyuan.cn",
    "https://registry.docker-cn.com",
    "https://mirror.ccs.tencentyun.com"
  ],
  "insecure-registries": ["172.25.254.200"]
}
EOF

# 重启Docker
[root@harbor ~]# systemctl daemon-reload
[root@harbor ~]# systemctl restart docker

# 验证加速器是否生效
[root@harbor ~]# docker info | grep -A 10 "Registry Mirrors"

三、部署Harbor

3.1 获取docker-compose文件

复制代码
[root@harbor ~]# wget https://github.com/docker/compose/releases/download/v2.2.3/docker-compose-linux-x86_64

# 查看文件
[root@harbor ~]# ls
docker-compose-linux-x86_64

# 移动位置
[root@harbor ~]# mv docker-compose-linux-x86_64   /usr/bin/docker-compose


# 添加执行权限
[root@harbor ~]# chmod +x /usr/bin/docker-compose

# 查看版本
[root@harbor ~]# docker-compose version
Docker Compose version v2.2.3

3.2 版本:Harbor 2.10.2

复制代码
# 下载Harbor(选择需要的版本)
[root@harbor ~]# wget https://github.com/goharbor/harbor/releases/download/v2.4.1/harbor-offline-installer-v2.4.1.tgz


# 解压
[root@harbor ~]# tar -zxf harbor-offline-installer-v2.14.0.tgz 
[root@harbor ~]# cd harbor

# 复制配置文件
[root@harbor harbor]# cp harbor.yml.tmpl harbor.yml

# 修改配置
[root@harbor harbor]# vim harbor.yml

# 第5行:hostname改为服务器IP
hostname: 172.25.254.200

#https: 注释
    #https port for harbor, default is 443
    #port: 443 注释
    #The path of cert and key files for nginx
    #certificate: /your/certificate/path 注释
    #private_key: /your/private/key/path 注释

3.3 启动Harbor

复制代码
# 运行安装脚本
[root@harbor harbor]# ./install.sh

# 启动Harbor(后台运行)
[root@harbor harbor]# docker-compose up -d

# 查看状态
[root@harbor harbor]# docker-compose ps

3.4 Harbor页面配置

第一步:访问Harbor

第二步:创建项目

  1. 登录后,点击"Projects"(项目)

  2. 点击"New Project"(新建项目)

  3. 填写:

  • Project Name(项目名):k8s
  • Access Level(访问级别):选择"Public"(公开)
  1. 点击"OK"

四、部署K8S

4.1 安装cri-docerd(master/node节点中安装)

复制代码
[root@master ~]# ls
anaconda-ks.cfg  cri-dockerd-0.3.14-3.el8.x86_64.rpm  libcgroup-0.41-19.el8.x86_64.rpm
[root@master ~]# rpm -ivh *.rpm

[root@master ~]# vim /lib/systemd/system/cri-docker.service
ExecStart=/usr/bin/cri-dockerd --container-runtime-endpoint fd:// --network-plugin=cni --pod-infra-container-image=172.25.254.200/k8s/pause:3.10.1

[root@master ~]# systemctl daemon-reload
[root@master ~]# systemctl enable --now cri-docker
[root@master ~]# systemctl status cri-docker

[root@master ~]# docker login 172.25.254.200 -u admin -p Harbor12345
[root@node1 ~]# docker login 172.25.254.200 -u admin -p Harbor12345
[root@node2 ~]# docker login 172.25.254.200 -u admin -p Harbor12345


# 所有主机配置kubernetes安装源
[root@master ~]# vim /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name = kubernetes
baseurl = https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.35/rpm/
gpgcheck = 0

4.2 安装构建kubernetes集群所需软件

复制代码
[root@master ~]# dnf install kubelet kubeadm  kubectl  -y
[root@master ~]# systemctl enable --now kubelet.service

# 所有节点执行:配置 kubelet 默认使用 cri-dockerd 套接字
[root@master ~]# cat > /etc/sysconfig/kubelet << EOF
KUBELET_EXTRA_ARGS="--container-runtime-endpoint=unix:///var/run/cri-dockerd.sock --runtime-request-timeout=15m"
EOF

# 重启 kubelet 生效
[root@master ~]# systemctl daemon-reload
[root@master ~]# systemctl restart kubelet

master节点中 kubectl 和kubeadm 补齐

复制代码
[root@master ~]# echo "source <(kubectl completion bash)" >> ~/.bashrc
[root@master ~]# echo "source <(kubeadm completion bash)" >> ~/.bashrc
[root@master ~]# source  ~/.bashrc

4.3 下载kubernetes集群所需镜像

下载镜像

复制代码
[root@master ~]# kubeadm config images pull \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.35.3 \
--cri-socket=unix:///var/run/cri-dockerd.sock

上传到本地harbor

复制代码
[root@master ~]# docker login 172.25.254.200 -u admin -p Harbor12345

[root@master ~]# docker images --format "{{.Repository}}:{{.Tag}}" | awk -F "/" '/google_containers/{system("docker tag "$0" 172.25.254.200/k8s/"$3)}'
[root@master ~]# docker images --format "{{.Repository}}:{{.Tag}}" | awk -F "/" '/172.25.254.200/{system("docker push "$0)}'

4.4 在master中初始化kubernetes集群

在master中完成集群初始化

复制代码
[root@master ~]# kubeadm init --pod-network-cidr=10.244.0.0/16 \
--image-repository 172.25.254.200/k8s \
--kubernetes-version v1.35.3 \
--cri-socket=unix:///var/run/cri-dockerd.sock
。。。
[root@master ~]# mkdir -p $HOME/.kube
[root@master ~]# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@master ~]# chown $(id -u):$(id -g) $HOME/.kube/config
[root@master ~]# echo "export KUBECONFIG=/etc/kubernetes/admin.conf" > ~/.bash_profile
[root@master ~]# source  ~/.bash_profile

在node1\node2上执行:
#每个人不一样,其他主机加入本集群的凭证
[root@node1/node2 ~]# kubeadm join 172.25.254.20:6443 --token 5myaaa.bivwm2319b1be73i \
	--discovery-token-ca-cert-hash sha256:789e1df79316e434e3864a2e243f3488f6652ebd5cf48885bdfdd83ef73cd9a5 \
--cri-socket unix:///var/run/cri-dockerd.sock


[root@master ~]# kubectl get nodes 

4.5 安装网络插件

4.5.1 加载离线镜像

复制代码
# 加载离线镜像
[root@master ~]# ls
172.25.254.200-flannel-io-flannel-cni-plugin-v1.9.0-flannel1.tar
172.25.254.200-flannel-io-flannel-v0.28.1.tar
 
 
# 推送到私有仓库
[root@master ~]# docker load -i 172.25.254.200-flannel-io-flannel-v0.28.1.tar
[root@master ~]# docker load -i 172.25.254.200-flannel-io-flannel-cni-plugin-v1.9.0-flannel1.tar

4.5.2 打标签

复制代码
[root@master ~]# docker tag 172.25.254.200/flannel-io/flannel:v0.28.1 172.25.254.200/flannel-io/flannel:v0.28.1
[root@master ~]# docker tag 172.25.254.200/flannel-io/flannel-cni-plugin:v1.9.0-flannel1 172.25.254.200/flannel-io/flannel-cni-plugin:v1.9.0-flannel1

4.5.3 推送到私有仓库

复制代码
[root@master ~]# docker push 172.25.254.200/flannel-io/flannel:v0.28.1
[root@master ~]# docker push 172.25.254.200/flannel-io/flannel-cni-plugin:v1.9.0-flannel1

4.5.4 修改kube-flannel.yml

复制代码
[root@master ~]# vim kube-flannel.yml

三个修改的地方:

4.6 应用网络插件

复制代码
[root@master ~]# kubectl apply -f kube-flannel.yml

4.7 测试


五、搭建CI/CD环境

5.1 部署GitLab代码仓库

5.1.1 在gitlab-server服务器执行如下命令来创建挂载卷

复制代码
[root@gitlab-server ~]# docker volume create gitlab-etc
[root@gitlab-server ~]# docker volume create gitlab-log
[root@gitlab-server ~]# docker volume create gitlab-opt

5.1.2 修改systcl.conf文件,防止后续运行是报错信息

复制代码
[root@gitlab-server ~]# cat >> /etc/sysctl.conf <<-'EOF'
kernel.perf_event_max_sample_rate=79000
vm.max_map_count=262144
EOF
sysctl -p

5.1.3 执行如下命令来安装gitlab服务容器

复制代码
[root@gitlab-server ~]# docker run --detach \
  --hostname 172.25.254.23 \
  -p 443:443 \
  -p 80:80 \
  --name gitlab \
  --restart always \
  --volume gitlab-etc:/etc/gitlab \
  --volume gitlab-log:/var/log/gitlab \
  --volume gitlab-opt:/var/opt/gitlab \
  --shm-size 256m \
gitlab/gitlab-ee:17.3.1-ee.0

[root@gitlab-server ~]# docker images
REPOSITORY         TAG           IMAGE ID       CREATED       SIZE
gitlab/gitlab-ce   17.3.1-ce.0   b3c3467dc55c   5 weeks ago   3.03GB

[root@gitlab-server ~]# docker ps

Gitlab 服务器的登录密码可通过如下命令来查看

复制代码
[root@gitlab-server ~]# docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password
Password: oJhP0nKx3SniZWHzgY+ckL7aYqxpMHabsrTwQ6n7YU0=

5.2 初始化GitLab

打开浏览器,输入http://172.25.254.23后,输入root用户名以及前面查询到的密码

点击登录按钮后,进入到界面

点击左上角的圆形图片,进入到User链接后点击Preferences

再点击Password便能修改密码

5.3 部署GitLab Runner

复制代码
# 执行如下命令下载GitLab提供的YUM安装源
[root@gitlab-runner local]# curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh" | sudo bash

# 查看仓库源
[root@gitlab-runner local]# ls /etc/yum.repos.d/
base.repo  docker-ce.repo  kubernetes.repo  redhat.repo  runner_gitlab-runner.repo

# 执行如下命令安装GItLab-Runner
[root@gitlab-runner local]# yum install -y gitlab-runner-17.3.1

# 接下来再执行如下命令查看所有用户
[root@gitlab-runner local]# cut -d: -f1 /etc/passwd

# 我们直接使用 root 用户来操作,执行如下命令来卸载原始信息
[root@gitlab-runner local]# sudo gitlab-runner uninstall

# 然后执行如下命令安装并设置 root 用户为操作用户
[root@gitlab-runner local]# gitlab-runner install --working-directory /home/gitlab-runner --user root Runtime platform arch=amd64 os=linux pid=20348 revision=66269445 version=17.3.1

# 接下执行如下命令来重新加载
[root@gitlab-runner local]# systemctl daemon-reload

# 然后启动 gitlab-runner 并设置为开机自启
[root@gitlab-runner local]# systemctl enable --now gitlab-runner

# 为了验证,我们可查看当前 runner 用户
[root@gitlab-runner local]# ps aux | grep gitlab-runner
[root@gitlab-runner local]# git config --system --add safe.directory '*'
[root@gitlab-runner local]# chmod -R 777 /home/gitlab-runner
[root@gitlab-runner local]# systemctl restart gitlab-runner

5.4 注册Runner

回到 Gitlab 服务管理界面并点击界面左下角的 Admin 按钮,点击后再点击左右菜单中的 CI/CD 链接下的 Runners 链接

然后点击上图中的 New instance runner 按钮

填写好一个标签后,其它都不选也不用输入。然后点击界面下的 Create runner 按钮

在这个界面中选择好操作系统后,复制上图指定的代码,然后在 gitlab-runner 主机上运行这段复制的代码

复制代码
[root@gitlab-runner local]#gitlab-runner register  --url http://172.25.254.23  --token glrt-no-xtLxm8Hq1XgxLKoi_

就会生成一个配置文件,路径为 /etc/gitlab-runner/config.toml。操作完成后,在 Gitlab 服务管理界面中就 Runner 面板中就会看到如下图所示的配置


六、项目文件结构

在Gitlab上创建项目:


七、核心配置文件

把代码放到 GitLab 仓库根目录,只需要 1 个配置文件,系统自动生成其他文件:

复制代码
[root@master ~]# mkdir /root/k8s/deploy  -p
[root@master ~]# cd /root/k8s/deploy/
[root@master deploy]# mkdir my-page
[root@master deploy]# cd my-page
[root@master my-page]# echo "hello,CICD" > index.html

配置 K8s 集群访问权限

复制代码
# 1. 从K8s Master节点(192.168.223.20)拷贝config文件
# 先在Master节点执行:
[root@master ~]# cat ~/.kube/config 复制内容

# 在Runner节点执行:
[root@gitlab-runner ~]# mkdir -p ~/.kube
[root@gitlab-runner ~]# vim ~/.kube/config
# 粘贴Master节点的config内容(确保内容完整,包含集群、用户、上下文信息)

[root@gitlab-runner ~]# vim /etc/yum.repos.d/kubernetes.repo 
[kubernetes]
name = kubernetes
baseurl = https://mirrors.aliyun.com/kubernetes-new/core/stable/v1.35/rpm/
gpgcheck = 0
[root@gitlab-runner ~]# yum install kubectl -y

# 2. 验证kubectl权限
[root@master ~]# kubectl get nodes -n default

# 若报错需检查:
# - Master节点的API Server地址是否可访问(6443端口)
# - config文件中的证书/令牌是否有效
# - Runner节点与Master节点的网络连通性

在项目根目录新建文件 .gitlab-ci.yml,复制以下全部内容:

复制代码
stages:
  - build
  - push
  - deploy

variables:
  HARBOR_REGISTRY: "192.168.223.200"
  HARBOR_PROJECT: "k8s-project"
  IMAGE_NAME: "my-page"
  TAG: "$CI_COMMIT_SHORT_SHA"
  NAMESPACE: "default"

# 构建镜像
build:
  stage: build
  tags:
    - shared
  script:
    - echo "=== 构建镜像 ==="
    - docker build -t ${HARBOR_REGISTRY}/${HARBOR_PROJECT}/${IMAGE_NAME}:${TAG} .

# 推送镜像
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 tag ${HARBOR_REGISTRY}/${HARBOR_PROJECT}/${IMAGE_NAME}:${TAG} ${HARBOR_REGISTRY}/${HARBOR_PROJECT}/${IMAGE_NAME}:latest
    - docker push ${HARBOR_REGISTRY}/${HARBOR_PROJECT}/${IMAGE_NAME}:latest

# 部署(完美无错版)
deploy:
  stage: deploy
  tags:
    - shared
  script:
    - echo "=== 开始部署 my-page ==="
    - export IMAGE=${HARBOR_REGISTRY}/${HARBOR_PROJECT}/${IMAGE_NAME}:${TAG}
    - echo "使用镜像:$IMAGE"

    # 渲染变量
    - envsubst '$IMAGE' < nginx-deploy.yaml > rendered.yaml

    # 部署
    - kubectl apply -f rendered.yaml

    # 等待发布完成
    - kubectl rollout status deployment my-page -n ${NAMESPACE} --timeout=120s

    # 清理异常Pod
    - kubectl delete pod -l app=my-page -n ${NAMESPACE} --field-selector=status.phase!=Running 2>/dev/null || true

    - rm -f rendered.yaml
    - echo "=== ✅ 部署成功 ==="
    - kubectl get pods -n ${NAMESPACE}

八、一键自动化部署

场景 1:首次部署(代码没上传过)

1、创建项目仓库

2、把前端代码 .gitlab-ci.yml 放到项目根目录

复制代码
[root@master my-page]# yum install git -y 

git config --global user.name "Administrator"
git config --global user.email "gitlab_admin_dc9ff2@example.com"

[root@master deploy]# cd my-page
[root@master deploy]# git init --initial-branch=main
[root@master deploy]# git remote add origin http://172.25.254.23/root/my-page.git
[root@master deploy]# git add .
[root@master deploy]# git commit -m "Initial commit"
[root@master deploy]# git push --set-upstream origin main

3、打开终端,执行 3 条命令:

复制代码
[root@master ~]# git add .
[root@master ~]# git commit -m "首次部署前端项目"
[root@master ~]# git push

4、全自动运行:GitLab 自动构建镜像 → 推送到 Harbor → 部署到 K8s

场景 2:修改代码后自动更新

1、 直接修改你的前端代码(比如 index.html

2、 执行 3 条命令,触发自动更新

复制代码
[root@master ~]# git add .
[root@master ~]# git commit -m "修改前端页面"
[root@master ~]# git push

3、 等待 1~2 分钟,刷新浏览器就是最新页面


九、查看部署进度

  1. 打开你的 GitLab 项目页面

  2. 左侧菜单栏 → 点击 Build → Jobs

  3. 看到绿色对勾 ✅ = 部署成功;红色 ❌ = 失败(看下面常见问题)


十、验证部署成果

方法一:浏览器访问

打开浏览器,输入地址:

复制代码
http://172.25.254.20:30083

方法二:命令行检查

查看pod状态:

复制代码
[root@master my-page]# kubectl get pods -n default | grep my-page
my-page-c45f78574-nh6c4   1/1     Running   0          97s

[root@master my-page]#  kubectl get svc -n default | grep my-page
my-page-svc   NodePort    10.97.86.56   <none>        80:30083/TCP   5m22s

[root@master my-page]# kubectl logs -f $(kubectl get pods -n default | grep my-page | awk '{print $1}') -n default

基于 CI/CD + K8s 环境部署 Java 项目

整体思路

Java 项目需要先编译打包(Maven) → 构建 Docker 镜像 → 推送 Harbor → 部署 K8s,核心是用 Docker 镜像封装 Java 运行环境,避免 Runner 装 Maven/JDK

【第一步】创建 Java 项目目录(和前端项目同级)

复制代码
# 回到部署根目录
[root@master ~]# cd /root/k8s/deploy

# 创建java项目目录
[root@master ~]# mkdir java-demo
[root@master ~]# cd java-demo

【第二步】编写 4 个核心文件(直接复制)

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

生成正确的 HelloController.java (java-demo 版)

复制代码
[root@master ~]# mkdir -p src/main/java/com/demo
[root@master ~]# 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 正常运行!";
    }
}
EOF

生成启动类 DemoApplication.java (war 包必备)

复制代码
[root@master ~]# 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)

复制代码
[root@master ~]# 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

复制代码
[root@node1 ~]# docker load -i tomcat-9.0-jdk11.tar 
Loaded image: tomcat:9.0-jdk11

[root@node1 ~]# docker tag tomcat:9.0-jdk11 172.25.254.200/k8s-project/tomcat:9.0-jdk11
[root@node1 ~]# docker push 172.25.254.200/k8s-project/tomcat:9.0-jdk11

[root@node1 ~]# cat Dockerfile 
FROM 172.25.254.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"]

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

复制代码
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

5. 在【Master +gitlab-runner节点】安装 Maven+JDK11(避免 Runner 拉取镜像报错)

复制代码
# 安装 JDK + Maven(编译环境)

# 1. 上传 jdk-11.tar.gz 到 /root 目录,执行解压
[root@gitlab-runner ~]# tar -zxf jdk-11_linux-x64_bin.tar.gz  
[root@gitlab-runner ~]# mv  jdk-11  jdk11

# 2. 配置全局环境变量(永久生效)
[root@gitlab-runner ~]# 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. 生效并验证
[root@gitlab-runner ~]# source /etc/profile.d/jdk.sh
[root@gitlab-runner ~]# java -version  # 输出JDK版本即成功


# 再gitlab-runner部署
# 1. 下载 Maven 3.9.6(适配JDK 11)
[root@gitlab-runner ~]# cd /root
[root@gitlab-runner ~]# wget https://archive.apache.org/dist/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz

# 2. 解压并重命名
[root@gitlab-runner ~]# tar -zxf   apache-maven-3.9.14-bin.tar.gz 
[root@gitlab-runner ~]# mv apache-maven-3.9.14    maven

# 3. 配置全局环境变量
[root@gitlab-runner ~]# cat > /etc/profile.d/maven.sh << 'EOF'
export MAVEN_HOME=/root/maven
export PATH=$MAVEN_HOME/bin:$PATH
EOF

[root@gitlab-runner ~]# source /etc/profile.d/maven.sh
[root@gitlab-runner ~]# mvn -version  # 输出Maven版本即成功

[root@gitlab-runner package]# vim /root/maven/conf/settings.xml
.....
<mirror>
    <id>tencentmaven</id>
    <mirrorOf>central</mirrorOf>
    <url>https://maven.aliyun.com/repository/public/</url>
</mirror>
....


# 3. 进入 java-demo 项目目录,本地编译
[root@gitlab-runner package]# cd /root/k8s/deploy/java-demo
[root@gitlab-runner package]# mvn clean package -DskipTests

【第三步】编写 GitLab CI/CD 配置(.gitlab-ci.yml)

复制代码
[root@master ~]# vim .gitlab-ci.yml
stages:
  - build
  - push
  - deploy

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

build:
  stage: build
  tags:
    - shared
  script:
    - echo "=== 编译打包 ==="
    - mvn clean package -DskipTests
    - 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:
    - 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:
    - 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
    - kubectl get pods -n ${NAMESPACE}

【第四步】推送到 GitLab 仓库(触发自动部署)

复制代码
# 初始化Git仓库
[root@master ~]# git init
# 添加所有文件
[root@master ~]# git add .
# 提交
[root@master ~]# git commit -m "init java demo: hello CICD, i am java"
# 添加远程仓库(替换成你的GitLab地址)
[root@master ~]# git remote add origin http://192.168.223.23/root/java-demo.git
# 推送
[root@master ~]# git push -u origin main

【第五步】验证部署结果

1. 查看 CI/CD 流水线

打开 GitLab → 项目 → CI/CD → Pipelines,确认 build/push/deploy 三个阶段都显示绿色 ✅。

2. 查看 K8s Pod 状态

复制代码
[root@master ~]# kubectl get pods -n default | grep java-demo
# 正常输出:java-demo-xxxxxx-xxxx   1/1     Running   0          10s

3. 访问 Java 页面

复制代码
http://172.25.254.20:30084
相关推荐
行者-全栈开发1 小时前
Jenkins 与 GitLab 深度集成实战:从 Webhook 到 Merge Request 全流程自动化
gitlab·jenkins·webhook·merge request·multibranch·source plugin·ci/cd 自动化
印度神油917 小时前
Windows Python 打包实战:Nuitka 环境踩坑总结与 CI 自动化构建全指南
windows·python·ci/cd
only_Klein18 小时前
k8sgpt集成Prometheus Grafana
gpt·kubernetes·prometheus
有毒的教程19 小时前
Kubernetes进阶实战教程(生产落地完整版)
云原生·容器·kubernetes
白日焰火121 小时前
Redis 哨兵搭建+ACL权限控制
linux·docker·kubernetes
h3guang Official1 天前
K8s安全实战:从漏洞靶场到红蓝对抗
安全·容器·kubernetes
X1ao hu1 天前
dashboard 动态卷 stateful
kubernetes
only_Klein1 天前
AI故障诊断工具—k8sGPT
人工智能·gpt·kubernetes
zhojiew2 天前
将 OCAI 接入 Kubernetes MCP Server 的实践
人工智能·容器·kubernetes