
bash
java后台
创建harbor镜像拉取Secret:
kubectl create secret docker-registry harbor-regcred \
--docker-server= \ #harbor仓库地址
--docker-username= \ #harbor 账号
--docker-password= \ #harbor密码
-n production
Dockerfile
FROM *harbor地址*/library/custom-jdk:1.8.0-alpine
LABEL maintainer="Winter Lee"
# 设置时区并安装字体包
RUN apk add --no-cache tzdata fontconfig ttf-dejavu && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
# 创建目录
RUN mkdir -p \
/home/backend/jar_28888 \
/home/backend/etc \
/home/logs \
/home/app/logs && \
# 修改目录权限
chmod -R 777 /home/app
WORKDIR /home
# 使用 ARG 定义动态路径
ARG JAR_PATH
COPY ${JAR_PATH} /home/backend/jar_28888/admin.jar
VOLUME /app/logs
EXPOSE 28888
# 添加无头模式参数并优化JVM参数
ENTRYPOINT ["java", \
"-Djava.awt.headless=true", \
"-Xms512m", \
"-Xmx2048m", \
"-DLOG_PATH=/app/logs", \
"-jar", \
"/jono/backend/jar_28888/admin.jar"]
JEKINS构建镜像推送到harbor私服
pipeline {
agent any
parameters {
gitParameter(
name: 'TAG_NAME',
type: 'PT_TAG',
description: '选择要构建的 Git 标签',
branch: 'test',
tagFilter: '*',
sortMode: 'DESCENDING',
defaultValue: ''
)
}
environment {
HARBOR_REG = "harbor地址"
PROJECT_NAME = "项目名称"
IMAGE_NAME = "镜像名称"
// 使用Harbor凭证(需先在Jenkins创建)
HARBOR_CRED = credentials('de3f0156-4c04-445d-9621-2f966ba40f28')
}
stages {
stage('Checkout Code') {
steps {
checkout([
$class: 'GitSCM',
branches: [[name: "refs/tags/${params.TAG_NAME}"]],
extensions: [
[$class: 'CloneOption', depth: 0, shallow: false]
],
userRemoteConfigs: [[
url: '代码仓库地址',
credentialsId: '代码仓库凭证',
refspec: '+refs/heads/*:refs/remotes/origin/* +refs/tags/*:refs/tags/*'
]]
])
}
}
stage('Maven Build') {
steps {
dir('.') {
timeout(time: 15, unit: 'MINUTES') {
sh 'mvn clean package -P sit'
}
sh 'ls -l target/admin.jar'
}
}
}
// 新增:准备镜像标签
stage('Prepare Image Tag') {
steps {
script {
// 清理标签名(替换非法字符为横杠,转小写)
env.IMAGE_TAG = params.TAG_NAME.replaceAll(/[^a-zA-Z0-9\\.-]/, '-').toLowerCase()
echo "使用镜像标签: ${env.IMAGE_TAG}"
}
}
}
stage('Docker Build') {
steps {
script {
// 安全登录Harbor
sh "echo ${HARBOR_CRED_PSW} | docker login -u ${HARBOR_CRED_USR} --password-stdin ${HARBOR_REG}"
// 使用Git标签名作为镜像标签
sh """
docker build \\
--build-arg JAR_PATH=target/admin.jar \\
-t ${HARBOR_REG}/${PROJECT_NAME}/${IMAGE_NAME}:${env.IMAGE_TAG} \\
-f env/sit/Dockerfile \\
.
"""
}
}
}
stage('Push to Harbor') {
steps {
script {
// 推送指定标签的镜像
sh "docker push ${HARBOR_REG}/${PROJECT_NAME}/${IMAGE_NAME}:${env.IMAGE_TAG}"
}
}
}
}
post {
always {
script {
// 清理本地镜像
sh "docker rmi ${HARBOR_REG}/${PROJECT_NAME}/${IMAGE_NAME}:${env.IMAGE_TAG} || true"
sh "docker logout ${HARBOR_REG}"
}
cleanWs()
}
}
}
K8s部署 yaml文件
## admin-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: admin-production
namespace: production # 建议使用独立命名空间
labels:
app: admin
env: production
spec:
replicas: 2
revisionHistoryLimit: 5 #进行滚动更新后,保留的历史版本数
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25% # 最大激增Pod数
maxUnavailable: 25% # 最大不可用Pod数
selector:
matchLabels:
app: admin
env: production
template:
metadata:
labels:
app: admin
env: production
spec:
securityContext: # 安全上下文
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
containers:
- name: admin
image: *代码仓库地址/项目名称*/admin:44-sit-202505231400
ports:
- containerPort: 28888
volumeMounts:
- name: etc-volume
mountPath: /home/backend/etc
readOnly: true # 根据实际需求设置读写权限
resources: # 资源限制(根据实际需求调整)
limits:
cpu: "1"
memory: 1Gi
requests:
cpu: "0.5"
memory: 512Mi
livenessProbe: # 存活探针
httpGet:
path: /admin/captchaImage
port: 28888
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe: # 就绪探针
httpGet:
path: /admin/captchaImage
port: 28888
initialDelaySeconds: 20
periodSeconds: 5
volumes:
- name: etc-volume
hostPath:
path: /tmp/etc
type: DirectoryOrCreate
imagePullSecrets: # 镜像拉取凭证(需提前创建)
- name: harbor-regcred
affinity: # 调度策略
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values: ["admin"]
topologyKey: kubernetes.io/hostname
## admin-service.yaml
apiVersion: v1
kind: Service
metadata:
name: admin-service
namespace: production
spec:
type: NodePort # 根据实际网络架构选择
selector:
app: admin
env: production
ports:
- protocol: TCP
port: 28888
targetPort: 28888
nodePort: 31000
滚动更新:
只有修改了 deployment 配置文件中的 template 中的属性后,才会触发更新操作
修改 nginx 版本号
kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
kubectl set image deployment/admin-production *harbor地址*/*项目名称*/admin=44-sit-202505231400
或者通过 kubectl edit deployment/nginx-deployment 进行修改
查看滚动更新的过程
kubectl rollout status deploy <deployment_name>
查看部署描述,最后展示发生的事件列表也可以看到滚动更新过程
kubectl describe deploy <deployment_name>
通过 kubectl get deployments 获取部署信息,UP-TO-DATE 表示已经有多少副本达到了配置中要求的数目
通过 kubectl get rs 可以看到增加了一个新的 rs
通过 kubectl get pods 可以看到所有 pod 关联的 rs 变成了新的
回滚:
有时候你可能想回退一个Deployment,例如,当Deployment不稳定时,比如一直crash looping。
默认情况下,kubernetes会在系统中保存前两次的Deployment的rollout历史记录,以便你可以随时会退(你可以修改revision history limit来更改保存的revision数)。
案例:
更新 deployment 时参数不小心写错,如 nginx:1.9.1 写成了 nginx:1.91
kubectl set image deployment/nginx-deploy nginx=nginx:1.91
监控滚动升级状态,由于镜像名称错误,下载镜像失败,因此更新过程会卡住
kubectl rollout status deployments nginx-deploy
结束监听后,获取 rs 信息,我们可以看到新增的 rs 副本数是 2 个
kubectl get rs
通过 kubectl get pods 获取 pods 信息,我们可以看到关联到新的 rs 的 pod,状态处于 ImagePullBackOff 状态
为了修复这个问题,我们需要找到需要回退的 revision 进行回退
通过 kubectl rollout history deployment/nginx-deploy 可以获取 revison 的列表
通过 kubectl rollout history deployment/nginx-deploy --revision=2 可以查看详细信息
确认要回退的版本后,可以通过 kubectl rollout undo deployment/nginx-deploy 可以回退到上一个版本
也可以回退到指定的 revision
kubectl rollout undo deployment/nginx-deploy --to-revision=2
再次通过 kubectl get deployment 和 kubectl describe deployment 可以看到,我们的版本已经回退到对应的 revison 上了
可以通过设置 .spec.revisonHistoryLimit 来指定 deployment 保留多少 revison,如果设置为 0,则不允许 deployment 回退了。
发布新版本操作流程
1. 修改 YAML 文件
yaml
# deployment.yaml 示例片段
spec:
template:
spec:
containers:
- name: your-app
image: local.harbor.com/sw/sw-web:NEW_TAG # 修改为新镜像标签
ports:
- containerPort: 8088
2. 应用新配置
bash
# 使用 kubectl apply 更新部署
kubectl apply -f deployment.yaml -n your-namespace
# 观察滚动更新进度(实时查看Pod重建过程)
kubectl rollout status deployment/your-deployment -n your-namespace
3. 验证新版本
bash
# 查看当前Pod状态
kubectl get pods -n your-namespace -l app=your-app-label
# 检查新版本日志
kubectl logs -f <new-pod-name> -n your-namespace
# 执行健康检查(替换为你的健康检查路径)
kubectl exec <new-pod-name> -n your-namespace -- curl -I http://localhost:8088/web/
二、回滚操作流程
方法一:使用 Kubernetes 内置回滚(推荐)
bash
# 1. 查看部署历史版本
kubectl rollout history deployment/your-deployment -n your-namespace
# 输出示例
REVISION CHANGE-CAUSE
1 Initial deployment
2 Update image to v1.2.3
3 Update image to v1.2.4 <--- 当前问题版本
# 2. 回滚到指定版本
kubectl rollout undo deployment/your-deployment --to-revision=2 -n your-namespace
# 3. 验证回滚状态
kubectl rollout status deployment/your-deployment -n your-namespace
方法二:通过旧版 YAML 文件回滚
bash
# 1. 检出旧版本YAML文件(假设使用Git管理)
git checkout v1.2.3 -- deployment.yaml
# 2. 应用旧配置
kubectl apply -f deployment.yaml -n your-namespace --force
# 3. 确认回滚完成
kubectl get pods -n your-namespace -l app=your-app-label
三、最佳实践建议
1. 版本追踪策略
bash
# 每次修改YAML文件后提交Git(带版本标签)
git add deployment.yaml
git commit -m "Update to v1.2.4"
git tag v1.2.4
git push origin master --tags
2. 增强部署可靠性
yaml
# 在YAML中添加健康检查
livenessProbe:
httpGet:
path: /healthz
port: 8088
initialDelaySeconds: 15
periodSeconds: 20
readinessProbe:
httpGet:
path: /ready
port: 8088
initialDelaySeconds: 5
periodSeconds: 10
3. 自动记录变更原因
bash
# 使用 kubectl 注解记录变更信息
kubectl annotate deployment/your-deployment \
kubernetes.io/change-cause="Update to v1.2.4 for feature X" \
-n your-namespace --overwrite
4. 多环境验证流程
bash
# 先发布到测试环境
kubectl apply -f deployment.yaml -n test-env
# 运行自动化测试
curl -X POST http://your-ci-server/run-tests
# 测试通过后发布生产
kubectl apply -f deployment.yaml -n prod-env
四、常见问题排查
1. 如果回滚失败
bash
# 查看部署详细状态
kubectl describe deployment/your-deployment -n your-namespace
# 检查事件日志
kubectl get events -n your-namespace --sort-by=.metadata.creationTimestamp
2. 保留历史版本数量控制
yaml
# 在YAML中配置 revisionHistoryLimit
spec:
revisionHistoryLimit: 5 # 保留最近5个版本
更新版本的时候可以添加 --record记录操作内容
[root@k8s-master ~]# kubectl set image deployment/web-production -n production web=web:v20250523_1.0.0 --record
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/web-production image updated
[root@k8s-master ~]# kubectl rollout history deployment/web-production -n production
deployment.apps/web-production
REVISION CHANGE-CAUSE
1 <none>
2 kubectl set image deployment/web-production web=web:v20250523_1.0.0 --namespace=production --record=true
查看对应revision的更新内容
kubectl rollout history deployment/web-production -n production --revision=2
deployment.apps/web-production with revision #2
Pod Template:
Labels: app=web
env=production
pod-template-hash=764cdbc6c4
Annotations: kubernetes.io/change-cause: kubectl set image deployment/web-production web=web:v20250523_1.0.0 --namespace=production --record=true
Containers:
web:
Image: web:v20250523_1.0.0
Port: 8088/TCP
Host Port: 0/TCP
Limits:
cpu: 200m
memory: 1Gi
Requests:
cpu: 100m
memory: 512Mi
Environment: <none>
Mounts: <none>
Volumes: <none>
版本回退操作
回退到revision 为1的版本
[root@k8s-master ~]# kubectl rollout undo deployment/web-production -n production --to-revision=1
deployment.apps/web-production rolled back
[root@k8s-master ~]# kubectl rollout history deployment/web-production -n production
deployment.apps/web-production
REVISION CHANGE-CAUSE
2 kubectl set image deployment/web-production web=web:v20250523_1.0.0 --namespace=production --record=true
3 <none>
查看回滚进度
kubectl rollout status deployment/web-production -n production
扩容缩容
kubectl scale --replicas=5 deployment web-production -n production 通过修改replicas的值完成扩容和缩容
暂停和恢复
kubectl rollout pause deploy web-production -n production
kubectl rollout resume deploy web-production -n production