一、运行Jenkins流水线流程思路:
场景1:常规java应用,使用jenkins pipeline 交付到Kubernetes集群中
1、准备好java代码、Dockerfile、 deploy. yaml资源清单文件
CI阶段:
1、获取代码
2、漏洞扫描
3、检测漏洞扫描结果,如果正常则继续、否则就终止
4、使用maven进行编译,打包
5、制作Docker镜像、推送到Harbor仓库
6、交付应用到K8S
CD阶段:
1、获取完整的镜像名称;从Harbor中获取 (curl命令去获取)
2、将完整的镜像名称替换到deploy.yaml这个资源清单中;
3、直接部署到K8S的生产环境名称空间;
4、询问是否需要回退;
二 - java代码提交
1、下载代码
代码地址: https://gitee.com/oldxuedu/springboot-helloworld
wget https://gitee.com/oldxuedu/springboot-helloworld/repository/blazearchive/master.zip
做域名解析 如 10.240.0.201 gitlab.oldxu.net
2、创建新仓库,推送到gitlab仓库
[root@master01 springboot-CICD]# cd springboot-helloworld-master/
[root@master01 springboot-helloworld-master]#
[root@master01 springboot-helloworld-master]# ls
deploy.yaml Dockerfile entrypoint.sh pom.xml push_jar.sh README.md src
git init
git add remote origin http://gitlab.oldxu.net/root/springboot.git
git add .
git config --global user.email "123456@qq.com"
git config --global user.name "oldxu"
git commit -m "初始化"
git push -u origin master
deploy.yaml 需要替换的变量:
{NameSpace}
{Image}
{host}
三、Pipeline流水线-获取代码
3.0 本小段流程思路:
1、获取代码
调用git来获取即可;
1、slavePod如何访问Gitlab
1、通过gitlab的service地址去访问项目;
2、通过Coredns配置自定义域名解析;(*本文采用该方式)
2、Gitlab项目是私有的 如何处理;
需要 在jenkins上配置好对应gitlab认证的信息;
才能使用pipeline去获取代码
environment{
Gitlab_Id = "gitlab-root-token"
Gitlab_Pro = "http://gitlab.oldxu.net/root/springboot.git"
}
stage('获取代码') {
steps {
container('maven') {
checkout([$class: 'GitSCM', branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: "${Gitlab_Id}", url: "${Gitlab_Pro}"]]])
}
}
}
3.1 修改coredns
#过Coredns配置自定义域名解析;
kubectl edit configmap -n kube-system coredns
根据实际情况加上:
hosts {
192.168.79.31 gitlab.oldxu.net
192.168.79.32 gitlab.oldxu.net
192.168.79.33 gitlab.oldxu.net
fallthrough
}
3.2 Jenkins -> 系统管理 -> 全局凭据 -> New credentials
将gitlab的登录信息添加
http://jenkins.oldxu.net:30080/manage/credentials/store/system/domain/_/
3.3 Jenkins -> 流水线语法 -> 生成对应的gitlab下拉项目的代码
选中checkout from version control
checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: 'gitlab-root-token', url: 'http://gitlab.oldxu.net:30080/root/springboot.git']])
3.4 编写对应pipeline代码:
主要看environment和stage的 ,
pipeline{
agent{
kubernetes{
cloud 'kubernetes'
yaml '''
apiVersion: v1
kind: Pod
spec:
imagePullSecrets:
- name: harbor-admin
volumes:
- name: data
nfs:
server: 192.168.79.33
path: /data/maven
- name: dockersocket
hostPath:
path: /run/docker.sock
containers:
- name: maven
image: harbor.oldxu.net/ops/maven:3.8.6
imagePullPolicy: IfNotPresent
command: ["cat"]
tty: true
volumeMounts:
- name: data
mountPath: /root/.m2
- name: nodejs
image: harbor.oldxu.net/ops/nodejs:14.20
imagePullPolicy: IfNotPresent
command: ["cat"]
tty: true
- name: sonar
image: harbor.oldxu.net/ops/sonar-scanner:2.3.0
imagePullPolicy: IfNotPresent
command: ["cat"]
tty: true
- name: docker
image: harbor.oldxu.net/ops/docker:20.10
imagePullPolicy: IfNotPresent
command: ["cat"]
tty: true
volumeMounts:
- name: dockersocket
mountPath: /run/docker.sock
- name: kubectl
image: harbor.oldxu.net/ops/kubectl:1.18.0
imagePullPolicy: IfNotPresent
command: ["cat"]
tty: true
'''
} // kubernetes end
}//agent end
environment{
Gitlab_Id="gitlab-root-token"
Gitlab_Pro="http://gitlab.oldxu.net:30080/root/springboot.git"
}
stages{
stage('获取代码'){
steps{
container('maven'){
checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: "${Gitlab_Id}", url: "${Gitlab_Pro}"]])
sh 'pwd && ls -l'
}
}
}
stage('docker'){
steps{
container('docker'){
sh 'docker ps'
}
}
}
}//stages end
} //pipeline end
结果:
四、Pipeline流水线-漏洞扫描
4.0 本小段流程思路(1、漏洞扫描 sonarqube来实现):
1、dns解析,slavePod需要访问sonarqube服务端;<--> jenkins
2、让Jenkins集成Sonarqube ???why sqa_01d17b84079611472bbfcf89f2a67e7556510fda
3、sonar-scanner客户端工具; (获取这个工具的实现方式以及实现参数等等)
4、编写Stage;
4.1 修改coredns
kubectl edit cm -n kube-system coredns
hosts {
192.168.79.31 gitlab.oldxu.net sonar.oldxu.net jenkins.oldxu.net
192.168.79.32 gitlab.oldxu.net sonar.oldxu.net jenkins.oldxu.net
192.168.79.33 gitlab.oldxu.net sonar.oldxu.net jenkins.oldxu.net
fallthrough
}
4.2 Jenkins集成Sonarqube
Sonarqube申请令牌 (http://sonar.oldxu.net:30080/account/security)
我的账号 -> 安全 -> 添加令牌
系统管理 -> 系统配置 -> Sonarqube
添加凭证:
sonarqube servers的配置:
4.3 sonar-scanner客户端工具
打开sonarqube网页, 项目 -> 手工
“分析你的项目”
#这个指令是要去到 代码路径上执行/分析
sonar-scanner \
-Dsonar.projectKey=springboot \
-Dsonar.sources=. \
-Dsonar.host.url=http://sonar.oldxu.net:30080 \
-Dsonar.login=sqa_62e525a80cecb1a6d0ebe0cafcd52c41b0e5729c
代码路径指的是:
4.4、编写Stage;
//这里与上面给复制的代码还是有几处不一样的。
stage('代码扫描'){
steps{
withSonarQubeEnv('sonar-k8s'){ //对应配置中的 sonorqube servers
container('sonar'){
sh 'pwd && ls -l'
sh 'sonar-scanner \
-Dsonar.projectKey=springboot \
-Dsonar.java.binaries=src \
-Dsonar.sources=.'
}
}
}
}
检测漏洞扫描结果,如果正常则继续、否则就终止
1、配置Sonarqube,让其将结果通知给Jenkins
http://admin:admin123@jenkins.oldxu.net/sonarqube-webhook
2、编写Stage,判断Sonarqube返回的检查结果,如果ok,则继续,否则就终止步骤的执行;
http://sonar.oldxu.net:30080/admin/webhooks
sonarqube网页 -> 配置 -> 网络调用 -> 创建
名称:jenkins
URL:http://admin:admin12345@jenkins.oldxu.net:30080/sonarqube-webhook
#注意要写对URL ,不然会一直卡5分钟,然后暂停检测
流水线语法:waitForQualityGate
可根据具体情况调整“质量阈”的条件指标
代码:
stage('检查漏洞扫描结果'){
steps{
container('sonar'){
script{
timeout(5){
def qg = waitForQualityGate()
if (qg.status != 'OK'){
error "Sonarqube 代码检查失败, error的原因 ${qg.status}"
}
}
}
}
}
}
运行结果:
五、Pipeline流水线-代码编译
5.0 使用maven进行编译,打包
stage('编译代码'){
steps{
container('maven'){
sh 'mvn package -Dmaven.test.skip=true'
sh 'pwd && ls -l'
}
}
}
六、Pipeline流水线-制作Docker镜像
6.0 本小段思路
制作Docker镜像、推送到Harbor仓库 (Dockerfile文件)
1、配置域名解析,让SlavePod能够访问到Harbor
2、配置凭据,确保后续在推送到Harbor仓库时,认证没有问题;
3、docker build 根据dockerfilee生成Docker的镜像
4、推送到Harbor仓库
6.1、配置域名解析,让SlavePod能够访问到Harbor
kubectl edit cm -n kube-system coredns
加上 192.168.79.34 harbor.oldxu.net
6.2、配置凭据,确保后续在推送到Harbor仓库时,认证没有问题;
http://jenkins.oldxu.net:30080/manage/credentials/store/system/domain/_/
Dashboard -> 系统管理 -> 凭据 -> 系统 -> 全局凭据 (unrestricted)
6.3 编写stage
3、docker build 根据dockerfilee生成Docker的镜像
4、推送到Harbor仓库
流水线语法: 加载刚才创建的harbor-auth用户名和密码
withCredentials: Bind credentials to variables -> Username and password (separated)
[root@master01 springboot-helloworld-master]# ls
deploy.yaml Dockerfile entrypoint.sh pom.xml push_jar.sh README.md src
[root@master01 springboot-helloworld-master]# git log -n1 --pretty=format:'%h'
4131cad
编写生成tag的流水线语法
sh returnStdout: true, script: '''git log -n1 --pretty=format:\'%h\'
#sh(returnStdout: true, script: "git log -n1 --pretty=format:'%h'").trim()
sh returnStdout: true, script: '''date +%Y%m%d_%H%M%S
#sh(returnStdout: true, script: "date +%Y%m%d_%H%M%S").trim()
//注意单引号和双引号的使用
environment{
Gitlab_Id="gitlab-root-token"
Gitlab_Pro="http://gitlab.oldxu.net:30080/root/springboot.git"
//harbor相关的全局变量
Url = "harbor.oldxu.net"
Pro = "base"
ImageName = "${Url}/${Pro}/springboot"
HARBOR_ID = "harbor-auth"
}//environment end
stage('生成镜像Tag'){
steps{
container('maven'){
script{
//本次git提交的commid (git log -n1 --pretty=format:'%h')
env.COMMITID = sh(returnStdout: true, script: "git log -n1 --pretty=format:'%h'").trim()
//构件时间
env.BuildTime = sh(returnStdout: true, script: "date +%Y%m%d_%H%M%S").trim()
//完整的镜像Tag (c106654_20221115_133911)
env.ImageTag = COMMITID + "_" BuildTime
}
sh 'echo "镜像的Tag: ${ImageTag}"'
}
}
}
stage('制作docker镜像'){
steps{
container('docker'){
withCredentials([usernamePassword(credentialsId: "${HARBOR_ID}", passwordVariable: 'HARBOR_PASSWORD', usernameVariable: 'HARBOR_USER')]) {
//登陆harbor
sh 'echo "${HARBOR_PASSWORD}" | docker login ${Url} -u "${HARBOR_USER}" --password-stdin '
// 构建 / 推送 / 删除本地镜像
sh 'docker build -t ${ImageName}:${ImageTag} .'
sh 'docker push ${ImageName}:${ImageTag}'
sh 'docker rmi ${ImageName}:${ImageTag}'
}
}
}
}
运行效果:
七、Pipeline流水线-交付应用至K8S
7.0 本小段思路
1、将应用交付到哪个K8S集群; (slavepod能够与对应的集群通信就行)
2、如何连接上对应的K8S集群;
1、配置Jenkins,将config文件制作为一个Scretfile;
2、编写Stage,在Stage引用这个config文件; 就可以操作对应的集群了;
{namespace}
{Image}
{host}
3、部署的名称空间需要提前创建 (k8s namespace dev)
4、需要创建对应的Harbor认证Secrets harbor-admin (k8s的kubectl create secret docker-registry harbor-admin )
deploy.yaml内容:
apiVersion: apps/v1
kind: Deployment
metadata:
name: springboot-dev
namespace: {namespace} #修改为{}特殊字符,后期好替换
spec:
replicas: 3
selector:
matchLabels:
app: spring-dev
template:
metadata:
labels:
app: spring-dev
spec:
imagePullSecrets:
- name: harbor-admin
containers:
- name: springboot-dev
image: {Image} # 修改为{}特殊字符,后期好替换
ports:
- name: http
containerPort: 8080
env: # 传递初始堆内存和最大堆内存占用
- name: XMS_OPTS
valueFrom:
resourceFieldRef:
resource: requests.memory
- name: XMX_OPTS
valueFrom:
resourceFieldRef:
resource: limits.memory
resources:
requests:
memory: 150Mi
limits:
memory: 300Mi
readinessProbe: # 就绪探针;如果端口不存活,则从负载均衡中移除
tcpSocket:
port: http # http是一个名字;它会获取这个名字对应的端口;
initialDelaySeconds: 10
failureThreshold: 3
livenessProbe: # 存活探针;获取url,状态码不对那么则触发重启操作
httpGet:
path: /
port: http
initialDelaySeconds: 10
failureThreshold: 3
---
apiVersion: v1
kind: Service
metadata:
name: spring-dev-svc
namespace: {namespace}
spec:
selector:
app: spring-dev
ports:
- port: 8080
targetPort: 8080
---
#apiVersion: networking.k8s.io/v1
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: springboot-ingress
namespace: {namespace}
spec:
ingressClassName: "nginx"
rules:
- host: "{host}"
http:
paths:
- path: /
pathType: Prefix
backend:
serviceName: spring-dev-svc
servicePort: 8080
#service:
# name: spring-dev-svc
# port:
# number: 8080
7.1 配置Jenkins,将config文件制作为一个Scret file;
#master节点,下载config文件
sz ~/.kube/config
Jenkins新增凭证(secret file)
http://jenkins.oldxu.net:30080/manage/credentials/store/system/domain/_/
流水线语法:
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
// some block
}
7.2 编写pipeline
environment{
//对外暴露的域名
Ingress_Host = "spring-dev.oldxu.net"
}//environment end
stage('交付至k8s'){
steps{
container('kubectl'){
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
sh 'mkdir -p ~/.kube && cp ${KUBECONFIG} ~/.kube/config'
//替换
sh 'sed -i "s#{namespace}#dev#g" deploy.yaml'
sh 'sed -i "s#{Image}#${ImageName}:${ImageTag}#g" deploy.yaml'
sh 'sed -i "s#{host}#${Ingress_Host}#g" deploy.yaml'
sh 'cat deploy.yaml'
sh 'kubectl apply -f deploy.yaml'
}
}
}
}
运行结果:
网页访问:
更新代码:验证再次发版:
修改代码的HomeController.java内容。
八、Pipeline流水线-全自动CI过程及测试
Jenkins的pipeline配置 -> 构建触发器 -> 勾上“build when a change …” ,生成secret令牌
高级
gitlab配置 开启外发请求
菜单 -> 管理员 -> 管理中心 -> 设置 -> 网络 -> 外发请求 -> 勾上两个“允许”
http://gitlab.oldxu.net:30080/admin/application_settings/network
springboot项目 -> 设置 -> webhook
参考地址:http://gitlab.oldxu.net:30080/root/springboot/-/hooks
可测试
更新代码,看看会不会触发自动发版CI
springboot-CI完整的pipeline代码
pipeline{
agent{
kubernetes{
cloud 'kubernetes'
yaml '''
apiVersion: v1
kind: Pod
spec:
imagePullSecrets:
- name: harbor-admin
volumes:
- name: data
nfs:
server: 192.168.79.33
path: /data/maven
- name: dockersocket
hostPath:
path: /run/docker.sock
containers:
- name: maven
image: harbor.oldxu.net/ops/maven:3.8.6
imagePullPolicy: IfNotPresent
command: ["cat"]
tty: true
volumeMounts:
- name: data
mountPath: /root/.m2
- name: nodejs
image: harbor.oldxu.net/ops/nodejs:14.20
imagePullPolicy: IfNotPresent
command: ["cat"]
tty: true
- name: sonar
image: harbor.oldxu.net/ops/sonar-scanner:2.3.0
imagePullPolicy: IfNotPresent
command: ["cat"]
tty: true
- name: docker
image: harbor.oldxu.net/ops/docker:20.10
imagePullPolicy: IfNotPresent
command: ["cat"]
tty: true
volumeMounts:
- name: dockersocket
mountPath: /run/docker.sock
- name: kubectl
image: harbor.oldxu.net/ops/kubectl:1.18.0
imagePullPolicy: IfNotPresent
command: ["cat"]
tty: true
'''
} // kubernetes end
}//agent end
environment{
Gitlab_Id="gitlab-root-token"
Gitlab_Pro="http://gitlab.oldxu.net:30080/root/springboot.git"
//harbor相关的全局变量
Url = "harbor.oldxu.net"
Pro = "base"
ImageName = "${Url}/${Pro}/springboot"
HARBOR_ID = "harbor-auth"
//对外暴露的域名
Ingress_Host = "spring-dev.oldxu.net"
}//environment end
stages{
stage('获取代码'){
steps{
container('maven'){
checkout scmGit(branches: [[name: '*/master']], extensions: [], userRemoteConfigs: [[credentialsId: "${Gitlab_Id}", url: "${Gitlab_Pro}"]])
sh 'pwd && ls -l'
}
}
}
stage('代码扫描'){
steps{
withSonarQubeEnv('sonar-k8s'){ //对应配置中的 sonorqube servers
container('sonar'){
sh 'pwd && ls -l'
sh 'sonar-scanner \
-Dsonar.projectKey=springboot \
-Dsonar.java.binaries=src \
-Dsonar.sources=.'
}
}
}
}
stage('检查漏洞扫描结果'){
steps{
container('sonar'){
script{
timeout(5){
def qg = waitForQualityGate()
if (qg.status != 'OK'){
error "Sonarqube 代码检查失败, error的原因 ${qg.status}"
}
}
}
}
}
}
stage('编译代码'){
steps{
container('maven'){
sh 'mvn package -Dmaven.test.skip=true'
sh 'pwd && ls -l'
}
}
}
stage('生成镜像Tag'){
steps{
container('maven'){
script{
//本次git提交的commid (git log -n1 --pretty=format:'%h')
env.COMMITID = sh(returnStdout: true, script: "git log -n1 --pretty=format:'%h'").trim()
//构件时间
env.BuildTime = sh(returnStdout: true, script: "date +%Y%m%d_%H%M%S").trim()
//完整的镜像Tag (c106654_20221115_133911)
env.ImageTag = COMMITID + "_" + BuildTime
}
sh 'echo "镜像的Tag: ${ImageTag}"'
}
}
}
stage('制作docker镜像'){
steps{
container('docker'){
withCredentials([usernamePassword(credentialsId: "${HARBOR_ID}", passwordVariable: 'HARBOR_PASSWORD', usernameVariable: 'HARBOR_USER')]) {
//登陆harbor
sh 'echo "${HARBOR_PASSWORD}" | docker login ${Url} -u "${HARBOR_USER}" --password-stdin '
// 构建 / 推送 / 删除本地镜像
sh 'docker build -t ${ImageName}:${ImageTag} .'
sh 'docker push ${ImageName}:${ImageTag}'
sh 'docker rmi ${ImageName}:${ImageTag}'
}
}
}
}
stage('交付至k8s'){
steps{
container('kubectl'){
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
sh 'mkdir -p ~/.kube && cp ${KUBECONFIG} ~/.kube/config'
//替换
sh 'sed -i "s#{namespace}#dev#g" deploy.yaml'
sh 'sed -i "s#{Image}#${ImageName}:${ImageTag}#g" deploy.yaml'
sh 'sed -i "s#{host}#${Ingress_Host}#g" deploy.yaml'
sh 'cat deploy.yaml'
sh 'kubectl apply -f deploy.yaml'
}
}
}
}
}//stages end
} //pipeline end
九、PipelineCD流水线-获取Harbor镜像Tag
9.0 CD阶段的思路
CD阶段:
1、获取完整的镜像名称; 从Harbor中获取 (curl命令去获取)
shell命令写出来;
curl -s -uadmin:Harbor12345 -H'Content-Type: application/json' -X GET https://harbor.oldxu.net/v2/base/springboot/tags/list | sed -r 's#(\{.*\[)(.*)(\]\})#\2#g' | xargs -d "," -n1 | xargs -n1 | sort -t "_" -k2 -k3 -nr | head -5
级联变量的方式来提取对应的tag;
三个变量:
Harbor_Url
Harbor_Pro
Image_Name
Image_Tag
def get_tag = [ "bash", "-c", "curl -s -uadmin:Harbor12345 -H 'Content-Type: application/json' -X GET https://${Harbor_Url}/v2/${Harbor_Pro}/${Image_Name}/tags/list | sed -r 's#(\\{.*\\[)(.*)(\\]\\})#\\2#g' | xargs -d ',' -n1 | xargs -n1 | sort -t '_' -k2 -k3 -nr | head -5"]
return get_tag.execute().text.tokenize("\n")
2、生产环境中已经是部署了对应的项目的;
2、kubectl set image;
3、直接部署到K8S的生产环境名称空间;
4、询问是否需要回退;
kubectl rollout undo deployment springboot -n prod
9.1 操作过程
安装active choices插件。 新建springboot-CD流水线,使用参数化构建过程
参数化构建过程
#1 Harbor_Url
添加参数 -> 选Active Choices Parameter
Name 填 Harbor_Url
Script -> Groovy Script 填 return ["harbor.oldxu.net","harbor-dev.oldxu.net","harbor-prod.oldxu.net"]
#2 Harbor_Pro
添加参数 -> 选Active Choices Parameter
Name 填 Harbor_Pro
Script -> Groovy Script 填 return ["base","app","springcloud","ops"]
#3 Image_Name
添加参数 -> 选Active Choices Parameter
Name 填 Image_Name
Script -> Groovy Script 填 return ["springboot","java","springcloud","shopping"]
#4 Image_Tag
添加参数 -> 选 Active Choices Reactive Parameter
Groovy Script填写:
def get_tag = [ "bash", "-c", "curl -s -uadmin:Harbor12345 -H 'Content-Type: application/json' -X GET https://${Harbor_Url}/v2/${Harbor_Pro}/${Image_Name}/tags/list | sed -r 's#(\\{.*\\[)(.*)(\\]\\})#\\2#g' | xargs -d ',' -n1 | xargs -n1 | sort -t '_' -k2 -k3 -nr | head -5"]
return get_tag.execute().text.tokenize("\n")
#
Referenced parameters框填写:Harbor_Url,Harbor_Pro,Image_Name
build with parameters效果
编写CD - pipeline
pipeline{
agent{
kubernetes{
cloud 'kubernetes'
yaml '''
apiVersion: v1
kind: Pod
spec:
imagePullSecrets:
- name: harbor-admin
containers:
- name: kubectl
image: harbor.oldxu.net/ops/kubectl:1.18.0
imagePullPolicy: IfNotPresent
command: ["cat"]
tty: true
'''
}
}
environment{
Full_Image = "${Harbor_Url}/${Harbor_Pro}/${Image_Name}:${Image_Tag}"
}//environment end
stages{
stage('输出完整的镜像名称'){
steps{
sh 'echo 镜像名称-tag: ${Full_Image}'
}
}
}
}//pipeline end
十、PipelineCD流水线-部署应用至K8S生产环境
kubectl create namespace prod
kubectl create secret docker-registry harbor-admin --docker-username=admin --docker-password=Harbor12345 --docker-server=harbor.oldxu.net -n prod
先在生产环境部署 deploy-prod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: springboot
namespace: prod #修改为{}特殊字符,后期好替换
spec:
replicas: 2
selector:
matchLabels:
app: spring-prod
template:
metadata:
labels:
app: spring-prod
spec:
imagePullSecrets:
- name: harbor-admin
containers:
# - name: springboot-prod
- name: springboot #注意这里的名字,要与 kubectl set images的一致
image: harbor.oldxu.net/base/springboot:fa71353_20230521_175420 # 修改为{}特殊字符,后期好替换
ports:
- name: http
containerPort: 8080
env: # 传递初始堆内存和最大堆内存占用
- name: XMS_OPTS
valueFrom:
resourceFieldRef:
resource: requests.memory
- name: XMX_OPTS
valueFrom:
resourceFieldRef:
resource: limits.memory
resources:
requests:
memory: 150Mi
limits:
memory: 300Mi
readinessProbe: # 就绪探针;如果端口不存活,则从负载均衡中移除
tcpSocket:
port: http # http是一个名字;它会获取这个名字对应的端口;
initialDelaySeconds: 10
failureThreshold: 3
livenessProbe: # 存活探针;获取url,状态码不对那么则触发重启操作
httpGet:
path: /
port: http
initialDelaySeconds: 10
failureThreshold: 3
---
apiVersion: v1
kind: Service
metadata:
name: spring-prod-svc
namespace: prod
spec:
selector:
app: spring-prod
ports:
- port: 8080
targetPort: 8080
---
#apiVersion: networking.k8s.io/v1
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: springboot-ingress
namespace: prod
spec:
ingressClassName: "nginx"
rules:
- host: "spring-prod.oldxu.net"
http:
paths:
- path: /
pathType: Prefix
backend:
serviceName: spring-prod-svc
servicePort: 8080
#service:
# name: spring-prod-svc
# port:
# number: 8080
如果dev环境没问题,则手动发布到prod环境
构建:
+ kubectl set image deployment/springboot springboot=harbor.oldxu.net/base/springboot:ccf31a9_20230521_213116 -n prod
9.2 对应pipeline代码:
stage('部署应用至生产 K8S'){
steps{
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
container('kubectl'){
sh 'mkdir -p ~/.kube && cp ${KUBECONFIG} ~/.kube/config'
sh 'kubectl set image deployment/${Image_Name} ${Image_Name}=${Full_Image} -n prod'
}
}
}
}
十一、PipelineCD流水线-应用回滚
4、询问是否需要回退;
kubectl rollout undo deployment springboot -n prod
流水线语法:
input message: '是否回退到上个版本', parameters: [choice(choices: ['No', 'Yes'], name: 'rollback')]
验证:发布与回滚
选择yes ,回滚
+ kubectl rollout undo deployment springboot -n prod
springboot-CD的完整代码
pipeline{
agent{
kubernetes{
cloud 'kubernetes'
yaml '''
apiVersion: v1
kind: Pod
spec:
imagePullSecrets:
- name: harbor-admin
containers:
- name: kubectl
image: harbor.oldxu.net/ops/kubectl:1.18.0
imagePullPolicy: IfNotPresent
command: ["cat"]
tty: true
'''
}
}
environment{
Full_Image = "${Harbor_Url}/${Harbor_Pro}/${Image_Name}:${Image_Tag}"
}//environment end
stages{
stage('输出完整的镜像名称'){
steps{
sh 'echo 镜像名称-tag: ${Full_Image}'
}
}
stage('部署应用至生产 K8S'){
steps{
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
container('kubectl'){
sh 'mkdir -p ~/.kube && cp ${KUBECONFIG} ~/.kube/config'
sh 'kubectl set image deployment/${Image_Name} ${Image_Name}=${Full_Image} -n prod'
}
}
}
}
stage('快速回滚'){
steps{
withCredentials([file(credentialsId: 'kubeconfig', variable: 'KUBECONFIG')]) {
container('kubectl'){
script{
timeout(time: 1, unit: 'HOURS'){
def UserInput = input message: '是否回退到上个版本', parameters: [choice(choices: ['No', 'Yes'], name: 'rollback')]
if (UserInput == "Yes"){
sh 'mkdir -p ~/.kube && cp ${KUBECONFIG} ~/.kube/config'
sh 'kubectl rollout undo deployment $Image_Name -n prod'
}
}
}
}
}
}
}
}//stages end
}//pipeline end
END 5.8~5.21 ELK+CICD