--- title: "kubectl을 이용한 모델 학습" slug: "ai-mlxp-pkubectlstudy" updated: 2026-10-15T09:27:14Z published: 2026-10-15T09:27:14Z canonical: "guide.ncloud-docs.com/ai-mlxp-pkubectlstudy" --- > ## Documentation Index > Fetch the complete documentation index at: https://guide.ncloud-docs.com/llms.txt > Use this file to discover all available pages before exploring further. # kubectl을 이용한 모델 학습 VPC 환경에서 이용 가능합니다. ML expert Platform은 모델 학습을 위한 여러 프레임워크의 Job을 제공합니다. kubectl을 이용한 모델 학습에서는 가장 많이 사용하는 형태인 단일 노드 학습(`Job`), 분산 노드 학습(`PytorchJob`, `TrainJob`) 형태로 설명합니다. Job vs PytorchJob 단일 노드 학습의 경우 `Job` 사용을 권장합니다. `PytorchJob`을 사용할 경우, 분산 노드 학습을 위한 기능으로 인해 Master와 Worker 형태로 배포 관리 되기 때문에 리소스를 불필요하게 낭비할 수 있습니다. ## 단일 노드 학습(Job) 실행하기 학습을 위해 Kubernetes Job 명세는 다음 예제와 같이 작성할 수 있습니다. 주의 - 고성능 스토리지를 마운트하여 사용하는 경우, 학습 이미지 내 UID 및 GID가 500으로 설정되어 있어야 합니다. - Pod의 `securityContext`에 `fsGroup`을 설정하지 마십시오. `fsGroup`이 설정되면 Kubernetes가 마운트된 볼륨 내 모든 파일의 소유권을 재귀적으로 변경하며, 대용량 데이터가 저장된 고성능 스토리지의 경우 Pod 초기화 시간이 극단적으로 길어질 수 있습니다. ``` # job.yaml apiVersion: batch/v1 kind: Job metadata: name: mnist namespace: p-{projectName} spec: backoffLimit: 1 template: metadata: annotations: sidecar.istio.io/inject: "false" spec: restartPolicy: Never nodeSelector: mlx.navercorp.com/zone: { 제공된 GPU Zone 이름 } # GPU Resources 에서 확인 가능한 Zone 명 containers: - name: main image: { 학습 이미지 (예: example.com/mnist:latest ) } # NVIDIA Base 이미지 기준으로 작성된 학습 코드 imagePullPolicy: Always resources: limits: memory: "8Gi" cpu: "4" nvidia.com/gpu: "1" command: ["python"] args: - /opt/mnist/src/mnist.py - --checkpoint_path - /opt/mnist/checkpoints/mnist.pt - --log_path - /opt/mnist/log - --data_path - /opt/mnist/data - --download_data ``` ``` kubectl apply -f job.yaml batch/mnist created ``` ### 외부 컨테이너 레지스트리 사용 컨테이너 레지스트리에 Secret 정보가 필요할 경우에는 [Container Secret 생성하기](/docs/ai-mlxp-pkubectlsecret)를 참고하여 생성할 수 있습니다. 생성된 Secret은 다음과 같이 사용할 수 있습니다. ``` ... spec: imagePullSecrets: - name: my-harbor-secret # 미리 만들어둔 Docker Credential Secret 이름 ... ``` ### 기존 Volume 사용 [Volumes](/docs/ai-mlxp-pvolumes)를 통해 생성된 Volume을 사용하기 위해서는 다음과 같이 사용할 수 있습니다. ``` ... spec: containers: - name: main ... volumeMounts: - mountPath: /data name: mnist-data # 하단 spec.volumes에 기재한 이름 volumes: - name: mnist-data persistentVolumeClaim: claimName: mnist-data # Volumes 를 통해 생성된 PVC 이름 ... ``` ### Job 라이프 사이클 Job이 종료될 경우, 일정 시간 동안 컨테이너 로그 및 상태를 남기기 위해 삭제되지 않고 목록에 남아 있습니다. 목록에 남아있을 수 있는 Job의 최대 개수 제한이 있기 때문에 TTL을 통해 라이프사이클을 관리해야 합니다. 자세한 정보는 [Kubernetes Job API](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#jobspec-v1-batch) 문서를 참고해 주십시오. Job을 생성하면서 TTL(Time To Live)을 임의로 설정할 수 있습니다. TTL은 Job이 완료(성공/실패)된 후에 활성화되고, TTL만큼 지나면 Job과 Job에 속하는 Pod이 모두 자동으로 삭제됩니다. 아래는 3주간의 TTL을 적용한 예시입니다. ``` apiVersion: batch/v1 kind: Job metadata: name: mnist namespace: p-{projectName} spec: ttlSecondsAfterFinished: 1814400 # TTL을 직접 설정하는 필드 (단위: sec) ``` ## 분산 노드 학습(PytorchJob) 실행하기 PyTorchJob 이용 시 다음과 같은 장점이 있습니다. - 작성된 컨테이너 spec을 기반으로 Master, Worker Pod을 적절히 생성합니다. - PyTorch 분산 학습에 일반적으로 필요한 환경변수 (예: WORLD_SIZE, RANK, MASTER_ADDR 등)를 자동으로 설정합니다. - 학습에 사용되는 Pod들이 서로 통신할 수 있도록 K8s Service를 자동으로 생성합니다. Master는 `<pytorch-job-name>-master-0`, Worker는 `<pytorch-job-name>-worker-<idx>` 와 같은 이름으로 접근할 수 있습니다. - 필요한 경우, [Elastic Policy 사용](/docs/ai-mlxp-pkubectlstudy#ElasticPolicy%EC%82%AC%EC%9A%A9)를 통해 torchrun에서 사용할 인자들을 환경 변수로 생성합니다(`--nnodes`, `--nproc-per-node`, `--rdzv-endpoint` 등). ### PytorchJob 작성하기 Pytorch로 분산 학습 시에는 `torchrun`(Elastic Launch) 사용을 권장합니다. 또한, `torchrun` 사용 시 마스터 Pod을 따로 명시하지 않습니다. Torch Elastic 에서는 마스터 노드 역할을 하는 RANK=0 Pod이 실행 도중 변경될 수 있습니다. - `spec.elasticPolicy` - torchrun 관련 설정입니다. 여기에 명시한 설정들이 환경 변수로 주입됩니다. 자세한 것은 [Elastic Policy 사용](/docs/ai-mlxp-pkubectlstudy#ElasticPolicy%EC%82%AC%EC%9A%A9)를 참고해 주십시오. - `spec.runPolicy` - PyTorchJob 실행 및 종료 후처리 관련된 파라미터들을 명시할 수 있습니다. 자세한 것은 [Run Policy 사용](/docs/ai-mlxp-pkubectlstudy#RunPolicy%EC%82%AC%EC%9A%A9)를 참고해 주십시오. - `spec.pytorchReplicaSpecs.Worker` - 분산 학습을 수행하는 Worker Pod에 대한 설정입니다. 주의 - 학습을 진행하는 컨테이너의 이름 (예: `spec.pytorchReplicaSpecs.Worker.template.spec.containers[*].name`)은 반드시 `pytorch` 이어야 합니다. - 원활한 분산학습을 위하여 Istio Sidecar가 Inject가 되지 않도록 `spec.pytorchReplicaSpecs.Worker.template.metadata.annotations`에 `sidecar.istio.io/inject: "false"`가 자동 설정됩니다. 해당 annotation이 설정되지 않는 경우, `RuntimeError: Connection reset by peer` 등 노드간 통신에 관련된 에러가 발생합니다. - 고성능 스토리지를 마운트하여 사용하는 경우, 학습 이미지 내 UID 및 GID가 500으로 설정되어 있어야 합니다. - Pod의 `securityContext`에 `fsGroup`을 설정하지 마십시오. `fsGroup`이 설정되면 Kubernetes가 마운트된 볼륨 내 모든 파일의 소유권을 재귀적으로 변경하며, 대용량 데이터가 저장된 고성능 스토리지의 경우 Pod 초기화 시간이 극단적으로 길어질 수 있습니다. 학습을 위해 PytorchJob 명세는 다음 예제와 같이 작성할 수 있습니다. ``` # pytorchjob.yaml apiVersion: kubeflow.org/v1 kind: PyTorchJob metadata: name: pytorch-mnist-dist-nccl namespace: p-{ projectName } # 프로젝트에 해당되는 Kubernetes Namespace 명 spec: pytorchReplicaSpecs: Worker: replicas: 2 restartPolicy: OnFailure template: metadata: annotations: sidecar.istio.io/inject: "false" # 자동 설정됨 (생략 가능) spec: nodeSelector: mlx.navercorp.com/zone: { 제공된 GPU Zone 이름 } # GPU Resources 에서 확인 가능한 Zone 명 containers: - name: pytorch # PyTorchJob의 container 이름은 반드시 pytorch로 설정 image: examples.com/pytorch-mnist-dist:23.03-py3 imagePullPolicy: Always command: ["bash", "-c"] args: - > torchrun --nnodes ${PET_NNODES} --nproc_per_node ${PET_NPROC_PER_NODE} --rdzv_id ${PET_RDZV_ID} --rdzv_backend ${PET_RDZV_BACKEND} --rdzv_endpoint ${PET_RDZV_ENDPOINT} /opt/mnist/src/mnist.py --checkpoint_path /data/checkpoints/mnist.pt --log_path /data/logs --data_path /data/dataset env: - name: NCCL_DEBUG value: INFO - name: GLOO_SOCKET_FAMILY value: AF_INET securityContext: # Infiniband 를 사용하기 위한 securityContext가 필요합니다. capabilities: add: ["IPC_LOCK"] # shared memory volumeMounts: - mountPath: /dev/shm name: shared-memory volumes: - emptyDir: medium: Memory name: shared-memory ``` ``` kubectl apply -f pytorchjob.yaml pytorchjob.kubeflow.org/pytorch-elastic-mnist-nccl created ``` ### Elastic Policy 사용 `torchrun` 을 사용하기 위해 `elasticPolicy` 를 작성합니다. ``` ... spec: ... elasticPolicy: rdzvId: mnist rdzvBackend: c10d minReplicas: 2 maxReplicas: 2 nProcPerNode: 8 ... ``` `elasticPolicy` 각 필드값을 기반으로 `PyTorchJob` 에 사용될 환경변수가 설정됩니다. 환경변수들은 `torchrun` 인자를 설정하는 데 쓰일 수 있습니다. `torchrun` 에서 사용하는 인자 등에 대한 자세한 설명은 [공식 문서](https://pytorch.org/docs/stable/elastic/run.html)를 참고해 주십시오. | `elasticPolicy` 필드 | 대응 환경변수 | 연관 `torchrun` 인자 | 설명 | | --- | --- | --- | --- | | `rdzvId` | `PET_RDZV_ID` | `--rdzv-id` | 랑데부용 Job ID | | `rdzvBackend` | `PET_RDZV_BACKEND` | `--rdzv-backend` | 랑데부 백엔드 (예: c10d) | | `minReplicas`, `maxReplicas` | `PET_NNODES` | `--nnodes` | 노드 개수 | | `nProcPerNode` | `PET_NPROC_PER_NODE` | `--nproc-per-node` | 노드당 GPU 개수 | | `maxRestarts` | `PET_MAX_RESTARTS` | `--max-restarts` | 최대 재시작 횟수 | ### Run Policy 사용 `torchrun`을 사용하기 위해 `runPolicy`를 작성합니다. ``` ... spec: runPolicy: cleanPodPolicy: None ttlSecondsAfterFinished: 1814400 # TTL을 직접 설정하는 필드 (단위: sec) ... ``` `spec.runPolicy`에는 `PyTorchJob` 의 실행 및 정리에 관련된 파라미터들을 명시할 수 있습니다. 명시하지 않을 시 기본값을 사용합니다. `spec.runPolicy` 하위에 명시할 수 있는 파라미터들은 다음과 같습니다. (참고 자료: [Kubeflow Trainer API Reference v1.9](https://github.com/kubeflow/trainer/blob/release-1.9/docs/api/kubeflow.org_v1_generated.asciidoc#runpolicy)) - `cleanPodPolicy` - `PytorchJob` 이 완료된 이후 Pod들을 어떻게 정리할지 결정합니다. - 기본값: `None` - `None`: Job이 완료된 후 Pod들을 삭제하지 않기 때문에 추후 로그를 확인하는 데 도움이 됩니다. - `All`: Job이 완료된 후 모든 Pod들을 삭제합니다. - `Running` 은 Job이 완료된 후 실행 중인 Pod을 제거합니다. 특수한 경우가 아니면 사용할 일이 없습니다. - `ttlSecondsAfterFinished` - Job이 완료된 이후 몇 초 후에 Job을 삭제할지 정합니다. - `activeDeadlineSeconds` - Job의 최대 실행 시간입니다. 명시된 시간이 지난 후에는 실패 처리됩니다. 설정되지 않은 경우 job의 실행 시간에 제한이 없습니다. - `backoffLimit` - Job이 실패했을 때 최대 재시도 횟수입니다. ### Infiniband 사용 참고 - 별도의 RDMA 리소스 설정(request/limit)은 필요하지 않습니다 - GPU Zone 정보는 [사용 가능한 GPU Zone 정보 조회](/docs/ai-mlxp-gpuresource#%EC%82%AC%EC%9A%A9%EA%B0%80%EB%8A%A5%ED%95%9CGPUZone%EC%A0%95%EB%B3%B4%EC%A1%B0%ED%9A%8C)를 참고해 주십시오. InfiniBand 네트워크로 연결된 노드들로 분산 학습을 실행하면 노드간 통신을 가속할 수 있습니다. 앞에서 다룬 예제를 InfiniBand 환경에 맞추기 위해서는 추가해야 하는 명세가 몇 가지 있는데, 다음과 같이 요약할 수 있습니다. - InfiniBand 네트워크가 구성된 구역 이름을 Annotation으로 명시합니다 (예: `mlx.navercorp.com/zone=ai-infra`) - InfiniBand 사용을 위해 `IPC_LOCK` capability를 `securityContext` 에 추가합니다. - 분산학습을 돕기 위한 Shared Memory 를 `volumes`로 설정합니다. Infiniband 사용을 위해서 다음과 같이 사용할 수 있습니다. ``` ... metadata: annotations: mlx.navercorp.com/zone="ai-infra" ... spec: ... pytorchReplicaSpecs: Worker: template: containers: - name: pytorch securityContext: # Infiniband 를 사용하기 위한 securityContext가 필요합니다. capabilities: add: ["IPC_LOCK"] # shared memory volumeMounts: - mountPath: /dev/shm name: shared-memory volumes: - emptyDir: medium: Memory name: shared-memory ... ``` ### PytorchJob 디버깅 `PytorchJob` 사용 시, 문제가 발생하여 디버깅이 필요할 때 다음과 같이 환경변수 값을 설정하는 것으로 필요한 정보를 로깅하도록 할 수 있습니다. - `NCCL_DEBUG`: NCCL 관련 디버깅 - `TORCH_DISTRIBUTED_DEBUG`, `TORCH_CPP_LOG_LEVEL`: 분산 학습에 대한 디버깅; 자세한 것은 [PyTorch 공식 문서](https://pytorch.org/docs/stable/distributed.html#torch-distributed-debug)를 참고해 주십시오. 디버깅을 위하여 다음과 같이 사용할 수 있습니다. ``` ... spec: ... pytorchReplicaSpecs: Worker: template: containers: - name: pytorch ... env: - name: NCCL_DEBUG value: "INFO" - name: TORCH_DISTRIBUTED_DEBUG value: "DETAIL" - name: TORCH_CPP_LOG_LEVEL value: "INFO" ... ``` ### 외부 컨테이너 레지스트리 사용 컨테이너 레지스트리에 Secret 정보가 필요할 경우에는 [Container Secret 생성하기](/docs/ai-mlxp-pkubectlsecret)를 참고하여 생성할 수 있습니다. 생성된 Secret은 다음과 같이 사용할 수 있습니다. ``` ... spec: ... pytorchReplicaSpecs: Worker: template: containers: - name: pytorch imagePullSecrets: - name: my-harbor-secret # 미리 만들어둔 Docker Credential Secret 이름 ... ``` ### 기존 Volume 사용 [Volumes](/docs/ai-mlxp-pvolumes)를 통해 생성된 Volume을 사용하기 위해서는 다음과 같이 사용할 수 있습니다. ``` ... spec: ... pytorchReplicaSpecs: Worker: template: containers: - name: pytorch volumeMounts: - mountPath: /data name: mnist-data # 하단 spec.volumes에 기재한 이름 volumes: - name: mnist-data persistentVolumeClaim: claimName: mnist-data # Volumes 를 통해 생성된 PVC 이름 ... ``` ## PytorchJob 상태 확인 `kubectl get`, `kubectl describe` 를 이용하여 `PyTorchJob` 의 상태를 확인할 수 있습니다. ``` kubectl get pytorchjob pytorch-elastic-mnist-nccl NAME STATE AGE pytorch-elastic-mnist-nccl Running 12s ``` ``` kubectl describe pytorchjob pytorch-elastic-mnist-nccl Status: Completion Time: 2024-11-22T09:16:58Z Conditions: Last Transition Time: 2024-11-22T09:15:43Z Last Update Time: 2024-11-22T09:15:43Z Message: PyTorchJob pytorch-elastic-mnist-nccl is created. Reason: PyTorchJobCreated Status: True Type: Created Last Transition Time: 2024-11-22T09:15:48Z Last Update Time: 2024-11-22T09:15:48Z Message: PyTorchJob nb12706/pytorch-elastic-mnist-nccl is running. Reason: PyTorchJobRunning Status: False Type: Running Last Transition Time: 2024-11-22T09:16:58Z Last Update Time: 2024-11-22T09:16:58Z Message: PyTorchJob nb12706/pytorch-elastic-mnist-nccl successfully completed. Reason: PyTorchJobSucceeded Status: True Type: Succeeded Last Reconcile Time: 2024-11-22T09:15:43Z Replica Statuses: Worker: Selector: training.kubeflow.org/job-name=pytorch-elastic-mnist-nccl,training.kubeflow.org/operator-name=pytorchjob-controller,training.kubeflow.org/replica-type=worker Succeeded: 2 Start Time: 2024-11-22T09:15:44Z Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulCreatePod 4m21s pytorchjob-controller Created pod: pytorch-elastic-mnist-nccl-worker-0 Normal SuccessfulCreatePod 4m21s pytorchjob-controller Created pod: pytorch-elastic-mnist-nccl-worker-1 Normal SuccessfulCreateService 4m21s pytorchjob-controller Created service: pytorch-elastic-mnist-nccl-worker-0 Normal SuccessfulCreateService 4m21s pytorchjob-controller Created service: pytorch-elastic-mnist-nccl-worker-1 Normal ExitedWithCode 3m7s (x3 over 3m8s) pytorchjob-controller Pod: nb12706.pytorch-elastic-mnist-nccl-worker-1 exited with code 0 Normal ExitedWithCode 3m7s (x2 over 3m8s) pytorchjob-controller Pod: nb12706.pytorch-elastic-mnist-nccl-worker-0 exited with code 0 Normal PyTorchJobSucceeded 3m7s pytorchjob-controller PyTorchJob nb12706/pytorch-elastic-mnist-nccl successfully completed. Normal JobTerminated 3m6s (x4 over 3m7s) pytorchjob-controller Job has been terminated. Deleting PodGroup Normal SuccessfulDeletePodGroup 3m6s (x4 over 3m7s) pytorchjob-controller Deleted PodGroup: pytorch-elastic-mnist-nccl ``` 학습 Pod이 제대로 생성되지 않는 경우 아래처럼 Events 를 통해 원인을 파악해볼 수 있습니다. ``` kubectl describe pytorchjob pytorch-elastic-mnist-nccl ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedCreatePod 47m (x3 over 103m) pytorchjob-controller Error creating: Pods "job-worker-1" is forbidden: exceeded quota: normal-quota, requested: requests.nvidia.com/gpu=1, used: requests.nvidia.com/gpu=2, limited: requests.nvidia.com/gpu=2 ``` ### 분산 학습 시 주의 사항 MLXP에서 분산 학습 시 주의해야 할 사항을 안내합니다. #### NVIDIA Driver와 호환되는 CUDA 버전 사용 CUDA Runtime 버전은 노드에 설치된 NVIDIA Driver와 호환되어야 합니다. CUDA Runtime이 요구하는 최소 Driver 버전을 충족하지 못할 경우 CUDA 초기화 오류 또는 런타임 오류가 발생하며 학습 작업이 정상적으로 실행되지 않을 수 있습니다. #### IPv6 사용 불가로 인한 GLOO_SOCKET_FAMILY=INET 설정 GLOO는 노드 간 상태 확인 및 Rank 관리를 위해 빈번한 TCP 연결을 생성합니다. IPv6를 사용할 수 없는 환경에서 대규모 학습을 수행할 경우, 각 연결 시도마다 IPv6 연결이 먼저 시도된 후 실패하고 IPv4로 재시도됩니다. 이러한 이중 시도 과정이 반복되면 파일 디스크립터 고갈 등의 자원 문제가 발생할 수 있으며, 결과적으로 학습이 중단될 수 있습니다. 이 문제를 방지하기 위해 `GLOO_SOCKET_FAMILY=AF_INET` 환경 변수를 설정하여 IPv4만 사용하도록 구성하는 것을 권장합니다. GLOO에서 IPv4를 강제하려면 다음과 같이 설정할 수 있습니다. ``` ... spec: ... pytorchReplicaSpecs: Worker: template: containers: - name: pytorch ... env: - name: GLOO_SOCKET_FAMILY value: AF_INET ... ``` #### PyTorchJob 이름 길이 제한 (권장) PyTorchJob 이름은 Kubernetes 리소스(Pod, Service 등) 생성 시 접두어로 사용되므로 50자 이내로 설정하는 것을 권장합니다. 50자를 초과하면 파생 리소스 이름이 길이 제한을 초과하여 생성이 실패하거나, worker index 파싱에 문제가 발생할 수 있습니다. #### Shared Memory 설정 시 memory limit 설정 제거 Shared Memory(`/dev/shm`)는 용량 제한을 두지 않거나 충분히 크게 설정하는 것을 권장합니다. `/dev/shm`이 부족하면 DataLoader의 멀티프로세싱 worker가 비정상 종료될 수 있으며, NCCL의 통신 성능 저하로 이어질 수 있습니다. Memory limit을 제거한 Shared Memory 설정 예시는 다음과 같습니다. ``` ... spec: ... pytorchReplicaSpecs: Worker: template: containers: - name: pytorch # shared memory volumeMounts: - mountPath: /dev/shm name: shared-memory volumes: - emptyDir: medium: Memory name: shared-memory ``` ## 분산 노드 학습(TrainJob) 실행하기 `TrainJob`은 Kubeflow Trainer v2에서 제공하는 학습 리소스입니다. 학습 Pod의 공통 명세를 담은 `TrainingRuntime`을 참조하는 방식이므로, `PytorchJob`처럼 매번 Pod 명세 전체를 작성하는 대신 학습마다 달라지는 값만 지정하여 실행할 수 있습니다. `TrainJob`으로 학습을 실행하려면 다음 두 단계가 필요합니다. 1. 학습 Pod의 공통 명세를 담은 `TrainingRuntime`을 생성합니다. 2. 생성한 `TrainingRuntime`을 참조하는 `TrainJob`을 생성합니다. 참고 - `TrainJob`은 고정된 노드 수를 전제로 동작합니다. 실행 중 노드 수가 변경되는 학습이 필요한 경우에는 `PytorchJob`의 [Elastic Policy 사용](/docs/ai-mlxp-pkubectlstudy#ElasticPolicy%EC%82%AC%EC%9A%A9)을 참조해 주십시오. - 분산 학습 시 주의해야 할 사항은 [분산 학습 시 주의 사항](/docs/ai-mlxp-pkubectlstudy#%EB%B6%84%EC%82%B0%ED%95%99%EC%8A%B5%EC%8B%9C%EC%A3%BC%EC%9D%98%EC%82%AC%ED%95%AD)을 함께 참조해 주십시오. - SDK 사용 등 더 자세한 내용은 [Kubeflow Trainer 공식 문서](https://trainer.kubeflow.org/en/latest/overview/index.html)를 참조해 주십시오. ### TrainingRuntime 작성하기 `TrainingRuntime`은 스케줄러, 볼륨, 기본 이미지 등 학습 Pod의 공통 명세를 담는 리소스입니다. 프로젝트에 해당되는 Namespace에 직접 생성하며, 같은 Namespace의 `TrainJob`에서만 참조할 수 있습니다. `TrainingRuntime`을 작성할 때 다음 항목을 반드시 포함해야 합니다. - `spec.podGroupPolicy.volcano`와 `schedulerName: volcano` - Gang Scheduling에 필요합니다. - `sidecar.istio.io/inject: "false"` Annotation - Istio Sidecar가 주입되지 않도록 합니다. 해당 Annotation이 설정되지 않는 경우, `RuntimeError: Connection reset by peer` 등 노드간 통신에 관련된 에러가 발생합니다. - `trainer.kubeflow.org/trainjob-ancestor-step: trainer` Label - 설정하지 않으면 `TrainJob`의 `spec.trainer`에 작성한 값(`image`, `command` 등)이 학습 Job에 적용되지 않습니다. - `nodeSelector`의 `mlx.navercorp.com/zone` - 학습을 실행할 GPU Zone을 지정합니다. `TrainingRuntime` 하나로 여러 Zone을 사용해야 하는 경우에는 [TrainJob에서 GPU Zone 지정하기](/docs/ai-mlxp-pkubectlstudy#TrainJob%EC%97%90%EC%84%9CGPUZone%EC%A7%80%EC%A0%95%ED%95%98%EA%B8%B0)를 참조해 주십시오. 주의 - 고성능 스토리지를 마운트하여 사용하는 경우, 학습 이미지 내 UID 및 GID가 500으로 설정되어 있어야 합니다. - Pod의 `securityContext`에 `fsGroup`을 설정하지 마십시오. `fsGroup`이 설정되면 Kubernetes가 마운트된 볼륨 내 모든 파일의 소유권을 재귀적으로 변경하며, 대용량 데이터가 저장된 고성능 스토리지의 경우 Pod 초기화 시간이 극단적으로 길어질 수 있습니다. PyTorch 분산 학습을 위한 `TrainingRuntime` 명세는 다음 예제와 같이 작성할 수 있습니다. `torchrun` 실행에 필요한 환경변수가 주입되도록 `spec.mlPolicy.torch`를 명시합니다. ``` # trainingruntime.yaml apiVersion: trainer.kubeflow.org/v1alpha1 kind: TrainingRuntime metadata: name: torch-distributed namespace: p-{ projectName } # 프로젝트에 해당되는 Kubernetes Namespace 명 spec: mlPolicy: numNodes: 2 # 기본 노드 개수 (TrainJob의 spec.trainer.numNodes로 재정의 가능) torch: {} # torchrun에 필요한 PET_* 환경변수를 주입합니다. podGroupPolicy: volcano: {} template: spec: replicatedJobs: - name: node template: metadata: labels: trainer.kubeflow.org/trainjob-ancestor-step: trainer spec: template: metadata: annotations: sidecar.istio.io/inject: "false" spec: schedulerName: volcano restartPolicy: OnFailure nodeSelector: mlx.navercorp.com/zone: { 제공된 GPU Zone 이름 } # GPU Resources 에서 확인 가능한 Zone 명 containers: - name: node image: { 학습 이미지 (예: example.com/pytorch-mnist-dist:latest ) } # 기본 이미지 (TrainJob의 spec.trainer.image로 재정의 가능) imagePullPolicy: Always securityContext: # Infiniband 를 사용하기 위한 securityContext가 필요합니다. capabilities: add: ["IPC_LOCK"] # shared memory volumeMounts: - mountPath: /dev/shm name: shared-memory volumes: - emptyDir: medium: Memory name: shared-memory ``` ``` kubectl apply -f trainingruntime.yaml trainingruntime.trainer.kubeflow.org/torch-distributed created ``` InfiniBand를 사용하는 경우에도 위 예제와 같이 `IPC_LOCK` capability와 Shared Memory를 `TrainingRuntime`에 설정하고, InfiniBand 네트워크가 구성된 GPU Zone을 `nodeSelector`에 지정합니다. 자세한 내용은 [Infiniband 사용](/docs/ai-mlxp-pkubectlstudy#Infiniband%EC%82%AC%EC%9A%A9)을 참조해 주십시오. ### TrainJob 작성하기 생성한 `TrainingRuntime`을 `spec.runtimeRef`로 참조하여 `TrainJob`을 작성합니다. 학습 명세는 다음 예제와 같이 작성할 수 있습니다. ``` # trainjob.yaml apiVersion: trainer.kubeflow.org/v1alpha1 kind: TrainJob metadata: name: pytorch-mnist-dist-nccl namespace: p-{ projectName } # 프로젝트에 해당되는 Kubernetes Namespace 명 spec: runtimeRef: apiGroup: trainer.kubeflow.org kind: TrainingRuntime name: torch-distributed # 미리 만들어둔 TrainingRuntime 이름 trainer: numNodes: 2 numProcPerNode: 1 # 노드당 프로세스 개수 (노드에 할당한 GPU 개수와 동일하게 지정) command: ["bash", "-c"] args: - > torchrun --nnodes ${PET_NNODES} --nproc_per_node ${PET_NPROC_PER_NODE} --rdzv_id mnist --rdzv_backend c10d --rdzv_endpoint ${PET_MASTER_ADDR}:${PET_MASTER_PORT} /opt/mnist/src/mnist.py --checkpoint_path /data/checkpoints/mnist.pt --log_path /data/logs --data_path /data/dataset env: - name: NCCL_DEBUG value: INFO - name: GLOO_SOCKET_FAMILY value: AF_INET resourcesPerNode: requests: memory: "8Gi" cpu: "4" nvidia.com/gpu: "1" limits: memory: "8Gi" cpu: "4" nvidia.com/gpu: "1" ``` ``` kubectl apply -f trainjob.yaml trainjob.trainer.kubeflow.org/pytorch-mnist-dist-nccl created ``` - `spec.trainer.numNodes` - 학습에 사용할 노드 개수입니다. `PytorchJob`의 `elasticPolicy.minReplicas`, `maxReplicas`(고정값)에 대응합니다. - `spec.trainer.numProcPerNode` - 노드당 프로세스 개수입니다. 일반적으로 노드에 할당한 GPU 개수와 동일하게 지정합니다. `PytorchJob`의 `elasticPolicy.nProcPerNode`에 대응하며, `auto`는 지원하지 않고 정수만 지정할 수 있습니다. - `spec.trainer.image` - 학습에 사용할 이미지입니다. 지정하지 않으면 `TrainingRuntime`의 기본 이미지를 그대로 사용합니다. - `spec.trainer.resourcesPerNode` - 노드(Pod) 하나에 할당할 리소스입니다. `PytorchJob`의 `resources`에 대응합니다. 주의 - `spec.trainer.resourcesPerNode`를 지정하면 `TrainingRuntime`에 작성한 컨테이너의 `resources`가 항목 단위로 병합되지 않고 전체가 재정의됩니다. 필요한 리소스를 모두 명시해 주십시오. - 같은 Namespace에서 `PytorchJob`과 `TrainJob`이 동일한 `metadata.name`을 사용하면 PodGroup을 공유하게 되어 Gang Scheduling이 정상적으로 동작하지 않을 수 있습니다. `TrainJob`을 생성하기 전에 같은 이름의 `PytorchJob`이 있는지 확인해 주십시오. ### TrainJob에서 GPU Zone 지정하기 `TrainingRuntime`에 GPU Zone을 고정하면 사용하는 Zone마다 `TrainingRuntime`을 생성해야 합니다. `TrainingRuntime` 하나로 여러 Zone을 사용하려면 `TrainJob`의 `spec.runtimePatches`로 `nodeSelector`를 지정할 수 있습니다. ``` ... spec: runtimePatches: - manager: { 패치 소유자 이름 (예: my-team/trainjob ) } # 비워 둘 수 없습니다. trainingRuntimeSpec: template: spec: replicatedJobs: - name: node # TrainingRuntime에 작성한 replicatedJob 이름과 동일하게 지정 template: spec: template: spec: nodeSelector: mlx.navercorp.com/zone: { 제공된 GPU Zone 이름 } # GPU Resources 에서 확인 가능한 Zone 명 ... ``` - `manager` - 패치의 소유자를 구분하는 값이며, 비워 둘 수 없습니다. Kubeflow SDK가 사용하는 `trainer.kubeflow.org/kubeflow-sdk`와 중복되지 않는 값을 지정해 주십시오. - `nodeSelector` 외에 `tolerations`, `serviceAccountName`, `volumes`도 같은 방식으로 지정할 수 있습니다. - `image`, `command`, `args`, `resources`는 `spec.runtimePatches`로 재정의할 수 없습니다. 해당 값은 `spec.trainer`에 작성해 주십시오. ### torchrun 환경변수 차이 `PytorchJob`의 `elasticPolicy`는 랑데부에 필요한 환경변수(`PET_RDZV_*`)를 주입하지만, `TrainJob`은 고정된 노드 수를 전제로 하기 때문에 0번 노드의 주소를 주입하는 `PET_MASTER_ADDR`, `PET_MASTER_PORT`를 사용합니다. 따라서 `PytorchJob`에서 사용한 `torchrun` 명령을 그대로 사용하면 학습이 실패할 수 있습니다. | `PytorchJob` 환경변수 | `TrainJob` 환경변수 | 설명 | | --- | --- | --- | | `PET_RDZV_ID` | 주입되지 않음 | `torchrun` 명령에 `--rdzv_id` 값을 직접 명시합니다. | | `PET_RDZV_BACKEND` | 주입되지 않음 | `torchrun` 명령에 `--rdzv_backend` 값을 직접 명시합니다. | | `PET_RDZV_ENDPOINT` | `PET_MASTER_ADDR`, `PET_MASTER_PORT` | `${PET_MASTER_ADDR}:${PET_MASTER_PORT}` 형태로 결합하여 `--rdzv_endpoint`에 사용합니다. | | `PET_NNODES` | `PET_NNODES` | `spec.trainer.numNodes`로 지정한 노드 개수입니다. | | `PET_NPROC_PER_NODE` | `PET_NPROC_PER_NODE` | `spec.trainer.numProcPerNode`로 지정한 노드당 프로세스 개수입니다. | | - | `PET_NODE_RANK` | Job의 Completion Index를 기반으로 배정되는 노드 번호입니다. `c10d` 랑데부를 사용하는 경우 랑데부가 Rank를 결정하므로 `--node_rank`를 지정하지 않아도 됩니다. | ### TrainJob 상태 확인 `kubectl get`, `kubectl describe` 를 이용하여 `TrainJob` 의 상태를 확인할 수 있습니다. ``` kubectl get trainjob pytorch-mnist-dist-nccl ``` ``` kubectl describe trainjob pytorch-mnist-dist-nccl ``` `TrainJob`은 JobSet과 Job을 거쳐 학습 Pod을 생성합니다. 학습 로그는 생성된 Pod을 확인한 후 조회할 수 있습니다. ``` kubectl get pods kubectl logs { 학습 Pod 이름 } ```