CICD

CI/CD

git基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
git init                      //初始化 
git add main.cpp //将某一个文件添加到暂存区
git add . //将文件夹下的所有的文件添加到暂存区
git commit -m ‘note‘ //将暂存区中的文件保存成为某一个版本
git log //查看所有的版本日志
git status //查看现在暂存区的状况
git diff //查看现在文件与上一个提交-commit版本的区别
git reset --hard HEAD^ //回到上一个版本
git reset --hard XXXXX //XXX为版本编号,回到某一个版本
git pull origin master //从主分支pull到本地
git push -u origin master //从本地push到主分支
git pull //pull默认主分支
git push //push默认主分支 ...
git checkout -b dev // 创建dev分支,然后切换到dev分支
git checkout // 命令加上-b参数表示创建并切换,相当于以下两条命令:
git branch dev git checkout dev
git branch // 命令查看当前分支,
git branch // 命令会列出所有分支,当前分支前面会标一个*号
git branch * dev master
git add readme.txt git commit -m "branch test" // 在dev分支上正常提交.

启动jenkins

1
nohup java -jar jenkins.war --httpPort=8080 &nohup java -jar jenkins.war --httpPort=8080 &

jenkins.maven

需要在gitlab上放上jenkins的公钥以便jenkins可以拉取gitlab的仓库

image-20250323114548139

配置全局变量

image-20250322220309535

配置mvn git jdk环境

1
2
3
mvn -version
which git
which java -->> ll /usr/bin/java

下载mvn插件能够让job构建一个maven项目

image-20250322220917348

image-20250322222318167

执行docker远程主机命令需要下载插件Publish Over SSH

image-20250322223005097

执行webhoob钩子需要下载插件Generic Webhook Trigger

image-20250322222731099

需要在gitlab上配置 搭配webhook

image-20250322223110245

image-20250322223331581

pipeline

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
pipeline {
agent any
tools {
maven "mvn" ##配置mvn环境 mvn是在配置变量里面写的名字
}
stages {
stage('拉取仓库') {
steps {
git branch: 'slave', url: '[email protected]:ceshi/test.git'
echo '拉取成功'
}
}

stage('mvn打包') {
steps {
sh '''cd /root/.jenkins/workspace/java-pipeline
mvn clean package'''
echo '打包完成'
}
}
stage('docker执行') {
steps {
sshPublisher(publishers: [sshPublisherDesc(configName: 'docker-java', transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: '', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '/root', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '**/*.jar'), sshTransfer(cleanRemote: false, excludes: '', execCommand: '''cd /root/root

docker stop java
docker rm -f java
docker rmi java
docker build -t java .
docker run -d --name java -p 8081:8080 java''', execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '/root', remoteDirectorySDF: false, removePrefix: '', sourceFiles: '**/Dockerfile')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
echo '执行成功'
}
}
}
}

基于k8s流水线

需要让jenkins机器能够调用api

1
# scp ~/.kube/config  192.168.85.132:~/.kube/

gitlab的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# cat k8s/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: {{PACKAGE_NAME}}
namespace: {{K8S_NAMESPACE}}
spec:
replicas: {{K8S_REPLICAS}}
selector:
matchLabels:
app: {{PACKAGE_NAME}}
template:
metadata:
labels:
app: {{PACKAGE_NAME}}
spec:
containers:
- name: {{PACKAGE_NAME}}
image: "{{IMAGE_NAME}}"
imagePullPolicy: Always
ports:
- containerPort: 8080
# cat Dockerfile
from openjdk
expose 8080
add ./target/simple-jar-project-1.0-SNAPSHOT.jar /root/
entrypoint ["java", "-jar", "/root/simple-jar-project-1.0-SNAPSHOT.jar"]

# cat Jenkinsfile

pipeline {
agent any

tools {
maven 'mvn'
}
parameters {
// GitLab 分支选择,允许用户选择需要部署的分支
string(name: 'GITLAB_BRANCH', defaultValue: 'slave', description: 'GitLab 分支名称')

// Java 包名字,允许用户自定义包名
string(name: 'PACKAGE_NAME', defaultValue: 'your-java-app', description: 'Java 包名字')

// 版本号,允许用户自定义
string(name: 'VERSION', defaultValue: '1.0.0', description: 'Java 包版本号')

// 部署类型选择,用户选择 deploy 或 update
choice(name: 'DEPLOY_TYPE', choices: ['deploy', 'update'], description: '选择部署或更新操作')

// Docker Registry,允许用户指定 Docker 镜像仓库
string(name: 'DOCKER_REGISTRY', defaultValue: '192.168.85.128', description: 'Docker 镜像仓库地址')

// Kubernetes 部署命名空间,允许用户自定义
string(name: 'K8S_NAMESPACE', defaultValue: 'default', description: 'Kubernetes 命名空间')

// Kubernetes 部署副本数,用户可以自定义
string(name: 'K8S_REPLICAS', defaultValue: '1', description: 'Kubernetes 部署副本数')

// 服务暴露端口,允许用户指定
string(name: 'SERVICE_PORT', defaultValue: '8080', description: '服务暴露端口')

// 自定义 Kubernetes 部署的其他信息,比如镜像仓库、标签等
string(name: 'K8S_DEPLOYMENT_FILE', defaultValue: 'k8s/deployment.yaml', description: 'Kubernetes 部署文件路径')
}

environment {
// 构建 Docker 镜像标签
IMAGE_NAME = "${params.DOCKER_REGISTRY}/nb/${params.PACKAGE_NAME}:${params.VERSION}"
// Kubernetes 配置文件临时路径
K8S_TEMP_FILE = "${WORKSPACE}/k8s-deployment-temp.yaml"
}

stages {
stage('检出代码') {
steps {
script {
echo "正在从 GitLab 拉取分支 ${params.GITLAB_BRANCH} 的代码..."
git branch: "${params.GITLAB_BRANCH}", url: '[email protected]:ceshi/test.git'
}
}
}

stage('构建 Java 应用') {
steps {
script {
echo "正在构建 Java 包 ${params.PACKAGE_NAME} 版本 ${params.VERSION}..."
sh "pwd && /usr/local/apache-maven-3.8.8/bin/mvn clean package -DskipTests -DartifactId=${params.PACKAGE_NAME} -Dversion=${params.VERSION}"
}
}
}

stage('构建 Docker 镜像') {
steps {
script {
echo "正在构建 Docker 镜像 ${env.IMAGE_NAME}..."
sh "docker build -t ${env.IMAGE_NAME} ."
}
}
}

stage('推送 Docker 镜像到镜像仓库') {
steps {
script {
echo "正在将 Docker 镜像 ${env.IMAGE_NAME} 推送到 ${params.DOCKER_REGISTRY}..."
sh "docker push ${env.IMAGE_NAME}"
}
}
}

stage('生成动态 Kubernetes 部署文件') {
steps {
script {
// 替换 Kubernetes 部署模板中的变量
echo "正在生成动态的 Kubernetes 部署文件..."

// 读取 Kubernetes 部署模板
def yamlTemplate = readFile("${params.K8S_DEPLOYMENT_FILE}")

// 使用 Groovy 的字符串替换功能,替换变量
def modifiedYaml = yamlTemplate.replace("{{IMAGE_NAME}}", env.IMAGE_NAME)
.replace("{{K8S_NAMESPACE}}", params.K8S_NAMESPACE)
.replace("{{K8S_REPLICAS}}", params.K8S_REPLICAS)
.replace("{{PACKAGE_NAME}}", params.PACKAGE_NAME)

// 写入临时文件
writeFile file: env.K8S_TEMP_FILE, text: modifiedYaml

echo "生成的 Kubernetes 部署文件路径: ${env.K8S_TEMP_FILE}"
}
}
}

stage('在 Kubernetes 上部署或更新') {
steps {
script {
echo "正在执行 Kubernetes 部署或更新..."

// 根据部署类型选择执行的操作
if (params.DEPLOY_TYPE == 'deploy') {
echo "正在将 ${params.PACKAGE_NAME} 版本 ${params.VERSION} 部署到 Kubernetes 命名空间 ${params.K8S_NAMESPACE}..."
// 执行 Kubernetes 部署,使用自定义的副本数和命名空间
sh """
kubectl apply -f ${env.K8S_TEMP_FILE} \
--namespace=${params.K8S_NAMESPACE}
"""
} else if (params.DEPLOY_TYPE == 'update') {
echo "正在更新 Kubernetes 中的 ${params.PACKAGE_NAME} 版本 ${params.VERSION}..."
// 更新 Kubernetes 部署镜像
// 更新副本数
sh """
# kubectl set image deployment/${params.PACKAGE_NAME} \
# ${params.PACKAGE_NAME}=${env.IMAGE_NAME} \
# --namespace=${params.K8S_NAMESPACE} --record \
# && \
# kubectl scale deployment ${params.PACKAGE_NAME} \
# --replicas=${params.K8S_REPLICAS} \
# --namespace=${params.K8S_NAMESPACE} --record 这样是分别记录 但是会有两个吧N本
kubectl apply -f ${env.K8S_TEMP_FILE} --namespace=${params.K8S_NAMESPACE}
"""

} else {
error "未知的部署类型: ${params.DEPLOY_TYPE}"
}
}
}
}
stage('创建 Kubernetes Service') {
steps {
script {
echo "正在创建 Kubernetes 服务 ${params.PACKAGE_NAME}..."
// 创建 Kubernetes 服务,将容器端口暴露出来
if (params.DEPLOY_TYPE == 'deploy') {
sh """
kubectl expose deployment ${params.PACKAGE_NAME} \
--type=NodePort \
--name=${params.PACKAGE_NAME}-svc \
--port=${params.SERVICE_PORT} \
--target-port=8080 \
--namespace=${params.K8S_NAMESPACE}
"""
}
}
}
}
}

post {
success {
echo "流水线执行成功!"
}
failure {
echo "流水线执行失败!"
}
}
}


测试

1.在gitlab修改java代码

image-20250506190019992

2.在jenkins构建

image-20250506190530570

image-20250506190610011

就是把变量赋值到gitlab 的 k8s/deployment.yaml下 然后 写入到jenkins机器上 writeFile file: env.K8S_TEMP_FILE, text: modifiedYaml

3.构建

image-20250506191617139

有红的也不用慌 控制台有报错原因 找找原因即可

再看下k8s机器 pod有两个容器因为里面我注入了sidecar

image-20250506191806352

image-20250506191835889


CICD
https://www.tiantian123.asia/2025/04/25/CICD/
作者
lht
发布于
2025年4月25日
许可协议