首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >从Jar包到K8s上线:全流程拆解+高可用实战

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

原创
作者头像
用户6788227
发布2025-10-29 10:24:10
发布2025-10-29 10:24:10
60
举报

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

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

  • 用户能通过域名order.example.com访问;
  • 不怕单个服务器挂掉(高可用);
  • 能自动处理故障,不用人工干预。

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


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

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

1. 写Dockerfile:镜像的“ recipe ”

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

代码语言:txt
复制
# 基础镜像:用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):

代码语言:txt
复制
# 构建镜像,打标签(格式:仓库地址/项目名/镜像名:版本)
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,定义流水线阶段:

代码语言:txt
复制
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:

代码语言:txt
复制
# 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:

代码语言:txt
复制
# 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:

代码语言:txt
复制
# 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部署:

代码语言:txt
复制
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 cpu或Insufficient memory。

​解决​:

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

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

(2)镜像拉取失败

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

​排查​:Events里会有Failed to pull image或ErrImagePull。

​解决​:

创建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,用户根本不会察觉到变化。


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


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

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

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

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

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


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


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

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

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

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

​验证​:检查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)——这些是生产环境的必备技能。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、先抛业务场景:我们要做什么?
  • 二、第一步:把Jar包变成Docker镜像
  • 三、第二步:CI/CD流水线:自动化部署
  • 五、第四步:典型问题排查指南——Pending状态怎么办?
    • 六、第五步:高可用保障——不怕节点挂,不怕Pod死
    • 七、第六步:验证上线——用户能访问了吗?
  • 八、总结:从Jar包到上线的完整链路
  • 最后:K8s给我们的价值
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档