使用Kubernetes来运行Tensorflow并使用GPU
在Kubernetes上使用GPU来运行Tensorflow。
Kubernetes 1.8版本提供了一个实验性功能,允许从Pod中使用GPU。
使用Kubernetes的GPU的好处在于可以结合深度学习和容器编排。
在深度学习的训练阶段,使用GPU可以加快速度。
Nvidia还提供了Nvidia Docker,以便从Docker中使用GPU和CUDA,并且在容器中使用GPU已经成为一种有效的方法。
在Kubernetes中,也有对GPU使用的需求,并且目前可以在alpha版中使用。
使用Kubernetes来利用GPU的方式。
更详细的信息请参考以下链接,其中描述了将安装在主机服务器上的Nvidia CUDA和Cudnn库挂载到Pod并进行调用的机制。
https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/
另外,还有一些在Kubernetes 1.6上试验Kubernetes GPU的例子,这也可以作为参考。
环境
以下是使用的基础设施和软件:
– 基础设施:一台谷歌云平台(GCP)的Cloud Engine(虚拟机)
– 规格:4个CPU、15GB内存、100GB SSD、1个GPU(Nvidia K80)
– 操作系统:Ubuntu16.04
– Docker CE 17.03
– Kubernetes 1.8
– Nvidia CUDA 8.0
– Nvidia Cudnn 6.0
– Pod的容器镜像:gcr.io/tensorflow/tensorflow:latest-gpu(目前是Python2.7和Tensorflow1.4)
各个软件版本都经过了我们在2017年11月尝试的多种组合,最终找到了一个有效的组合。版本匹配起来确实很麻烦。
我选择使用GCP,原因是虚拟机部署速度快且按分钟计费。由于需要多次制作和破坏,以便稳定运行不同版本的软件,所以我需要能够快速重建,而且不会浪费金钱。
如果我没有错的话,AWS EC2是按秒计费的(惊讶)。
嗯,既然这次使用的 Kubernetes 和 Tensorflow 都是谷歌开发的,并且云端也可以选择谷歌,应该是很好的选择。
建立
在GCP的Cloud Engine上部署一台Ubuntu16.04虚拟机后,我们将首先进行更新并安装Docker CE,然后进行各种配置。有关Docker CE的安装方法,请参考以下链接:https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/。有关Kubeadm的独立安装,请参考以下链接:https://kubernetes.io/docs/setup/independent/install-kubeadm/。
# update Linux and install docker
sudo su -
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
apt-get -y update && apt-get -y upgrade
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/docker.list
deb https://download.docker.com/linux/$(lsb_release -si | tr '[:upper:]' '[:lower:]') $(lsb_release -cs) stable
EOF
apt-get update && apt-get install -y curl apt-transport-https git vim jq docker-ce=$(apt-cache madison docker-ce | grep 17.03 | head -1 | awk '{print $3}')
# start docker
systemctl start docker && systemctl enable docker
# set network
cat << EOF > /tmp/host
localhost
10.10.0.2
EOF
mkdir -p ~/.ssh/
for i in $(cat /tmp/host); do ssh-keyscan -H $i >> ~/.ssh/known_hosts ; done
下面是CUDA和Cudnn的安装过程。
当在Kubernetes上使用GPU时,需要加载主机服务器的库文件,因此主机服务器需要安装CUDA和Cudnn。
CUDA和Cudnn都可以使用版本指定进行安装。
详细信息请访问https://developer.nvidia.com/cuda-toolkit。
## find nvidia GPU
lspci | grep -i nvidia
# install requirements for cuda and cndnn
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/cuda-repo-ubuntu1604_8.0.61-1_amd64.deb
dpkg -i cuda-repo-ubuntu1604_8.0.61-1_amd64.deb
apt-get -y update
apt-get -y install --allow-unauthenticated cuda-8-0
echo 'export CUDA_HOME=/usr/local/cuda' >> /etc/profile
echo 'export PATH=/usr/local/cuda-8.0/bin:${PATH}' >> /etc/profile
echo 'export LD_LIBRARY_PATH=/usr/local/cuda-8.0/lib64:/usr/lib/nvidia-384:/usr/lib/nvidia:${CUDA_HOME}:${LD_LIBRARY_PATH}' >> /etc/profile
source /etc/profile
您可以使用wget获取CUDA的安装程序,但需要将Cudnn从浏览器中下载并上传到虚拟机。
请在以下命令之前下载Cudnn并上传到虚拟机。
下载Cudnn需要在Nvidia进行注册并回答问卷调查。
https://developer.nvidia.com/rdp/cudnn-download
# prerequisite: upload cudnn to the server
tar zxvf cudnn-8.0-linux-x64-v6.0.tgz
cp cuda/include/cudnn.h /usr/local/cuda/include
cp cuda/lib64/libcudnn* /usr/local/cuda/lib64
chmod a+r /usr/local/cuda/include/cudnn.h /usr/local/cuda/lib64/libcudnn*
nvcc --version
nvidia-smi
请确认GPU已被正确识别。
接下来安装Kubernetes。
使用Kubeadm进行构建,首先安装Kubeadm。
https://kubernetes.io/docs/setup/independent/install-kubeadm/
# install kube tools
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 <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get -y update
apt-get install -y --allow-unauthenticated kubelet kubeadm kubectl kubernetes-cni
为了在Kubernetes中使用GPU,需要在Kubelet的启动命令中添加–feature-gates=Accelerators=true选项。
可以通过将此选项追加到/etc/systemd/system/kubelet.service.d/目录下的*-kubeadm.conf文件中来添加该选项。
FILE_NAME=$(ls /etc/systemd/system/kubelet.service.d/*-kubeadm.conf)
sed -i '/^ExecStart=\/usr\/bin\/kubelet/ s/$/ --feature-gates=Accelerators=true/' ${FILE_NAME}
systemctl daemon-reload
systemctl restart kubelet
使用Kubeadm搭建Kubernetes集群。
https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/
# initialize kubeadm and kube cluster
kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=$(hostname -i)
systemctl enable kubelet && systemctl start kubelet
systemctl status kubelet -l
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
kubectl cluster-info
# install flannel
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.9.0/Documentation/kube-flannel.yml
kubectl get pods --all-namespaces
由于本次仅配置一个主服务器,所以需要启用对主服务器的部署。
# allow deployment to Kubernetes master
kubectl taint nodes --all node-role.kubernetes.io/master-
为了确认是否运作正常,我们将部署一家袜子店。
# deploy sample sock-shop app
kubectl create namespace sock-shop
kubectl apply -n sock-shop -f "https://github.com/microservices-demo/microservices-demo/blob/master/deploy/kubernetes/complete-demo.yaml?raw=true"
kubectl -n sock-shop get svc front-end
kubectl get pods -n sock-shop
如果能夠順利部署,我會將其刪除。
# delete after deployment
kubectl delete namespace sock-shop
使用Kubernetes来运行Tensorflow并利用GPU。
这样就已经构建完成了。
然后我们将从Kubernetes的Pod中使用GPU来运行Tensorflow。
Pod的定义yml如下:
将环境变量设置为CUDA、Cudnn等Nvidia GPU库的路径。
另外,由于Kubernetes使用主机服务器的库来运行GPU,所以将主机服务器上的CUDA、Cudnn等Nvidia GPU相关目录挂载到容器中。
(虽然我们可能挂载了很多东西,但也许有些是不必要的……)
cat <<- EOF > kubegpu.yml
kind: Pod
apiVersion: v1
metadata:
name: gpu-pod
spec:
containers:
- name: gpu-container
image: gcr.io/tensorflow/tensorflow:latest-gpu
resources:
limits:
alpha.kubernetes.io/nvidia-gpu: 1
env:
- name: CUDA_HOME
value: '/usr/local/cuda'
- name: PATH
value: '/usr/local/cuda-8.0/bin:${PATH}'
- name: LD_LIBRARY_PATH
value: '/usr/local/cuda-8.0/lib64:/usr/lib/nvidia-384:/usr/lib/nvidia:${CUDA_HOME}:${LD_LIBRARY_PATH}'
volumeMounts:
- mountPath: /usr/lib/nvidia-384/bin
name: bin
- mountPath: /usr/lib/nvidia-384
name: lib
- mountPath: /usr/local/cuda-8.0
name: cuda
- mountPath: /usr/lib/x86_64-linux-gnu
name: gnu
- mountPath: /usr/bin/nvidia-smi
name: nvs
- mountPath: /usr/local/cuda/lib64
name: clib64
- mountPath: /usr/local/cuda/include
name: include
volumes:
- hostPath:
path: /usr/lib/nvidia-384/bin
name: bin
- hostPath:
path: /usr/lib/nvidia-384
name: lib
- hostPath:
path: /usr/local/cuda-8.0
name: cuda
- hostPath:
path: /usr/lib/x86_64-linux-gnu
name: gnu
- hostPath:
path: /usr/bin/nvidia-smi
name: nvs
- hostPath:
path: /usr/local/cuda/lib64
name: clib64
- hostPath:
path: /usr/local/cuda/include
name: include
EOF
让我们试着动一下吧。
# create pod
kubectl create -f kubegpu.yml
# see if it is running
kubectl get pods
当pod启动(Running)后,您可以登录到pod并检查是否可以识别GPU。
kubectl exec -it gpu-pod /bin/bash
nvidia-smi
如果GPU被识别到,将会显示如下内容。
让我们最后尝试一下在Tensorflow中使用GPU。
我们将使用以下的程序:
https://www.tensorflow.org/tutorials/using_gpu
cat << EOF > ten.py
import tensorflow as tf
# Creates a graph.
a = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3], name='a')
b = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[3, 2], name='b')
c = tf.matmul(a, b)
# Creates a session with log_device_placement set to True.
sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
# Runs the op.
print(sess.run(c))
EOF
python ten.py
我正在运行类似上面简单计算的测试,看起来GPU被成功识别并使用。
最后
我能够使用Kubernetes来利用GPU运行TensorFlow。
深度学习训练往往是临时性的运行,每次使用容器准备环境非常合适。
一旦开始利用深度学习,为了创建不同的模型,您将需要及时部署大量的容器来执行训练。
为此,像Kubernetes这样的容器编排工具非常方便。
使用Nvidia-docker来在容器中进行深度学习是一个有效的方法,但是当需要管理大量的容器时,就需要使用Kubernetes来利用GPU。
本次介绍了实现这两种需求的方法。
尽管在Kubernetes中使用GPU仍处于实验性的Alpha版功能阶段,但希望尽快达到GA,并变得更加方便易用。