以在线商城为例,实践完整的微服务部署:API Gateway + 用户服务 + 商品服务 + 订单服务 + 支付服务,使用K8s原生能力实现服务发现、配置管理、弹性伸缩。
┌────────── 在线商城微服务架构 ──────────┐
│ │
│ ┌──────────────────────────────────┐ │
│ │ Ingress (Nginx) │ │
│ │ shop.example.com → Gateway │ │
│ └─────────────┬────────────────────┘ │
│ │ │
│ ┌─────────────▼────────────────────┐ │
│ │ API Gateway (Kong/Nginx) │ │
│ │ /api/users → user-svc:8080 │ │
│ │ /api/products → product-svc:80 │ │
│ │ /api/orders → order-svc:8080 │ │
│ │ /api/payments → payment-svc:80 │ │
│ └──┬──────┬──────┬──────┬─────────┘ │
│ │ │ │ │ │
│ ┌──▼──┐┌──▼──┐┌──▼──┐┌──▼──┐ │
│ │User ││Prod ││Order││Pay │ │
│ │ Svc ││ Svc ││ Svc ││ Svc │ │
│ └──┬──┘└──┬──┘└──┬──┘└──┬──┘ │
│ │ │ │ │ │
│ ┌──▼──┐┌──▼──┐┌──▼──┐┌──▼──┐ │
│ │MySQL││Mongo││MySQL││Redis│ │
│ │ PVC ││ PVC ││ PVC ││ PVC │ │
│ └─────┘└─────┘└─────┘└─────┘ │
│ │
│ 共享基础设施: │
│ Redis Cluster | Kafka | Prometheus │
└──────────────────────────────────────────┘
# namespace-structure.yaml
apiVersion: v1
kind: Namespace
metadata:
name: shop-system
labels:
env: production
team: platform
---
apiVersion: v1
kind: Namespace
metadata:
name: shop-monitoring
labels:
env: production
team: sre
# 每个微服务独立部署,共享shop-system命名空间
# 或每个服务独立命名空间(更严格隔离)
# user-service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
namespace: shop-system
labels:
app: user-service
version: v1
spec:
replicas: 3
selector:
matchLabels:
app: user-service
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: user-service
version: v1
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
spec:
serviceAccountName: user-service-sa
containers:
- name: user-service
image: registry.example.com/shop/user-service:v1.5.0
ports:
- name: http
containerPort: 8080
- name: metrics
containerPort: 9090
env:
- name: DB_HOST
valueFrom:
configMapKeyRef:
name: user-config
key: DB_HOST
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: user-secrets
key: password
- name: REDIS_HOST
valueFrom:
configMapKeyRef:
name: shared-config
key: REDIS_HOST
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
livenessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 15
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: http
initialDelaySeconds: 5
periodSeconds: 5
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: user-service
---
apiVersion: v1
kind: Service
metadata:
name: user-service
namespace: shop-system
spec:
selector:
app: user-service
ports:
- name: http
port: 8080
targetPort: http
- name: metrics
port: 9090
targetPort: metrics
---
apiVersion: v1
kind: ConfigMap
metadata:
name: user-config
namespace: shop-system
data:
DB_HOST: "user-mysql.shop-system.svc.cluster.local"
DB_PORT: "3306"
DB_NAME: "userdb"
LOG_LEVEL: "info"
JWT_EXPIRY: "24h"
---
apiVersion: v1
kind: Secret
metadata:
name: user-secrets
namespace: shop-system
type: Opaque
stringData:
password: "changeme-in-production"
# ✅ 验证通过
kubectl apply -f user-service.yaml
kubectl get pods -n shop-system -l app=user-service
# NAME READY STATUS RESTARTS AGE
# user-service-6c8f9d7b5e-abc12 1/1 Running 0 30s
# user-service-6c8f9d7b5e-def34 1/1 Running 0 30s
# user-service-6c8f9d7b5e-ghi56 1/1 Running 0 30s
# product-service.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: product-mysql
namespace: shop-system
spec:
serviceName: product-mysql
replicas: 1
selector:
matchLabels:
app: product-mysql
template:
metadata:
labels:
app: product-mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: product-secrets
key: mysql-root-password
- name: MYSQL_DATABASE
value: "productdb"
ports:
- containerPort: 3306
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: [ReadWriteOnce]
storageClassName: standard
resources:
requests:
storage: 20Gi
---
# 商品服务Deployment + HPA
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: product-service-hpa
namespace: shop-system
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: product-service
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "500"
# api-gateway.yaml - Nginx Ingress作为API Gateway
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop-gateway
namespace: shop-system
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
nginx.ingress.kubernetes.io/rate-limit: "100"
nginx.ingress.kubernetes.io/limit-rps: "50"
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
ingressClassName: nginx
tls:
- hosts: [shop.example.com]
secretName: shop-tls
rules:
- host: shop.example.com
http:
paths:
- path: /api/users(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: user-service
port: {number: 8080}
- path: /api/products(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: product-service
port: {number: 8080}
- path: /api/orders(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: order-service
port: {number: 8080}
- path: /()(.*)
pathType: ImplementationSpecific
backend:
service:
name: frontend
port: {number: 80}
# ✅ 验证通过
kubectl get ingress -n shop-system
# NAME CLASS HOSTS ADDRESS PORTS AGE
# shop-gateway nginx shop.example.com 1.2.3.4 80,443 30s
# shop-networkpolicy.yaml
# 默认拒绝
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: shop-system
spec:
podSelector: {}
policyTypes: [Ingress, Egress]
---
# 允许DNS
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: shop-system
spec:
podSelector: {}
policyTypes: [Egress]
egress:
- to:
- namespaceSelector: {}
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- {port: 53, protocol: UDP}
---
# 服务间通信
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: order-to-payment
namespace: shop-system
spec:
podSelector:
matchLabels:
app: payment-service
policyTypes: [Ingress]
ingress:
- from:
- podSelector:
matchLabels:
app: order-service
ports:
- {port: 8080, protocol: TCP}
下一课预告:第22课深入CI/CD流水线——从代码到K8s的自动化。
21-微服务部署补充要点K8s生产实践扩展
🔹 资源配额(ResourceQuota):限制命名空间总资源
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: production
spec:
hard:
requests.cpu: "20"
requests.memory: 40Gi
limits.cpu: "40"
limits.memory: 80Gi
pods: "50"
services: "10"
🔹 LimitRange:设置默认资源限制
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
spec:
limits:
- type: Container
default:
cpu: "200m"
memory: 256Mi
defaultRequest:
cpu: "100m"
memory: 128Mi
max:
cpu: "2"
memory: 4Gi
🔹 Pod优先级与抢占
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000
globalDefault: false
---
spec:
preemptionPolicy: PreemptLowerPriority
🔹 优雅处理Pod中断
• PDB保证最小可用副本
• preStop钩子处理连接排空
• terminationGracePeriodSeconds充足
• 应用必须处理SIGTERM信号
🔹 生产环境Checklist
✅ 设置resources requests/limits
✅ 配置liveness/readiness探针
✅ 使用PDB保护关键服务
✅ 实现优雅关闭(SIGTERM)
✅ 配置HPA自动伸缩
✅ 使用NetworkPolicy隔离
✅ 开启RBAC最小权限
✅ 日志结构化输出
✅ 指标暴露/metrics端点
✅ 配置PVC数据备份