本文最后更新于:2024年7月24日 晚上
前言
最近忙的要死, 👻👻👻. 上一周来了一次比 996 更猛的 907
. 这周二终于有点遭不住了, 调休一天, 稍微歇息一下.
同时手痒的不行, 把筹备了好久的重磅文章发上来哈哈. 😆😆😆
不过时间还是有点仓促, 所以这次就先开个头, 后面有时间再细化.
容器化应用系统上生产的最佳实践
- 检查镜像、容器是否是用
root
启动以及配置其他特权. 如无必要, 一律使用普通用户.
- 检查镜像
LANG
配置: LANG = en_US.UTF-8
. 目的: 避免生产出现 乱码等问题
- 检查镜像时区配置:
TZ=Asia/Shanghai
目的: 避免生产出现时区不一致的问题
- 配置外部化. 外部化手段有多种.
- ConfigMap/Secret
- 配置中心
- Env
- …
- 同一个镜像, 从测试流转到生产. 给镜像打
${version}
或${gitCommitId}
这一类的标签. 目的: 通过版本号或 commit id, 保证正确地的版本流转到生产
- 讨论每个组件的
- 日志输出优化:
- 日志到标准输出还是到目录?
- 日志采用 JSON 格式输出
- 禁止
DEBUG
日志
- 如果到目录, 目录是否需要持久化? 是否共享? 要注意日志命名冲突.
- (可选) 根据需要, 安装 redis/kafka/rabbitmq 集群(并配置 exporter 监控)
- 确定每个服务(Deployment/Statefulset):
- Node Selector: zone/rack/arch…
- 资源用量: CPU/Memory 的 Requests/Limits
- 更新策略:
rolling
还是 recreate
还是其他更高阶策略
- 微服务参数优化:
- JVM Heap/NonHeap 参数优化
- 是否有其他 java 参数要配置:
JAVA_OPTIONS
或者CATALINA_OPTS
- 其他…
- 制作 DEV, TEST, UAT, Pre-PROD, PROD 的 DevOps pipeline.
- 配置 Readiness 和 Liveness 探针.
- 增加 Metric(如 JMX-exporter) 监控和 Tracing 监控.
- NGINX conf 建议增加:
worker_processes 1;
然后按需调节副本数.
- (可选)配置 PDB, 指定升级或重启过程中:
maxUnavailable
或minAvailable
(特别适用于: 有状态应用. 典型如: redis, kafka, zookeeper 等)
- 配置反亲和性
podAntiAffinity
. 保证同一组微服务 / 应用 / 组件尽可能打散在不同 node 上.
8 操作步骤:
1 2
| nodeSelector: zone: DMZ
|
11 步示例如下:
1 2 3 4 5 6 7 8 9 10
| livenessProbe: tcpSocket: port: 8080 initialDelaySeconds: 60 readinessProbe: httpGet: path: /myapp/services/ port: 8080 scheme: HTTP initialDelaySeconds: 60
|
14 步示例如下: (注意关键词: maxUnavailable
和 minAvailable
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| kind: PodDisruptionBudget apiVersion: policy/v1beta1 metadata: name: kafka-prod-kafka labels: app.kubernetes.io/instance: kafka-prod app.kubernetes.io/managed-by: strimzi-cluster-operator app.kubernetes.io/name: strimzi strimzi.io/cluster: kafka-prod strimzi.io/kind: Kafka strimzi.io/name: kafka-prod-kafka spec: selector: matchLabels: strimzi.io/cluster: kafka-prod strimzi.io/kind: Kafka strimzi.io/name: kafka-prod-kafka maxUnavailable: 1
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| kind: PodDisruptionBudget apiVersion: policy/v1beta1 metadata: name: redis-cluster-redis namespace: myapp labels: app.kubernetes.io/component: redis app.kubernetes.io/managed-by: redis-operator app.kubernetes.io/name: redis app.kubernetes.io/part-of: redis-cluster redis.kun/v1beta1: myapp_redis spec: minAvailable: 2 selector: matchLabels: app.kubernetes.io/component: redis app.kubernetes.io/managed-by: redis-operator app.kubernetes.io/name: redis app.kubernetes.io/part-of: redis-cluster redis.kun/v1beta1: myapp_redis
|
15 步骤示例如下: (注意关键词: podAntiAffinity
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| kind: StatefulSet apiVersion: apps/v1 metadata: name: redis-cluster-redis labels: app.kubernetes.io/component: redis app.kubernetes.io/managed-by: redis-operator app.kubernetes.io/name: redis app.kubernetes.io/part-of: redis-cluster redis.kun/v1beta1: myapp_redis spec: replicas: 3 selector: matchLabels: app.kubernetes.io/component: redis app.kubernetes.io/managed-by: redis-operator app.kubernetes.io/name: redis app.kubernetes.io/part-of: redis-cluster redis.kun/v1beta1: myapp_redis template: metadata: creationTimestamp: null labels: app.kubernetes.io/component: redis app.kubernetes.io/managed-by: redis-operator app.kubernetes.io/name: redis app.kubernetes.io/part-of: redis-cluster redis.kun/v1beta1: myapp_redis spec: containers: <...> affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: app.kubernetes.io/component: redis app.kubernetes.io/managed-by: redis-operator app.kubernetes.io/name: redis app.kubernetes.io/part-of: redis-cluster redis.kun/v1beta1: myapp_redis topologyKey: kubernetes.io/hostname ...
|
完
🎉🎉🎉