使用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)

0.png

各个软件版本都经过了我们在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已被正确识别。

1.PNG

接下来安装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
2.PNG

当pod启动(Running)后,您可以登录到pod并检查是否可以识别GPU。

kubectl exec -it gpu-pod /bin/bash
nvidia-smi

如果GPU被识别到,将会显示如下内容。

3.PNG

让我们最后尝试一下在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被成功识别并使用。

4.PNG

最后

我能够使用Kubernetes来利用GPU运行TensorFlow。
深度学习训练往往是临时性的运行,每次使用容器准备环境非常合适。
一旦开始利用深度学习,为了创建不同的模型,您将需要及时部署大量的容器来执行训练。
为此,像Kubernetes这样的容器编排工具非常方便。

使用Nvidia-docker来在容器中进行深度学习是一个有效的方法,但是当需要管理大量的容器时,就需要使用Kubernetes来利用GPU。

本次介绍了实现这两种需求的方法。
尽管在Kubernetes中使用GPU仍处于实验性的Alpha版功能阶段,但希望尽快达到GA,并变得更加方便易用。

广告
将在 10 秒后关闭
bannerAds