Nesta página, mostramos como resolver problemas com o programador do Kubernetes
(kube-scheduler
) para o Google Distributed Cloud.
O Kubernetes sempre programa os pods para o mesmo conjunto de nós
Esse erro pode surgir por alguns motivos diferentes:
Uso desequilibrado do cluster. É possível inspecionar a utilização do cluster para cada nó com o comando
kubectl top nodes
. Este exemplo exagerado de saída mostra a utilização pronunciada de determinados nós:NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% XXX.gke.internal 222m 101% 3237Mi 61% YYY.gke.internal 91m 0% 2217Mi 0% ZZZ.gke.internal 512m 0% 8214Mi 0%
Excesso de solicitações. Se você programar muitos pods de uma só vez no mesmo nó e esses pods fizerem solicitações HTTP, o nó poderá ter limitação de taxa. O erro comum retornado pelo servidor nesse cenário é
429 Too Many Requests
.Serviço indisponível. Um servidor da Web, por exemplo, hospedado em um nó com carga alta, pode responder a todas as solicitações com erros
503 Service Unavailable
até que esteja sob carga mais leve.
Para verificar se você tem pods sempre programados para os mesmos nós, siga as etapas abaixo:
Execute o comando
kubectl
a seguir para conferir o status dos pods:kubectl get pods -o wide -n default
Para mostrar a distribuição de pods entre nós, marque a coluna
NODE
na saída. No exemplo de saída a seguir, todos os pods são programados no mesmo nó:NAME READY STATUS RESTARTS AGE IP NODE nginx-deployment-84c6674589-cxp55 1/1 Running 0 55s 10.20.152.138 10.128.224.44 nginx-deployment-84c6674589-hzmnn 1/1 Running 0 55s 10.20.155.70 10.128.226.44 nginx-deployment-84c6674589-vq4l2 1/1 Running 0 55s 10.20.225.7 10.128.226.44
Os pods têm vários recursos para ajustar o comportamento de
programação. Esses recursos incluem restrições de distribuição de topologia e regras
antiafinidade. É possível usar um desses recursos ou uma combinação deles. Os requisitos
definidos são unidos por kube-scheduler
.
Os registros do programador não são capturados no nível de detalhamento de geração de registros padrão. Caso você precise capturar os registros do programador para solucionar problemas, siga estas etapas:
Aumente o nível de detalhamento da geração de registros:
Edite o Deployment
kube-scheduler
:kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG edit deployment kube-scheduler \ -n USER_CLUSTER_NAMESPACE
Adicione a flag
--v=5
na seçãospec.containers.command
:containers: - command: - kube-scheduler - --profiling=false - --kubeconfig=/etc/kubernetes/scheduler.conf - --leader-elect=true - --v=5
Quando terminar a solução de problemas, redefina o nível de detalhamento para o padrão:
Edite o Deployment
kube-scheduler
:kubectl --kubeconfig ADMIN_CLUSTER_KUBECONFIG edit deployment kube-scheduler \ -n USER_CLUSTER_NAMESPACE
Retorne o nível de detalhamento ao valor padrão:
containers: - command: - kube-scheduler - --profiling=false - --kubeconfig=/etc/kubernetes/scheduler.conf - --leader-elect=true
Restrições de distribuição de topologia
As restrições de distribuição de topologia
podem ser usadas para distribuir uniformemente os pods entre os nós de acordo com zones
,
regions
, node
ou outra topologia personalizada.
O seguinte manifesto de exemplo mostra uma implantação que distribui réplicas uniformemente entre todos os nós programáveis usando restrições de distribuição de topologia:
apiVersion: apps/v1
kind: Deployment
metadata:
name: topology-spread-deployment
labels:
app: myapp
spec:
replicas: 30
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
topologySpreadConstraints:
- maxSkew: 1 # Default. Spreads evenly. Maximum difference in scheduled Pods per Node.
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule # Default. Alternatively can be ScheduleAnyway
labelSelector:
matchLabels:
app: myapp
matchLabelKeys: # beta in 1.27
- pod-template-hash
containers:
# pause is a lightweight container that simply sleeps
- name: pause
image: registry.k8s.io/pause:3.2
As considerações a seguir se aplicam ao uso de restrições de distribuição de topologia:
- O
labels.app: myapp
de um pod corresponde aolabelSelector
da restrição. - O
topologyKey
especificakubernetes.io/hostname
. Esse rótulo é anexado automaticamente a todos os nós e é preenchido com o nome do host do nó. - O
matchLabelKeys
impede que os lançamentos de novas implantações considerem pods de revisões antigas ao calcular onde programar um pod. O rótulopod-template-hash
é preenchido automaticamente por uma implantação.
Antiafinidade de pods
A antiafinidade de pods serve para definir restrições sobre quais pods podem ser colocalizados no mesmo nó.
O seguinte manifesto de exemplo mostra uma implantação que usa antiafinidade para limitar as réplicas a um pod por nó:
apiVersion: apps/v1
kind: Deployment
metadata:
name: pod-affinity-deployment
labels:
app: myapp
spec:
replicas: 30
selector:
matchLabels:
app: myapp
template:
metadata:
name: with-pod-affinity
labels:
app: myapp
spec:
affinity:
podAntiAffinity:
# requiredDuringSchedulingIgnoredDuringExecution
# prevents Pod from being scheduled on a Node if it
# does not meet criteria.
# Alternatively can use 'preferred' with a weight
# rather than 'required'.
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp
# Your nodes might be configured with other keys
# to use as `topologyKey`. `kubernetes.io/region`
# and `kubernetes.io/zone` are common.
topologyKey: kubernetes.io/hostname
containers:
# pause is a lightweight container that simply sleeps
- name: pause
image: registry.k8s.io/pause:3.2
Este exemplo de implantação especifica 30
réplicas, mas se expande somente para o número de nós
disponíveis no cluster.
As seguintes considerações se aplicam ao usar antiafinidade de pods:
- O
labels.app: myapp
de um pod corresponde aolabelSelector
da restrição. - O
topologyKey
especificakubernetes.io/hostname
. Esse rótulo é anexado automaticamente a todos os nós e é preenchido com o nome do host do nó. É possível usar outros rótulos se o cluster tiver suporte para eles, comoregion
ouzone
.
Pré-extrair imagens de contêiner
Na ausência de outras restrições, por padrão, kube-scheduler
prefere programar pods em nós
que já tenham feito o download da imagem
do contêiner. Esse comportamento pode ser interessante para clusters menores, sem outras
configurações de programação, em que seria possível fazer o download das imagens
em cada nó. No entanto, use esse conceito como último recurso. Uma
solução melhor é usar nodeSelector
, restrições de distribuição de topologia ou
afinidade / antiafinidade. Para mais informações, consulte
Como atribuir pods a nós.
Se você quiser garantir que as imagens de contêiner sejam pré-extraídas para
todos os nós, use um DaemonSet
como no exemplo a seguir:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: prepulled-images
spec:
selector:
matchLabels:
name: prepulled-images
template:
metadata:
labels:
name: prepulled-images
spec:
initContainers:
- name: prepulled-image
image: IMAGE
# Use a command the terminates immediately
command: ["sh", "-c", "'true'"]
containers:
# pause is a lightweight container that simply sleeps
- name: pause
image: registry.k8s.io/pause:3.2
Depois que o pod estiver Running
em todos os nós, os podem devem ser reimplantados para confirmar se os
contêineres estão distribuídos de maneira uniforme entre os nós.