25
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

KubernetesAdvent Calendar 2017

Day 4

KubernetesからGPUを使ってTensorflowを動かす

Last updated at Posted at 2017-12-03

KubernetesからGPUを使ってTensorflowを動かす

Kubernetes 1.8ではα版(実験的)機能としてPodからGPUを使うことが可能になっています。
KubernetesからGPUを使うメリットは、ディープラーニングとコンテナ・オーケストレーションを組み合わせられることです。
ディープラーニングのトレーニングフェーズではGPUを使うことでスピードアップするのが一般的です。
NvidiaもDockerからGPUとCUDAを使うためのNvidia Dockerを提供しており、コンテナ上でGPUを使うのは有効な手段として広まっていっていると感じます。
KubernetesでもGPU使用が要望されており、現在はα版として使用可能になっています。

KubernetesからGPUを使う方法

詳しくは以下で書かれていますが、ホストサーバにインストールしたNvidia CUDAやCudnnのライブラリをPodにマウントして呼び出す仕組みになっています。
https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/

なお、Kubernetes on GPUをKubernetes1.6で試している例もありますので、こちらも参考になります。
https://github.com/Langhalsdino/Kubernetes-GPU-Guide

環境

インフラ、ソフトウェアは以下を使います。

  • 基盤:Google Cloud Platform(GCP)のCloud Engine(仮想マシン)1台
  • スペック:4CPU, 15GB RAM, 100GB SSD, 1GPU(Nvidia K80)
  • OS: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は秒単位課金になっていたんですね(驚き)。
http://www.itmedia.co.jp/news/articles/1709/19/news049.html

まあ今回使うKubernetesもTensorflowもGoogle発ですし、クラウドもGoogleで揃えて良いでしょう。

構築

それでは早速構築していきます。
GCPのCloud EngineでUbuntu16.04仮想マシンを1台配備したら、まずはアップデートしてDocker CEをインストールして諸々設定します。
Docker CEのインストール方法は以下をご参照ください。
https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/
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

CUDAはwgetでインストーラを入手できますが、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

今回はマスター1台のみの構成にするので、マスターへのデプロイを有効化します。

# 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からGPUを使ってTensorflowを動かす

これで構築完了です。
それではKubernetesのPodからGPUを使ってTensorlfowを動かします。

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

起動(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でGPUを使う方法が有効ですが、多数のコンテナを管理しようとなると、KubernetesでGPUを使う必要が出てきます。

今回はこの両方のニーズを実現する方法を紹介しました。
KubernetesからGPUを使うのはまだ実験的なα版機能ですが、はやくGAしてもっと手軽に使えるようになってほしいものです。

25
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?