精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

探索Kubernetes與AI的結合:PyTorch訓練任務在k8s上調度實踐

人工智能
通過搭建本地的k8s GPU環境,可以方便的進行AI相關的開發和測試,也能充分利用閑置的筆記本GPU性能。利用kueue、karmada、kuberay和ray等框架,讓GPU等異構算力調度在云原生成為可能。

概述

Kubernetes的核心優勢在于其能夠提供一個可擴展、靈活且高度可配置的平臺,使得應用程序的部署、擴展和管理變得前所未有的簡單。通用計算能力方面的應用已經相對成熟,云原生化的應用程序、數據庫和其他服務可以輕松部署在Kubernetes環境中,實現高可用性和彈性。

然而,當涉及到異構計算資源時,情形便開始變得復雜。異構計算資源如GPU、FPGA和NPU,雖然能夠提供巨大的計算優勢,尤其是在處理特定類型的計算密集型任務時,但它們的集成和管理卻不像通用計算資源那樣簡單。由于硬件供應商提供的驅動和管理工具差異較大,Kubernetes在統一調度和編排這些資源方面還存在一些局限性。這不僅影響了資源的利用效率,也給開發者帶來了額外的管理負擔。

下面分享下如何在個人筆記本電腦上完成K8s GPU集群的搭建,并使用kueue、kubeflow、karmada在具有GPU節點的k8s集群上提交pytorch的訓練任務。

k8s支持GPU

  1. kubernetes對于GPU的支持是通過設備插件的方式來實現,需要安裝GPU廠商的設備驅動,通過POD調用GPU能力。
  2. Kind、Minikube、K3d等常用開發環境集群構建工具對于GPU的支持也各不相同,Kind暫不支持GPU,Minikube和K3d支持Linux環境下的NVIDIA的GPU

RTX3060搭建具有GPU的K8s

GPU K8s

先決條件

  • Go 版本 v1.20+
  • kubectl 版本 v1.19+
  • Minikube 版本 v1.24.0+
  • Docker 版本v24.0.6+
  • NVIDIA Driver 最新版本
  • NVIDIA Container Toolkit 最新版本

備注:

  • ubuntu 系統的 RTX3060+顯卡(不能是虛擬機系統,除非你的虛擬機支持pve或則esxi顯卡直通功能), windows的wsl 是不支持的,因為wsl的Linux內核是一個自定義的內核,里面缺失很多內核模塊,導致NVIDIA的驅動調用有問題
  • 需要Github、Google、Docker的代碼和倉庫訪問能力

GPU Docker

完成以上操作后,確認Docker具備GPU的調度能力,可以通過如下的方式來進行驗證

  1. 創建如下的docker compose 文件
services:
  test:
    image: nvidia/cuda:12.3.1-base-ubuntu20.04
    command: nvidia-smi
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]
  1. 使用Docker啟動cuda任務
docker compose up
Creating network "gpu_default" with the default driver
Creating gpu_test_1 ... done
Attaching to gpu_test_1    
test_1  | +-----------------------------------------------------------------------------+
test_1  | | NVIDIA-SMI 450.80.02    Driver Version: 450.80.02    CUDA Version: 11.1     |
test_1  | |-------------------------------+----------------------+----------------------+
test_1  | | GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
test_1  | | Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
test_1  | |                               |                      |               MIG M. |
test_1  | |===============================+======================+======================|
test_1  | |   0  Tesla T4            On   | 00000000:00:1E.0 Off |                    0 |
test_1  | | N/A   23C    P8     9W /  70W |      0MiB / 15109MiB |      0%      Default |
test_1  | |                               |                      |                  N/A |
test_1  | +-------------------------------+----------------------+----------------------+
test_1  |                                                                                
test_1  | +-----------------------------------------------------------------------------+
test_1  | | Processes:                                                                  |
test_1  | |  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
test_1  | |        ID   ID                                                   Usage      |
test_1  | |=============================================================================|
test_1  | |  No running processes found                                                 |
test_1  | +-----------------------------------------------------------------------------+
gpu_test_1 exited with code 0

GPU Minikube

配置Minikube,啟動kubernetes集群

minikube start --driver docker --container-runtime docker --gpus all

驗證集群的GPU能力

  1. 確認節點具備GPU信息
kubectl describe node minikube
...
Capacity:
  nvidia.com/gpu: 1
...
  1. 測試在集群中執行CUDA
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  restartPolicy: Never
  containers:
    - name: cuda-container
      image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda10.2
      resources:
        limits:
          nvidia.com/gpu: 1 # requesting 1 GPU
  tolerations:
  - key: nvidia.com/gpu
    operator: Exists
    effect: NoSchedule
EOF
$ kubectl logs gpu-pod
[Vector addition of 50000 elements]
Copy input data from the host memory to the CUDA device
CUDA kernel launch with 196 blocks of 256 threads
Copy output data from the CUDA device to the host memory
Test PASSED
Done

使用kueue提交pytorch訓練任務

kueue簡介

kueue是k8s特別興趣小組(SIG)的一個開源項目,是一個基于 Kubernetes 的任務隊列管理系統,旨在簡化和優化 Kubernetes 中的作業管理。 主要具備以下功能:

  • 作業管理:支持基于優先級的作業隊列,提供不同的隊列策略,如StrictFIFO和BestEffortFIFO。
  • 資源管理:支持資源的公平分享和搶占,以及不同租戶之間的資源管理策略。
  • 動態資源回收:一種釋放資源配額的機制,隨著作業的完成而動態釋放資源。
  • 資源靈活性:在 ClusterQueue 和 Cohort 中支持資源的借用或搶占。
  • 內置集成:內置支持常見的作業類型,如 BatchJob、Kubeflow 訓練作業、RayJob、RayCluster、JobSet 等。
  • 系統監控:內置 Prometheus 指標,用于監控系統狀態。
  • 準入檢查:一種機制,用于影響工作負載是否可以被接受。
  • 高級自動縮放支持:與 cluster-autoscaler 的 provisioningRequest 集成,通過準入檢查進行管理。
  • 順序準入:一種簡單的全或無調度實現。
  • 部分準入:允許作業以較小的并行度運行,基于可用配額。

kueue的架構圖如下:

圖片圖片

通過拓展workload來支持BatchJob、Kubeflow 訓練作業、RayJob、RayCluster、JobSet 等作業任務,通過ClusterQueue來共享LocalQueue資源,任務最終提交到LocalQueue進行調度和執行,而不同的ClusterQueue可以通過Cohort進行資源共享和通信,通過Cohort->ClusterQueue->LocalQueue->Node實現不同層級的資源共享已支持AI、ML等Ray相關的job在k8s集群中調度。 在kueue中區分管理員用戶和普通用戶,管理員用戶負責管理ResourceFlavor、ClusterQueue、LocalQueue等資源,以及管理資源池的配額(quota)。普通用戶負責提批處理任務或者各類的Ray任務。

運行PyTorch訓練任務

安裝kueue

需要k8s 1.22+,使用如下的命令安裝

kubectl apply --server-side -f https://github.com/kubernetes-sigs/kueue/releases/download/v0.6.0/manifests.yaml

配置集群配額

git clone https://github.com/kubernetes-sigs/kueue.git && cd kueue
kubectl apply -f examples/admin/single-clusterqueue-setup.yaml

其實不安裝kueue也是能夠提交Pytorch的訓練任務,因為這個PytorchJob是kubeflow traning-operator的一個CRD,但是安裝kueue的好處是,他可以支持更多任務。

除了kubeflow的任務,還可以支持kuberay的任務,并且它內置了管理員角色,方便對于集群的配置和集群的資源做限額和管理,支持優先級隊列和任務搶占,更好的支持AI、ML等任務的調度和管理。上面安裝的集群配額就是設置任務的限制,避免一些負載過高的任務提交,在任務執行前快速失敗。

安裝kubeflow的training-operator

kubectl apply -k "github.com/kubeflow/training-operator/manifests/overlays/standalone"

運行FashionMNIST的訓練任務

FashionMNIST 數據集是一個用于圖像分類任務的常用數據集,類似于經典的 MNIST 數據集,但是它包含了更加復雜的服裝類別。

  • FashionMNIST 數據集包含了 10 個類別的服裝圖像,每個類別包含了 6,000 張訓練圖像和 1,000 張測試圖像,共計 60,000 張訓練圖像和 10,000 張測試圖像。
  • 每張圖像都是 28x28 像素的灰度圖像,表示了不同類型的服裝,如 T 恤、褲子、襯衫、裙子等。

在kueue上提交PyTorchJob類型的任務,為了能夠保存訓練過程中的日志和結果,我們需要使用openebs的hostpath來將訓練過程的數據保存到節點上,因為任務訓練結束后,不能登錄到節點查看。所以創建如下的資源文件

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pytorch-results-pvc
spec:
  storageClassName: openebs-hostpath
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
---
apiVersion: "kubeflow.org/v1"
kind: PyTorchJob
metadata:
  name: pytorch-simple
  namespace: kubeflow
spec:
  pytorchReplicaSpecs:
    Master:
      replicas: 1
      restartPolicy: OnFailure
      template:
        spec:
          containers:
            - name: pytorch
              image: pytorch-mnist:2.2.1-cuda12.1-cudnn8-runtime
              imagePullPolicy: IfNotPresent
              command:
                - "python3"
                - "/opt/pytorch-mnist/mnist.py"
                - "--epochs=10"
                - "--batch-size"
                - "32"
                - "--test-batch-size"
                - "64"
                - "--lr"
                - "0.01"
                - "--momentum"
                - "0.9"
                - "--log-interval"
                - "10"
                - "--save-model"
                - "--log-path"
                - "/results/master.log"
              volumeMounts:
              - name: result-volume
                mountPath: /results
          volumes:
          - name: result-volume
            persistentVolumeClaim:
              claimName: pytorch-results-pvc
    Worker:
      replicas: 1
      restartPolicy: OnFailure
      template:
        spec:
          containers:
            - name: pytorch
              image: pytorch-mnist:2.2.1-cuda12.1-cudnn8-runtime
              imagePullPolicy: IfNotPresent
              command:
                - "python3"
                - "/opt/pytorch-mnist/mnist.py"
                - "--epochs=10"
                - "--batch-size"
                - "32"
                - "--test-batch-size"
                - "64"
                - "--lr"
                - "0.01"
                - "--momentum"
                - "0.9"
                - "--log-interval"
                - "10"
                - "--save-model"
                - "--log-path"
                - "/results/worker.log"
              volumeMounts:
              - name: result-volume
                mountPath: /results
          volumes:
          - name: result-volume
            persistentVolumeClaim:
              claimName: pytorch-results-pvc

其中pytorch-mnist:v1beta1-45c5727是一個在pytorch上運行CNN訓練任務的代碼,具體的代碼如下:

from __future__ import print_function

import argparse
import logging
import os

from torchvision import datasets, transforms
import torch
import torch.distributed as dist
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

WORLD_SIZE = int(os.environ.get("WORLD_SIZE", 1))


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 20, 5, 1)
        self.conv2 = nn.Conv2d(20, 50, 5, 1)
        self.fc1 = nn.Linear(4*4*50, 500)
        self.fc2 = nn.Linear(500, 10)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        x = F.max_pool2d(x, 2, 2)
        x = F.relu(self.conv2(x))
        x = F.max_pool2d(x, 2, 2)
        x = x.view(-1, 4*4*50)
        x = F.relu(self.fc1(x))
        x = self.fc2(x)
        return F.log_softmax(x, dim=1)


def train(args, model, device, train_loader, optimizer, epoch):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        output = model(data)
        loss = F.nll_loss(output, target)
        loss.backward()
        optimizer.step()
        if batch_idx % args.log_interval == 0:
            msg = "Train Epoch: {} [{}/{} ({:.0f}%)]\tloss={:.4f}".format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                100. * batch_idx / len(train_loader), loss.item())
            logging.info(msg)
            niter = epoch * len(train_loader) + batch_idx


def test(args, model, device, test_loader, epoch):
    model.eval()
    test_loss = 0
    correct = 0
    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            test_loss += F.nll_loss(output, target, reductinotallow="sum").item()  # sum up batch loss
            pred = output.max(1, keepdim=True)[1]  # get the index of the max log-probability
            correct += pred.eq(target.view_as(pred)).sum().item()

    test_loss /= len(test_loader.dataset)
    logging.info("{{metricName: accuracy, metricValue: {:.4f}}};{{metricName: loss, metricValue: {:.4f}}}\n".format(
        float(correct) / len(test_loader.dataset), test_loss))


def should_distribute():
    return dist.is_available() and WORLD_SIZE > 1


def is_distributed():
    return dist.is_available() and dist.is_initialized()


def main():
    # Training settings
    parser = argparse.ArgumentParser(descriptinotallow="PyTorch MNIST Example")
    parser.add_argument("--batch-size", type=int, default=64, metavar="N",
                        help="input batch size for training (default: 64)")
    parser.add_argument("--test-batch-size", type=int, default=1000, metavar="N",
                        help="input batch size for testing (default: 1000)")
    parser.add_argument("--epochs", type=int, default=10, metavar="N",
                        help="number of epochs to train (default: 10)")
    parser.add_argument("--lr", type=float, default=0.01, metavar="LR",
                        help="learning rate (default: 0.01)")
    parser.add_argument("--momentum", type=float, default=0.5, metavar="M",
                        help="SGD momentum (default: 0.5)")
    parser.add_argument("--no-cuda", actinotallow="store_true", default=False,
                        help="disables CUDA training")
    parser.add_argument("--seed", type=int, default=1, metavar="S",
                        help="random seed (default: 1)")
    parser.add_argument("--log-interval", type=int, default=10, metavar="N",
                        help="how many batches to wait before logging training status")
    parser.add_argument("--log-path", type=str, default="",
                        help="Path to save logs. Print to StdOut if log-path is not set")
    parser.add_argument("--save-model", actinotallow="store_true", default=False,
                        help="For Saving the current Model")

    if dist.is_available():
        parser.add_argument("--backend", type=str, help="Distributed backend",
                            choices=[dist.Backend.GLOO, dist.Backend.NCCL, dist.Backend.MPI],
                            default=dist.Backend.GLOO)
    args = parser.parse_args()

    # Use this format (%Y-%m-%dT%H:%M:%SZ) to record timestamp of the metrics.
    # If log_path is empty print log to StdOut, otherwise print log to the file.
    if args.log_path == "":
        logging.basicConfig(
            format="%(asctime)s %(levelname)-8s %(message)s",
            datefmt="%Y-%m-%dT%H:%M:%SZ",
            level=logging.DEBUG)
    else:
        logging.basicConfig(
            format="%(asctime)s %(levelname)-8s %(message)s",
            datefmt="%Y-%m-%dT%H:%M:%SZ",
            level=logging.DEBUG,
            filename=args.log_path)

    use_cuda = not args.no_cuda and torch.cuda.is_available()
    if use_cuda:
        print("Using CUDA")

    torch.manual_seed(args.seed)

    device = torch.device("cuda" if use_cuda else "cpu")

    if should_distribute():
        print("Using distributed PyTorch with {} backend".format(args.backend))
        dist.init_process_group(backend=args.backend)

    kwargs = {"num_workers": 1, "pin_memory": True} if use_cuda else {}

    train_loader = torch.utils.data.DataLoader(
        datasets.FashionMNIST("./data",
                              train=True,
                              download=True,
                              transform=transforms.Compose([
                                  transforms.ToTensor()
                              ])),
        batch_size=args.batch_size, shuffle=True, **kwargs)

    test_loader = torch.utils.data.DataLoader(
        datasets.FashionMNIST("./data",
                              train=False,
                              transform=transforms.Compose([
                                  transforms.ToTensor()
                              ])),
        batch_size=args.test_batch_size, shuffle=False, **kwargs)

    model = Net().to(device)

    if is_distributed():
        Distributor = nn.parallel.DistributedDataParallel if use_cuda \
            else nn.parallel.DistributedDataParallelCPU
        model = Distributor(model)

    optimizer = optim.SGD(model.parameters(), lr=args.lr, momentum=args.momentum)

    for epoch in range(1, args.epochs + 1):
        train(args, model, device, train_loader, optimizer, epoch)
        test(args, model, device, test_loader, epoch)

    if (args.save_model):
        torch.save(model.state_dict(), "mnist_cnn.pt")


if __name__ == "__main__":
    main()

將訓練任務提交到k8s集群

kubectl apply -f sample-pytorchjob.yaml

提交成功后會出現兩個訓練任務,分別是master和worker的訓練任務,如下:

?  ~ kubectl get po
NAME                      READY   STATUS    RESTARTS   AGE
pytorch-simple-master-0   1/1     Running   0          5m5s
pytorch-simple-worker-0   1/1     Running   0          5m5s

再查看宿主機的顯卡運行情況,發現能夠明顯聽到集群散熱的聲音,運行nvida-smi可以看到有兩個Python任務在執行,等待執行完后,會生成模型文件mnist_cnn.pt。

?  ~ nvidia-smi
Mon Mar  4 10:18:39 2024
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.161.07             Driver Version: 535.161.07   CUDA Version: 12.2     |
|-----------------------------------------+----------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |         Memory-Usage | GPU-Util  Compute M. |
|                                         |                      |               MIG M. |
|=========================================+======================+======================|
|   0  NVIDIA GeForce RTX 3060 ...    Off | 00000000:01:00.0 Off |                  N/A |
| N/A   39C    P0              24W /  80W |    753MiB /  6144MiB |      1%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+

+---------------------------------------------------------------------------------------+
| Processes:                                                                            |
|  GPU   GI   CI        PID   Type   Process name                            GPU Memory |
|        ID   ID                                                             Usage      |
|=======================================================================================|
|    0   N/A  N/A      1674      G   /usr/lib/xorg/Xorg                          219MiB |
|    0   N/A  N/A      1961      G   /usr/bin/gnome-shell                         47MiB |
|    0   N/A  N/A      3151      G   gnome-control-center                          2MiB |
|    0   N/A  N/A      4177      G   ...irefox/3836/usr/lib/firefox/firefox      149MiB |
|    0   N/A  N/A     14476      C   python3                                     148MiB |
|    0   N/A  N/A     14998      C   python3                                     170MiB |
+---------------------------------------------------------------------------------------+

在提交和執行任務的時候,要注意cuda的版本和pytorch的版本要保持對應,官方demo中的dockerfile是這樣的

FROM pytorch/pytorch:1.0-cuda10.0-cudnn7-runtime

ADD examples/v1beta1/pytorch-mnist /opt/pytorch-mnist
WORKDIR /opt/pytorch-mnist

# Add folder for the logs.
RUN mkdir /katib

RUN chgrp -R 0 /opt/pytorch-mnist \
  && chmod -R g+rwX /opt/pytorch-mnist \
  && chgrp -R 0 /katib \
  && chmod -R g+rwX /katib

ENTRYPOINT ["python3", "/opt/pytorch-mnist/mnist.py"]

這個要求你要使用pytorch1.0和cuda10的版本進行訓練,而我們實際的使用的cuda12,所以直接用這個基礎鏡像去構建是不行,任務會一致處于運行中,永遠結束不了,為了能夠避免每次重復下載mnist的數據集,我們需要提前下載然后將數據集打包到容器里面,所以修改后的Dockerfile如下:

FROM pytorch/pytorch:2.2.1-cuda12.1-cudnn8-runtime

ADD . /opt/pytorch-mnist
WORKDIR /opt/pytorch-mnist

# Add folder for the logs.
RUN mkdir /katib

RUN chgrp -R 0 /opt/pytorch-mnist \
  && chmod -R g+rwX /opt/pytorch-mnist \
  && chgrp -R 0 /katib \
  && chmod -R g+rwX /katib

ENTRYPOINT ["python3", "/opt/pytorch-mnist/mnist.py"]

使用最終的訓練結束后mnist_cnn.pt模型文件,進行模型預測和測試得到的結果如下:{metricName: accuracy, metricValue: 0.9039};{metricName: loss, metricValue: 0.2756}, 即這個模型的準確性為90.39%,模型損失值為0.2756,說明我們訓練的模型在FashionMNIST 數據集上表現良好,在訓練過程中epoch參數比較重要,它代表訓練的輪次,過小會出現效果不好,過大會出現過擬合問題,在測試的時候我們可以適當調整這個參數來控制模型訓練運行的時間。 

通過kueue通過webhook的方式對于的進行AI、ML等GPU任務進行準入控制和資源限制,提供租戶隔離的概念,為k8s對于GPU的支持提供了根據豐富的場景。如果筆記本的顯卡能力夠強,可以將chatglm等開源的大模型部署到k8s集群中,從而搭建自己個人離線專屬的大模型服務。

karmada多集群提交pytorch訓練任務

創建多集群k8s

在多集群的管控上,我們可以使用karamda來實現管理,其中member2作為控制面主集群,member3、member4作為子集群。在完成minikube的nvidia的GPU配置后,使用如下的命令創建3個集群。

docker network create --driver=bridge --subnet=xxx.xxx.xxx.0/24 --ip-range=xxx.xxx.xxx.0/24 minikube-net
minikube start --driver docker --cpus max --memory max --container-runtime docker --gpus all --network minikube-net --subnet='xxx.xxx.xxx.xxx' --mount-string="/run/udev:/run/udev" --mount -p member2 --static-ip='xxx.xxx.xxx.xxx'
minikube start --driver docker --cpus max --memory max --container-runtime docker --gpus all --network minikube-net --subnet='xxx.xxx.xxx.xxx' --mount-string="/run/udev:/run/udev" --mount -p member3 --static-ip='xxx.xxx.xxx.xxx'
minikube start --driver docker --cpus max --memory max --container-runtime docker --gpus all --network minikube-net --subnet='xxx.xxx.xxx.xxx' --mount-string="/run/udev:/run/udev" --mount -p member4 --static-ip='xxx.xxx.xxx.xxx'
?  ~ minikube profile list
|---------|-----------|---------|-----------------|------|---------|---------|-------|--------|
| Profile | VM Driver | Runtime |      IP         | Port | Version | Status  | Nodes | Active |
|---------|-----------|---------|-----------------|------|---------|---------|-------|--------|
| member2 | docker    | docker  | xxx.xxx.xxx.xxx | 8443 | v1.28.3 | Running |     1 |        |
| member3 | docker    | docker  | xxx.xxx.xxx.xxx | 8443 | v1.28.3 | Running |     1 |        |
| member4 | docker    | docker  | xxx.xxx.xxx.xxx | 8443 | v1.28.3 | Running |     1 |        |
|---------|-----------|---------|-----------------|------|---------|---------|-------|--------|

在3個集群分別安裝Training Operator、karmada,并且需要在karmada的控制面安裝Training Operator,這樣才能在控制面提交pytorchjob的任務。由于同一個pytorch任務分布在不同的集群在服務發現和master、worker交互通信會存在困難,所以我們這邊只演示將同一個pytorch任務提交到同一個集群,通過kosmos的控制面實現將多個pytorch任務調度到不同的集群完成訓練。 在karmada的控制面上創建訓練任務

apiVersion: "kubeflow.org/v1"
kind: PyTorchJob
metadata:
  name: pytorch-simple
  namespace: kubeflow
spec:
  pytorchReplicaSpecs:
    Master:
      replicas: 1
      restartPolicy: OnFailure
      template:
        spec:
          containers:
            - name: pytorch
              image: pytorch-mnist:2.2.1-cuda12.1-cudnn8-runtime
              imagePullPolicy: IfNotPresent
              command:
                - "python3"
                - "/opt/pytorch-mnist/mnist.py"
                - "--epochs=30"
                - "--batch-size"
                - "32"
                - "--test-batch-size"
                - "64"
                - "--lr"
                - "0.01"
                - "--momentum"
                - "0.9"
                - "--log-interval"
                - "10"
                - "--save-model"
                - "--log-path"
                - "/opt/pytorch-mnist/master.log"
    Worker:
      replicas: 1
      restartPolicy: OnFailure
      template:
        spec:
          containers:
            - name: pytorch
              image: pytorch-mnist:2.2.1-cuda12.1-cudnn8-runtime
              imagePullPolicy: IfNotPresent
              command:
                - "python3"
                - "/opt/pytorch-mnist/mnist.py"
                - "--epochs=30"
                - "--batch-size"
                - "32"
                - "--test-batch-size"
                - "64"
                - "--lr"
                - "0.01"
                - "--momentum"
                - "0.9"
                - "--log-interval"
                - "10"
                - "--save-model"
                - "--log-path"
                - "/opt/pytorch-mnist/worker.log"

在karmada的控制面上創建傳播策略

apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
  name: pytorchjob-propagation
  namespace: kubeflow
spec:
  resourceSelectors:
    - apiVersion: kubeflow.org/v1
      kind: PyTorchJob
      name: pytorch-simple
      namespace: kubeflow
  placement:
    clusterAffinity:
      clusterNames:
        - member3
        - member4
    replicaScheduling:
      replicaDivisionPreference: Weighted
      replicaSchedulingType: Divided
      weightPreference:
        staticWeightList:
          - targetCluster:
              clusterNames:
                - member3
            weight: 1
          - targetCluster:
              clusterNames:
                - member4
            weight: 1

然后我們就可以看到這個訓練任務成功的提交到member3和member4的子集群上執行任務

?  pytorch kubectl karmada  --kubeconfig ~/karmada-apiserver.config  get po -n kubeflow
NAME                                 CLUSTER   READY   STATUS      RESTARTS   AGE
pytorch-simple-master-0              member3   0/1     Completed   0          7m51s
pytorch-simple-worker-0              member3   0/1     Completed   0          7m51s
training-operator-64c768746c-gvf9n   member3   1/1     Running     0          165m
pytorch-simple-master-0              member4   0/1     Completed   0          7m51s
pytorch-simple-worker-0              member4   0/1     Completed   0          7m51s
training-operator-64c768746c-nrkdv   member4   1/1     Running     0          168m

總結

通過搭建本地的k8s GPU環境,可以方便的進行AI相關的開發和測試,也能充分利用閑置的筆記本GPU性能。利用kueue、karmada、kuberay和ray等框架,讓GPU等異構算力調度在云原生成為可能。目前只是在單k8s集群完成訓練任務的提交和運行,在實際AI、ML或者大模型的訓練其實更加復雜,組網和技術架構也需要進行精心的設計。要實現千卡、萬卡的在k8s集群的訓練和推理解決包括但不僅限于

  • 網絡通信性能:傳統的數據中心網絡一般是10Gbps,這個在大模型訓練和推理中是捉襟見肘的,所以需要構建RDMA網絡(Remote Direct Memory Access)
  • GPU調度和配置:多云多集群場景下,如何進行GPU的調度和管理
  • 監控和調試:如何進行有效地監控和調試訓練任務,以及對異常情況進行處理和服務恢復

參考資料

1. [Go](https://go.dev/)

2. [Docker](https://docker.com)

3. [minikube](https://minikube.sigs.k8s.io/docs/tutorials/nvidia/)

4. [nvidia](https://docs.nvidia.com/datacenter/tesla/tesla-installation-notes/index.html)

5. [kubernetes](https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/)

6. [kueue](https://github.com/kubernetes-sigs/kueue)

7. [kubeflow](https://github.com/kubeflow/training-operator)

8. [ray](https://github.com/ray-project/ray)

9. [kuberay](https://github.com/ray-project/kuberay)

10. [karmada](https://github.com/karmada-io/karmada)

11. [kind](https://kind.sigs.k8s.io/)

12. [k3s](https://github.com/k3s-io/k3s)

13. [k3d](https://github.com/k3d-io/k3d)

責任編輯:武曉燕 來源: 暢聊云原生
相關推薦

2023-09-07 08:58:36

K8s多集群

2023-11-06 07:16:22

WasmK8s模塊

2021-11-29 08:48:00

K8S KubernetesAirflow

2022-09-05 08:26:29

Kubernetes標簽

2021-06-09 13:22:54

WSLWindowsLinux

2024-03-01 19:59:17

2020-12-28 09:56:45

K8sDevOps容器技術

2024-06-26 00:22:35

2025-07-02 03:00:00

2025-04-16 03:25:00

2025-03-26 00:00:00

k8m工具Kubernete

2022-04-22 13:32:01

K8s容器引擎架構

2022-04-02 09:57:51

技術京東實踐

2023-11-07 08:23:05

2023-11-24 17:51:18

Kubernetes云原生

2023-12-01 15:46:01

Kubernetes容器

2023-09-11 14:21:00

2023-09-27 22:33:40

KubernetesK8S

2023-12-25 07:35:40

數據集成FlinkK8s

2022-10-10 12:54:00

Flink運維
點贊
收藏

51CTO技術棧公眾號

国产亚洲精品成人a| 中文字幕精品—区二区日日骚| 日韩黄色a级片| 亚洲人成精品久久久 | 国产丝袜精品第一页| 日韩欧美xxxx| 91国内在线| wwwwww.欧美系列| 成人国产亚洲精品a区天堂华泰| 麻豆视频在线观看| 精品国精品国产自在久国产应用| 91精品国产色综合久久不卡蜜臀| 男人添女人下部高潮视频在观看| 成人亚洲综合天堂| 国产成人8x视频一区二区| 欧洲美女免费图片一区| 五月天色婷婷丁香| 一本色道久久综合亚洲精品酒店| 欧美一区日韩一区| 北条麻妃在线一区| 久久亚洲资源| 国产精品沙发午睡系列990531| 国产精品久久7| 91av久久久| 视频精品一区二区| 国模叶桐国产精品一区| 国产又粗又长又黄的视频| 久久久久久毛片免费看 | 日本午夜在线视频| 国产成人精品免费网站| 国产精品欧美日韩久久| 亚洲男人的天堂在线视频| 亚洲最新色图| 精品激情国产视频| 欧美性受xxxx黑人| 综合亚洲自拍| 日韩国产一区三区| 久久久男人的天堂| 日本成人精品| 制服丝袜国产精品| 欧美成人福利在线观看| 亚洲精品555| 在线观看视频一区| 国产欧美高清在线| 卡通欧美亚洲| 欧美午夜精品久久久久久人妖| 成人黄色大片网站| 久草在线资源站资源站| 伊人婷婷欧美激情| 四虎影院一区二区| 成人在线观看免费网站| 亚洲免费观看高清在线观看| 中文字幕人成一区| 黄色网在线播放| 亚洲日本丝袜连裤袜办公室| 伊人色综合影院| 欧美精品日韩少妇| 中文字幕亚洲视频| 91手机视频在线| av网站在线看| 一区二区三区免费观看| 精品免费久久久久久久| 国产精品一区hongkong| 亚洲国产日韩av| 欧美视频在线观看视频| 9999精品成人免费毛片在线看 | 99久久婷婷国产| 久久精品日产第一区二区三区| 天天在线女人的天堂视频| 久久综合av免费| 日韩精品资源| 黄a在线观看| 亚洲综合精品久久| 可以在线看的av网站| 中国字幕a在线看韩国电影| 色哟哟国产精品免费观看| 嫩草影院国产精品| 精品一区二区三区四区五区| 欧美变态tickle挠乳网站| 日韩av手机在线播放| 伊人春色之综合网| 日韩中文字幕精品| 久草国产在线观看| 国产精品一区亚洲| 国产欧美日韩丝袜精品一区| 精品久久久无码中文字幕| 懂色av一区二区夜夜嗨| 蜜桃999成人看片在线观看| www.av在线| 夜夜亚洲天天久久| 精品www久久久久奶水| 亚洲图片小说区| 亚洲国产精品999| 国产农村妇女精品一区| 欧美日韩 国产精品| 55夜色66夜色国产精品视频| 亚洲中文一区二区三区| 成人av网站在线| 亚洲乱码一区二区三区| 99色在线观看| 欧美日韩国产一二三| 四虎永久免费观看| 久久91精品| 久久69精品久久久久久国产越南| 精品人妻一区二区色欲产成人| 九色porny丨国产精品| 精品无人区一区二区三区| 老司机精品影院| 色噜噜夜夜夜综合网| 无码人妻一区二区三区一| 国产中文精品久高清在线不| 欧美激情一二三| 亚洲天堂2021av| 91在线国产观看| 91麻豆天美传媒在线| 九九热线视频只有这里最精品| 日韩精品在线一区二区| 国产一二三四视频| 久久黄色网页| 国产美女精品在线观看| 日本在线www| 日本丶国产丶欧美色综合| 日本道中文字幕| 中文字幕一区二区三区在线视频 | 欧美经典三级视频一区二区三区| 青青在线视频免费观看| 国产亚洲精彩久久| 亚洲精品自产拍| 日韩欧美亚洲视频| 国产精品一区二区不卡| 欧美 日韩 国产 在线观看| 欧美va在线| 亚洲奶大毛多的老太婆| 日韩三级一区二区三区| 床上的激情91.| 日本精品福利视频| 激情视频亚洲| 久久精品国产96久久久香蕉 | 日韩欧美美女一区二区三区| 色偷偷www8888| 开心九九激情九九欧美日韩精美视频电影 | 精品日韩一区| 欧美中文字幕在线观看| 神马午夜在线观看| 亚洲sss视频在线视频| 亚洲欧美日韩偷拍| 亚洲人成人一区二区三区| 国产成人免费观看| 麻豆av在线播放| 亚洲成色999久久网站| 国产一级视频在线播放| 成人免费黄色在线| 亚洲精品无码国产| 麻豆精品av| 日本精品久久久久影院| 青青草视频免费在线观看| 色综合久久久久| 国产特级黄色录像| 日韩av在线播放中文字幕| 亚洲精品乱码视频| 99tv成人影院| 大胆人体色综合| 亚洲国产精品18久久久久久| 亚洲成av人影院在线观看网| 精品国产一区在线| 久久午夜精品| 亚洲精品二区| 日本免费精品| 5566日本婷婷色中文字幕97| 国产区av在线| 欧美精品免费视频| 国产亚洲欧美久久久久| www.日韩在线| 国产无套粉嫩白浆内谢的出处| 亚洲男人都懂第一日本| 国产精品视频最多的网站| 黄色免费网站在线| 精品国产亚洲在线| 日韩美一区二区| 自拍偷自拍亚洲精品播放| 涩视频在线观看| 日韩精品亚洲一区| 亚洲成人蜜桃| 亚洲高清在线一区| 日本国产精品视频| 超碰在线caoporn| 亚洲精品国产欧美| 又骚又黄的视频| 亚洲成人自拍偷拍| 国产真人做爰视频免费| 国产91在线观看丝袜| 午夜精品久久久内射近拍高清| 999国产精品视频| 韩国成人av| 亚洲欧洲一二区| 欧美一级片在线播放| 久久综合网导航| 日韩精品高清视频| 国产女人18毛片18精品| 欧美日韩亚洲一区二| 日本 欧美 国产| 91蜜桃在线免费视频| 视频区 图片区 小说区| 玖玖玖国产精品| 2019日韩中文字幕mv| 日韩专区精品| 欧美二级三级| 波多野结衣在线一区二区| 国产成人免费av| 黄色成人在线网| 日韩一区视频在线| 欧美成人免费| 亚洲第一网站免费视频| 国产乱人乱偷精品视频| 色婷婷综合五月| 黄色小说在线观看视频| 亚洲色图视频免费播放| 老头老太做爰xxx视频| 99久久精品99国产精品| 在线观看视频在线观看| 久久99精品久久久久| 人妻无码视频一区二区三区| 亚洲午夜精品久久久久久app| 一区二区精品在线| 欧美精品一区二区三区精品| 国产尤物99| 国产一区二区三区精品在线观看| 国产精品扒开腿爽爽爽视频| 午夜伦理福利在线| 久久久久久久一区二区| 污污网站在线看| 另类少妇人与禽zozz0性伦| lutube成人福利在线观看| 日韩电影免费观看在线观看| 丁香花免费高清完整在线播放 | 91 在线视频观看| 蜜桃av综合| avav在线看| 亚洲美女少妇无套啪啪呻吟| 国产freexxxx性播放麻豆| 女人色偷偷aa久久天堂| 99热一区二区三区| 91精品国产91久久久久久密臀| 亚洲在线视频一区二区| 色天天综合网| 一区二区欧美日韩| 99视频精品全国免费| 中文字幕在线观看一区二区三区| 人人狠狠综合久久亚洲婷| 亚洲精品电影在线一区| 99精品在线观看| a级片一区二区| 欧美网站在线| 国产精品国产亚洲精品看不卡| 在线国产欧美| 国产女女做受ⅹxx高潮| 日韩av二区在线播放| 91精品999| 国产精品一区二区在线观看不卡| 久久久久久无码精品人妻一区二区| 国产精品一区二区不卡| 欧美xxxxx少妇| 91美女片黄在线观看91美女| 91l九色lporny| 亚洲少妇最新在线视频| 久久免费视频6| 欧美视频在线免费| 波多野结衣爱爱| 欧美日韩精品一区二区在线播放| 国产色综合视频| 亚洲成人久久久久| 大片免费播放在线视频| www.久久久久| 免费不卡av| 国产成人97精品免费看片| 9999精品免费视频| 国产乱人伦精品一区二区| av在线不卡顿| 亚洲第一页在线视频| 亚洲精品资源| 污色网站在线观看| 国产+成+人+亚洲欧洲自线| 亚洲中文字幕一区| 国产精品国产自产拍高清av王其 | 高清国语自产拍免费一区二区三区| 国产欧美啪啪| 色一情一乱一伦一区二区三区| 欧美 日韩 国产 一区| 91国视频在线| 黄一区二区三区| 中国极品少妇videossexhd| 中文字幕乱码亚洲精品一区| 久久综合久久鬼| 在线影视一区二区三区| www日本视频| 中国人与牲禽动交精品| 国产丝袜在线播放| 国产精品久久久久久久app| 视频在线观看免费影院欧美meiju| 欧美日本韩国国产| 欧美激情视频一区二区三区在线播放 | 日本不卡高清视频一区| 国产精品va| 亚洲污视频在线观看| 波多野结衣在线一区| 国产免费美女视频| 在线看不卡av| 天天干天天草天天射| 麻豆国产精品va在线观看不卡| 我爱我色成人网| 国产91精品入口17c| 久久精品国产68国产精品亚洲| 久久亚洲中文字幕无码| 国产精品一级在线| 亚洲毛片亚洲毛片亚洲毛片| 粉嫩老牛aⅴ一区二区三区| 精品国产va久久久久久久| 一本一道久久a久久精品逆3p| 国产色播av在线| 99久久精品无码一区二区毛片| 99re6这里只有精品| 国产精品少妇在线视频| av在线免费不卡| 国产一级二级三级视频| 欧美日本国产视频| 懂色av中文在线| 欧美制服第一页| 亚洲免费福利一区| 浮妇高潮喷白浆视频| 成人一道本在线| 亚洲国产精品午夜在线观看| 91精品国产麻豆国产自产在线 | 亚洲高清免费在线| 国产视频第一页| 久久天天躁狠狠躁夜夜av| 久久久精品一区二区毛片免费看| 丝袜美腿玉足3d专区一区| 久久永久免费| 蜜桃久久精品成人无码av| 91高清在线观看| 成人性生交大片免费看午夜 | 中文字幕一区二区三区波野结| 亚洲香蕉成人av网站在线观看| 亚洲黄色网址| 欧美一区二区三区四区五区六区| 久久亚洲电影| 国产美女永久免费无遮挡 | 亚洲av无码片一区二区三区| 欧美另类99xxxxx| 999国产精品一区| 黄色成人在线看| 91网站最新网址| 色屁屁影院www国产高清麻豆| 亚洲欧美中文字幕在线一区| 欧美精品日日操| 亚洲毛片aa| 国产一区二区三区美女| 日本妇女毛茸茸| 精品处破学生在线二十三| 欧美日韩在线观看首页| 欧美精品国产精品久久久| 青娱乐精品在线视频| 黑人狂躁日本娇小| 欧美一区二区在线观看| 高h视频在线播放| 久久另类ts人妖一区二区| 日韩精品一二区| 免费在线观看h片| 亚洲福利视频网站| 国产精品av一区二区三区 | 亚洲AV无码国产成人久久| 欧日韩精品视频| 看黄网站在线| 国产一区免费| 麻豆91小视频| 久草视频免费播放| 亚洲视屏在线播放| 亚洲综合伊人| 日本少妇高潮喷水视频| 中文字幕精品综合| 国内老熟妇对白xxxxhd| 欧美专区在线视频| 五月精品视频| 久久国产精品无码一级毛片| 欧美三级中文字| 污片在线免费观看| 欧美一区二区三区电影在线观看| 国产一区二三区| 国产无遮挡呻吟娇喘视频| 精品国产欧美一区二区五十路| 草莓视频一区二区三区| 手机在线免费观看毛片| 亚洲永久精品国产| 国产福利在线观看| 成人永久免费| 老司机精品视频在线| 成人精品免费在线观看| 久久综合久久八八| 国产精品手机在线播放| 亚洲美女精品视频|