springboot项目部署到K8S

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
相关推荐
乘云数字DATABUFF3 天前
5分钟部署开源APM Databuff:OpenTelemetry全链路追踪入门实战
运维·后端
荣--5 天前
一键部署不是为了省时间 —— 它是把"买来的 PaaS"变成"自己的平台"的拐点
运维·zabbix·工程化·一键部署·平台化·边界设计
江华森5 天前
动手实战学 Docker — 从零到集群编排完全指南
运维
Avan_菜菜5 天前
FRP 内网穿透完整实战:从 HTTP 映射到 HTTPS 自签代理
运维·nginx·https
SelectDB6 天前
Litefuse 开源并推出单进程轻量模式,25 秒就能跑起来的 Agent 可观测与评估平台
运维·后端·自动化运维
XIAOHEZIcode8 天前
Linux系统鼠标偏移常见原因以及修复方案
linux·运维·游戏
用户0328472220708 天前
如何搭建本地yum源(上)
运维
大树8811 天前
金刚石散热越强,管路越先见顶
大数据·运维·服务器·人工智能·ai
摇滚侠11 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
霸道流氓气质11 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务