基于 CI/CD 平台将应用程序自动部署到 Kubernetes 集群
序:核心背景与需求
在现代软件开发与运维体系中,基于 CI/CD 平台将应用程序自动部署到 Kubernetes 集群的项目,源于以下核心背景与需求:
1. 技术与行业趋势驱动
- 容器化普及:Docker 等容器技术实现了应用与运行环境的 “封装一致”,解决了 “开发环境能跑,生产环境报错” 的历史难题,成为应用交付的标准载体。
- Kubernetes 主导编排:随着应用向分布式、微服务架构演进,Kubernetes 凭借对容器的自动化编排能力(部署、扩缩容、自愈等),成为大规模容器化应用的 “标配管理平台”。
- CI/CD 需求升级:市场对软件迭代速度、交付稳定性的要求急剧提升,传统 “手动编译→打包→上传→部署” 的流程效率低下、易出错,必须通过 ** 持续集成(CI,代码提交后自动编译、测试)和持续部署(CD,测试通过后自动发布到生产环境)** 实现全链路自动化。
2. 企业面临的核心痛点
- 环境一致性问题:开发、测试、生产环境的依赖、配置差异,导致应用部署后行为不一致,排查成本高。
- 手动运维效率低下:应用容器化后,若仍依赖人工操作部署到 Kubernetes,在集群规模扩大(如百级、千级容器)时,运维成本呈指数级增长,且无法保障部署时效性与准确性。
- 迭代周期长:从代码开发到用户可用的链路冗长,需经历 “提交→等待人工编译→等待人工测试→等待人工部署” 等环节,难以快速响应业务需求。
3. 项目核心目标
通过搭建 CI/CD 自动化流水线,实现从 “代码提交” 到 “Kubernetes 集群部署” 的全流程自动化:
- 开发者提交代码后,自动触发编译、单元测试、镜像构建;
- 镜像自动推送到私有镜像仓库(如内网 Registry);
- 最终自动将应用部署到 Kubernetes 集群,并完成服务暴露、健康检查等运维配置,实现 “代码提交即部署,快速验证且稳定交付”。
4. 技术栈协同逻辑
项目需整合多类技术形成闭环:
- 版本控制(Git):作为代码仓库,触发 CI/CD 流程的 “源头”;
- CI/CD 平台(Jenkins/GitLab CI 等):作为 “中枢”,编排 “编译→测试→镜像构建→部署” 的自动化步骤;
- 容器化(Docker):封装应用与依赖,生成标准镜像;
- 私有镜像仓库:存储构建好的镜像,供 Kubernetes 拉取;
- Kubernetes:作为 “运行时平台”,负责应用容器的调度、扩缩容与高可用管理。
简言之,该项目是容器化、编排技术与自动化交付流程的结合,旨在解决传统部署的效率与稳定性问题,支撑企业快速迭代、规模化运维的需求。
一、基础环境配置(所有节点)
1. 域名解析(/etc/hosts
)
在涉及的主机(如 Jenkins 主机 host1
、K8s 节点 host2
、GitLab 服务器)上配置内网域名解析,方便服务间访问:
[root@host1 ~]# sudo vi /etc/hosts
[root@host1 ~]# sudo cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.197.91 registry.abc.com
192.168.197.9 jenkins-host # Jenkins 所在主机 IP
192.168.197.9 gitlab.abc.com # GitLab 服务器 IP
192.168.197.91 k8s.abc.com # K8s 集群节点(host2)IP
2. Docker 配置国内镜像源(加速镜像拉取)
在 host1
(Jenkins 主机,需构建 Docker 镜像)和 host2
(K8s 节点,需拉取镜像)上,修改 Docker 守护进程配置:
[root@host1 ~]# vi /etc/docker/daemon.json
[root@host1 ~]# cat /etc/docker/daemon.json
{"registry-mirrors": ["https://9fbd5949cbc94e4a9581e33b9077c811.mirror.swr.myhuaweicloud.com","https://jnh8ca4k.mirror.aliyuncs.com","https://mirror.ccs.tencentyun.com","https://registry.docker-cn.com"],"insecure-registries": ["192.168.197.9:5000","registry.abc.com:5000"],"live-restore": true
}
[root@host1 ~]# sudo systemctl daemon-reload
[root@host1 ~]# sudo systemctl restart docker
host2 上同步操作:
[root@host2 ~]# sudo vi /etc/hosts
[root@host2 ~]# sudo cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.197.91 registry.abc.com
192.168.197.9 jenkins-host # Jenkins 所在主机 IP
192.168.197.9 gitlab.abc.com # GitLab 服务器 IP
192.168.197.91 k8s.abc.com # K8s 集群节点(host2)IP
[root@host2 ~]# sudo vi /etc/docker/daemon.json
[root@host2 ~]# sudo cat /etc/docker/daemon.json
{"registry-mirrors": ["https://9fbd5949cbc94e4a9581e33b9077c811.mirror.swr.myhuaweicloud.com","https://jnh8ca4k.mirror.aliyuncs.com","https://mirror.ccs.tencentyun.com","https://registry.docker-cn.com"],"insecure-registries": ["192.168.197.9:5000","registry.abc.com:5000"],"live-restore": true
}
[root@host2 ~]# sudo systemctl daemon-reload
[root@host2 ~]# sudo systemctl restart docker
[root@host2 ~]# sudo docker run -d --restart=always -p 5000:5000 --name registry registry:2
Unable to find image 'registry:2' locally
2: Pulling from library/registry
44cf07d57ee4: Pull complete
bbbdd6c6894b: Pull complete
8e82f80af0de: Pull complete
3493bf46cdec: Pull complete
6d464ea18732: Pull complete
Digest: sha256:a3d8aaa63ed8681a604f1dea0aa03f100d5895b6a58ace528858a7b332415373
Status: Downloaded newer image for registry:2
27101e645df048203dba9a00fb36f55a84328dd6d2297af327c091be15702dc0
[root@host2 ~]# sudo firewall-cmd --add-port=5000/tcp --permanent
FirewallD is not running
[root@host2 ~]# curl http://registry.abc.com:5000/v2/
{}
二、GitLab 代码仓库准备
1. 创建项目(之前有跳过)
在 GitLab 中创建名为 k8s-demo
的空白项目(若无 GitLab,可临时用本地仓库,生产建议用 GitLab/Gitee)。
[root@host1 ~]# mkdir k8s-demo && cd k8s-demo
[root@host1 k8s-demo]# git init
bash: git: 未找到命令...
安装软件包“git-core”以提供命令“git”? [N/y] y* 正在队列中等待... * 正在载入软件包列表。...
下列软件包必须安装:git-core-2.47.3-1.el9.x86_64Core package of git with minimal functionality
继续更改? [N/y] y* 正在队列中等待... * 正在等待认证... * 正在队列中等待... * 正在下载软件包... * 正在请求数据... * 正在测试更改... * 正在安装软件包...
提示: 使用 'master' 作为初始分支的名称。这个默认分支名称可能会更改。要在新仓库中
提示: 配置使用初始分支名,并消除这条警告,请执行:
提示:
提示: git config --global init.defaultBranch <名称>
提示:
提示: 除了 'master' 之外,通常选定的名字有 'main'、'trunk' 和 'development'。
提示: 可以通过以下命令重命名刚创建的分支:
提示:
提示: git branch -m <name>
已初始化空的 Git 仓库于 /root/k8s-demo/.git/[root@host1 k8s-demo]# git init
已重新初始化已存在的 Git 仓库于 /root/k8s-demo/.git/
[root@host1 k8s-demo]# touch spring-boot-hello.yaml
2. 本地初始化代码(host1
操作)
克隆仓库并添加项目文件:
# 切换到项目目录(如 ~/ch08)
cd ~/ch08
# 克隆 GitLab 仓库(替换为实际 GitLab 地址)
git clone ssh://git@gitlab.abc.com:2222/root/k8s-demo.git
cd k8s-demo
3. 添加核心文件
(1)Dockerfile
(构建 Spring Boot 镜像)
FROM openjdk:11-jre-slim # 基于国内镜像源加速拉取的 OpenJDK 镜像
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]
(2)pom.xml
(Maven 构建配置)
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.5</version><relativePath/></parent><groupId>com.abc</groupId><artifactId>spring-boot-hello</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-boot-hello</name><properties><java.version>11</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>
(3)src/main/java/com/abc/hello/HelloController.java
(Spring Boot 控制器)
package com.abc.hello;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class HelloController {@GetMapping("/")public String hello() {return "Hello! Please test K8S CI/CD!";}
}
(4)src/main/java/com/abc/hello/SpringBootHelloApplication.java
(启动类)
package com.abc.hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringBootHelloApplication {public static void main(String[] args) {SpringApplication.run(SpringBootHelloApplication.class, args);}
}
(5)kube.yaml
(Kubernetes 资源配置)
apiVersion: apps/v1
kind: Deployment
metadata:name: sbdemo-deploy
spec:replicas: 1selector:matchLabels:app: spring-boot-hellotemplate:metadata:labels:app: spring-boot-hellospec:containers:- name: spring-boot-helloimage: registry.abc.com:5000/spring-boot-hello # 内网私有仓库地址ports:- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:name: sbdemo-svc
spec:type: NodePortselector:app: spring-boot-helloports:- port: 8080targetPort: 8080nodePort: 30008 # 暴露到主机的端口(30000-32767 区间)
(6)Jenkinsfile
(Jenkins 流水线脚本)
pipeline {agent anystages {stage('Build') {steps {// Maven 构建(跳过测试加速)sh 'mvn -B -DskipTests clean package'// 构建 Docker 镜像(关联 Maven 打包的 JAR)sh 'docker build --build-arg JAR_FILE=target/spring-boot-hello-0.0.1-SNAPSHOT.jar -t registry.abc.com:5000/spring-boot-hello .'// 推送镜像到内网私有仓库sh 'docker push registry.abc.com:5000/spring-boot-hello'}}stage('Deploy') {steps {// 通过 SSH 传输配置文件并部署到 K8s 集群sshPublisher(publishers: [sshPublisherDesc(configName: 'K8SHost', // Jenkins 中配置的 SSH 服务器名transfers: [sshTransfer(cleanRemote: false,excludes: '',execCommand: 'cd ~/spring-boot-hello && kubectl delete -f kube.yaml || true && kubectl apply -f kube.yaml',execTimeout: 120000,flatten: false,makeEmptyDirs: false,noDefaultExcludes: false,patternSeparator: '[, ]+',remoteDirectory: 'spring-boot-hello',remoteDirectorySDF: false,removePrefix: '',sourceFiles: '**/kube.yaml')],usePromotionTimestamp: false,useWorkspaceInPromotion: false,verbose: false)])}}}
}
三、Jenkins 配置
1. 安装必要插件
进入 Jenkins → Manage Jenkins → Manage Plugins,安装:
Maven Integration
(Maven 项目支持)Publish Over SSH
(SSH 远程部署支持)
2. 系统配置(Manage Jenkins → Configure System
)
(1)Maven 配置
- 找到 Maven 区域,点击 “Add Maven”,命名为
Maven-3.8.6
(可选择 “Install automatically” 或指定本地 Maven 路径)。
(2)Publish Over SSH 配置
- 找到 Publish Over SSH 区域,点击 “Add → SSH Server”:
- Name:
K8SHost
(与Jenkinsfile
中configName
一致)。 - Hostname:
k8s.abc.com
(K8s 节点host2
的主机名 / IP)。 - Username:
root
(或 K8s 节点上有权限的用户)。 - 点击 “Advanced”,勾选 “Use password authentication, or use a different key”,填写 K8s 节点的 SSH 密码。
- Remote Directory:
~
(或指定部署目录,如/root
)。 - 点击 “Test Configuration”,显示
Success
则配置正常。
- Name:
四、推送代码到 GitLab
将所有文件提交并推送到 GitLab 仓库:
cd ~/ch08/k8s-demo
git add .
git commit -m "Init K8s CI/CD project with domestic mirrors"
git push origin main
五、Jenkins 创建流水线项目
1. 新建任务
- 进入 Jenkins → New Item,选择 “Pipeline”,命名为
k8s-demo
→ 点击 “OK”。
2. 配置流水线
- Pipeline → Definition:选择
Pipeline script from SCM
。 - SCM:选择
Git
。 - Repository URL:填写 GitLab 仓库地址(如
ssh://git@gitlab.abc.com:2222/root/k8s-demo.git
)。 - Branch Specifier:
*/main
(或*/master
,根据仓库分支名调整)。 - Script Path:
Jenkinsfile
(与项目中文件名一致)。
3. 执行构建
点击 “Save” 保存配置,然后点击 “Build Now” 启动流水线。
六、验证部署(K8s 节点 host2
操作)
1. 查看 Kubernetes 资源
kubectl get deployments # 应看到 sbdemo-deploy(READY 1/1)
kubectl get pods # 应看到 sbdemo-deploy-xxx(STATUS Running)
kubectl get services # 应看到 sbdemo-svc(TYPE NodePort,PORT(S) 8080:30008/TCP)
2. 访问服务
curl 127.0.0.1:30008
# 预期输出:Hello! Please test K8S CI/CD!
关键说明
国内镜像源:通过
daemon.json
的registry-mirrors
加速 OpenJDK、Maven 等基础镜像的拉取,避免依赖 Docker Hub 外网速度。私有仓库:
registry.abc.com:5000
需确保是 HTTP 服务,且 Docker 配置了insecure-registries
,否则镜像推送 / 拉取会失败。SSH 部署:Jenkins 需能通过 SSH 免密(或密码)登录 K8s 节点,并具备
kubectl
操作权限。动态调整:需根据实际环境修改域名、IP、仓库地址、K8s 资源配置(如 NodePort 端口、镜像名)。
通过以上步骤,即可实现基于国内镜像源的从代码提交到 Kubernetes 部署的全流程自动化 CI/CD。
代码部分过程:
Activate the web console with: systemctl enable --now cockpit.socketLast login: Mon Sep 29 17:54:00 2025 from 192.168.197.1
[root@host1 ~]# sudo vi /etc/hosts
[root@host1 ~]# sudo cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.197.91 registry.abc.com
192.168.197.9 jenkins-host # Jenkins 所在主机 IP
192.168.197.9 gitlab.abc.com # GitLab 服务器 IP
192.168.197.91 k8s.abc.com # K8s 集群节点(host2)IP
[root@host1 ~]# vi /etc/docker/daemon.json
[root@host1 ~]# cat /etc/docker/daemon.json
{"registry-mirrors": ["https://9fbd5949cbc94e4a9581e33b9077c811.mirror.swr.myhuaweicloud.com","https://jnh8ca4k.mirror.aliyuncs.com","https://mirror.ccs.tencentyun.com","https://registry.docker-cn.com"],"insecure-registries": ["192.168.197.9:5000","registry.abc.com:5000"],"live-restore": true
}
[root@host1 ~]# sudo systemctl daemon-reload
[root@host1 ~]# sudo systemctl restart docker
[root@host1 ~]# cd ~/ch08
[root@host1 ch08]# cd
[root@host1 ~]#
[root@host1 ~]#
[root@host1 ~]# mkdir k8s-demo && cd k8s-demo
[root@host1 k8s-demo]# git init
bash: git: 未找到命令...
安装软件包“git-core”以提供命令“git”? [N/y] y* 正在队列中等待... * 正在载入软件包列表。...
下列软件包必须安装:git-core-2.47.3-1.el9.x86_64Core package of git with minimal functionality
继续更改? [N/y] y* 正在队列中等待... * 正在等待认证... * 正在队列中等待... * 正在下载软件包... * 正在请求数据... * 正在测试更改... * 正在安装软件包...
提示: 使用 'master' 作为初始分支的名称。这个默认分支名称可能会更改。要在新仓库中
提示: 配置使用初始分支名,并消除这条警告,请执行:
提示:
提示: git config --global init.defaultBranch <名称>
提示:
提示: 除了 'master' 之外,通常选定的名字有 'main'、'trunk' 和 'development'。
提示: 可以通过以下命令重命名刚创建的分支:
提示:
提示: git branch -m <name>
已初始化空的 Git 仓库于 /root/k8s-demo/.git/[root@host1 k8s-demo]# git init
已重新初始化已存在的 Git 仓库于 /root/k8s-demo/.git/
[root@host1 k8s-demo]# touch spring-boot-hello.yaml
[root@host1 k8s-demo]# git add .
[root@host1 k8s-demo]# git commit -m "Initial commit"
作者身份未知*** 请告诉我您是谁。运行git config --global user.email "you@example.com"git config --global user.name "Your Name"来设置您账号的缺省身份标识。
如果仅在本仓库设置身份标识,则省略 --global 参数。致命错误:无法自动探测邮件地址(得到 'root@host1.(none)')
[root@host1 k8s-demo]#
[root@host1 k8s-demo]#
[root@host1 k8s-demo]# cd ~/ch08
[root@host1 ch08]# git clone ssh://git@192.168.197.9.com:2222/root/k8s-demo.git
正克隆到 'k8s-demo'...
ssh: Could not resolve hostname 192.168.197.9.com: Name or service not known
致命错误:无法读取远程仓库。请确认您有正确的访问权限并且仓库存在。
[root@host1 ch08]#
[root@host1 ch08]# cd
[root@host1 ~]# git config --global user.name "root"
[root@host1 ~]# git config --global user.email "root@host1.local"
[root@host1 ~]# git config --list | grep user
user.name=root
user.email=root@host1.local
[root@host1 ~]# cd ~/k8s-demo
[root@host1 k8s-demo]# git add .
[root@host1 k8s-demo]# git commit -m "Initial commit: Add spring-boot-hello.yaml"
[master(根提交) 00e64fa] Initial commit: Add spring-boot-hello.yaml1 file changed, 0 insertions(+), 0 deletions(-)create mode 100644 spring-boot-hello.yaml
[root@host1 k8s-demo]#