#はじめに
今回の検証では、Kubernetes上でML環境を提供するKubeflowを試します。Kubeflowは、シングルノードのKubernetesの実験環境であるminikubeでも実行できます。しかし、大規模な計算を行うMLにおいて、シングルノードの計算リソースでは実用に耐えられません。そのため、マルチノードのKubernetesクラスタ上にKubeflowをセットアップしたい人も多いかと思います。
しかし、セットアップに際し、ひとつ問題があります。それが永続ストレージです。Kubeflowをセットアップするためには、データを保存するための永続ストレージが必要となります。minikubeでは、minikubeが提供するprovisionerによって、minikubeのVMを利用し永続ストレージを提供しています。GKEなどのパブリッククラウドのサービスを使っている場合も、比較的容易に永続ストレージを準備することができます。しかし、自宅や小規模なオフィスなどでKubernetesを運用している場合は、なかなか準備できない人も多いかと思います。さらには、Kubeflowで必要とされている永続ストレージはDBなどのバックエンドで利用することから、ファイルストレージ(NAS)は非推奨であることからブロックストレージを準備しないといけません。
そこで、今回は、自宅や小規模なオフィスでも容易に準備できるブロックストレージとしてKubernetes: Local Volumeの検証で紹介したLocal Volumeを使ってKubeflowを使いKubeflowの動作検証を行います。
#検証環境
以下のKubernetes環境を使います。
- Kubernetes v1.11.1
- Master x 1, Worker x 2
- Kubeflow v0.3
#動作検証
ksnonnet のインストール
Kubeflow 0.3では、ksonnet 0.11.0 or laterが必要になります。
そのため、brewを使いksonnetをインストールします。
$ brew install ksonnet/tap/ks
...
$ ks version
ksonnet version: 0.13.0
jsonnet version: v0.11.2
client-go version: kubernetes-1.10.4
##Kubeflowのダウンロード
GitHubにあるKubeflowのセットアップに必要なファイル一式をダウンロードします。
$ mkdir kubeflow
$ cd kubeflow/
$ export KUBEFLOW_TAG=v0.3.0
$ curl https://raw.githubusercontent.com/kubeflow/kubeflow/${KUBEFLOW_TAG}/scripts/download.sh | bash
...
ダウンロードが完了するとkubeflow
とscript
ディレクトリが作成され、その配下にセットアップで利用するスクリプトが配置されます。
##Kubeflowのセットアップ
はじめに、セットアップ用の環境変数の設定スクリプトを生成します。
$ scripts/kfctl.sh init kfapp --platform none
...
$ cd kfapp/
次に、環境変数の設定スクリプトのあるディレクトリにて、ksonnet appを生成します。
$ ../scripts/kfctl.sh generate k8s
...
続いて、Kubeflowをデプロイする先のNamespace(kubeflow
)をKubernetes上に作成します。
$ kubectl create ns kubeflow
Kubeflowをデプロイします。
$ ../scripts/kfctl.sh apply k8s
...
デプロイが完了後、KubernetesにデプロイされたPodを確認します。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
ambassador-868d5dbdc4-6psgx 3/3 Running 0 22m
ambassador-868d5dbdc4-rxz2s 3/3 Running 0 22m
ambassador-868d5dbdc4-wpw67 3/3 Running 0 22m
argo-ui-84464bd59c-9gwsn 1/1 Running 0 21m
centraldashboard-c76877875-x4pgb 1/1 Running 0 22m
modeldb-backend-58969447f6-hszg9 1/1 Running 0 21m
modeldb-db-57b855f5b7-lc47p 1/1 Running 0 21m
modeldb-frontend-769d5bdd66-77964 1/1 Running 0 21m
spartakus-volunteer-5974ff4c8c-8qmfr 1/1 Running 0 20m
studyjob-controller-56588dc6f9-l4rqc 1/1 Running 0 21m
tf-hub-0 1/1 Running 0 22m
tf-job-dashboard-7777b6bf-mlk2g 1/1 Running 0 22m
tf-job-operator-v1alpha2-5c5b4dcfdf-2knwd 1/1 Running 0 22m
vizier-core-5584ccbd8-wt9zm 0/1 Error 6 21m
vizier-db-547967c899-sgmmz 0/1 Pending 0 21m
vizier-suggestion-grid-8547dbb55b-4qpwp 1/1 Running 0 21m
vizier-suggestion-random-d7c5cd68b-fg7sl 1/1 Running 0 21m
workflow-controller-5c95f95f58-cpbh5 1/1 Running 0 21m
すると、残念ながらvizierの起動に失敗しています。
失敗している原因は、vizer-db(実体はMySQL)にPersistentVolumeが割り当てられていないためです。そのため、vizier-dbがPendingとなりvizier-coreの起動に失敗しています。
kubectl describeコマンドで確認することで原因がわかります。
なお、PersistentVolumeがDynamic Provisioningできる環境であれば、本問題は発生しないかもしれません。
$ kubectl describe pod vizier-db-547967c899-sgmmz
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 3m46s (x363 over 23m) default-scheduler pod has unbound PersistentVolumeClaims (repeated 3 times)
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
vizier-db Pending 24m
$ kubectl get pv
No resources found.
そこで、Kubernetes: Local Volumeの検証を参考にし、Local Volumeを割り当てるようにします。
作成したPersistent Volumeは以下です。
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
local-pv 10Gi RWO Retain Available local-storage 17s
以上で、KubeflowがKubernetes上にデプロイされます。
vizer-dbが利用するPersistentVolumeClaim(vizier-db
)が要求しているサイズが10Gbyteのため、Local VolumeのPersistentVolume(local-pv
)も10GByteとしています。
次に、PersistentVolumeClaim(vizier-db
)と、PersistentVolume(local-pv
)をBoundさせます。
まず、PersistentVolumeClaim(vizier-db
)をYAMLフォーマットでManifestファイルに保存します。
$ kubectl get pvc vizier-db -o yaml > vizier-db.yaml
続いて、保存したManifestファイルを編集します。
編集箇所を以下に示します。
特に必要なのは、.spec.storageClassNameにLocal Volume用のStorageClassであるlocal-storage
を指定することです。
--- vizier-db.yaml.org 2018-10-17 17:45:09.000000000 +0900
+++ vizier-db.yaml 2018-10-17 17:45:41.000000000 +0900
@@ -3,7 +3,6 @@
metadata:
annotations:
ksonnet.io/managed: '{"pristine":"H4sIAAAAAAAA/0yOsU7tQAxE+/cZU+cBt01LQYVAFJcCUTibAVlJ1svaAYmr/Xe0KRDd6Nhz7Auk6JnV1TJGfJ4wYNE8Y8Rjpx7McbZ133i7im4YsDFklhCMF6wycfWepJTe129lxYBkW7HMHBgxT13qljPjSu3672yR0AltQJaNv4L/R6UjL5I6X/aJb6t99VUvTMfJlOh+bzMd4wueKPNz1eBDTsTrgEq3vSYe/1V+7PQ4sodVee/a082dorXW/v0AAAD//wEAAP//j1cT1gkBAAA="}'
- creationTimestamp: 2018-10-17T07:51:18Z
finalizers:
- kubernetes.io/pvc-protection
labels:
@@ -14,13 +13,11 @@
name: vizier-db
namespace: kubeflow
resourceVersion: "4672936"
- selfLink: /api/v1/namespaces/kubeflow/persistentvolumeclaims/vizier-db
uid: 6eb34226-d1e1-11e8-a0a0-080027571559
spec:
+ storageClassName: local-storage
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
-status:
- phase: Pending
編集が完了後、Manifestファイルを使いデプロイします。
$ kubectl delete pvc vizier-db
persistentvolumeclaim "vizier-db" deleted
$ kubectl create -f vizier-db.yaml
persistentvolumeclaim/vizier-db created
PersistentVolumeClimのデプロイが完了すると、vizier-coreとvizier-dbが起動します。
$ kubectl get pod
...
vizier-core-5584ccbd8-wt9zm 1/1 Running 12 1h
vizier-db-547967c899-sgmmz 1/1 Running 0 1h
...
これでKubeflowのPodが全て起動しました。
##動作確認
###port-forwadingの設定
次のコマンドでreverse proxyを提供するambassadorのPodにポートをフォワードします。
$ export NAMESPACE=kubeflow
$ kubectl port-forward -n ${NAMESPACE} `kubectl get pods -n ${NAMESPACE} --selector=service=ambassador -o jsonpath='{.items[0].metadata.name}'` 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
Webブラウザでhttp://localhost:8080/
にアクセスすると以下のようなKubeflow navigation UIにアクセスできます。
###Jupyter Notebookへのアクセス
Kubeflow navigation UIからJUPYTERHUB
を選択します。
すると、ログイン画面が起動するため、好きなUsername, Passwordを入力しSign in
をクリックします。
次にSpawnerの選択画面が出てます。
Imageに、tensorflowのイメージを指定します。
GPUを使う人は、イメージ名にgpu
が入ったものを選択し、CPUのみ使う人はcpu
が入ったものを選択します。
Imageを選択後、Spawn
を選択します。
すると、Jupyter Notebookの環境作成が始まります。
ここで、数分待っても終わらないようであれば、Jupyter NotebookのPodの状態を確認してください。kubectl getコマンドで確認すると、jupyter-のPod(本検証ではjupyter-ysakashita)が生成され、Pending
になっています。
これは、vizier-dbと同じく、jupyter-のPodが利用するPersistent Volumeが作成出来ていないからです。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
...
jupyter-ysakashita 0/1 Pending
0 2m
...
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
...
claim-ysakashita Pending 2m
そこで、Kubernetes: Local Volumeの検証を参考にし、Local Volumeを割り当てるようにします。
作成したPersistent Volumeは以下です。
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
...
local-pv2 10Gi RWO Retain Available local-storage 18s
次に、PersistentVolumeClaim(claim-ysakashita
)と、PersistentVolume(local-pv2
)をBoundさせます。
まず、PersistentVolumeClaim(claim-ysakashita
)をYAMLフォーマットでManifestファイルに保存します。
$ kubectl get pvc claim-ysakashita -o yaml >claim-ysakashita.yaml
続いて、保存したManifestファイルを編集します。
編集箇所を以下に示します。
$ diff -u claim-ysakashita.yaml.org claim-ysakashita.yaml
--- claim-ysakashita.yaml.org 2018-10-17 18:25:18.000000000 +0900
+++ claim-ysakashita.yaml 2018-10-17 18:25:59.000000000 +0900
@@ -3,7 +3,6 @@
metadata:
annotations:
hub.jupyter.org/username: ysakashita
- creationTimestamp: 2018-10-17T09:14:11Z
finalizers:
- kubernetes.io/pvc-protection
labels:
@@ -12,9 +11,9 @@
name: claim-ysakashita
namespace: kubeflow
resourceVersion: "4681970"
- selfLink: /api/v1/namespaces/kubeflow/persistentvolumeclaims/claim-ysakashita
uid: 026fd018-d1ed-11e8-a0a0-080027571559
spec:
+ storageClassName: local-storage
accessModes:
- ReadWriteOnce
resources:
編集が完了後、Manifestファイルを使いデプロイします。
$ kubectl delete pvc claim-ysakashita
persistentvolumeclaim "claim-ysakashita" deleted
$ kubectl create -f claim-ysakashita.yaml
persistentvolumeclaim/claim-ysakashita created
PersistentVolumeClimのデプロイが完了すると、jupyter-ysakashitaのPodが起動します。
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
...
jupyter-ysakashita 1/1 Running 0 19m
...
Podが起動すると、以下のようにJupyter Notebookが立ち上がります。
Jupyter Notebookでnew
を選択し、新しいソースコードを作成し開発を開始します。
以上で、KuberflowのセットアップとJupyter Notebookの起動まで動作検証を実施しました。
#おわりに
今回は、Local Volumeを使ったKubeflowのセットアップと動作検証を行いました。
これまで、永続ストレージが準備できずminikubeで仕方なくKubeflowを使っていた人もいたかと思います。minikubeだと、どうしてもCPUやメモリなどのリソースが不足しがちになります。
今回の検証で単にLocal Volumeを使うというだけでなく、minikubeから卒業しCPUやメモリに加えGPUなどのリソースが潤沢に使えるKubernetesクラスタ環境へ移行出来るのではないでしょうか。
また、今回利用したLocal Volumeは、自宅や小規模オフィスのようにあまりインフラにお金をかけられない環境において、手軽に利用できるブロックストレージです。しかし、2018/10時点での最新のKubernetes 1.12.1でもLocal Volumeは、未だDynamic Provisioningが正式にサポートされていません。KubeflowのようにDynamic Provisioningを前提としている場合、Local Volumeはまだまだ扱いにくいのが現状です。今回実施したように一つ一つ確かめながらLocal Volumeを割り当てていく必要があります。そのため、非常に手間がかかってしまうのが残念です。お金をかけるか手間をかけるかの天秤ですね。もし、Local VolumeのDynamic Provisioningの正式サポートが待てないという人はKubernetes incubatorのDynamic Provisioningを利用する方法もあります。私も機会があれば試してみたいと思います。
#参考情報