工作负载推荐配置

ACK集群中配置工作负载(Deployment、StatefulSet、DaemonSet、Job、CronJob等)时,您需考虑多种因素,以确保应用可以稳定、可靠地运行。

声明每个PodRequestsLimits

在 Kubernetes 集群中,节点上调度过多 Pod 会导致负载过高,无法正常提供服务。配置Pod时,建议声明其所需的requestslimits,以便集群在部署Pod时可以根据资源需求找到合适的节点。

下方示例中,Nginx Pod的资源配置为:

  • CPU请求:1核;内存请求:1024MiB

  • CPU限制:2核;内存限制:4096MiB

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
    resources: # 资源声明
      requests:
        memory: "1024Mi"
        cpu: "1000m"
      limits:
        memory: "4096Mi"
        cpu: "2000m"

Kubernetes采用静态资源调度机制。每个节点的剩余资源的计算公式为节点剩余资源 = 节点总资源 - 已分配资源。手动运行资源密集型程序时,Kubernetes无法感知其实际资源使用量。因此公式中基于已分配资源进行计算,而非实际使用资源。

此外,所有Pod都应声明resources。如果Pod未声明resources,调度到节点后,Kubernetes不会为其预留资源。这可能导致节点上调度过多Pod,进而引发资源争用问题。

推荐使用ACK提供的资源画像功能,基于资源使用量的历史数据获得容器粒度的资源规格推荐,简化容器requestslimits的配置复杂度。

启动时等待下游服务,不要直接退出

有些应用可能存在一些外部依赖,例如需要从数据库(DB)读取数据或者依赖另外一个服务的接口。应用启动时,外部依赖可能无法完全满足。在传统手动运维中,通常采用“依赖不满足即退出”的方式(即failfast)。但在Kubernetes中,大多运维操作是自动化的,无需人工干预。例如部署应用时系统会自动选择节点并启动应用,应用失败时系统会自动重启,负载增加时可以通过HPA(Horizontal Pod Autoscaler)实现自动扩容。

假设有两个应用AB,A依赖B,并且它们运行在同一节点上。如果该节点因某种原因重启,重启后A先启动,而B尚未启动,此时A的依赖无法满足。如果A按照传统方式直接退出,即使B启动后,A也不会自动恢复,需要人工干预。

Kubernetes集群中,建议在启动时检查依赖。如果依赖不满足,可以通过轮询等待,而不是直接退出。这一功能可以通过Init Container实现。

配置restart policy

Pod 运行期间,进程退出是一种常见现象。代码缺陷或内存占用过多等问题都可能导致应用程序进程退出,从而导致 Pod 终止。您可以为 Pod 配置restartPolicy,确保在 Pod 退出后能够自动重启。`

apiVersion: v1
kind: Pod
metadata:
  name: nginx-test
spec:
  restartPolicy: OnFailure 
  containers:
  - name: nginx
    image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6

restartPolicy可选值如下:

  • Always:总是自动重启。

  • OnFailure:异常退出时自动重启(进程退出状态非0)。

  • Never:从不重启。

配置Liveness ProbeReadiness Probe

Pod 处于 Running 状态并不等同于Pod能够正常提供服务。对于处于Running状态的 Pod,其内部进程可能发生死锁,导致无法正常提供服务。但由于 Pod 仍处于 Running 状态,Kubernetes 不会自动重启它。

因此,建议为所有 Pod 配置探针:

  • Liveness Probe用于探测 Pod 是否真正存活并具备服务能力。当Liveness Probe 检测到问题时,Kubernetes 会自动重启该 Pod。

  • Readiness Probe用于检测 Pod 是否已准备好对外提供服务。在应用启动期间,初始化过程可能需要一定时间,在此期间 Pod 无法对外提供服务。Readiness Probe可以通知 Ingress 或 Service 是否可将流量转发至该 Pod。当 Pod 出现问题时,它能够防止新流量继续转发到该 Pod。

apiVersion: v1
kind: Pod
metadata:
  name: tomcat
spec:
  containers:
  - name: tomcat
    image: tomcat
    livenessProbe:
      httpGet:
        path: /index.jsp
        port: 8080
      initialDelaySeconds: 3
      periodSeconds: 3
    readinessProbe:
      httpGet:
        path: /index.jsp
        port: 8080

每个进程一个容器

部分开发者习惯将容器当作虚拟机(VM)使用,并在一个容器中运行多个进程,例如监控进程、日志进程、sshd 进程,甚至整个 Systemd。这种做法会带来以下问题:

  • 判断 Pod 的整体资源占用会更加复杂,也不利于正确配置 Requests 和 Limits。

  • 如果容器内仅运行单个进程,当该进程中断时,外部容器引擎能够立即感知并重启容器。若容器内运行多个进程,即使其中一个进程崩溃,外部容器引擎也无法感知,可能导致容器无法正常工作。

Kubernetes支持多个进程的协同工作。例如,Nginx 和 PHP-FPM 可通过 Unix Domain Socket 通信,您可创建一个包含2个容器的 Pod,并将 Unix Domain Socket 存放于两者的共享 Volume 中。

确保不存在SPOF(Single Point of Failure)

如果应用仅有一个实例,当该实例发生故障时,尽管 Kubernetes 能够自动重启实例,但在这期间不可避免地会出现短暂的服务中断。即使在更新应用或发布新版本时,也可能出现类似的服务中断情况。

在 Kubernetes 中,应尽量避免直接管理 Pod,而是通过 Deployment 或 StatefulSet 来管理,并确保应用至少运行两个以上的 Pod 实例。这种做法能够有效提升系统的高可用性,避免因单个实例故障导致的服务中断。

相关文档