[Kubeflow] 初探基本功能與概念

Kubeflow 是 Google 開源的機器學習工具,目標是簡化在 Kubernetes 上運行機器學習的過程,使之更簡單、可攜帶與可擴展。Kubeflow 目標不是在於重建其他服務,而是提供一個最佳開發系統來部署到各種基礎設施架構中,另外由於使用 Kubernetes 來做為基礎,因此只要有 Kubernetes 的地方,都能夠執行 Kubeflow。

該工具能夠建立以下幾項功能:

  • 用於建議與管理互動式 Jupyter notebook 的 JupyterHub。
  • 可以設定使用 CPU 或 GPU,並透過單一設定調整單個叢集大小的 Tensorflow Training Controller。
  • 用 TensorFlow Serving 容器來提供模型服務。

Kubeflow 目標是透過 Kubernetes 的特性使機器學習更加簡單與快速:

  • 在不同基礎設施上實現簡單、可重複的攜帶性部署(Laptop <-> ML rig <-> Training cluster <-> Production cluster)。
  • 部署與管理松耦合的微服務。
  • 根據需求進行縮放。

節點資訊

本次安裝作業系統採用Ubuntu 16.04 Server,測試環境為實體機器:

IP Address Role vCPU RAM Extra Device
172.22.132.51 gpu-node1 8 16G GTX 1060 3G
172.22.132.52 gpu-node2 8 16G GTX 1060 3G
172.22.132.53 master1 8 16G

事前準備

使用 Kubeflow 之前,需要確保以下條件達成:

  • 所有節點正確安裝指定版本的 NVIDIA driver、CUDA、Docker、NVIDIA Docker,請參考 安裝 Nvidia Docker 2
  • (option)所有 GPU 節點安裝 cuDNN v7.1.2 for CUDA 9.1,請至 NVIDIA cuDNN 下載。
$ tar xvf cudnn-9.1-linux-x64-v7.1.tgz
$ sudo cp cuda/include/cudnn.h /usr/local/cuda/include/
$ sudo cp cuda/lib64/libcudnn* /usr/local/cuda/lib64/
# 在 master 執行
$ sudo apt-get update && sudo apt-get install -y nfs-server
$ sudo mkdir /nfs-data
$ echo "/nfs-data *(rw,sync,no_root_squash,no_subtree_check)" | sudo tee -a /etc/exports
$ sudo /etc/init.d/nfs-kernel-server restart

# 在 node 執行
$ sudo apt-get update && sudo apt-get install -y nfs-common
  • 安裝ksonnet 0.9.2,請參考以下:
$ wget https://github.com/ksonnet/ksonnet/releases/download/v0.9.2/ks_0.9.2_linux_amd64.tar.gz
$ tar xvf ks_0.9.2_linux_amd64.tar.gz
$ sudo cp ks_0.9.2_linux_amd64/ks /usr/local/bin/
$ ks version
ksonnet version: 0.9.2
jsonnet version: v0.9.5
client-go version: 1.8

部署 Kubeflow

本節將說明如何利用 ksonnet 來部署 Kubeflow 到 Kubernetes 叢集中。首先在master節點初始化 ksonnet 應用程式目錄:

$ ks init my-kubeflow

如果遇到以下問題的話,可以自己建立 GitHub Token 來存取 GitHub API,請參考 Github rate limiting errors

ERROR GET https://api.github.com/repos/ksonnet/parts/commits/master: 403 API rate limit exceeded for 122.146.93.152.

接著安裝 Kubeflow 套件至應用程式目錄:

$ cd my-kubeflow
$ ks registry add kubeflow github.com/kubeflow/kubeflow/tree/master/kubeflow
$ ks pkg install kubeflow/core
$ ks pkg install kubeflow/tf-serving
$ ks pkg install kubeflow/tf-job

然後建立 Kubeflow 核心元件,該元件包含 JupyterHub 與 TensorFlow job controller:

$ kubectl create namespace kubeflow
$ kubectl create clusterrolebinding tf-admin --clusterrole=cluster-admin --serviceaccount=default:tf-job-operator
$ ks generate core kubeflow-core --name=kubeflow-core --namespace=kubeflow

# 啟動收集匿名使用者使用量資訊,如果不想開啟則忽略
$ ks param set kubeflow-core reportUsage true
$ ks param set kubeflow-core usageId $(uuidgen)

# 部署 Kubeflow
$ ks param set kubeflow-core jupyterHubServiceType LoadBalancer
$ ks apply default -c kubeflow-core

詳細使用量資訊請參考 Usage Reporting

完成後檢查 Kubeflow 元件部署結果:

$ kubectl -n kubeflow get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE
ambassador-7956cf5c7f-6hngq 2/2 Running 0 34m 10.244.41.132 kube-gpu-node1
ambassador-7956cf5c7f-jgxnd 2/2 Running 0 34m 10.244.152.134 kube-gpu-node2
ambassador-7956cf5c7f-jww2d 2/2 Running 0 34m 10.244.41.133 kube-gpu-node1
spartakus-volunteer-8c659d4f5-bg7kn 1/1 Running 0 34m 10.244.152.135 kube-gpu-node2
tf-hub-0 1/1 Running 0 34m 10.244.152.133 kube-gpu-node2
tf-job-operator-78757955b-2jbdh 1/1 Running 0 34m 10.244.41.131 kube-gpu-node1

這時候就可以登入 Jupyter Notebook,但這邊需要修改 Kubernetes Service,透過以下指令進行:

$ kubectl -n kubeflow get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
ambassador ClusterIP 10.101.157.91 <none> 80/TCP 45m service=ambassador
ambassador-admin ClusterIP 10.107.24.138 <none> 8877/TCP 45m service=ambassador
k8s-dashboard ClusterIP 10.111.128.104 <none> 443/TCP 45m k8s-app=kubernetes-dashboard
tf-hub-0 ClusterIP None <none> 8000/TCP 45m app=tf-hub
tf-hub-lb ClusterIP 10.105.47.253 <none> 80/TCP 45m app=tf-hub

# 修改 svc 將 Type 修改成 LoadBalancer,並且新增 externalIPs 指定為 Master IP。
$ kubectl -n kubeflow edit svc tf-hub-lb
...
spec:
type: LoadBalancer
externalIPs:
- 172.22.132.41
...

測試 Kubeflow

開始測試前先建立一個 NFS PV 來提供給 Kubeflow Jupyter 使用:

$ cat <<EOF | kubectl create -f -
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
nfs:
server: 172.22.132.41
path: /nfs-data
EOF

完成後連接 http://Master_IP,並輸入任意帳號密碼進行登入。

登入後點選Start My Server按鈕來建立 Server 的 Spawner options,預設會有多種映像檔可以使用:

  • CPU:gcr.io/kubeflow-images-staging/tensorflow-notebook-cpu。
  • GPU:gcr.io/kubeflow-images-staging/tensorflow-notebook-gpu。

這邊也使用以下 GCP 建構的映像檔做測試使用(GPU 當前為 CUDA 8):

  • gcr.io/kubeflow/tensorflow-notebook-cpu:latest
  • gcr.io/kubeflow/tensorflow-notebook-gpu:latest

若 CUDA 版本不同,請自行修改 GCP Tensorflow Notebook image 或是 Kubeflow Tensorflow Notebook image 重新建構。

如果使用 GPU 請執行以下指令確認是否可被分配資源:

$ kubectl get nodes "-o=custom-columns=NAME:.metadata.name,GPU:.status.allocatable.nvidia\.com/gpu"
NAME GPU
kube-gpu-master1 <none>
kube-gpu-node1 1
kube-gpu-node2 1

最後點選Spawn來完成建立 Server,如下圖所示:

這邊先用 CPU 進行測試,由於本篇是安裝 CUDA 9.1 + cuDNN 7,因此要自己建構映像檔。

接著等 Kubernetes 下載映像檔後,就會正常啟動,如下圖所示:

當正常啟動後,點選New > Python 3建立一個 Notebook 並貼上以下範例程式:

from __future__ import print_function

import tensorflow as tf

hello = tf.constant('Hello TensorFlow!')
s = tf.Session()
print(s.run(hello))

正確執行會如以下圖所示:

若想關閉叢集的話,可以點選Control Plane

另外由於 Kubeflow 會安裝 TF Operator 來管理 TFJob,這邊可以透過 Kubernetes 來手動建立 Job:

$ kubectl create -f https://raw.githubusercontent.com/kubeflow/tf-operator/master/examples/tf_job.yaml
$ kubectl get po
NAME READY STATUS RESTARTS AGE
example-job-ps-qq6x-0-pdx7v 1/1 Running 0 5m
example-job-ps-qq6x-1-2mpfp 1/1 Running 0 5m
example-job-worker-qq6x-0-m5fm5 1/1 Running 0 5m

若想從 Kubernetes 叢集刪除 Kubeflow 相關元件的話,可執行下列指令達成:

$ ks delete default -c kubeflow-core
Share Comments