你可能知道,Jetson Nano是一款低成本(99美元)的单板电脑,用于物联网类型的用例。在众多类似设备中,它的关键卖点是全功能GPU,与NVidia CUDA库兼容。
CUDA是现代机器学习计算的实际标准。它通常与GeForce、Quadro或特斯拉(Tesla)电路板、高端工作站和英伟达(NVidia)生产的服务器一起使用,这些设备性能非常好,但价格昂贵、耗电。
简而言之,我们有能力使用一个便宜的,配备cuda的设备,我们想——让我们建立自己的机器学习集群。现在,如果你想到“集群”,你通常会想到“Kubernetes”。Kubernetes——最初由谷歌创建,是一个非常常用的工具,用于管理运行在数百、数千甚至数十万台机器上的分布式应用程序。
我们的项目目标没有那么远。我们的集群由4台Jetson Nano机器组成。下面是关于我们如何构建和配置工作集群的详细指南。它适用于任何数量的Jetson nano -但是,您应该至少有两个Nano来搭建集群。
材料准备:
另外,我们假设您的所有nano都能够联网以下载额外的软件包。
第一步:刷机
请用Jetpack 4.2.1或者更新的版本(目前是4.2.2)刷机,因为早期的版本不支持基于Docker的容器的GPU支持,这是我们计划实现的严格要求。
要与Nanos交互,您应该使用显示器和键盘,或者使用更方便的远程SSH连接。为此,您需要计算出由本地DHCP分配的IP地址。如果不确定-插入显示器并设置/检查系统设置。Jetpack是一个基于Ubuntu的系统,所以最初的设置应该很简单。
第二部:配置基本的系统
这些步骤应该在每个NANO上重复:
1.禁用GUI模式,默认是启用的,会消耗资源:
sudo systemctl set-default multi-user.target
记住,这样做,你的Jetson Nano将启动到文本模式。但是,如果需要,您可以通过将默认系统模式重置为“graphics .target”来逆转这种情况。
2. 确认你的NANO是在高功耗 (10W) 模式下:
sudo nvpmodel -m 0
这通常是一个默认设置。然而,最好还是检查一下。低功耗(5W)模式降低了板的计算性能。
3. 禁用swap——swap会导致Kubernetes的问题:
sudo swapoff -a
4.将NVidia运行时设置为Docker中的默认运行时。对于这个编辑/etc/docker/daemon.json文件,所以它看起来像这样:
在这里提供的设置中,上面的设置是非常、非常、非常关键的。如果您没有正确地设置此选项,您将遇到很多问题。关于为什么需要这个的详细信息,请看这里的例子
https://github.com/NVIDIA/nvidia-docker/wiki/Advanced-topics#default-runtime.
通过改变默认的运行时,你可以确保每个Docker命令和每个基于Docker的工具都可以访问GPU。
5. 最后,只是为了确保,更新您的系统到最新版本的安装包:
sudo apt-get update sudo apt-get dist-upgrade
6. 将当前用户添加到docker组以使用docker命令而不使用sudo,请遵循以下指南: https://docs.docker.com/install/linux/linux-postinstall/.所需的命令如下:
sudo groupadd docker sudo usermod -aG docker $USER newgrp docker
7. 在所有这些之后,强烈建议重新启动系统。记住,它应该重新启动到文本模式,这很好!
测试Docker的GPU支持
在这一阶段,我们准备测试Docker是否正确运行并支持GPU。
为了更简单,我们使用CUDA SDK中的“deviceQuery”工具创建了一个专用的Docker图像,用于查询GPU并展示其功能。运行它的命令很简单:
docker run -it jitteam/devicequery ./deviceQuery
如果运行正常,会出现这个熟悉的画面:
如果您在输出的末尾看到“Result = PASS”,那么一切都会很好,您可以继续。如果没有,停止并调试这个问题(或者在评论中向我们提问)!
设置Kubernetes
1.静态IP寻址
为了简化网络设置,在设置Kubernetes之前,建议为Jetsons设置静态IP地址。这不是严格要求的,但它会使您的生活更容易。你可以通过不同的方法得到它——配置你的DHCP服务器来基于MAC地址静态分配地址或者手动配置每个板子上的网络。
安装Kubernetes
现在,我们准备安装Kubernetes与所有的依赖。这是通过以下命令实现的:
配置主节点
Kubernetes在最简单的设置中是主从类型的架构(在这里,从被称为工人)。我们需要配置一个主节点。在我们的例子中,这将是jetson1机器。所以这一步应该只在Jetsons中的一个上执行!
集群初始化:
sudo kubeadm init --pod-network-cidr=10.244.10.0/16 --kubernetes-version “1.15.2”
这个命令的输出相对复杂,但是我们需要仔细研究它。在我们的例子中,它看起来是这样的:
请注意,在底部有关于下一步要做什么(开始使用集群)的特定说明。消息的关键部分是“kubeadm连接”命令,其中包含IP地址、端口和秘密令牌(这与您的设置不同!)这是我们在其他节点(jetson2、jetson3和jetson4)上使用的基本命令。
现在,在所有工作节点上使用kubeadm连接命令!每个节点上的命令完全相同。
完成Kubernetes设置
现在,在您的主节点(jetson1)上,您应该能够看到集群中所有节点的列表:
kubectl get nodes
如果它返回一个错误消息,比如:“The connection to the server localhost:8080 was refused — did you specify the right host or port?”,运行以下命令:
sudo cp /etc/kubernetes/admin.conf $HOME/ sudo chown $(id -u):$(id -g) $HOME/admin.conf export KUBECONFIG=$HOME/admin.conf
…并重试。它应该会给出一个很好的节点列表。我们现在可以将新节点标记为worker:
....现在我们应该可以看到这样的东西:
当然,你的“AGE ”栏会有所不同。
运行第一个启用gpu的Pod
现在,我们准备检查启用了gpu的Pod (Kubernetes部署)是否工作。创建一个文件gpu-test.yaml,包含以下内容:
正如您所看到的,我们使用与之前相同的Docker映像来执行deviceQuery工具。我们把它提交给集群执行:
kubectl apply -f gpu-test.yml kubectl logs devicequery
输出应该与我们之前在Docker中运行“deviceQuery”的尝试相对应,因此我们不会在这里再次复制它。无论如何,在日志的末尾查找“Result = PASS”。
运行Tensorflow
我们快到了!现在是时候检查Tensorflow是否工作正常了!为此,我们创建另一个Pod。YAML文件tensorflow.yaml应该是这样的:
注意,这里的命令非常奇怪。Pod会运行…然后停止!这是有意的,因为我们要spin-up Pod,,然后访问它与互动会话,以检查事情是否顺利。
这里使用的Docker图像是我们的“jetson-nano-tf-gpu”。它是一个小型的Docker映像,带有当前版本的为Jetson Nano编译的启用gpu的Tensorflow。注意,由于Jetson Nano是基于ARM64的,标准的Tensorflow Docker图像将无法工作!
我们的Docker镜像发布在Docker Hub上(https://hub.docker.com/r/jitteam/jetson-nano-tf-gpu), 但是我们不能使用Docker Hub的构建基础设施来托管,因为映像本身需要构建在Jetson Nano上!作为参考,你可以看到下面的Dockerfile: https://github.com/jit-team/jetson-nano/tree/master/docker/jetson-nano-tf-gpu
如果你喜欢,你可以用它来创建你自己的图像。
tensorflow。准备好,让我们试着运行它,并访问Pod:
kubectl apply -f tensorflow.yml kubectl exec -it tf -- /bin/bash
外壳应该在运行的容器内产生,从那里我们可以验证Tensorflow是否工作,并看到我们的GPU。让我们执行:
python3 -c "from tensorflow.python.client import device_lib; print(device_lib.list_local_devices());"
输出大概是这样子的:
这证实了一个Kubernetes管理的实例,Docker托管的容器与一个新版本的Tensorflow可以与GPU通信,这是我们的最终目标。
有了这个工作,您就可以开始使用您的Tensorflow应用程序了。
最终的想法
这就完成了我们指令的第一部分。在这个阶段,我们有一个非常基本的Kubernetes集群,有3个支持GPU的工作节点和1个主节点,在这些节点上,您可以使用GPU加速Tensorflow运行机器学习工作负载来进行推理甚至训练。其他流行的机器学习框架也可以(但是,有时可能需要从源代码构建它们)。
我们仍然需要做的是开始使用NVidia设备插件Kubernetes,这是高度推荐的高负载集群 (https://github.com/NVIDIA/k8s-device-plugin),因为它可以帮助监控可用gpu的状态。