云原生踩坑记录
这次做云原生改造,从容器到 Kubernetes,再到服务网格,。
下面只记真正影响结果的部分。
容器化
Docker 基础
# Dockerfile
FROM node:16-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]
Docker Compose
# docker-compose.yml
version: '3'
services:
app:
build: .
ports:
- "3000:3000"
depends_on:
- db
- redis
environment:
- DATABASE_URL=postgres://postgres:password@db:5432/myapp
- REDIS_URL=redis://redis:6379
db:
image: postgres:13
environment:
- POSTGRES_PASSWORD=password
volumes:
- db-data:/var/lib/postgresql/data
redis:
image: redis:alpine
volumes:
- redis-data:/data
volumes:
db-data:
redis-data:
Kubernetes
部署应用
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp:latest
ports:
- containerPort: 3000
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
配置管理
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: myapp-config
data:
DATABASE_URL: "postgres://postgres:password@db:5432/myapp"
REDIS_URL: "redis://redis:6379"
LOG_LEVEL: "info"
---
# secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: myapp-secret
type: Opaque
stringData:
API_KEY: "your-api-key"
JWT_SECRET: "your-jwt-secret"
存储管理
# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myapp-storage
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard
---
# 使用 PVC
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: myapp
image: myapp:latest
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: myapp-storage
服务网格
Istio 部署
# 安装 Istio
istioctl install --set profile=demo -y
# 给命名空间打标签
kubectl label namespace default istio-injection=enabled
虚拟服务
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: myapp
spec:
hosts:
- "myapp.example.com"
gateways:
- myapp-gateway
http:
- match:
- uri:
prefix: /api
route:
- destination:
host: myapp
subset: v1
weight: 90
- destination:
host: myapp
subset: v2
weight: 10
目标规则
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: myapp
spec:
host: myapp
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
网关
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: myapp-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "myapp.example.com"
可观测性
监控
# Prometheus ServiceMonitor
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: myapp
spec:
selector:
matchLabels:
app: myapp
endpoints:
- port: metrics
interval: 30s
日志
# Fluentd DaemonSet
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
spec:
selector:
matchLabels:
app: fluentd
template:
metadata:
labels:
app: fluentd
spec:
containers:
- name: fluentd
image: fluent/fluentd-kubernetes-daemonset:v1-debian-elasticsearch
env:
- name: FLUENT_ELASTICSEARCH_HOST
value: "elasticsearch.logging"
- name: FLUENT_ELASTICSEARCH_PORT
value: "9200"
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
追踪
# Jaeger Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: jaeger
spec:
replicas: 1
selector:
matchLabels:
app: jaeger
template:
metadata:
labels:
app: jaeger
spec:
containers:
- name: jaeger
image: jaegertracing/all-in-one:latest
ports:
- containerPort: 5775
- containerPort: 6831
- containerPort: 6832
- containerPort: 5778
- containerPort: 16686
- containerPort: 14268
踩过的坑
坑一:资源限制没配好
Kubernetes 集群资源耗尽,Pod 无法调度。
解决:为所有 Pod 配置资源限制。
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
坑二:健康检查失败
健康检查配置不当,Pod 不断重启。
解决:正确配置健康检查。
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 3
坑三:配置管理混乱
配置分散在各个地方,难以管理。
解决:使用 ConfigMap 和 Secret 统一管理。
apiVersion: v1
kind: ConfigMap
metadata:
name: myapp-config
data:
config.yaml: |
database:
url: "postgres://postgres:password@db:5432/myapp"
redis:
url: "redis://redis:6379"
写在最后
云原生这东西,不只是技术,是架构和文化。
解决了:
- 可扩展性
- 高可用性
- 运维效率
带来了:
- 学习成本
- 运维成本
- 复杂度增加
实施之前先评估:
- 团队能力
- 项目规模
- 业务需求
- 预算
不是所有应用都需要云原生,有时候简单的部署就够用。
这次云原生改造花了一个月,从容器到 Kubernetes,再到服务网格。改造完成后,部署时间从 30 分钟降到 5 分钟,可用性从 99.5% 提升到 99.9%。
版权声明: 本文首发于 指尖魔法屋-云原生踩坑记录(https://blog.thinkmoon.cn/post/80-cloud-native-container-service-mesh-practice/) 转载或引用必须申明原指尖魔法屋来源及源地址!
评论
使用 GitHub 账号登录后即可留言,支持 Markdown。