Kubeflow(https://github.com/kubeflow)是基於Kubernetes(https://kubernets.io,容器編排與管理服務軟件)和TensorFlow(https://tensorflow.org,深度學習庫)的機器學習流程工具,使用Ksonnet進行應用包的管理。html
本文簡要介紹Kubeflow的部署和交互操做的基本概念和方法,對於Kubernetes、Tensorflow和Ksonnet 的瞭解對於本文內容的理解將頗有幫助,點擊下面的連接查看相關的內容。node
對部署Kubeflow和運行一個簡單的訓練任務的手把手教的例子,能夠看這個教程( tutorial)。git
咱們將使用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
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
當啓用時,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)
這裏的 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,若是設置了代理,須要對該地址關閉 。
將看到一個提示窗口。
使用任何username/password登陸。
點擊 "Start My Server" 按鈕,將會打開一個對話框。
選擇鏡像爲CPU 或 GPU 類型,在 Image一項有菜單列出預構建的Docker鏡像。也能夠直接輸入Tensorflow的鏡像名稱,用於運行。
分配內存、CPU、GPU和其餘的資源,根據需求而定。 (1 CPU 和 2Gi 內存已是一個好的起點,能夠知足初始練習的須要。)
kubectl get nodes "-o=custom-columns=NAME:.metadata.name,GPU:.status.allocatable.nvidia\.com/gpu"
Extra Resource Limits
section: {"nvidia.com/gpu": "1"}
點擊 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
完成後,將會打開 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。
咱們將每個部署的模型都做爲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-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。
注意:在提交訓練任務以前,你首先須要有一個 deployed kubeflow to your cluster。提交訓練任務時,首先確認 TFJob
custom resource 是可用的。
咱們將每個TensorFlow job做爲APP中的 component 看待。
爲訓練任務建立 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
文件。
ks apply ${KF_ENV} -c ${JOB_NAME}
監視任務執行狀況,參見 TfJob docs.
ks delete ${KF_ENV} -c ${JOB_NAME}
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
注意:在提交任務以前,你須要有一個部署好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}
設置磁盤參數,以分號隔開,設置你想要掛載的 Google persistent disks。
建立磁盤:
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 ,Virtualbox/VMware drivers是已知在 KVM/KVM2 driver 和 TensorFlow Serving之間的問題. 該問題跟蹤在 kubernetes/minikube#2377。
咱們建議增長 Minikube分配的資源總量,以下:
minikube start --cpus 4 --memory 8096 --disk-size=40g
若是遇到jupyter-xxxx pod 進入Pending 狀態,獲取描述信息:
Warning FailedScheduling 8s (x22 over 5m) default-scheduler 0/1 nodes are available: 1 Insufficient memory.
若是你運行的集羣開啓了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 notebooks遇到麻煩,檢查該 pod 是否已經被調度運行:
kubectl -n ${NAMESPACE} get pods
jupyter-${USERNAME}
若是你使用 IAP on GKE,pod 將被命名爲:
jupyter-accounts-2egoogle-2ecom-3USER-40DOMAIN-2eEXT
一旦你知道pod的名稱:
kubectl -n ${NAMESPACE} describe pods ${PODNAME}
若是部署 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 社區版帶有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
由於 ksonnet 使用 Github 拉取 kubeflow,除非用戶指定Github API token,將會快速消耗最大的 API 匿名調用限量,爲了解決該問題,能夠建立 Github API token,參考這裏 guide,,而後將該token 賦給GITHUB_TOKEN 環境變量。
export GITHUB_TOKEN=<< token >>
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。
Ksonnet 是一個命令行工具,使管理包含多個部件的複雜部署變得更爲容易,設計爲與kubectl各自完成特定的操做。
Ksonnet 容許咱們從參數化的模版中建立 Kubernetes manifests。這使參數化 Kubernetes manifests 用於特定的場景變得容易。在上面的例子中,咱們爲 TfServing 建立了manifests,爲model提供用戶化的URI。
我蠻喜歡ksonnet的一個緣由是,對待 environment (如dev, test, staging, prod) 做爲頭等的概念。對於每個環境,咱們部署一樣的 components只須要對特定環境有一些很小的定製化修改。咱們認爲這對於一般的工做流來講是很是友好的一種映射。例如,該特徵讓在本地沒有GPU的狀況下運行任務,使代碼運行經過,而後將其移到帶有大量GPU可規模伸縮的雲計算環境之中。