本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
EKS 数据平面
要运行高可用性和弹性的应用程序,您需要一个高可用性和弹性的数据平面。弹性数据平面可确保 Kubernetes 可以自动扩展和修复您的应用程序。弹性数据平面由两个或更多工作节点组成,可以随着工作负载的变化而增长和缩小,并自动从故障中恢复。
对于带有 EKS 的工作节点,您有两种选择:EC2实例和 Fargat e。如果您选择 EC2 实例,则可以自己管理工作节点或使用 EKS 托管节点组。你可以拥有一个混合了托管、自我管理的工作节点和 Fargate 的集群。
Fargate 上的 EKS 提供了通往弹性数据平面的最简单途径。Fargate 在隔离的计算环境中运行每个 Pod。在 Fargate 上运行的每个 Pod 都有自己的工作节点。当 Kubernetes 缩放 pod 时,Fargate 会自动缩放数据平面。您可以使用水平容器自动扩缩器来扩展数据平面和工作负载。
扩展 EC2 工作节点的首选方法是使用 Kubernetes 集群自动EC2扩缩器、Auto Scaling 群组或社区项目,
建议
使用 EC2 Auto Scaling 组创建工作节点
最佳做法是使用 A EC2 uto Scaling 组创建工作节点,而不是创建单个 EC2 实例并将其加入集群。Auto Scaling Groups 将自动替换任何已终止或出现故障的节点,确保集群始终有能力运行您的工作负载。
使用 Kubernetes 集群自动扩缩器来扩展节点
当有因集群资源不足而无法运行的 pod 时,Cluster Autoscaler 会调整数据平面的大小,添加另一个工作节点会有所帮助。尽管 Cluster Autoscaler 是一个被动过程,但由于集群中的容量不足,它会一直等到 pod 处于 Pending 状态。当此类事件发生时,它会向集群添加EC2 实例。每当集群容量耗尽时,新的副本或新 Pod 将不可用(处于 Pen ding 状态),直到添加工作节点为止。如果数据平面无法足够快地扩展以满足工作负载的需求,则这种延迟可能会影响应用程序的可靠性。如果工作节点一直未得到充分利用,并且其所有 pod 都可以调度到其他工作节点上,则 Cluster Autoscaler 会将其终止。
使用集群自动扩缩器配置预留空间
当集群中的 Pod 已处于待处理状态时,集群自动扩缩器会触发数据平面的扩展。因此,在您的应用程序需要更多副本与实际获得更多副本之间可能会有延迟。要解决这种可能的延迟,可以选择添加超过所需数量的副本,从而增加应用程序的副本数量。
Cluster Autoscaler 推荐的另一种模式使用暂停 Pod 和优先级抢占
将集群自动扩缩器与多个 Auto Scaling 组一起使用
在启用该--node-group-auto-discovery
标志的情况下运行集群自动扩缩程序。这样做可以让 Cluster Autoscaler 找到包含特定定义标签的所有自动扩缩组,并且无需在清单中定义和维护每个自动缩放组。
将集群自动扩缩器与本地存储一起使用
默认情况下,Cluster Autoscaler 不会缩小那些部署了 pod 并连接了本地存储空间的节点。将该--skip-nodes-with-local-storage
标志设置为 false 以允许集群自动扩缩程序缩小这些节点。
将工作节点和工作负载分散到多个工作节点 AZs
您可以通过在多个可用区中运行工作节点和 Pod 来保护您的工作负载免受单个可用区故障的影响 AZs。您可以使用在其中创建节点的子网来控制创建工作节点的可用区。
如果您使用 AZs 的是 Kubernetes 1.18+,则建议使用 Pod 的拓扑
AZs 如果可能的话,下面的部署将 pod 分散到各处,如果不是,则让这些 pod 无论如何都能运行:
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
replicas: 3
selector:
matchLabels:
app: web-server
template:
metadata:
labels:
app: web-server
spec:
topologySpreadConstraints:
- maxSkew: 1
whenUnsatisfiable: ScheduleAnyway
topologyKey: topology.kubernetes.io/zone
labelSelector:
matchLabels:
app: web-server
containers:
- name: web-app
image: nginx
resources:
requests:
cpu: 1
注意
kube-scheduler
只能通过带有这些标签的节点来识别拓扑域。如果将上述部署部署部署到仅在单个区域中的节点的集群上,则所有 pod 都将在这些节点上进行调度,因为kube-scheduler
他们不知道其他区域。要使此拓扑分布在调度器中按预期运行,节点必须已存在于所有区域中。这个问题将在 Kubernetes 1.24 中通过添加MinDomainsInPodToplogySpread
功能门来解决,该功能minDomains
属性来通知调度器符合条件的域的数量。
警告
如果无法whenUnsatisfiable
满足拓扑分布约束,则设置为DoNotSchedule
将导致 pod 不可调度。只有当 pod 最好不要运行而不是违反拓扑分布约束时,才应设置它。
在旧版本的 Kubernetes 上,你可以使用容器反关联性规则跨多个容器调度 Pod。 AZs下面的清单告知 Kubernetes 调度器更喜欢以不同的方式调度 pod。 AZs
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
labels:
app: web-server
spec:
replicas: 4
selector:
matchLabels:
app: web-server
template:
metadata:
labels:
app: web-server
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web-server
topologyKey: failure-domain.beta.kubernetes.io/zone
weight: 100
containers:
- name: web-app
image: nginx
警告
不要求在 distinct 之间调度 pod, AZs 否则,部署中的 Pod 数量将永远不会超过 pod 的数量 AZs。
使用 EBS 卷时,请确保每个可用区的容量
如果您使用 Amazon EBS 提供永久卷,则需要确保 Pod 和关联的 EBS 卷位于同一个可用区中。在撰写本文时,EBS 卷仅在单个可用区内可用。Pod 无法访问位于不同可用区的 EBS 支持的永久卷。Kubernetes 调度器知道工作节点位于哪个可用区
为每个具有足够容量的可用区创建 Auto Scaling 组,以确保集群始终有能力在与所需的 EBS 卷相同的可用区中调度 Pod。此外,您应该在集群自动扩缩器中启用该--balance-similar-node-groups
功能。
如果您运行的应用程序使用 EBS 卷,但对高可用性没有要求,则可以将该应用程序的部署限制在单个可用区。在 EKS 中,工作节点会自动添加failure-domain.beta.kubernetes.io/zone
标签,其中包含可用区的名称。您可以通过运行来查看附加到节点的标签kubectl get nodes --show-labels
。有关内置节点标签的更多信息,请点击此处
在下面的示例中,Pod 将仅在 us-west-2c
AZ 中调度:
apiVersion: v1
kind: Pod
metadata:
name: single-az-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: failure-domain.beta.kubernetes.io/zone
operator: In
values:
- us-west-2c
containers:
- name: single-az-container
image: kubernetes/pause
永久卷(由 EBS 支持)也会自动标有 AZ 的名称;您可以通过运行kubectl get pv -L topology.ebs.csi.aws.com/zone
来查看您的永久卷属于哪个可用区。创建 Pod 并声明卷后,Kubernetes 会将 Pod 调度到与该卷位于同一可用区的节点上。
考虑这个场景;你有一个包含一个节点组的 EKS 集群。该节点组有三个工作节点,分布在三个工作节点 AZs。您的应用程序使用 EBS 支持的永久卷。当你创建这个应用程序和相应的卷时,它的 Pod 将在三个卷中的第一个中创建 AZs。然后,运行此 Pod 的工作节点变得不健康,随后无法使用。Cluster Autoscaler 会将运行状况不佳的节点替换为新的工作节点;但是,由于自动扩缩组跨越三个 AZs,因此新的工作节点可能会在第二个或第三个可用区启动,但不会根据情况在第一个可用区启动。由于受可用区限制的 EBS 卷仅存在于第一个可用区中,但该可用区中没有工作节点可用,因此无法调度 Pod。因此,您应该在每个 AZ 中创建一个节点组,以便始终有足够的容量来运行无法在其他可用区中调度的 Pod AZs。
或者,EFS
使用节点监控代理检测节点问题
工作节点中的故障可能会影响应用程序的可用性。您可以使用节点监控代理来检测和显示运行状况问题。您还可以启用节点自动修复功能,以便在检测到问题时自动替换节点。
节点监控代理是所有 Amazon EKS 自动模式集群中都包含的一项功能。对于其他集群类型,您可以将监控代理作为 Amazon EKS 附加组件添加。有关更多信息,请参阅 Amazon EKS 用户指南中的启用节点自动修复和调查节点运行状况问题。
为系统和 Kubernetes 守护程序预留资源
您可以通过为操作系统和 Kubernetes 守护程序预留计算容量来提高工作节点的limits
声明的 Pod)可能会使系统资源饱和,使节点处于操作系统进程和 Kubernetes 守护程序(kubelet
容器运行时等)与 Pod 争夺系统资源的境地。您可以使用kubelet
标志--system-reserved
和--kube-reserved
分别为系统进程(udev
sshd
、等)和 Kubernetes 守护程序预留资源。
如果您使用经过 EKS 优化的 Linux AMI,则默认情况下,CPU、内存和存储空间是为系统和 Kubernetes 守护程序预留的。当基于此 AMI 的工作节点启动时,将 EC2 用户数据配置为触发bootstrap.sh
脚本KubeletConfiguration
的文件中/etc/kubernetes/kubelet/kubelet-config.json
。
如果您在节点上运行自定义守护程序,并且默认情况下预留的 CPU 和内存量不足,则可能需要增加系统资源预留。
eksctl
提供了为系统和 Kubernetes 守护程序自定义资源预留
实施 QoS
对于关键应用程序,可以考虑为 Pod 中的容器定义 requests
= limits
。这将确保在另一个 Pod 请求资源时容器不会被杀死。
最佳做法是对所有容器实施 CPU 和内存限制,因为这样可以防止容器无意中消耗系统资源,从而影响其他共置进程的可用性。
为所有工作负载配置和调整资源请求/限制
在调整资源请求和工作负载限制时,可以应用一些一般指南:
-
不要指定 CPU 的资源限制。在没有限制的情况下,请求充当容器获得的相对 CPU 时间的
权重。这使您的工作负载能够使用完整的 CPU,而不会受到人为限制或饥饿。 -
对于非 CPU 资源,配置
requests
= 可limits
提供最可预测的行为。如果requests
! =limits
,容器的 QOS也从 “保证” 降低到 Burstable,因此在节点压力下更有可能被驱逐。 -
对于非 CPU 资源,请勿指定比请求大得多的限制。相对于的配置越大
limits
requests
,节点被过度使用的可能性就越大,从而导致工作负载中断的可能性很大。 -
在使用 Karpen
ter 或 Cluster 等节点自动缩放解决方案时,正确调整请求大小尤为重要。AutoScaler 这些工具会查看您的工作负载请求,以确定要配置的节点的数量和大小。如果你的请求太小,限制更大,那么如果你的工作负载被紧密地挤在节点上,你可能会发现工作负载被驱逐或 OOM 终止。
确定资源请求可能很困难,但是像 Vertic al Pod Autoscaler
为命名空间配置资源配额
命名空间适用于众多用户分散在多个团队或项目中的环境。它们为名称提供了范围,并且是在多个团队、项目和工作负载之间分配群集资源的一种方式。您可以限制命名空间中的聚合资源消耗。该ResourceQuota
如果为计算资源(如 CPU 和内存)启用了命名空间的资源配额,则用户必须为该命名空间中的每个容器指定请求或限制。
考虑为每个命名空间配置配额。考虑使用自动LimitRanges
将预配置的限制应用于命名空间内的容器。
限制命名空间内的容器资源使用量
资源配额有助于限制命名空间可以使用的资源量。该LimitRange
对象LimitRange
可以为容器设置默认请求和限制,如果设置计算资源限制不是组织中的标准做法,这会很有用。顾名思义,LimitRange
可以强制命名空间中每个 Pod 或容器的最低和最大计算资源使用量。并且,在命名空间 PersistentVolumeClaim 中强制执行每个存储请求的最小和最大值。
考虑与结合使用 LimitRange
ResourceQuota
,在容器和命名空间级别强制执行限制。设置这些限制将确保容器或命名空间不会影响集群中其他租户使用的资源。
CoreDNS
CoreDNS 在 Kubernetes 中实现了名称解析和服务发现功能。默认情况下,它安装在 EKS 集群上。为了实现互操作性,适用于 CoreDNS 的 Kubernetes 服务仍被命名为 kube-dns。kube-system
在命名空间中运行,在 EKS 中,默认情况下,它运行两个具有声明请求和限制的副本。DNS 查询被发送到在kube-system
命名空间中运行的kube-dns
服务。
建议
监控 CoreDNS 指标
CoreDNS 已经内置了对 Prometheus 的支持。coredns_dns_request_duration_seconds_sum
(在 1.7.0 版本之前core_dns_response_rcode_count_total
调用)、错误coredns_dns_responses_total
(、NXDOMAIN、SERVFAIL 等)和 CoreDNS Pod 的内存消 FormErr耗。
出于疑难解答的目的,你可以使用 kubectl 查看 CoreDNS 日志:
for p in $(kubectl get pods -n kube-system -l k8s-app=kube-dns -o jsonpath='{.items[*].metadata.name}'); do kubectl logs $p -n kube-system; done
使用 NodeLocal DNSCache
您可以通过运行来提高集群 DNS 的性能NodeLocalDNSCachekube-dns
ervice。
为 Cor cluster-proportional-scaler eDNS 进行配置
提高集群 DNS 性能的另一种方法是根据集群中的节点和 CPU 内核数自动横向扩展 CoreDNS
节点和节点中 CPU 内核的总量是您可以用来扩展 CoreDNS 的两个指标。您可以同时使用这两个指标。如果您使用更大的节点,CoreDNS 的扩展将基于 CPU 内核的数量。但是,如果您使用较小的节点,则CoreDNS副本的数量取决于数据平面中的CPU内核。比例自动扩缩器配置如下所示:
linear: '{"coresPerReplica":256,"min":1,"nodesPerReplica":16}'
选择带有节点组的 AMI
EKS 提供了经过优化的服务 EC2 AMIs ,供客户用来创建自我管理和托管的节点组。 AMIs 它们会在每个受支持的 Kubernetes 版本的每个地区发布。当发现任何 CVEs 错误时AMIs ,EKS 会将其标记为已弃用。因此,建议在为节点组选择 AMI AMIs 时不要使用已弃用的。
AMIs 可以使用以下命令使用 Ec2 describe-images api 筛选已弃用:
aws ec2 describe-images --image-id ami-0d551c4f633e7679c --no-include-deprecated
您还可以通过验证描述图像输出是否包含作为字段来识别已弃用的 AMI。 DeprecationTime 例如:
aws ec2 describe-images --image-id ami-xxx --no-include-deprecated
{
"Images": [
{
"Architecture": "x86_64",
"CreationDate": "2022-07-13T15:54:06.000Z",
"ImageId": "ami-xxx",
"ImageLocation": "123456789012/eks_xxx",
"ImageType": "machine",
"Public": false,
"OwnerId": "123456789012",
"PlatformDetails": "Linux/UNIX",
"UsageOperation": "RunInstances",
"State": "available",
"BlockDeviceMappings": [
{
"DeviceName": "/dev/xvda",
"Ebs": {
"DeleteOnTermination": true,
"SnapshotId": "snap-0993a2fc4bbf4f7f4",
"VolumeSize": 20,
"VolumeType": "gp2",
"Encrypted": false
}
}
],
"Description": "EKS Kubernetes Worker AMI with AmazonLinux2 image, (k8s: 1.19.15, docker: 20.10.13-2.amzn2, containerd: 1.4.13-3.amzn2)",
"EnaSupport": true,
"Hypervisor": "xen",
"Name": "aws_eks_optimized_xxx",
"RootDeviceName": "/dev/xvda",
"RootDeviceType": "ebs",
"SriovNetSupport": "simple",
"VirtualizationType": "hvm",
"DeprecationTime": "2023-02-09T19:41:00.000Z"
}
]
}