K8s 1.13.3部署电商微服务:从安装包到上线的完整实践
2026/9/14 1:39:34 网站建设 项目流程

简介:这套实战资料面向需要系统掌握Kubernetes容器编排与微服务部署的运维、云计算工程师,围绕k8s 1.13.3版本在电商微服务场景下的落地展开,提供从镜像打包、Java环境配置到Ingress接入的完整链路。包体共6个文件,包含tar与gz格式的JDK、Maven、Nginx Ingress Controller等镜像安装包,yaml编排文件,以及docx格式的部署文档笔记,压缩包约950.8MB。已有222人学习下载,内容按实际部署顺序组织,非常适合作为生产环境前的模拟练习案例。文档详细记录了基于simple-microservice的电商应用部署细节、mandatory原版配置用法与版本兼容性注意事项,读者可参照笔记逐步复现一套可运行的电商微服务集群,理解镜像导入、环境变量配置与Ingress流量接入等关键操作。同时,打包齐全的基础组件省去另找安装包的麻烦,配套笔记让部署过程有据可依,适合边学边练,快速积累Kubernetes实战经验。

1. 为什么是k8s 1.13.3:电商微服务稳定优先

把 K8s 版本锁在 1.13.3,不是因为它新,而是因为它旧得刚刚好。这个版本没有后来频繁的 API 组迁移和运行时变更,很多电商系统在生产环境一跑就是两三年,稳定压倒一切。用 k8s 1.13.3 部署电商微服务,你需要关心的不是新特性,而是如何把注册中心、配置中心、消息队列和业务服务合理地放进同一个集群。这篇记录从安装包整理到微服务上线的完整路径,适合手里有内网机器、想复现一套电商微服务案例的运维或开发。


2. 集群与资源规划,先给 k8s 1.13.3 一个能跑微服务的底座

2.1 硬件与操作系统选型:别让 Master 成为瓶颈

电商微服务至少包含用户、商品、订单、支付和网关五个应用,再加上 MySQL、Redis、Nacos、RabbitMQ 这些中间件,一台机器根本扛不住。我习惯准备 1 台 Master 和 3 台 Node,硬件规格如下表。

节点角色CPU内存系统盘数据盘用途
Master4 核8 GB100 GB SSD无需etcd、kube-apiserver、scheduler
Node18 核16 GB100 GB SSD200 GB SSD业务 Pod 与部分中间件
Node28 核16 GB100 GB SSD200 GB SSD业务 Pod 与部分中间件
Node34 核8 GB80 GB SSD100 GB SSDNacos、RabbitMQ 等有状态服务

操作系统建议 CentOS 7.6 或 Ubuntu 18.04,内核版本至少 3.10。安装前必须关闭交换分区,否则 kubelet 在内存压力下会拒绝调度 Pod,表现为节点反复 NotReady。此外 etcd 对磁盘 IO 很敏感,Master 千万不要用机械盘,否则 etcd 的 fsync 延迟会拖垮整个集群的写入性能。

2.2 安装包与离线镜像整理:从 bin 到 images 的固定套路

标题里的“安装包”并不是指某个现成的压缩包,而是把 kubeadm、kubelet、kubectl 三个二进制和对应镜像,按照固定的目录结构整理好。1.13.3 的三个二进制版本必须完全一致,镜像版本也要锁定。我的习惯是:

k8s-1.13.3-installer/ ├── bin/ │ ├── kubeadm │ ├── kubelet │ └── kubectl ├── images/ │ ├── kube-apiserver-v1.13.3.tar │ ├── kube-controller-manager-v1.13.3.tar │ ├── kube-scheduler-v1.13.3.tar │ ├── kube-proxy-v1.13.3.tar │ ├── pause-3.1.tar │ ├── etcd-3.2.24.tar │ └── coredns-1.2.6.tar └── yaml/ └── kubeadm-init.yaml

内网环境用docker save把镜像导出,再在目标机器上docker load。注意 1.13.3 的 pause 镜像版本是 3.1,etcd 是 3.2.24,这两个版本号是强绑定关系,随意替换会导致 kubelet 启动后反复 crash。整理好目录后,第一时间用md5sum生成校验文件,防止内网拷贝造成文件损坏。

2.3 命名空间与节点标签:划分电商微服务的调度边界

把中间件和业务服务混在 default 命名空间里,是一种短期省事、长期痛苦的写法。我先创建两个命名空间,再给节点打上调度标签。

kubectl create namespace middleware kubectl create namespace mall kubectl label nodes node1 middleware=true kubectl label nodes node2 middleware=true kubectl label nodes node3 app=true

这样中间件只会调度到 node1 和 node2,业务服务只会调度到 node3。1.13.3 的调度器还没有后来版本中完善拓扑分布约束,用 nodeSelector 是最直接可用的方案。另外,命名空间隔离也方便配合 Kubernetes 的 RBAC,后续给不同团队分配权限时不需要重新划分整个集群。

2.4 网络组件与网段规划:flannel 和 calico 怎么选

1.13.3 里网络插件通常二选一:flannel 和 calico。如果电商微服务规模不大,且没有 NetworkPolicy 需求,flannel 的 VXLAN 模式最省心;如果以后要做多租户隔离或网络策略,一开始就装 calico,省得后面迁移。

kubeadm 初始化时要把 Pod 网段和 Service 网段规划好:

# kubeadm-init.yaml apiVersion: kubeadm.k8s.io/v1beta1 kind: ClusterConfiguration networking: podSubnet: "10.244.0.0/16" serviceSubnet: "10.96.0.0/12"

这里的podSubnet要与 flannel 的配置保持一致,flannel 默认使用 10.244.0.0/16。Service 网段建议避开公司内网段和 Pod 网段,否则会出现访问冲突,最常见的问题是 DNS 解析到错误的地址。初始化命令为kubeadm init --config=kubeadm-init.yaml,初始化完成后 kubelet 才能正常启动。


3. 在 K8s 1.13.3 部署电商微服务公共依赖:MySQL、Nacos、Redis、RabbitMQ

3.1 MySQL:用 StatefulSet 固定数据和网络身份

MySQL 是有状态服务,不能像无状态 Pod 一样动不动重建。1.13.3 上部署 MySQL 首选 StatefulSet,因为它能保证 Pod 名称和网络标识稳定,且每个副本有独立的 PVC。下面是一个简化但可用的 StatefulSet:

apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql namespace: middleware spec: serviceName: mysql replicas: 1 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: nodeSelector: middleware: "true" containers: - name: mysql image: mysql:5.7 ports: - containerPort: 3306 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: root-password volumeMounts: - name: data mountPath: /var/lib/mysql volumes: - name: data hostPath: path: /data/mysql type: DirectoryOrCreate

注意 1.13.3 中 StatefulSet 的 API 版本是apps/v1,不是更早的apps/v1beta1。这里用 hostPath 是为了演示,生产环境建议先创建 Local PV 再绑定。hostPath 的path如果不存在,DirectoryOrCreate会帮你创建,但权限要提前处理好,否则 MySQL 会因为没有写权限而启动失败。

提示:如果 MySQL 需要对外提供管理访问,可以额外创建一个独立 Service,类型为 NodePort,避免直接暴露 3306 端口给集群外。

3.2 Nacos:注册中心必须让业务稳定地找到它

电商微服务的服务发现,我用 Nacos 的场景远多于 Eureka,因为 Nacos 同时承担配置中心。在 1.13.3 上,Nacos 可以直接使用 Deployment 加 Service:

apiVersion: apps/v1 kind: Deployment metadata: name: nacos namespace: middleware spec: replicas: 1 selector: matchLabels: app: nacos template: metadata: labels: app: nacos spec: nodeSelector: middleware: "true" containers: - name: nacos image: nacos/nacos-server:v2.2.0 env: - name: MODE value: standalone - name: NACOS_SERVER_IP valueFrom: fieldRef: fieldPath: status.podIP ports: - containerPort: 8848 - containerPort: 9848

这里用MODE=standalone是为了在资源有限时快速跑通案例。如果要做高可用,需要把 replicas 设为 3,并配置NACOS_SERVERS指向彼此。Nacos 2.x 的 gRPC 端口 9848 必须暴露在 Service 里,否则 Spring Cloud 服务在注册后会因为无法建立 gRPC 连接而频繁报错。

对应 Service 定义:

apiVersion: v1 kind: Service metadata: name: nacos namespace: middleware spec: selector: app: nacos ports: - name: http port: 8848 targetPort: 8848 - name: grpc port: 9848 targetPort: 9848 type: ClusterIP

业务服务注册时地址写nacos.middleware.svc.cluster.local:8848即可,不需要关心 Nacos Pod 的 IP 变化。这样微服务架构图中的注册中心节点才真正稳定。

3.3 Redis 与 RabbitMQ:削峰填谷的最小却完整的部署

Redis 和 MQ 是电商在大促时兜底的关键,但在部署案例里,不需要一开始就上集群。我会用 Deployment 快速跑起来,先保证功能链路完整。Redis 的命令:

kubectl run redis --image=redis:5.0 --replicas=1 --port=6379 -n middleware

这样创建的 Deployment 默认不会持久化数据。如果只是演示,可以接受;但为了笔记里能说明白持久化问题,我一般会补一条 PVC 挂载。RabbitMQ 用管理镜像:

kubectl run rabbitmq --image=rabbitmq:3.8-management --port=5672 --port=15672 -n middleware

然后手动创建一个 Service,把 15672 暴露为 NodePort,方便在浏览器里看队列积压情况。RabbitMQ 的数据目录默认在容器内,应用重启就丢失,所以这个方案只适合“先跑通”阶段。真正上线前需要换成 StatefulSet 并配置 PVC。

3.4 私有镜像仓库与 imagePullSecret:微服务镜像的交付前提

电商微服务的镜像不能都放在 Docker Hub,内网需要一套私有仓库。常见做法是部署 Harbor,也可以直接用带 TLS 的 Docker Registry。镜像上传完成后,K8s 节点拉取私有镜像需要认证。

kubectl create secret docker-registry registry-secret \ --docker-server=registry.internal \ --docker-username=admin \ --docker-password=your-password \ -n mall

在业务 Deployment 里通过imagePullSecrets引用:

spec: imagePullSecrets: - name: registry-secret

这里很容易踩坑:如果业务服务在多个命名空间,每个命名空间都要单独创建一份 Secret,因为 K8s 的 Secret 默认只属于单个命名空间。没有这个配置,Pod 状态会一直卡在ImagePullBackOff,日志里的错误是unauthorized: authentication required


4. 电商微服务编排:从 Deployment、Service 到 Ingress 的实战参数

4.1 微服务核心清单:资源配额、探针和 Nacos 连接配置

电商微服务中的每个应用都需要一份规范的 Deployment。以下单服务为例:

apiVersion: apps/v1 kind: Deployment metadata: name: order-service namespace: mall labels: app: order-service spec: replicas: 2 selector: matchLabels: app: order-service template: metadata: labels: app: order-service spec: nodeSelector: app: "true" containers: - name: order-service image: registry.internal/mall/order-service:1.3.3 imagePullPolicy: IfNotPresent ports: - containerPort: 8080 resources: requests: cpu: 200m memory: 512Mi limits: cpu: 1 memory: 1Gi env: - name: SPRING_PROFILES_ACTIVE value: "k8s" - name: NACOS_ADDR value: "nacos.middleware.svc.cluster.local:8848" readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 20 periodSeconds: 10 timeoutSeconds: 3 livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 30 periodSeconds: 20

initialDelaySeconds必须大于 Spring Boot 的完整启动时间,否则容器刚启动还在初始化,探针就开始探测,连续失败几次就会被 kubelet 杀死,进入CrashLoopBackOffrequestslimits的差距不要太大,这里设置 requests 200m CPU、limits 1 CPU,是为了让 HPA 在流量上涨时有扩容空间。

另外,如果整合了 knife4j 做 API 文档,实际上只需要确保网关服务能访问到订单服务的/v3/api-docs路径即可。Knife4j 在 K8s 环境里最常见的坑是文档地址写死了本机 localhost,导致网关聚合文档时拿到错误地址。解决办法是在 Nacos 配置中注册实例时,显式指定ip为 Pod IP,不要依赖自动探测。

4.2 Service 与 Ingress:网关如何暴露给外部调用

内部服务之间使用 ClusterIP 足够,但外部请求必须经过网关。网关的 Service 类型可以选择 NodePort,然后再由 Ingress 根据域名和路径转发:

apiVersion: v1 kind: Service metadata: name: gateway-service namespace: mall spec: selector: app: gateway-service ports: - name: http port: 8080 targetPort: 8080 type: NodePort nodePort: 30880

Ingress 配置:

apiVersion: extensions/v1beta1 kind: Ingress metadata: name: mall-gateway namespace: mall annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - host: mall.example.com http: paths: - path: /api backend: serviceName: gateway-service servicePort: 8080

1.13.3 中 Ingress 的 API 版本是extensions/v1beta1,如果拿到新版本的 YAML 直接 apply 会报no matches for kind "Ingress"。注意rewrite-target注释,如果你希望访问https://mall.example.com/api/order时实际转发到网关的/order,就需要这个重写规则。网关内部再通过 Nacos 找到具体服务,这样整条链路就是:客户端 → Ingress → 网关 → 微服务。

4.3 优雅上下线与配置热更新:大促前必须做的两件事

发版时如果直接删 Pod,正在处理的订单请求会瞬间失败。K8s 默认发送 SIGTERM,但 Spring Boot 需要时间完成事务和连接池清理。在容器里加 preStop 钩子:

lifecycle: preStop: exec: command: ["/bin/sh", "-c", "sleep 10"]

这个等待时间最好与 readinessProbe 的periodSeconds配合。我的习惯是 readiness 每 10 秒探测一次,preStop 睡眠 10 秒,这样可以保证在 Endpoint 更新后,流入旧 Pod 的流量完全耗尽。

配置热更新方面,不建议把应用配置写死在镜像里。用 ConfigMap 挂载配置文件,修改 ConfigMap 后,可以通过kubectl rollout restart deployment/order-service -n mall让 Pod 重新加载。1.13.3 还不支持kubectl set env直接触发生成新 ReplicaSet,所以最稳妥的方式就是 rollout restart。

4.4 用 HPA 应对流量峰值:autoscaling/v1 在 1.13.3 的边界

电商大促时流量是平时的几十倍,提前扩容不如自动扩容。1.13.3 的 HPA 只支持autoscaling/v1,也就是只有 CPU 指标,不包含自定义指标。创建一个基于 CPU 的 HPA:

apiVersion: autoscaling/v1 kind: HorizontalPodAutoscaler metadata: name: order-service-hpa namespace: mall spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: order-service minReplicas: 2 maxReplicas: 10 targetCPUUtilizationPercentage: 60

这里 targetCPUUtilizationPercentage 指的是所有 Pod 的平均 CPU 使用率。如果订单服务的单个 Pod 在 200m requests 下已经跑满,HPA 会自动增加副本数。但注意 1.13.3 无法根据 QPS 或消息队列积压量扩容,只能依赖 CPU。如果业务对响应时间敏感,建议把 requests 设低一点,让 HPA 有更充裕的扩容空间。

提示:HPA 扩容不是瞬时的,默认每 30 秒评估一次,新 Pod 拉起还需要镜像拉取和启动时间。大促前可以先手动把 minReplicas 调高,降低冷启动风险。


5. 部署后的验证与笔记整理:k8s 1.13.3 案例可复制的关键

5.1 安装包版本锁定与校验文件

案例部署完成,第一件事就是把安装包目录重新固化。把二进制文件名带上版本号,避免以后多个版本混在一起。然后生成校验文件:

cd k8s-1.13.3-installer find . -type f -exec md5sum {} \; > checksum.md5

checksum.md5可以交给所有后续接触这套环境的人。每次更新二进制或镜像后,重新生成一遍,并在 docs/change-log.md 里记录变更原因。这样即便过去半年再回来看,也能快速确认当时部署的精确版本组合。

5.2 导出运行时 YAML 并与原始清单做 diff

部署完不要只保留 src 目录下的 YAML。K8s 会为资源补充很多默认字段,只有导出运行时的 YAML,才能反映系统真实状态:

kubectl get deploy order-service -n mall -o yaml > deployed/order-service.deployed.yaml kubectl get statefulset mysql -n middleware -o yaml > deployed/mysql.deployed.yaml kubectl get hpa order-service-hpa -n mall -o yaml > deployed/order-service-hpa.deployed.yaml

导出后与原始清单做 diff,能发现很多隐蔽问题,比如镜像 tag 被替换、副本数被 HPA 修改、默认添加了revisionHistoryLimit等。把 diff 的关键行写进 notes.md,这就是最有价值的排错笔记。

5.3 一条命令定位“服务注册不上 Nacos”问题

最后留一个压箱底的检查手段。电商微服务最常见的故障是“服务已经启动,但 Nacos 控制台看不到实例”。不要急着翻业务日志,先检查网络:

kubectl exec -it order-service-xxx -n mall -- /bin/sh \ -c "telnet nacos.middleware.svc.cluster.local 8848"

如果 telnet 不通,再检查 Service 的 Endpoints:

kubectl get endpoints nacos -n middleware

Endpoints 列表为空,说明 Service 的 selector 和 Pod 标签不匹配;列表有 IP 但 telnet 不通,则需要检查网络插件或安全组规则。这个排查顺序比直接看应用日志快得多,因为“注册不上”八成是网络问题而不是代码问题。把这组命令连同典型输出写进笔记最前面,下次遇到同类故障时,30 秒就能定位到根因。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询