从Jar包到K8s上线:全流程拆解+高可用实战

以创建 pod 为例:

集群管理员或者开发人员通过 kubectl 或者客户端等构建 REST 请求,经由 apiserver 进行鉴权认证(使用 kubeconfig 文件),验证准入信息后将请求数据(metadata)写入 etcd 中;

ControllerManager(控制器组件)通过 watch 机制发现创建 pod 的信息,并将整合信息通过 apiservre 写入 etcd 中,此时 pod 处于可调度状态

Scheduler(调度器组件)基于 watch 机制获取可调度 pod 列表信息,通过调度算法(过滤或打分)为待调度 pod 选择最适合的节点,并将创建pod 信息写入 etcd 中,创建请求发送给节点上的 kubelet;

kubelet 收到 pod 创建请求后,调用 CNI 接口为 pod 创建网络环境,调用 CRI 接口创建 pod 内部容器,调用 CSI 接口对 pod 进行存储卷的挂载;

等待 pod 内部运行环境创建完成,基于探针或者健康检查监测业务运行容器启动状态,启动完成后 pod 处于 running 状态,pod 进入运行阶段。

上述引用自:Kubernetes超详细教程,一篇文章帮助你从零开始学习k8s,从入门到实战-CSDN博客https://blog.csdn.net/weixin_43980547/article/details/137085690

一、先抛业务场景:我们要做什么?

假设我们是一个电商团队,刚开发完订单服务​(一个Spring Boot Jar包),需要把它部署到生产环境,要求:

  • 用户能通过域名order.example.com访问;

  • 不怕单个服务器挂掉(高可用);

  • 能自动处理故障,不用人工干预。

接下来,我们会走完​"代码提交→镜像构建→CI/CD→K8s部署→暴露访问→高可用保障"​的完整链路,逐一解决每个环节的问题。


二、第一步:把Jar包变成Docker镜像

K8s只认识容器镜像,所以得先把Jar包打包成Docker镜像------这是上云的"原材料"。

1. 写Dockerfile:镜像的" recipe "

Dockerfile是构建镜像的说明书,告诉Docker如何一步步生成镜像。比如订单服务的Dockerfile:

复制代码
# 基础镜像:用OpenJDK 17(和本地开发一致)
FROM openjdk:17-jdk-slim
# 作者信息(可选)
LABEL maintainer="your-email@example.com"
# 把本地Jar包拷贝到镜像里的/app目录
COPY order-service-1.0.jar /app/order.jar
# 暴露容器的8080端口(和Jar包的server.port一致)
EXPOSE 8080
# 容器启动时执行的命令:运行Jar包
ENTRYPOINT ["java", "-jar", "/app/order.jar"]

2. 构建并推送镜像到仓库

docker build构建镜像,然后推送到容器镜像仓库​(比如Harbor、阿里云镜像仓库、Docker Hub):

复制代码
# 构建镜像,打标签(格式:仓库地址/项目名/镜像名:版本)
docker build -t harbor.example.com/order-service:1.0 .
# 登录镜像仓库(如果是私有仓库需要这步)
docker login harbor.example.com
# 推送镜像到仓库
docker push harbor.example.com/order-service:1.0

这一步完成后,镜像就像"预制菜",随时可以在K8s节点上"加热"运行


三、第二步:CI/CD流水线:自动化部署

手动部署太麻烦,我们需要CI/CD流水线​(持续集成+持续部署):代码提交后自动构建镜像、测试、部署到K8s。

1. 选工具:GitLab CI(或Jenkins)

以GitLab CI为例,只需要在项目根目录写.gitlab-ci.yml,定义流水线阶段:

复制代码
stages:
  - build   # 构建Jar包
  - test    # 单元测试
  - push    # 推送镜像到仓库
  - deploy  # 部署到K8s

# 全局变量:镜像仓库地址、K8s配置
variables:
  IMAGE_REPO: harbor.example.com/order-service
  K8S_NAMESPACE: production-order
  KUBE_CONFIG: $KUBE_CONFIG_PROD  # 从GitLab Secrets拿K8s配置

# 1. 构建Jar包(如果用Maven,这里跑mvn package)
build_jar:
  stage: build
  image: maven:3.8.6-openjdk-17
  script:
    - mvn clean package -DskipTests
  artifacts:
    paths:
      - target/order-service-1.0.jar

# 2. 单元测试(可选,但建议做)
unit_test:
  stage: test
  image: maven:3.8.6-openjdk-17
  script:
    - mvn test

# 3. 推送镜像到仓库
push_image:
  stage: push
  image: docker:24.0.7
  services:
    - docker:24.0.7-dind  # Docker-in-Docker,用于构建镜像
  before_script:
    - docker login -u $HARBOR_USER -p $HARBOR_PASSWORD harbor.example.com
  script:
    - docker build -t $IMAGE_REPO:1.0 ./target
    - docker push $IMAGE_REPO:1.0

# 4. 部署到K8s
deploy_to_k8s:
  stage: deploy
  image: bitnami/kubectl:1.28  # 用kubectl镜像执行部署命令
  script:
    - kubectl config use-context production-cluster  # 切换到生产集群
    - kubectl set image deployment/order-service order-service=$IMAGE_REPO:1.0 -n $K8S_NAMESPACE
    # 或者用apply:kubectl apply -f k8s/deployment.yaml -n $K8S_NAMESPACE

流水线的作用​:开发提交代码→触发CI/CD→自动构建、测试、推送镜像→部署到K8s,全程不用人工干预。

四、第三步:K8s部署:定义应用的"运行规则"

K8s不是直接运行容器,而是通过资源对象 ​(比如Deployment、Service)定义应用的运行方式。我们需要写两个核心文件:deployment.yaml(管理Pod)和service.yaml(暴露服务)。

1. Deployment:管理Pod的"副本集"

Deployment是K8s的"应用管理者",负责创建、更新、重启Pod。比如订单服务的Deployment:

复制代码
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment  # 资源类型:Deployment
metadata:
  name: order-service  # Deployment名字
  namespace: production-order  # 命名空间(隔离环境)
spec:
  replicas: 3  # 运行3个Pod副本(高可用关键)
  selector:
    matchLabels:
      app: order-service  # 选择带有app=order-service标签的Pod
  template:  # Pod的模板(每个Pod都按这个创建)
    metadata:
      labels:
        app: order-service  # Pod的标签,和selector对应
    spec:
      # 1. 容器定义
      containers:
      - name: order-container
        image: harbor.example.com/order-service:1.0  # 用的镜像
        ports:
        - containerPort: 8080  # 容器暴露的端口(和Dockerfile的EXPOSE一致)
        # 2. 资源限制(避免Pod占用太多资源导致节点崩溃)
        resources:
          requests:  # 请求的资源(调度时保证节点有足够资源)
            cpu: "500m"  # 0.5核CPU
            memory: "1Gi"  # 1G内存
          limits:  # 最大允许使用的资源
            cpu: "1000m"
            memory: "2Gi"
        # 3. 健康检查(确保Pod是"活的")
        livenessProbe:  # 存活检查:如果失败,K8s会重启Pod
          httpGet:
            path: /actuator/health/liveness  # Spring Boot的健康检查接口
            port: 8080
          initialDelaySeconds: 30  # 容器启动后30秒开始检查
          periodSeconds: 10  # 每10秒检查一次
        readinessProbe:  # 就绪检查:如果失败,K8s不会把Pod加入Service的负载均衡
          httpGet:
            path: /actuator/health/readiness
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
      # 4. Pod反亲和性(高可用关键:让Pod分布在不同节点)
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:  # 必须满足的规则
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - order-service
            topologyKey: kubernetes.io/hostname  # 按节点主机名分布,确保Pod不在同一个节点

2. Service:暴露Pod的"负载均衡器"

Service是K8s的"服务发现+负载均衡"组件,负责把流量转发到健康的Pod。订单服务的Service:

复制代码
# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: order-service
  namespace: production-order
spec:
  type: ClusterIP  # 默认类型:集群内部访问(外部需要Ingress)
  selector:
    app: order-service  # 关联带有这个标签的Pod
  ports:
  - protocol: TCP
    port: 80  # Service的端口(集群内部访问用)
    targetPort: 8080  # 转发到Pod的8080端口

3. Ingress:暴露到公网的"入口"

如果要让外部用户访问,需要Ingress------相当于K8s的"反向代理",把域名转发到Service。比如用Nginx Ingress:

复制代码
# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: order-ingress
  namespace: production-order
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$1  # 重写URL(可选)
spec:
  ingressClassName: nginx  # 用Nginx Ingress Controller
  rules:
  - host: order.example.com  # 绑定的域名
    http:
      paths:
      - path: /(.*)  # 匹配所有路径
        pathType: Prefix
        backend:
          service:
            name: order-service  # 关联的Service
            port:
              number: 80  # Service的端口

4. 部署到K8s

把这三个文件放到k8s目录,然后用kubectl apply部署:

复制代码
kubectl apply -f k8s/

或者用CI/CD里的kubectl set image命令(更灵活,直接更新镜像版本)。


五、第四步:典型问题排查指南------Pending状态怎么办?

部署后,用kubectl get pods查看Pod状态,如果出现Pending,说明Pod没调度成功,需要排查:

1. Pending的常见原因及解决

Pending的本质是:​Pod没找到合适的节点运行。常见原因:

(1)资源不足(最常见)

比如节点的CPU/内存不够,无法满足Pod的requests

  • 排查 ​:kubectl describe pod order-service-xxx -n production-order,看Events里的提示,比如Insufficient cpuInsufficient memory

  • 解决​:

    • 调整Pod的resources.requests(比如把CPU从500m降到250m);

    • 扩容节点(加机器,或者给现有节点加资源)。

(2)镜像拉取失败

比如私有镜像仓库没配置Secret,或者镜像名称错了。

  • 排查 ​:Events里会有Failed to pull imageErrImagePull

  • 解决​:

    • 创建docker-registry secret:kubectl create secret docker-registry regcred --docker-server=harbor.example.com --docker-username=xxx --docker-password=xxx -n production-order

    • 在Deployment的Pod模板里引用secret:imagePullSecrets: - name: regcred

(3)存储卷未绑定

如果Pod依赖PVC(比如数据库存储),但PVC没绑定到PV。

  • 排查 ​:Events里有MountVolume failed for volume "pvc-xxx"

  • 解决 ​:检查PVC状态:kubectl get pvc -n production-order,确保存在可用的PV。


六、第五步:高可用保障------不怕节点挂,不怕Pod死


K8s的核心优势就是自动化高可用,我们来看看它是怎么做到的:

1. 多副本(Replicas):不怕Pod死

Deployment里设置replicas: 3,意味着会创建3个相同的Pod。如果其中一个Pod挂了,Deployment会自动在其他节点创建新的Pod,保持总数3个。

2. Pod反亲和性:不怕节点挂

前面Deployment里的podAntiAffinity规则,强制让Pod分布在不同节点。比如3个Pod会在3个不同的节点上运行------即使一个节点挂了,也只剩2个Pod,不会全军覆没。

3. 健康检查:自动清理"死Pod"

  • Liveness Probe ​:检查Pod是否"活着"。比如订单服务的/actuator/health/liveness接口返回200才算活,否则K8s会重启Pod。

  • Readiness Probe ​:检查Pod是否"准备好接收流量"。比如启动时需要加载数据,没加载完前readinessProbe失败,K8s不会把Pod加入Service的负载均衡,避免用户访问到未就绪的Pod。

4. 自动重建:节点挂了也不怕

如果某个节点挂了(比如硬件故障),K8s的节点控制器 会检测到节点不可用,标记该节点上的Pod为NotReady。然后Deployment会自动在其他健康节点创建新的Pod,替换掉挂掉的Pod。

5. 流量自动转移:用户无感知

当Pod被替换或重启时,Service的selector会自动关联新的Pod(因为Pod的标签没变)。Service的负载均衡会把流量转发到健康的Pod,用户根本不会察觉到变化。


七、第六步:验证上线------用户能访问了吗?


部署完成后,我们需要验证:

  1. 检查Pod状态 ​:kubectl get pods -n production-order,所有Pod应该是Running状态。

  2. 检查Service ​:kubectl get service -n production-order,Service的Endpoints应该有3个Pod的IP(说明关联了所有健康Pod)。

  3. 检查Ingress ​:kubectl get ingress -n production-order,确认ADDRESS有值(Ingress Controller分配的IP)。

  4. 测试访问 ​:用浏览器或curl访问http://order.example.com/health,应该返回Spring Boot的健康状态(比如{"status":"UP"})。


八、总结:从Jar包到上线的完整链路


  1. 打包​:用Dockerfile把Jar包变成镜像,推送到仓库;

  2. CI/CD​:自动化构建、测试、部署;

  3. K8s部署​:用Deployment管理Pod副本,Service暴露服务,Ingress暴露到公网;

  4. 高可用​:多副本、反亲和性、健康检查,确保节点或Pod故障时自动恢复;

  5. 验证​:检查Pod、Service、Ingress状态,测试用户访问。


最后:K8s给我们的价值


  • 自动化​:不用手动登录服务器部署,CI/CD搞定一切;

  • 高可用​:自动处理故障,用户无感知;

  • 弹性​:可以随时扩容副本数(比如大促时把replicas从3改成10);

  • 可观测 ​:通过kubectl和监控工具(比如Prometheus)随时查看应用状态。

其实,K8s的本质是​"应用的操作系统"​------它帮我们管理应用的生命周期,让我们专注于写业务代码,不用操心服务器、网络、故障这些问题。


附:关键命令速查

  • 查看Pod:kubectl get pods -n <namespace>

  • 查看Pod详情:kubectl describe pod <pod-name> -n <namespace>

  • 查看Service:kubectl get service -n <namespace>

  • 查看Ingress:kubectl get ingress -n <namespace>

  • 查看集群事件:kubectl get events -n <namespace> --sort-by='.metadata.creationTimestamp'


如果想深入,可以再学K8s的监控 ​(Prometheus+Grafana)、日志 ​(ELK Stack)、弹性伸缩​(HPA)------这些是生产环境的必备技能。

相关推荐
YA3333 小时前
java设计模式八、组合模式
java·设计模式·组合模式
一枚码仔4 小时前
SpringBoot启动时执行自定义内容的5种方法
java·spring boot·后端
桦说编程4 小时前
如何在Java中实现支持随机访问的固定窗口队列
java·数据结构·后端
小白黑科技测评4 小时前
2025 年编程工具实测:零基础学习平台适配性全面解析!
java·开发语言·python
qwfys2004 小时前
实时Java规范(RTSJ):从理论到实践的实时系统编程范式
java·实时·java规范·rtsj
ejinxian4 小时前
Python 3.14 发布
java·开发语言·python
喜欢读源码的小白4 小时前
【Spring Boot + Spring Security】从入门到源码精通:藏经阁权限设计与过滤器链深度解析
java·开发语言·spring boot·spring security
BAGAE4 小时前
MQTT 与 HTTP 协议对比
java·linux·http·https·硬件工程
oak隔壁找我4 小时前
Spring框架中的跨域CORS配置详解
java·后端