Kubeflow 使用指南

Kubeflow 使用指南

JupyterHub subsystemsKubeflow(https://github.com/kubeflow)是基於Kubernetes(https://kubernets.io,容器編排與管理服務軟件)和TensorFlow(https://tensorflow.org,深度學習庫)的機器學習流程工具,使用Ksonnet進行應用包的管理。html

本文簡要介紹Kubeflow的部署和交互操做的基本概念和方法,對於Kubernetes、Tensorflow和Ksonnet 的瞭解對於本文內容的理解將頗有幫助,點擊下面的連接查看相關的內容。node

對部署Kubeflow和運行一個簡單的訓練任務的手把手教的例子,能夠看這個教程( tutorial)。git

環境要求

部署 Kubeflow

咱們將使用Ksonnet來部署kubeflow到Kubernetes集羣上,支持本地的和GKE、Azure中的集羣。github

初始化一個目錄,包含有ksonnet application。docker

ks init my-kubeflow

安裝Kubeflow packages到Ksonnet application中。json

# For a list of releases see:
# https://github.com/kubeflow/kubeflow/releases
VERSION=v0.1.2

cd my-kubeflow
ks registry add kubeflow github.com/kubeflow/kubeflow/tree/${VERSION}/kubeflow
ks pkg install kubeflow/core@${VERSION}
ks pkg install kubeflow/tf-serving@${VERSION}
ks pkg install kubeflow/tf-job@${VERSION}

建立Kubeflow core component. 這個core component 包括:api

ks generate core kubeflow-core --name=kubeflow-core

# Enable collection of anonymous usage metrics
# Skip this step if you don't want to enable collection.
# Or set reportUsage to false (the default).
ks param set kubeflow-core reportUsage true
ks param set kubeflow-core usageId $(uuidgen)

Ksonnet 容許參數化 Kubeflow的部署,能夠按照需求設定。咱們定義兩個環境變量:nocloud和cloud。瀏覽器

ks env add nocloud
ks env add cloud

環境變量 nocloud 用於 minikube和其它的標準 k8s clusters,環境變量 cloud 用於GKE和Azure。安全

若是使用 GKE, 咱們配置雲計算環境的參數來使用 GCP的特徵,以下:服務器

ks param set kubeflow-core cloud gke --env=cloud

若是集羣建立在 Azure 上,使用 AKS/ACS:

ks param set kubeflow-core cloud aks --env=cloud

若是建立時使用acs-engine來代替:

ks param set kubeflow-core cloud acsengine --env=cloud

而後咱們設置 ${KF_ENV} 爲 cloud 或 nocloud ,從而反映咱們在本教程中使用的環境。

$ KF_ENV=cloud|nocloud
  • 缺水狀況下,Kubeflow沒有持久化咱們在Jupyter notebook所作的工做。
  • 若是容器被銷燬或從新建立,全部的內容,包括 notebooks 和其它的文件都會被刪除。
  • 爲了持久化這些文件,用戶須要一個缺省的 StorageClass,在 persistent volumes 中定義。
  • 能夠運行下面的命令來檢查是否有了一個 storage class。
kubectl get storageclass
  • 有了缺省的storage class定義的用戶,可使用jupyterNotebookPVCMount參數去建立一個volume,將被掛載到notebook之中。

    ks param set kubeflow-core jupyterNotebookPVCMount /home/jovyan/work
    • 這裏咱們掛載捲到 /home/jovyan/work ,由於notebook一直以用戶jovyan來執行。
    • 選中的目錄將被存儲到集羣的缺省存儲上(典型地是永久磁盤)。

建立部署的命名空間(namespace)而且設爲換的一部分。能夠將namespace設爲更適合你本身的kubernetes cluster的名稱,以下。

NAMESPACE=kubeflow
kubectl create namespace ${NAMESPACE}
ks env set ${KF_ENV} --namespace ${NAMESPACE}

而後應用該components到咱們的Kubernetes cluster。

ks apply ${KF_ENV} -c kubeflow-core

任什麼時候候,可使用 ks show 探查特定的 ksonnet component在kubernetes的對象定義。

ks show ${KF_ENV} -c kubeflow-core

用法報告(Usage Reporting)

當啓用時,Kubeflow將使用 spartakus 報告匿名數據,這是Kubernetes的一個彙報工具。Spartakus不會報告任何我的信息。查看 here 獲得更多細節。這是徹底志願的行爲,也能夠可選將其關閉,以下所示:

ks param set kubeflow-core reportUsage false

# Delete any existing deployments of spartakus
kubectl delete -n ${NAMESPACE} deploy spartakus-volunteer

爲了明確開啓用法報告,設置 reportUsage 爲 true,以下所示:

ks param set kubeflow-core reportUsage true

# Delete any existing deployments of spartakus
kubectl delete -n ${NAMESPACE} deploy spartakus-volunteer

報告數據是你對Kubeflow的顯著貢獻之一,因此請考慮將其開啓。這些數據容許咱們改善Kubeflow項目而且幫助Kubeflow上開展工做的企業評估其持續的投資。

你能夠改進數據質量,經過給每個Kubeflow deployment 一個單獨的ID。

ks param set kubeflow-core usageId $(uuidgen)

打開 Jupyter Notebook

這裏的 kubeflow-core component 部署JupyterHub和對應的load balancer service,查看狀態使用下面的 kubectl 命令行:

kubectl get svc -n=${NAMESPACE}

NAME               TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
...
tf-hub-0           ClusterIP      None            <none>        8000/TCP       1m
tf-hub-lb          ClusterIP      10.11.245.94    <none>        80/TCP         1m
...

缺水狀況下,咱們使用ClusterIPs來訪問JupyterHub UI,在下面狀況會有所改變:

  • NodePort (for non-cloud) ,經過指示:

    ks param set kubeflow-core jupyterHubServiceType NodePort
    ks apply ${KF_ENV}
  • LoadBalancer (for cloud) ,經過指示:

    ks param set kubeflow-core jupyterHubServiceType LoadBalancer
    ks apply ${KF_ENV}

可是,這將使 Jupyter notebook 開放予Internet網絡(有潛在的安全風險)。

本地鏈接到 Jupyter Notebook 可使用:

PODNAME=`kubectl get pods --namespace=${NAMESPACE} --selector="app=tf-hub" --output=template --template="{{with index .items 0}}{{.metadata.name}}{{end}}"`
kubectl port-forward --namespace=${NAMESPACE} $PODNAME 8000:8000

而後,到瀏覽器中打開 http://127.0.0.1:8000,若是設置了代理,須要對該地址關閉 。

將看到一個提示窗口。

  1. 使用任何username/password登陸。

  2. 點擊 "Start My Server" 按鈕,將會打開一個對話框。

  3. 選擇鏡像爲CPU 或 GPU 類型,在 Image一項有菜單列出預構建的Docker鏡像。也能夠直接輸入Tensorflow的鏡像名稱,用於運行。

  4. 分配內存、CPU、GPU和其餘的資源,根據需求而定。 (1 CPU 和 2Gi 內存已是一個好的起點,能夠知足初始練習的須要。)

    • 分配 GPUs, 須要確認你的集羣中有可用數量的 GPUs,GPU將會被容器實例獨佔使用,若是資源不夠,該實例將會一直掛起,處於Pending狀態。
    • 檢查是否有足夠的nvidia gpus可用: kubectl get nodes "-o=custom-columns=NAME:.metadata.name,GPU:.status.allocatable.nvidia\.com/gpu"
    • 若是 GPUs 可用,你能夠調度你的服務器到 GPU node,經過指定下面的json, 在 Extra Resource Limits section: {"nvidia.com/gpu": "1"}
  5. 點擊 Spawn

    • 該鏡像將近 10 GBs,下載須要比較長的時間,取決於網絡狀況。

    • 檢查 pod 的狀態,經過:

      kubectl -n ${NAMESPACE} describe pods jupyter-${USERNAME}
      • 這裏 ${USERNAME} 是你 login時用到的名稱。

      • GKE users,若是你有 IAP turned on the pod,將會名稱有所不一樣:

        jupyter-accounts-2egoogle-2ecom-3USER-40DOMAIN-2eEXT
  6. 完成後,將會打開 Jupyter Notebook 初始界面。

上面提供的容器鏡像能夠用於 Tensorflow models的訓練,使用Jupyter便可操做。該鏡像包含全部須要的plugins, 包括 Tensorboard,能夠用於對模型進行豐富的可視化和探查分析。

將來測試安裝狀況,咱們運行一個基本的hello world應用 (來自 mnist_softmax.py )

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

import tensorflow as tf

x = tf.placeholder(tf.float32, [None, 784])

W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

y = tf.nn.softmax(tf.matmul(x, W) + b)

y_ = tf.placeholder(tf.float32, [None, 10])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))

train_step = tf.train.GradientDescentOptimizer(0.05).minimize(cross_entropy)

sess = tf.InteractiveSession()
tf.global_variables_initializer().run()

for _ in range(1000):
  batch_xs, batch_ys = mnist.train.next_batch(100)
  sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))

粘貼上面的例子到新的 Python 3 Jupyter notebook,而後 shift+enter 執行代碼。這裏會獲得基於測試數據的 0.9014 結果精度。

須要注意的是,運行大多數 cloud providers時,public IP address 將會暴露到internet,而且缺省是沒有安全控制的endpoint。爲了產品級部署,須要使用 SSL 和 authentication, 參考 documentation

使用TensorFlow Serving提供model服務

咱們將每個部署的模型都做爲APP中的 component 。

在雲計算中建立一個模型的component:

MODEL_COMPONENT=serveInception
MODEL_NAME=inception
MODEL_PATH=gs://kubeflow-models/inception
ks generate tf-serving ${MODEL_COMPONENT} --name=${MODEL_NAME}
ks param set ${MODEL_COMPONENT} modelPath ${MODEL_PATH}

(或者) 建立一個model的component 在 nfs 上,瞭解和參考 components/k8s-model-server,以下:

MODEL_COMPONENT=serveInceptionNFS
MODEL_NAME=inception-nfs
MODEL_PATH=/mnt/var/nfs/general/inception
MODEL_STORAGE_TYPE=nfs
NFS_PVC_NAME=nfs
ks generate tf-serving ${MODEL_COMPONENT} --name=${MODEL_NAME}
ks param set ${MODEL_COMPONENT} modelPath ${MODEL_PATH}
ks param set ${MODEL_COMPONENT} modelStorageType ${MODEL_STORAGE_TYPE}
ks param set ${MODEL_COMPONENT} nfsPVC ${NFS_PVC_NAME}

部署model component。Ksonnet將選擇你的環境中的已存在的參數 (e.g. cloud, nocloud),而後定製化結果部署爲合適的:

ks apply ${KF_ENV} -c ${MODEL_COMPONENT}

以前, 一些pods和services已經建立在你的集羣中。你能夠查詢kubernetes獲得服務endpoint:

kubectl get svc inception -n=${NAMESPACE}
NAME        TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)          AGE
...
inception   LoadBalancer   10.35.255.136   ww.xx.yy.zz   9000:30936/TCP   28m
...

在這裏,你可使用的 inception_client 爲 ww.xx.yy.zz:9000

在gs://kubeflow-models/inception 的model 是能夠公開訪問的。可是,若是你的環境沒有配置google cloud credential,TF serving 將沒法讀取model,查看 issue 獲取樣本。爲了設置google cloud credential,你須要環境變量 GOOGLE_APPLICATION_CREDENTIALS 指向credential 文件,或者運行 gcloud auth login. 查看 doc 獲取更多詳細說明。

經過 Seldon 服務 model

Seldon-core 提供了任意機器學習運行時的部署,將其 packaged in a Docker container

安裝seldon package:

ks pkg install kubeflow/seldon

建立 core components:

ks generate seldon seldon

Seldon 容許複雜的 runtime graphs用於模型推理的部署。一個 end-to-end整合的例子參見 kubeflow-seldon example。更多的細節參考 seldon-core documentation

提交一個TensorFlow訓練任務

注意:在提交訓練任務以前,你首先須要有一個 deployed kubeflow to your cluster。提交訓練任務時,首先確認 TFJob custom resource 是可用的。

咱們將每個TensorFlow job做爲APP中的 component 看待。

A、建立工做任務

爲訓練任務建立 component:

JOB_NAME=myjob
ks generate tf-job ${JOB_NAME} --name=${JOB_NAME}

爲了配置這個 job須要設置一系列的參數。爲了查看參數列表,運行:

ks prototype describe tf-job

參數設置使用 ks param ,設置 Docker image 使用:

IMAGE=gcr.io/tf-on-k8s-dogfood/tf_sample:d4ef871-dirty-991dde4
ks param set ${JOB_NAME} image ${IMAGE}

你能夠編輯 params.libsonnet 文件,直接設置參數。

警告 因爲escaping序列問題,目前命令行的設置參數不能工做 (參見 ksonnet/ksonnet/issues/235)。所以,設置參數須要直接編輯 params.libsonnet 文件。

B、運行工做任務

ks apply ${KF_ENV} -c ${JOB_NAME}

C、監視工做任務

監視任務執行狀況,參見 TfJob docs.

D、刪除工做任務

ks delete ${KF_ENV} -c ${JOB_NAME}

運行例程-TfCnn

Kubeflow 附帶了一個 ksonnet prototype ,適合運行 TensorFlow CNN Benchmarks

建立component:

CNN_JOB_NAME=mycnnjob
ks generate tf-cnn ${CNN_JOB_NAME} --name=${CNN_JOB_NAME}

提交任務:

ks apply ${KF_ENV} -c ${CNN_JOB_NAME}

查看運行狀況 (注意 tf-cnn job 也是 tfjobs. 參考 TfJob docs)

kubectl get -o yaml tfjobs ${CNN_JOB_NAME}

刪除任務:

ks delete ${KF_ENV} -c ${CNN_JOB_NAME}

該 prototype提供了一系列參數控制任務的運行 (如使用 GPUs,分佈式運行等...)。查看參數運行:

ks prototype describe tf-cnn

提交 PyTorch 訓練任務

注意:在提交任務以前,你須要有一個部署好Kubeflow的集羣(參見 deployed kubeflow to your cluster)。提交,確保 PyTorchJob custom resource 可用。

咱們將每個PyTorch任務看做爲APP中的 component 。

爲工做任務建立一個 component。

JOB_NAME=myjob
ks generate pytorch-job ${JOB_NAME} --name=${JOB_NAME}

爲了配置工做任務,須要設置一系列的參數。 顯示參數使用:

ks prototype describe pytorch-job

參數設置使用 ks param ,設置Docker image 使用:

IMAGE=<your pytorch image>
ks param set ${JOB_NAME} image ${IMAGE}

也能夠編輯文件 params.libsonnet 來直接設置參數。

警告 因爲escaping序列問題,目前命令行的設置參數不能工做 (參見 ksonnet/ksonnet/issues/235)。所以,設置參數須要直接編輯 params.libsonnet 文件。

運行工做任務:

ks apply ${KF_ENV} -c ${JOB_NAME}

刪除工做任務:

ks delete ${KF_ENV} -c ${JOB_NAME}

高級定製

  • 數據科學家常常要求一個 POSIX 兼容的文件系統:
    • 例如,大多數HDF5 libraries 要求 POSIX,對於GCS或S3的object store沒法工做。
  • 當共享 POSIX 文件系統被掛載到 notebook 環境,數據科學家能夠在同一數據集上協同工做。
  • 這裏將展現如何部署Kubeflow來達到這個要求。

設置磁盤參數,以分號隔開,設置你想要掛載的 Google persistent disks。

  • 這些磁盤必須在你的集羣的同一個 zone 上。
  • 這些磁盤須要經過 gcloud 或 Cloud console手動建立。
  • 這些磁盤不能被引用到任何已存在的 VM 或 POD上。

建立磁盤:

gcloud --project=${PROJECT} compute disks create  --zone=${ZONE} ${PD_DISK1} --description="PD to back NFS storage on GKE." --size=1TB
  gcloud --project=${PROJECT} compute disks create  --zone=${ZONE} ${PD_DISK2} --description="PD to back NFS storage on GKE." --size=1TB

配置環境來使用這些磁盤:

ks param set --env=cloud kubeflow-core disks ${PD_DISK1},${PD_DISK2}

部署環境。

ks apply cloud

啓動Juptyer,你將能夠看見你的 NFS volumes 掛載爲 /mnt/${DISK_NAME}。在Juptyer cell中運行:

!df

將看到以下的輸出:

https://github.com/jlewi/deepvariant_on_k8s
Filesystem                                                     1K-blocks    Used  Available Use% Mounted on
overlay                                                         98884832 8336440   90532008   9% /
tmpfs                                                           15444244       0   15444244   0% /dev
tmpfs                                                           15444244       0   15444244   0% /sys/fs/cgroup
10.11.254.34:/export/pvc-d414c86a-e0db-11e7-a056-42010af00205 1055841280   77824 1002059776   1% /mnt/jlewi-kubeflow-test1
10.11.242.82:/export/pvc-33f0a5b3-e0dc-11e7-a056-42010af00205 1055841280   77824 1002059776   1% /mnt/jlewi-kubeflow-test2
/dev/sda1                                                       98884832 8336440   90532008   9% /etc/hosts
shm                                                                65536       0      65536   0% /dev/shm
tmpfs                                                           15444244       0   15444244   0% /sys/firmware
  • 這裏 jlewi-kubeflow-test1 和 jlewi-kubeflow-test2 是 PDs的名稱。

問題解決

Minikube

在 Minikube ,Virtualbox/VMware drivers是已知在 KVM/KVM2 driver 和 TensorFlow Serving之間的問題. 該問題跟蹤在 kubernetes/minikube#2377

咱們建議增長 Minikube分配的資源總量,以下:

minikube start --cpus 4 --memory 8096 --disk-size=40g
  • Minikube 缺省分配 2048Mb RAM給虛擬機,對於 JupyterHub是不夠的。
  • 最大的磁盤容量須要知足 Kubeflow's Jupyter images,包含額外的庫超過10G以上。

若是遇到jupyter-xxxx pod 進入Pending 狀態,獲取描述信息:

Warning  FailedScheduling  8s (x22 over 5m)  default-scheduler  0/1 nodes are available: 1 Insufficient memory.
  • 而後嘗試從新建立 Minikube cluster (從新使用Ksonnet應用 Kubeflow) ,並指定更多的資源。

RBAC clusters

若是你運行的集羣開啓了RBAC(參考 RBAC enabled),,運行Kubeflow可能遇到以下的錯誤:

ERROR Error updating roles kubeflow-test-infra.jupyter-role: roles.rbac.authorization.k8s.io "jupyter-role" is forbidden: attempt to grant extra privileges: [PolicyRule{Resources:["*"], APIGroups:["*"], Verbs:["*"]}] user=&{your-user@acme.com  [system:authenticated] map[]} ownerrules=[PolicyRule{Resources:["selfsubjectaccessreviews"], APIGroups:["authorization.k8s.io"], Verbs:["create"]} PolicyRule{NonResourceURLs:["/api" "/api/*" "/apis" "/apis/*" "/healthz" "/swagger-2.0.0.pb-v1" "/swagger.json" "/swaggerapi" "/swaggerapi/*" "/version"], Verbs:["get"]}] ruleResolutionErrors=[]

該錯誤指示沒有足夠的權限。在大多數狀況下,解決這個問題經過建立合適的 clusterrole binding 而後從新部署kubeflow:

kubectl create clusterrolebinding default-admin --clusterrole=cluster-admin --user=your-user@acme.com
  • 替換 your-user@acme.com 爲在錯誤信息提示的用戶名。

若是你使用 GKE, 你能夠參考 GKE's RBAC docs 去了解如何設置 RBAC,經過 IAM on GCP來實現。

spawning Jupyter pods的問題

若是你 spawning jupyter notebooks遇到麻煩,檢查該 pod 是否已經被調度運行:

kubectl -n ${NAMESPACE} get pods
  • 查看啓動juypter的pod名稱。
  • 若是使用username/password auth,Jupyter  pod 將被命名:
jupyter-${USERNAME}
  • 若是你使用 IAP on GKE,pod 將被命名爲:

    jupyter-accounts-2egoogle-2ecom-3USER-40DOMAIN-2eEXT

一旦你知道pod的名稱:

kubectl -n ${NAMESPACE} describe pods ${PODNAME}
  • 查看events ,能夠看到試圖schedule pod的錯誤緣由。
  • 沒法schedule pod的常見緣由是集羣上沒有足夠的資源可用。

OpenShift

若是部署 Kubeflow 在 OpenShift 環境( 是對 Kubernetes的封裝),你須要調整 security contexts,爲了ambassador 和 jupyter-hub 部署的運行。

oc adm policy add-scc-to-user anyuid -z ambassador
oc adm policy add-scc-to-user anyuid -z jupyter-hub

一旦安全策略設置好,你須要刪除失敗的pods 而後容許在 project deployment時能夠從新建立。

你須要調整 tf-job-operator service 張好的權限,以使TFJobs可以運行。以下運行一個TFJobs:

oc adm policy add-role-to-user cluster-admin -z tf-job-operator

Docker for Mac

Docker for Mac 社區版帶有Kubernetes支持 (1.9.2) ,能夠從edge channel啓用。若是決定私用 Kubernetes environment on Mac,部署 Kubeflow時可能遇到以下的問題:

ks apply default -c kubeflow-core
ERROR Attempting to deploy to environment 'default' at 'https://127.0.0.1:8443', but cannot locate a server at that address

該錯誤是由於Docker for Mac安裝時設置的缺省集羣爲 https://localhost:6443.,一個選項是直接編輯建立的 environments/default/spec.json 文件設置 "server" 變量爲正確的位置,而後重試部署。不過,更好的方式是使用但願的kube config來建立Ksonnet app。

kubectl config use-context docker-for-desktop
ks init my-kubeflow

403 API rate limit 超出錯誤

由於 ksonnet 使用 Github 拉取 kubeflow,除非用戶指定Github API token,將會快速消耗最大的 API 匿名調用限量,爲了解決該問題,能夠建立 Github API token,參考這裏 guide,,而後將該token 賦給GITHUB_TOKEN 環境變量。

export GITHUB_TOKEN=<< token >>

ks apply 產生錯誤 "Unknown variable: env"

Kubeflow 要求版本 0.9.2 或更高,查看 see here。若是你運行 ks apply 使用的老版本ksonnet,將獲得錯誤 Unknown variable: env ,以下所示:

ks apply ${KF_ENV} -c kubeflow-core
ERROR Error reading /Users/xxx/projects/devel/go/src/github.com/kubeflow/kubeflow/my-kubeflow/environments/nocloud/main.jsonnet: /Users/xxx/projects/devel/go/src/github.com/kubeflow/kubeflow/my-kubeflow/components/kubeflow-core.jsonnet:8:49-52 Unknown variable: env

  namespace: if params.namespace == "null" then env.namespace else params.namespace

檢查ksonnet 版本,以下:

ks version

若是 ksonnet版本低於 v0.9.2, 請升級並按照 user_guide 從新建立app。

爲何 Kubeflow 要使用 Ksonnet?

Ksonnet 是一個命令行工具,使管理包含多個部件的複雜部署變得更爲容易,設計爲與kubectl各自完成特定的操做。

Ksonnet 容許咱們從參數化的模版中建立 Kubernetes manifests。這使參數化 Kubernetes manifests 用於特定的場景變得容易。在上面的例子中,咱們爲 TfServing 建立了manifests,爲model提供用戶化的URI。

我蠻喜歡ksonnet的一個緣由是,對待 environment  (如dev, test, staging, prod) 做爲頭等的概念。對於每個環境,咱們部署一樣的 components只須要對特定環境有一些很小的定製化修改。咱們認爲這對於一般的工做流來講是很是友好的一種映射。例如,該特徵讓在本地沒有GPU的狀況下運行任務,使代碼運行經過,而後將其移到帶有大量GPU可規模伸縮的雲計算環境之中。

相關文章
相關標籤/搜索