Evite los bloqueos en los trabajos distribuidos. Para ello, asegúrese de que todos los pods obligatorios se inicien al mismo tiempo o que no se inicie ninguno.
Funcionamiento
ACK implementa gang scheduling mediante un resource PodGroup. Cada pod se asigna a un PodGroup con una cantidad mínima de pods (min-available). El programador mantiene el grupo en estado Pending hasta que se cumple este mínimo y luego despacha todos los pods juntos.
ACK admite tres métodos para definir un PodGroup:
|
Método |
Agrupación de pods |
Recomendado para |
|
Etiquetas |
kube-scheduler crea automáticamente un PodGroup |
Trabajos sencillos donde no se requiere un objeto PodGroup independiente |
|
CRD PodGroup |
Resource PodGroup explícito con control de tiempo de espera |
Trabajos que necesitan |
|
Anotaciones de Koordinator |
Agrupación basada en anotaciones |
Clústeres que usan la pila de programación de Koordinator |
En todos los casos, los pods y su PodGroup deben residir en el mismo namespace. Además, todos los pods de un PodGroup deben compartir la misma prioridad.
Requisitos previos
Antes de empezar, asegúrese de contar con lo siguiente:
Un ACK managed Pro cluster que ejecute Kubernetes 1.16 o posterior. Si es necesario, Upgrade the cluster.
Para configuraciones avanzadas (GangGroup y match policy): un clúster que ejecute Kubernetes 1.22 o posterior, con una versión de kube-scheduler superior a
1.xx.xx-aliyun-4.0.
Asegúrese de que el node pool elástico tenga suficiente capacidad máxima de recursos y etiquetas de nodo coincidentes para la programación de pods. De lo contrario, los pods podrían no utilizar los nodos escalados horizontalmente por dicho node pool.
Habilitar gang scheduling
Método 1: etiquetas (recomendado)
Agregue dos etiquetas a cada pod. kube-scheduler crea automáticamente un PodGroup cuyo nombre corresponde al valor de pod-group.scheduling.sigs.k8s.io/name.
labels:
pod-group.scheduling.sigs.k8s.io/name: tf-smoke-gpu # PodGroup name (must be a valid DNS subdomain)
pod-group.scheduling.sigs.k8s.io/min-available: "3" # Minimum pods required to start the job
El valor de pod-group.scheduling.sigs.k8s.io/name debe ser un nombre de subdominio DNS válido.
Método 2: CRD PodGroup
Cree un resource PodGroup y luego haga referencia a él desde cada pod mediante una etiqueta.
Desde ACK 1.31, solo se admite scheduling.x-k8s.io/v1alpha1. La versión scheduling.sigs.k8s.io/v1alpha1 ya no es compatible.
# PodGroup resource
apiVersion: scheduling.x-k8s.io/v1alpha1
kind: PodGroup
metadata:
name: nginx
spec:
scheduleTimeoutSeconds: 10 # Seconds to wait before rejecting the group if min-available is not met
minMember: 3 # Minimum number of pods required to start the job
---
# Pod label — must match the PodGroup name and namespace
labels:
pod-group.scheduling.sigs.k8s.io/name: nginx
Método 3: anotaciones de Koordinator
Agregue anotaciones a cada pod. Este método no admite los parámetros total-number ni mode de la API de Koordinator.
annotations:
gang.scheduling.koordinator.sh/name: "gang-example"
gang.scheduling.koordinator.sh/min-available: "2"
Configuraciones avanzadas
Agrupar varios gangs (GangGroup)
Algunos trabajos tienen roles con distintos requisitos de min-available. Por ejemplo, los trabajos de PyTorch con un servidor de parámetros y workers. Un solo PodGroup no permite expresar mínimos por rol, mientras que varios PodGroups independientes no pueden coordinarse entre sí.
GangGroup vincula varios PodGroups. El trabajo se inicia únicamente cuando cada gang cumple su propio min-available. Agregue la siguiente etiqueta a cada pod o PodGroup. Si utiliza el método de Koordinator, use la clave de anotación correspondiente:
|
Método |
Resource |
Clave |
|
Etiquetas |
Pod |
|
|
CRD PodGroup |
PodGroup |
|
|
Anotaciones de Koordinator |
Pod |
|
Ejemplo de valor (una matriz JSON con entradas <namespace>/<gang-name>):
pod-group.scheduling.sigs.k8s.io/groups: "[\"default/gang-example1\", \"default/gang-example2\"]"
GangGroup requiere Kubernetes 1.22 o posterior, con una versión de kube-scheduler superior a 1.xx.xx-aliyun-4.0 .
Configurar la match policy
De forma predeterminada, un PodGroup solo cuenta los pods que completaron la preasignación de recursos (only-waiting). Utilice match-policy para incluir pods en otros estados dentro del mínimo. Esto resulta útil, por ejemplo, cuando aún se están ejecutando pods de un ciclo anterior.
Agregue la etiqueta a cada pod (método de etiquetas) o al resource PodGroup (método de CRD PodGroup). El método de anotaciones de Koordinator solo admite once-satisfied.
|
Match policy |
Pods contados para min-available |
Cuándo usarla |
|
|
Pods que completaron la preasignación de recursos |
Es la opción más estricta. Úsela para trabajos sin estado que no heredan pods de ciclos anteriores. |
|
|
Pods en estado Running y pods que completaron la preasignación |
Úsela cuando los pods en ejecución de un ciclo anterior deban contar para el mínimo. |
|
|
Pods en estado Succeeded, Running y con preasignación completada |
Úsela para trabajos que toleran reinicios parciales, donde los pods ya finalizados siguen contando. |
|
|
Pods que completaron la preasignación de recursos; el PodGroup deja de ser válido una vez satisfecho |
Úsela para trabajos de una sola ejecución. Una vez despachado el gang, el PodGroup se invalida. |
Ejemplo con el método de etiquetas:
pod-group.scheduling.sigs.k8s.io/match-policy: "waiting-and-running"
Ejemplo con el método de CRD PodGroup (agréguelo al PodGroup, no al pod):
pod-group.scheduling.sigs.k8s.io/match-policy: "waiting-and-running"
La configuración de match policy requiere Kubernetes 1.22 o posterior, con una versión de kube-scheduler superior a 1.xx.xx-aliyun-4.0 .
Ejemplo: trabajo distribuido de TensorFlow
Este ejemplo compara un trabajo distribuido de TensorFlow con y sin gang scheduling. El clúster tiene 4 GPU. El trabajo consta de 1 pod PS y 4 pods worker, cada uno con un requerimiento de 2 GPU y un valor de min-available establecido en 5.
Paso 1: Install Arena y prepare el clúster para los trabajos de TensorFlow.
Arena es un subproyecto de Kubeflow diseñado para gestionar el ciclo de vida de los trabajos de aprendizaje automático. Permite configurar el entorno, preparar datos, desarrollar modelos, entrenarlos y ejecutar predicciones mediante una CLI o un SDK.
Paso 2: Envíe el trabajo de TensorFlow. Las plantillas de PS y de worker incluyen las etiquetas de gang scheduling con min-available: "5".
apiVersion: "kubeflow.org/v1"
kind: "TFJob"
metadata:
name: "tf-smoke-gpu"
spec:
tfReplicaSpecs:
PS:
replicas: 1
template:
metadata:
creationTimestamp: null
labels:
pod-group.scheduling.sigs.k8s.io/name: tf-smoke-gpu
pod-group.scheduling.sigs.k8s.io/min-available: "5"
spec:
containers:
- args:
- python
- tf_cnn_benchmarks.py
- --batch_size=32
- --model=resnet50
- --variable_update=parameter_server
- --flush_stdout=true
- --num_gpus=1
- --local_parameter_device=cpu
- --device=cpu
- --data_format=NHWC
image: registry.cn-hangzhou.aliyuncs.com/kubeflow-images-public/tf-benchmarks-cpu:v20171202-bdab599-dirty-284af3
name: tensorflow
ports:
- containerPort: 2222
name: tfjob-port
resources:
limits:
cpu: '1'
workingDir: /opt/tf-benchmarks/scripts/tf_cnn_benchmarks
restartPolicy: OnFailure
Worker:
replicas: 4
template:
metadata:
creationTimestamp: null
labels:
pod-group.scheduling.sigs.k8s.io/name: tf-smoke-gpu
pod-group.scheduling.sigs.k8s.io/min-available: "5"
spec:
containers:
- args:
- python
- tf_cnn_benchmarks.py
- --batch_size=32
- --model=resnet50
- --variable_update=parameter_server
- --flush_stdout=true
- --num_gpus=1
- --local_parameter_device=cpu
- --device=gpu
- --data_format=NHWC
image: registry.cn-hangzhou.aliyuncs.com/kubeflow-images-public/tf-benchmarks-gpu:v20171202-bdab599-dirty-284af3
name: tensorflow
ports:
- containerPort: 2222
name: tfjob-port
resources:
limits:
nvidia.com/gpu: 2
workingDir: /opt/tf-benchmarks/scripts/tf_cnn_benchmarks
restartPolicy: OnFailure
Sin gang scheduling habilitado:
Compruebe el estado de los pods:
kubectl get pods
Como solo hay 4 GPU disponibles, 2 workers pasan al estado Running y consumen todas las GPU. Los 2 restantes permanecen en Pending y bloquean el trabajo:
NAME READY STATUS RESTARTS AGE
tf-smoke-gpu-ps-0 1/1 Running 0 6m43s
tf-smoke-gpu-worker-0 1/1 Running 0 6m43s
tf-smoke-gpu-worker-1 1/1 Running 0 6m43s
tf-smoke-gpu-worker-2 0/1 Pending 0 6m43s
tf-smoke-gpu-worker-3 0/1 Pending 0 6m43s
Revise los registros de un worker en ejecución:
kubectl logs -f tf-smoke-gpu-worker-0
Los workers se detienen porque esperan a los pods en estado Pending. Las GPU quedan retenidas y el entrenamiento no avanza:
INFO|2020-05-19T07:02:18|/opt/launcher.py|27| 2020-05-19 07:02:18.199696: I tensorflow/core/distributed_runtime/master.cc:221] CreateSession still waiting for response from worker: /job:worker/replica:0/task:3
INFO|2020-05-19T07:02:28|/opt/launcher.py|27| 2020-05-19 07:02:28.199798: I tensorflow/core/distributed_runtime/master.cc:221] CreateSession still waiting for response from worker: /job:worker/replica:0/task:2
Con gang scheduling habilitado:
Los 5 pods permanecen en estado Pending hasta que el clúster cuenta con recursos suficientes para cumplir min-available: 5:
NAME READY STATUS RESTARTS AGE
tf-smoke-gpu-ps-0 0/1 Pending 0 43s
tf-smoke-gpu-worker-0 0/1 Pending 0 43s
tf-smoke-gpu-worker-1 0/1 Pending 0 43s
tf-smoke-gpu-worker-2 0/1 Pending 0 43s
tf-smoke-gpu-worker-3 0/1 Pending 0 43s
Una vez que se agregan 4 GPU al clúster, el programador despacha los 5 pods de manera simultánea:
kubectl get pods
Resultado esperado:
NAME READY STATUS RESTARTS AGE
tf-smoke-gpu-ps-0 1/1 Running 0 3m16s
tf-smoke-gpu-worker-0 1/1 Running 0 3m16s
tf-smoke-gpu-worker-1 1/1 Running 0 3m16s
tf-smoke-gpu-worker-2 1/1 Running 0 3m16s
tf-smoke-gpu-worker-3 1/1 Running 0 3m16s
Revise el registro del worker para confirmar que el entrenamiento comenzó:
kubectl logs -f tf-smoke-gpu-worker-0
Resultado esperado:
INFO|2020-05-19T07:15:24|/opt/launcher.py|27| Running warm up
INFO|2020-05-19T07:21:04|/opt/launcher.py|27| Done warm up
INFO|2020-05-19T07:21:04|/opt/launcher.py|27| Step Img/sec loss
INFO|2020-05-19T07:21:05|/opt/launcher.py|27| 1 images/sec: 31.6 +/- 0.0 (jitter = 0.0) 8.318
INFO|2020-05-19T07:21:15|/opt/launcher.py|27| 10 images/sec: 31.1 +/- 0.4 (jitter = 0.7) 8.343
INFO|2020-05-19T07:21:25|/opt/launcher.py|27| 20 images/sec: 31.5 +/- 0.3 (jitter = 0.7) 8.142
Solución de problemas
Error: "rejected by podgroup xxx"
Cuando existen varios PodGroups, la cola de retroceso de kube-scheduler puede rechazar pods que completaron la preasignación en un ciclo si después se procesan otros PodGroups.
Este comportamiento es normal. Ignore el error si se resuelve en menos de 20 minutos. Si persiste, envíe un ticket.
Siguientes pasos
Work with capacity scheduling: utilice grupos de cuotas elásticas para mejorar el uso de los recursos del clúster.