专栏名称: 机器之心
专业的人工智能媒体和产业服务平台
目录
相关文章推荐
黄建同学  ·  3D生成Rodin,第一次引入了 ... ·  2 天前  
宝玉xp  ·  brilliant.org ... ·  2 天前  
爱可可-爱生活  ·  【Preference Proxy ... ·  5 天前  
宝玉xp  ·  //@_慎行_:GPT已经极大提升我的工作效 ... ·  5 天前  
宝玉xp  ·  //@韦恩卑鄙:补一句 一样好的技术 ... ·  6 天前  
51好读  ›  专栏  ›  机器之心

教程 | 如何使用Kubernetes GPU集群自动训练和加速深度学习?

机器之心  · 公众号  · AI  · 2017-06-14 12:24

正文

选自GitHub

机器之心编译

参与:蒋思源、Smith、吴攀


像 Docker 这样的容器格式和 Kubernetes 之类的容器管理平台正越来越受到人们的欢迎,这不仅仅是因为人们喜欢微服务,出于很多原因,公司的首席信息官和工程高管都乐于接受微服务,他们也会把容器视为他们的混合云战略的关键组成部分。这是因为容器空间(Docker、Kubernetes 和 DC / OS 等)的核心技术、生态系统是全面开源的,这为用户提供了抽象的虚拟化工具。近日,卡尔斯鲁厄理工学院(KIT)的计算机科学学生 Frederic J. Tausch 在 GitHub 上发布了一篇详细教程,「可以帮助研究人员和爱好者们用他们的 Kubernetes GPU 集群轻松地对深度学习的训练过程进行自动操作和加速。」机器之心对本教程进行了编译。


教程地址及相关文件:https://github.com/Langhalsdino/Kubernetes-GPU-Guide


在这个教程中,我将要介绍如何轻松地在多个 Ubuntu 16.04 裸机服务器上进行 Kubernetes GPU 集群配置,并且提供一些有用的脚本和.yaml 文件,它们可以给你提供全部配置。


顺便说一句:如果你是用 Kubernetes GPU 集群做一些其他的东西,这篇教程也同样适用于你。


我为什么要写这篇教程?


我现在是新创办的 understand.ai 公司的一名实习生,我在平时的工作中注意到:先在本地设置机器学习算法,然后把它放进云端用不同参数和数据集去进行训练,这一过程是很麻烦的。


第二点,把它放进云端进行大量的训练往往比预想的还要费时间,这是令人沮丧的,并且通常包含很多缺陷。


基于这个原因我下定决心要解决这个问题,并且让第二部分变得容易,简单,快捷。

这是一篇实践教程,是关于怎样设置我们自己的 Kubernetes GPU 集群来提升工作速度的。


深度学习科研人员的新工作流程:


用 Kubernetes GPU 集群进行自动化的深度学习训练显著地改善了在云端进行模型训练的流程。


此说明呈现了新的工作流程,只包含两个简单步骤:



免责声明:


请注意,以下部分仅代表个人观点。Kubernetes 是一个正在快速升级的环境,这意味着本篇教程可能会在将来的某个时间失效,这取决于工作者们的空余时间和个人贡献。由于这个原因我们也很希望大家可以群策群力,做出新的贡献。


目录


  • Kubernetes 的快速回顾

  • 集群结构概览

  • 初始化节点

  • 我的配置

  • 配置指令

  • 使用快速配置的脚本

  • 步骤的详细说明

  • 怎样创建你的 GPU 容器

  • .yml 的重要部分

  • GPU 实例的使用

  • 一些有用的指令

  • 致谢

  • 作者

  • 版权


Kubernetes 的快速回顾


如果你需要更新你的 Kubernetes 的相关知识,这些文章可能对你是有用处的:


  •  Introduction to Kubernetes by DigitalOcean (https://www.digitalocean.com/community/tutorials/an-introduction-to-kubernetes)

  • Kubernetes concepts (https://kubernetes.io/docs/concepts/)

  • Kubernetes by example (http://kubernetesbyexample.com/)

  • Kubernetes basics - interactive tutorial (https://kubernetes.io/docs/tutorials/kubernetes-basics/)


集群结构的概览


主要思想:即用一个小 CPU 作为主控节点(master node)来控制一个集群的 GPU-工作节点(GPU-worker nodes)。



初始化节点


在我们使用集群之前,先对集群进行初始化是很重要的。因此每个节点必须被手动初始化,然后才能加入到集群当中。


我的配置


此配置对上述案例十分适用——对其他实例或操作系统来说,往往需要一些额外的调试。


Master 主控节点


  • 有根权限的 Ubuntu 16.04

  • 我使用的是谷歌计算引擎 VM-Instance

  • SSH 访问

  • ufw 停用

  • 启用端口(udp 和 tcp)

  • 6443, 443, 8080 

  • 30000-32767(仅在你的应用需要它们的情况下)

  • 从集群外部访问服务器


Worker 工作站


  • 有根权限的 Ubuntu16.04

  •  我使用的是谷歌计算引擎

  • SSH 访问

  • ufw 停用

  • 启用端口(udp 和 tcp)

  •  6443, 443


关于安全性:在使用过程中你应该关闭一些防火墙——为了更加简单,应该禁用 ufw。为实际的生产工作负载设置 Kubernetes 当然应该包括启用一些防火墙,像 ufw, iptables 或你的云端服务器的防火墙。也要注意在云端设置一个工作集群可能更加复杂。你的云端供应商通常会提供一个他们自己的防火墙,这是和主机防火墙相分离的。你可能必须要停用 ufw,并且也要启用云端供应商的防火墙,使本教程的步骤可以正常进行下去。


设置向导


这些说明涵盖了我们在 Ubuntu 16.04 系统上的操作经验,可能有些地方并不适合于转移到其他操作平台。


如下所示,我们构建了两个脚本,它们能完全启动主控节点(master node)和工作节点(worker node)。如果你希望快速运行,那么就只需要使用以下两个脚本就行。否则的话,我建议跟着设置向导一步步阅读。


快速通道—设置脚本


下面我们将利用脚本进行快速设定。首先需要复制对应的脚本到主节点和工作节点的机器上:


  • 主控节点:https://github.com/Langhalsdino/Kubernetes-GPU-Guide/blob/master/scripts/init-master.sh

  • 工作结点:https://github.com/Langhalsdino/Kubernetes-GPU-Guide/blob/master/scripts/init-worker.sh


主控节点


执行上面的主控节点初始化脚本,并记下代号。代号通常看起来像:--token f38242.e7f3XXXXXXXXe231e


chmod +x init-master.sh

sudo ./init-master.sh


工作节点


执行上面的工作节点初始化脚本,并要求输入正确的主控节点代号和 IP,端口通常使用 6443。


chmod +x init-worker.sh

sudo ./init-worker.sh :


详细的安装说明


主控节点


1. 添加 Kubernetes 资源库到软件包管理器中:


sudo bash -c 'apt-get update && apt-get install -y apt-transport-https

curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -

cat </etc/apt/sources.list.d/kubernetes.list

deb http://apt.kubernetes.io/ kubernetes-xenial main

EOF

apt-get update'


2. 安装 docker-engine、kubeadm、kubectl 和 kubernetes-cni 库


sudo apt-get install -y docker-engine

sudo apt-get install -y kubelet kubeadm kubectl kubernetes-cni

sudo groupadd docker

sudo usermod -aG docker $USER

echo 'You might need to reboot / relogin to make docker work correctly'


3. 因为我们希望使用 GPU 构建一个计算机集群,所以我们需要 GPU 能在主控节点中进行加速。当然,也许该说明会因为新版本的 Kubernetes 出现而需要更改。


3.1 将 GPU 支持添加到 Kubeadm 配置中,这个时候集群是没有初始化的。这一步需要在集群每一个节点的机器中完成,即使有一些没有 GPU。


sudo vim /etc/systemd/system/kubelet.service.d/<>-kubeadm.conf


因此,添加 flag --feature-gates="Accelerators=true" 到 ExecStart 中,命令行大概如下所示:


ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS [...] --feature-gates="Accelerators=true"


3.2 重启 kubelet


sudo systemctl daemon-reload

sudo systemctl restart kubelet


4. 现在我们需要初始化主控节点。


这一步我们需要主控节点的 IP,同时该步骤也会提供添加其他工作结点的认证信息,所以还是需要记住代号。代号通常看起来像:--token f38242.e7f3XXXXXXXXe231e 130.211.XXX.XXX:6443


sudo kubeadm init --apiserver-advertise-address=


5. 自从 Kubernetes 1.6 从 ABAC roll-management 改为 RBAC,我们需要通知用户的认证信息。每一次在登录机器时,我们都需要执行这一步骤。


sudo cp /etc/kubernetes/admin.conf $HOME/

sudo chown $(id -u):$(id -g) $HOME/admin.conf

export KUBECONFIG=$HOME/admin.conf


6. 安装网络扩展以令 pod 能相互交流。Kubernetes 1.6 对安装这种网络扩展有一些环境要求,如:


  • CNI-based 网络

  • RBAC 支持环境


下面该链接汇聚了一些合适的网络扩展:https://docs.google.com/spreadsheets/d/1Nqa6y4J3kEE2wW_wNFSwuAuADAl74vdN6jYGmwXRBv8/edit#gid=0


kubectl apply -f https://git.io/weave-kube-1.6


5.2 现在检查 pod,以确定所有 pod 在线验证了能正常运行。


kubectl get pods --all-namespaces


注意:如果你需要删除主控节点,那么你就需要重置它。


sudo kubeadm reset


工作节点


前面的部分和主控节点的步骤是差不多的,所以可能设置地快一些。


1. 添加 Kubernetes 资源库到软件包管理器中:


sudo bash -c 'apt-get update && apt-get install -y apt-transport-https

curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -

cat </etc/apt/sources.list.d/kubernetes.list

deb http://apt.kubernetes.io/ kubernetes-xenial main

EOF

apt-get update'


2. 安装 docker-engine、kubeadm、kubectl 和 kubernetes-cni 库


sudo apt-get install -y docker-engine

sudo apt-get install -y kubelet kubeadm kubectl kubernetes-cni

sudo groupadd docker

sudo usermod -aG docker $USER

echo 'You might need to reboot / relogin to make docker work correctly'


3. 因为我们希望使用 GPU 构建一个计算机集群,所以我们需要 GPU 能在工作结点中进行加速。当然,也许该说明会因为更新版本的 Kubernetes 出现而需要更改。


3.1 将 GPU 支持添加到 Kubeadm 配置中,这个时候集群是没有初始化的。这一步需要在集群的每一个节点中完成,即使有一些没有 GPU。


sudo vim /etc/systemd/system/kubelet.service.d/<>-kubeadm.conf


因此,添加 flag --feature-gates="Accelerators=true" 到 ExecStart 中,命令行大概如下所示:


ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS [...] --feature-gates="Accelerators=true"


3.2 重启 kubelet


sudo systemctl daemon-reload

sudo systemctl restart kubelet


4. 现在我们需要将工作站添加到集群中。


因此,你需要记住主控节点的代号(token),以在工作站中添加:


sudo kubeadm join --token f38242.e7f3XXXXXXe231e 130.211.XXX.XXX:6443


5. 完成了,现在检查你的工作结点以确保能正常运行。


kubectl get nodes


注意:如果你想删除工作节点,那么就需要从集群中移除节点并重置工作节点。另外,从计算机集群移除工作节点是有益的。


在主控节点:


kubectl delete node


在工作结点:


sudo kubeadm reset


为了控制你的集群,比如从你的客户端(client)到你的主控节点(master),你需要用正确的用户来认证你的客户端(client)。这篇指导没有说明给客户端创建单独用户的内容,我们只是从主控节点来复制用户。


[Instruction to add custom user, will be added in the future]


在你的客户端上安装 kubectl。我仅用 Mac 进行了测试,在 Linux 系统里应该也可以正常工作。但我不知道在 Windows 系统里怎么样。


在 Mac 上


brew install kubectl


在 Ubuntu 上你也要遵循官方指导 https://kubernetes.io/docs/tasks/tools/install-kubectl/,或者你可以从上述关于工作站(worker)的指导(可能仅适用于 Ubuntu)中提取出你需要的步骤。


2. 从主节点复制管理权限到你的客户端。


scp [email protected]:~/admin.conf ~/.kube/


3. 添加 admin.conf 配置和授予 Kubernetes 配置认证。你需要为每一个代理完成该步骤。


export KUBECONFIG=~/.kube/admin.conf


现在你已经准备好在本地客户端使用 kubectl 了。


3.2 可以通过列出你所有的 pod 而测试。


kubectl get pods --all-namespaces


安装 Kubernetes 控制面板


Kubernetes 控制面板非常美观和简洁,它可以令脚本小子(script kiddies)有机会实现很多功能。为了使用控制面板,我们首先需要运行客户端,而 RBAC 能确保这一点。


你可以在主节点或从客户端直接执行下面两个步骤:


1. 检查控制面板是否已经安装了 kubectl:get pods --all-namespaces | grep dashboard

2. 如果控制面板没有安装,请安装:


  • kubectl create -f https://git.io/kube-dashboard


如果这没效果,请检查 .yaml git.io/kube-dashboard 中是否定义了容器。(这个 bug 花了我好多时间)


为了访问你的控制面板(dashboard),你需要为你的客户端授权。


3. 为你的客户端配置控制面板代理


在你的客户端运行以下代码:


kubectl proxy


4. 在你的浏览器中访问 127.0.0.1:8001/ui 进入控制面板。


怎么构建你的 GPU 容器


这个指导应该可以帮助你让一个需要 GPU 接入的 Docker 容器运行起来。


在这个指南中,我构建了一个示例 Docker 容器,其使用了 TensorFlow GPU 二进制文件,且可以在一个 Jupyter Notebook 中运行 TensorFlow 程序。


记住,本指南是为 Kubernetes 1.6 编写的,如果你的配置不一样,可能会需要一些修改。


.yml 的关键部分


为了让你带有 CUDA 的英伟达 GPU 正常运行,你必须将英伟达驱动和 CUDA 库传递到你的容器。所以我们将使用 hostPath 以确保 Kubernetes pod 可以使用它们。其实际路径因机器不同而有所差别,因为它们是由你的英伟达驱动和 CUDA 安装定义的。


volumes:

 - hostPath:

 path: /usr/lib/nvidia-375/bin

 name: bin

 - hostPath:

 path: /usr/lib/nvidia-375

 name: lib


将带有驱动和 CUDA 的卷安装到正确的目录,以便你的容器使用。这个目录可能配置得不一样,具体看你的情况:


volumeMounts:

 - mountPath: /usr/local/nvidia/bin

 name: bin

 - mountPath: /usr/local/nvidia/lib

 name: lib


因为你需要告诉 Kubernetes 你需要多少个 GPU,所以你可以在这里定义你的需求:


resources:

 limits:

 alpha.kubernetes.io/nvidia-gpu: 1


就是这些了。这就是构建你的 Kubernetes 1.6 容器所需要的一切。


后面给出了一些笔记。这里描述一下我的整个经历:


Kubernetes + Docker + Machine Learning + GPUs = Pure awesomeness


GPU 部署举例


我的 example-gpu-deployment.yaml 文件描述了 2 个部分——一个部署(deployment)和一个服务(service),因为我想通过外部访问这个 jupyter notebook。


运行 kubectl,使之可以外部可用:


kubectl create -f deployment.yaml


该 deployment.yaml 文件看起来是这样的:


---

apiVersion: extensions/v1beta1

kind: Deployment

metadata:

 name: tf-jupyter

spec:

 replicas: 1

 template:

 metadata:

 labels:

 app: tf-jupyter

 spec:

 volumes:

 - hostPath:

 path: /usr/lib/nvidia-375/bin

 name: bin

 - hostPath:

 path: /usr/lib/nvidia-375

 name: lib

 containers:

 - name: tensorflow

 image: tensorflow/tensorflow:0.11.0rc0-gpu

 ports:

 - containerPort: 8888

 resources:

 limits:

 alpha.kubernetes.io/nvidia-gpu: 1

 volumeMounts:

 - mountPath: /usr/local/nvidia/bin

 name: bin

 - mountPath: /usr/local/nvidia/lib

 name: lib

---

apiVersion: v1

kind: Service

metadata:

 name: tf-jupyter-service

 labels:

 app: tf-jupyter

spec:

 selector:

 app: tf-jupyter

 ports:

 - port: 8888

 protocol: TCP

 nodePort: 30061

 type: LoadBalancer

---


为了验证该配置有效,请访问你的 JupyterNotebook 实例:http://:30061


现在你需要验证你的 JupyterNotebook 实例可以访问 GPU。因此,请在一个新的 Notebook 中运行以下代码。这会列出所有 TensorFlow 可用的设备。


from tensorflow.python.client import device_lib


def get_available_devices():

 local_device_protos = device_lib.list_local_devices()

 return [x.name for x in local_device_protos]

print(get_available_devices())


这应该会输出 [u'/cpu:0', u'/gpu:0'] 这样的结果。


一些有用的指令


获取基本输出指令


kubectl get services # List all services in the namespace

kubectl get pods --all-namespaces # List all pods in all namespaces

kubectl get pods -o wide # List all pods in the namespace, with more details

kubectl get deployments # List all deployments

kubectl get deployment my-dep # List a particular deployment


使用 verbose 输出描述指令


kubectl describe nodes

kubectl describe pods


删除资源


kubectl delete -f ./pod.yaml # Delete a pod using the type and name specified in pod.yaml

kubectl delete pod,service baz foo # Delete pods and services with same names "baz" and "foo"

kubectl delete pods,services -l name=

kubectl -n delete po,svc --all # Delete all pods and services in namespace my-ns


进入你的一个 pod 的 bash 控制台:


kubectl exec -it -- /bin/bash



本文为机器之心编译,转载请联系本公众号获得授权

✄------------------------------------------------

加入机器之心(全职记者/实习生):[email protected]

投稿或寻求报道:[email protected]

广告&商务合作:[email protected]


点击阅读原文,查看机器之心官网↓↓↓