假设我们是一个电商团队,刚开发完订单服务(一个Spring Boot Jar包),需要把它部署到生产环境,要求:
接下来,我们会走完“代码提交→镜像构建→CI/CD→K8s部署→暴露访问→高可用保障”的完整链路,逐一解决每个环节的问题。
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"]用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流水线(持续集成+持续部署):代码提交后自动构建镜像、测试、部署到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不在同一个节点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端口如果要让外部用户访问,需要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的端口把这三个文件放到k8s目录,然后用kubectl apply部署:
kubectl apply -f k8s/或者用CI/CD里的kubectl set image命令(更灵活,直接更新镜像版本)。
部署后,用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。
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"})。
打包:用Dockerfile把Jar包变成镜像,推送到仓库;
CI/CD:自动化构建、测试、部署;
K8s部署:用Deployment管理Pod副本,Service暴露服务,Ingress暴露到公网;
高可用:多副本、反亲和性、健康检查,确保节点或Pod故障时自动恢复;
验证:检查Pod、Service、Ingress状态,测试用户访问。
其实,K8s的本质是“应用的操作系统”——它帮我们管理应用的生命周期,让我们专注于写业务代码,不用操心服务器、网络、故障这些问题。
附:关键命令速查
如果想深入,可以再学K8s的监控(Prometheus+Grafana)、日志(ELK Stack)、弹性伸缩(HPA)——这些是生产环境的必备技能。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。