基于 docker swarm 和 NVIDIA MIG 并行部署 AI 推理服务

  • 实现效果(笔者看中且本文介绍的功能)

    1. docker swarm 自带的负载均衡
    2. 更加底层的并行运行 GPU 程序
    3. 节点伸缩用 docker 接口管理
    4. 更多优点请参考 https://docs.docker.com/engine/swarm/ 和 NVIDIA MIG 的介绍
  • 具体方法

    1. 创建 swarm 集群(所创建集群的服务器默认为管理节点,管理节点默认也是工作节点)

      docker swarm init
      Swarm initialized: current node (dxn1zf6l61qsb1josjja83ngz) is now a manager.
      
      To add a worker to this swarm, run the following command:
      
          docker swarm join \
          --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
          192.168.99.100:2377
      
      To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
      

      Note❗ : 如果你的 Docker 主机有多个网卡,拥有多个 IP,必须使用 --advertise-addr 指定 IP。[1]

    2. 配置 docker GPU 资源以让 docker swarm 的服务的任务能够用上 GPU[2]

      1. 切分出多个 GPU 实例[4]

        1. kill cuda 相关的进程、docker stop 相关的容器(比如 dcgm-exporter)或相关的 GPU 应用

        2. 开启 MIG mode (之后都需要 root 权限)

          1. nvidia-smi -i 0 -mig 1

            如果提示如下说没有开启持续模式 persistence mode,输入 nvidia-smi -pm 1 开启,说明参见[7]

            [guido@centos7-gpu ~]# sudo nvidia-smi -i 0 -mig 1
            Enabled MIG Mode for GPU 00000000:00:07.0
            
            Warning: persistence mode is disabled on device 00000000:00:07.0. See the Known Issues section of the nvidia-smi(1) man page for more information. Run with [--help | -h] switch to get more information on how to enable persistence mode.
            All done.
            

            开启后会降低使用 GPU 程序的加载延迟,重启后 persistence mode 失效,需重新开启,仅 Linux 支持

          2. nvidia-smi -i 0 --query-gpu=pci.bus_id,mig.mode.current --format=csv

        3. 查看 GPU 支持切分的配置

          nvidia-smi mig -lgip

        4. (可选,步骤 3 也有)查看可切分的程度的各配置的 ID

          1. nvidia-smi mig -lgipp
        5. 创建 4 个配置方式是 ID 为 14 所映射的配置的 A30 MIG 实例

          sudo nvidia-smi mig -cgi 14,14,14,14 -C

          -C 选项说明:创建 GI 的时候自动创建对应的 CI

          原文:Once the GPU instances are created, one needs to create the corresponding Compute Instances (CI). By using the -C option, nvidia-smi creates these instances.

        6. 此时已经切分好 GPU 计算卡了,可跳转至 2.2 小节,此节后续是笔者对 GI 和 CI 的关系的探讨。

          正如管网所说,GI 可以进一步切分出多个 CI,但笔者所用的服务器是一块 A30,只有 4 个 CI,故切分出 4 个 GI 后而不能再细分出 CI。

          • nvidia-smi --gpu-reset 后,可重新配置 MIG

          • 进一步细分 CI 的时候,也会有对应映射的设备 UUID

            1. 列出支持进一步细分的 CI

              nvidia-smi mig -lcip [-gi <gi_id>]

            2. CI 映射的设备 UUID

              [root@gpu-test-centos7 client]# nvidia-smi mig -cci 0,0 -gi <gi_id>
              [root@gpu-test-centos7 client]# nvidia-smi -L
              GPU 0: NVIDIA A30 (UUID: GPU-bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb)
                MIG 1c.2g.12gb  Device  0: (UUID: MIG-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
                MIG 1c.2g.12gb  Device  1: (UUID: MIG-yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy)
                MIG 1c.2g.12gb  Device  2: (UUID: MIG-zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz)
                MIG 1c.2g.12gb  Device  3: (UUID: MIG-aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa)
              
      2. 复制 nvidia-smi -L 输出的 MIG 的 UUID

        Note ❗: 实际的 MIG UUID 应是形如 MIG-a1b33b37c-dcd4-5676-8918-1a4fce9ee04e 的 uuid,本处已隐去。因为笔者发现关闭再重新切分后的 UUID 是不变的。

        [guido@centos7-gpu ~]# nvidia-smi -L
        GPU 0: NVIDIA A30 (UUID: GPU-bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb)
          MIG 1g.6gb      Device  0: (UUID: MIG-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
          MIG 1g.6gb      Device  1: (UUID: MIG-yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy)
          MIG 1g.6gb      Device  2: (UUID: MIG-zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz)
          MIG 1g.6gb      Device  3: (UUID: MIG-aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa)
        
      3. 将 UUID 通过形如 vim /etc/docker/daemon.json 添加到 daemon.json 里的 node-generic-resources

        Note❗:节点通用资源 node-generic-resources 中的键名是可自由指定的,笔者之后的示例都以 gpu 呈现[5]

        P.S. 🧐:参考链接中的说明非常生动形象。

        {
          "runtimes": {
            "nvidia": {
              "path": "/usr/bin/nvidia-container-runtime",
              "runtimeArgs": []
            }
          },
          "default-runtime": "nvidia",
          "node-generic-resources": [
            "gpu=<指令 nvidia-smi -L 输出的完整的 GPU 实例(GI)的 UUID>"
            ]
        }
        
        • 例如

          {
              "insecure-registries": [
                  "xxx.xxx.xxx.xxx:xxxx",
              ],
              "registry-mirrors": [
                  "http://xxx.xxx.xxx.xxx:xxxx",
              ],
              "runtimes": {
                  "nvidia": {
                      "args": [],
                      "path": "nvidia-container-runtime"
                  }
              },
              "default-runtime": "nvidia",
              "node-generic-resources": [
                  "gpu=MIG-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
                  "gpu=MIG-yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
                  "gpu=MIG-zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz",
                  "gpu=MIG-aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
              ]
          }
          
      4. vim /etc/nvidia-container-runtime/config.toml 取消注释或添加

        swarm-resource = "DOCKER_RESOURCE_GPU"

      5. 重启 docker 服务 sudo systemctl restart docker.service

    3. 在管理节点上创建服务

      1. (可选)子节点以工作节点管理节点的身份加入docker swarm[11]

        1. 连接要做工作节点的服务器

        2. 输入 docker swarm init 后,终端打印的提示的命令

          docker swarm join \
          --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
          192.168.99.100:2377
          
        • 忘记如何以工作节点加入则

          docker swarm join-token worker
          
          To add a worker to this swarm, run the following command:
          
              docker swarm join \
              --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
              192.168.99.100:2377
          
        • 要以管理节点加入则

           docker swarm join-token manager
          
          To add a manager to this swarm, run the following command:
          
              docker swarm join \
              --token SWMTKN-1-61ztec5kyafptydic6jfc1i33t37flcl4nuipzcusor96k7kby-5vy9t8u35tuqm7vh67lrz9xp6 \
              192.168.99.100:2377
          
      2. 准备调用 GPU 的程序并写好 Dockerfile。比如基于 FastAPI 或 Flask 的 python 程序[9],不是本文的重点故省略。

      3. 准备 docker stack.yml 配置文件,比如叫 swarm_compose.yml

        下列示例中没有说明的配置字段用法,请参看官网。

        Note❗: docker compose 的有些字段在后续用 docker stack 部署到 swarm 里不兼容

        services:
          api:
            image: Your-Registry-IP/Your-Repository/Your-Docker-Image
            build:
              context: .
              dockerfile: Dockerfile
            ports:
              - '6666:8000'
        
            deploy:
              resources:
                reservations:
                  generic_resources:
                    - discrete_resource_spec:
        				# kind 对应 node-generic-resources 里配置的键名即配置用什么资源
                        kind: "gpu"
        				# value 表示要用多少个 kind 对应的资源
                        value: 1
              mode: replicated
              replicas: 2
        
      4. 启动服务

        docker stack deploy -c swarm_compose.yml my_inference_server

        然后 docker 会用 swarm_compose.yml 里 services 字段里服务的名字加个后缀,如 my_inference_server_api

        Note❗:子节点如果找不到配置文件中的镜像时,子节点里的任务会启动失败。故建议如配置文件中的部署私有的docker镜像仓库。读者可以参看 Harbor Registry 或 docker 官方提供的工具docker-registry,点击跳转url。

      5. 任务伸缩

        • 此处笔者在两个服务器上实验,工作节点的 A30 分了 4 个 GI,管理节点的 A30 没有应用 MIG,故最大并行服务的任务只能拉到 5 个

          [guido@centos7-gpu ~]# docker service scale my_inference_server_api=5
          my_inference_server_api scaled to 5
          overall progress: 5 out of 5 tasks 
          1/5: running   [==================================================>] 
          2/5: running   [==================================================>] 
          3/5: running   [==================================================>] 
          4/5: running   [==================================================>] 
          5/5: running   [==================================================>] 
          verify: Service converged
          
        • 否则,docker swarm 会如下一直寻找符合资源配置的服务器创建任务。

          可以用 docker service ps --no-trunc my_inference_server_api 查看节点未启动的原因,比如第 6 个任务除了会说 "no suitable node (insufficient resources on 2 nodes)"还有更多详细信息

          [guido@centos7-gpu ~]# docker service scale my_inference_server_api=6
          my_inference_server_api scaled to 6
          overall progress: 5 out of 6 tasks 
          1/6: running   [==================================================>] 
          2/6: running   [==================================================>] 
          3/6: running   [==================================================>] 
          4/6: running   [==================================================>] 
          5/6: running   [==================================================>] 
          6/6: no suitable node (insufficient resources on 2 nodes)
          ^cOperation continuing in background.
          Use `docker service ps my_inference_server_api` to check progress.
          [guido@centos7-gpu ~]# docker service ls
          ID             NAME                      MODE         REPLICAS   IMAGE                                      PORTS
          ijrdszbvp6ro   my_inference_server_api   replicated   5/6        xxx/xxx/object_detect:latest   *:6666->8000/tcp
          
    4. 监控运行日志

      docker service logs -f my_inference_server_api

      此时会看到如下各节点,my_inference_server 服务的各任务[8]的运行情况

      my_inference_server_api.2.j804048caq63@centos7-gpu    | [07.20.2024 16:45:55] xxx
      my_inference_server_api.2.j804048caq63@centos7-gpu    | [07.20.2024 16:45:55] xxx
      my_inference_server_api.3.jt5euhhxi1i7@centos7-gpu    | xxx
      my_inference_server_api.3.jt5euhhxi1i7@centos7-gpu    | xxx
      
    5. 删除 docker swarm 服务和退出 MIG 模式

      1. docker stack rm my_inference_server

        等待 docker 清理完毕后再执行后续命令

      2. sudo nvidia-smi mig -dci && sudo nvidia-smi mig -dgi

      3. nvidia-smi -mig 0

  • 参考链接

    1. https://yeasy.gitbook.io/docker_practice/swarm_mode/create
    2. https://gist.github.com/tomlankhorst/33da3c4b9edbde5c83fc1244f010815c
    3. https://docs.docker.com/engine/swarm/swarm-tutorial/
    4. https://docs.nvidia.com/datacenter/tesla/mig-user-guide/index.html#running-with-mig
    5. https://gabrieldemarmiesse.github.io/python-on-whales/user_guide/generic_resources/
    6. https://docs.docker.com/engine/swarm/stack-deploy/?highlight=docker&highlight=stack&highlight=deploy#set-up-a-docker-registry
    7. https://developer.download.nvidia.com/compute/DCGM/docs/nvidia-smi-367.38.pdf
    8. https://docs.docker.com/engine/swarm/key-concepts/
    9. https://docs.docker.com/engine/swarm/stack-deploy/#create-the-example-application
    10. https://docs.docker.com/engine/swarm/
    11. https://docs.docker.com/engine/swarm/join-nodes/
  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java可以通过Docker Java API来实现远程控制Docker Swarm和Docker Compose部署服务。 对于Docker Swarm,可以使用Docker Java API提供的SwarmCmdExecFactory类来创建一个SwarmClient对象,进而实现对Swarm集群的控制。例如,以下代码展示了如何使用Docker Java API创建一个SwarmClient对象,并获取Swarm集群的节点列表: ``` SwarmCmdExecFactory swarmCmdExecFactory = new SwarmCmdExecFactory() DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder().build() DockerClient dockerClient = DockerClientBuilder.getInstance(config) .withDockerCmdExecFactory(swarmCmdExecFactory) .build() List<Node> nodes = dockerClient.listNodesCmd().exec() ``` 对于Docker Compose,可以使用Docker Java API提供的ComposeCmdExecFactory类来创建一个ComposeClient对象,进而实现对Docker Compose服务的控制。例如,以下代码展示了如何使用Docker Java API创建一个ComposeClient对象,并启动一个Compose服务: ``` ComposeCmdExecFactory composeCmdExecFactory = new ComposeCmdExecFactory() DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder().build() DockerClient dockerClient = DockerClientBuilder.getInstance(config) .withDockerCmdExecFactory(composeCmdExecFactory) .build() File composeFile = new File("docker-compose.yml") Up up = dockerClient.composeUpCmd() .withProjectName("myproject") .withFile(composeFile) .execute() ``` 需要注意的是,在使用Docker Java API远程控制Docker Swarm和Docker Compose之前,需要确保已经正确配置了Docker Swarm集群和Docker Compose服务,并且Java应用程序所在的机器上已经安装了Docker Engine。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值