前提
kubernetes環境構築済み
yamlファイルが書ける
[k8sで作る機械学習環境]Kubernetes1.10でGPUを使う~NVIDIAドライバーのインストールから~
↑を参考にGPUドライバーが使えること
しないこと
kubectlコマンドの使用方法
k8sの用語の詳細な説明
ゴール
MLP01のIPでjupyterコンテナへブラウザでアクセスし、tensorflowのコードからGPUを使用できるか確認。
本記事で構築するjupyter
・namespaceはdefaultではなく「mle」とする
・DockerRegistryからjupyterのイメージをpullして、ReplicaSetを作成しPodを1つ動かす
・PodへはMLP01のIPを使用してアクセス
・PodからMLP01のGPUを使うようにyamlファイルに記述をする
・podからnfsをマウントしてjupyterで記述したコードを保存
環境
# cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04 LTS"
# dpkg -l | grep kube
ii kubeadm 1.10.3-00 amd64 Kubernetes Cluster Bootstrapping Tool
ii kubectl 1.10.3-00 amd64 Kubernetes Command Line Tool
ii kubelet 1.10.3-00 amd64 Kubernetes Node Agent
ii kubernetes-cni 0.6.0-00 amd64 Kubernetes CNI
k8sでいろいろ作っていく!
PersistentVolume
まずはNFSマウントをpodから行うためにk8sのPersistentVolume機能を使ってボリュームを作成します。
k8sのPersistentVolumeサブシステムは、ストレージがどのように消費されてからどのように提供されるかの詳細を抽象化するAPIを提供しているらしいです。
ちゃちゃっとyamlを作成しましょう。
apiVersion: v1
kind: PersistentVolume
metadata:
name: daichi
labels:
volume: jupyter-volume
app: dev
namespace: mle
spec:
accessModes:
- ReadWriteMany
capacity:
storage: 100Gi
nfs:
server: 192.168.100.150
path: "/opt/nfs/jupyter/daichi"
accessModes
accessModesは3種類あります。
・ReadWriteOnce – 単一のノードでボリュームを読み書き可能にマウント
・ReadOnlyMany – 複数のノードでボリュームを読み取り専用でマウント
・ReadWriteMany – 複数のノードでボリュームを読み書き可能にマウント
capacity
capacityに容量を記述しないと、NFSサーバの容量を無制限に使えてしまうので制限を設定しています。
yamlを実行したらPVが作成されたか確認します。
$ kubectl get pv --namespace=mle
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
daichi 100Gi RWX Retain Available 8m
容量が100GBでReadWriteManyのPVが作成されました!
PersistentVolumeClaim
作成したnfsの100Giのpvからpodに紐付けるための領域を要求します。PVCを作ることでPodにストレージを追加することができます。
試しに、PVから10Giのストレージを要求するためにPVCを作成します。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: daichi
labels:
volume: jupyter-volume
app: dev
namespace: mle
spec:
resources:
requests:
storage: 10Gi
accessModes:
- ReadWriteMany
selector:
matchLabels:
volume: jupyter-volume
kubectlコマンドで確認します。
$ kubectl get pvc --namespace=mle daichi
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
daichi Bound daichi 100Gi RWX 46s
statusがBoundになってれば成功です。
PVの確認をするとSTATUSがAvailableからBoundに変更されているはずです。
これでPodからアクセスする準備ができました。
$ kubectl get pv --namespace=mle daichi
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
daichi 100Gi RWX Retain Bound mle/daichi 5s
jupyterコンテナの作成
jupyterコンテナを作成してGPU割当、PVCのマウントをしましょう
ReplicaSet
ReplicaSetは、指定された数のPodがいつでも実行されていることを保証します。
k8sの公式ドキュメントではDeploymentを使ってReplicaSetを管理すべし、と書いてありますがローリングアップデートをする必要はjupyterでは無いのでReplicaSetを使用します。
今回の構成ではDeploymentではなくてReplicaSetを使用します。
apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
name: jupyter
labels:
app: jupyter
pj: dev
namespace: mle
spec:
replicas: 1
selector:
matchLabels:
app: jupyter
template:
metadata:
labels:
app: jupyter
pj: dev
namespace: mle
spec:
####コンテナのイメージを指定###########
containers:
- name: notebooks
image: 192.168.100.150:5000/daichi/notebooks:1.2
resources:
####コンテナが要求するリソース###########
requests:
cpu: "4000m"
memory: "8Gi"
####ここでGPUを要求###################
nvidia.com/gpu: 1
####コンテナに割り当てるリソース#########
limits:
cpu: "8000m"
memory: "16Gi"
nvidia.com/gpu: 1
####jupyterが動くポートを指定###########
ports:
- containerPort: 9999
volumeMounts:
- name: daichi
####マウントしたいコンテナ内のpathを記載###
mountPath: "/notebooks"
volumes:
- name: daichi
####PVCを指定#########################
persistentVolumeClaim:
claimName: daichi
####コンテナのDNSサーバの向き先を指定#####
dnsConfig:
nameservers:
- 8.8.8.8
yaml内にコメントアウトで説明書きました。
注意事項はDockerRegistryからイメージをpullする場合、すべてのNodeからdocker login 192.168.100.150:5000を事前に実行しておく必要があります。
でないと、イメージのpullが失敗してしまいます。
ReplicaSetができたか確認します。
$ kubectl get replicaset --namespace=mle jupyter
NAME DESIRED CURRENT READY AGE
jupyter 1 1 1 5m
Podができているかの確認もしときます。
$ kubectl get pod --namespace=mle jupyter-xvmcj
NAME READY STATUS RESTARTS AGE
jupyter-xvmcj 1/1 Running 0 6m
Service
最後に作ったjupyterのPodにアクセスするためにServiceを作成します。
kind: Service
apiVersion: v1
metadata:
name: jupyter
labels:
app: jupyter
pj: dev
namespace: mle
spec:
selector:
app: jupyter
ports:
- name: port-jupyter
####コンテナ内のport###################
port: 9999
protocol: TCP
targetPort: 9999
####ブラウザからアクセスするときのport#####
nodePort: 30888
type: "NodePort"
service_for_jupyter.yamlを実行するとServiceが作成されます。
ブラウザからアクセスするさいのポートは30888になります。
$ kubectl get svc --namespace=mle jupyter
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jupyter NodePort 10.100.202.239 <none> 9999:30888/TCP 6m
jupyterにアクセス
NodeのIPでアクセスするためにどこのNodeで動いてるか確認します。
$ kubectl describe pod --namespace=mle jupyter-xvmcj
Name: jupyter-xvmcj
Namespace: mle
Node: mlp03/192.168.200.153
Start Time: Thu, 07 Jun 2018 17:15:36 +0900
Labels: app=jupyter
pj=dev
Annotations: <none>
Status: Running
IP: 10.244.2.51
Controlled By: ReplicaSet/jupyter
Containers:
notebooks:
Container ID: docker://f4c0e6c321bdb47b6ad39eb88f41984d9d1c88698fab7b86f47f50602e6978b5
Image: 192.168.100.150:5000/daichi/notebooks:1.2
Image ID: docker-pullable://192.168.100.150:5000/daichi/notebooks@sha256:fb2199cce57e7bcfead825860f42c3e668a641ab91293ee25e3e098be7095cda
Port: 9999/TCP
Host Port: 0/TCP
State: Running
Started: Thu, 07 Jun 2018 17:15:38 +0900
Ready: True
Restart Count: 0
Limits:
cpu: 8
memory: 16Gi
nvidia.com/gpu: 1
Requests:
cpu: 4
memory: 8Gi
nvidia.com/gpu: 1
Environment: <none>
Mounts:
/notebooks from daichi (rw)
/var/run/secrets/kubernetes.io/serviceaccount from default-token-fhmb8 (ro)
Conditions:
Type Status
Initialized True
Ready True
PodScheduled True
Volumes:
daichi:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: daichi
ReadOnly: false
default-token-fhmb8:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-fhmb8
Optional: false
QoS Class: Burstable
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 9m default-scheduler Successfully assigned jupyter-xvmcj to mlp03
Normal SuccessfulMountVolume 9m kubelet, mlp03 MountVolume.SetUp succeeded for volume "default-token-fhmb8"
Normal SuccessfulMountVolume 9m kubelet, mlp03 MountVolume.SetUp succeeded for volume "daichi"
Normal Pulled 9m kubelet, mlp03 Container image "192.168.100.150:5000/daichi/notebooks:1.2" already present on machine
Normal Created 9m kubelet, mlp03 Created container
Normal Started 9m kubelet, mlp03 Started container
MLP03で動いてますね。
http://192.168.200.153:30888/
にブラウザからアクセスするとjupyterの画面が見えるはずです。
tensorflowのコードを実行してGPUをちゃんと使えているか確認してみます。
from tensorflow.python.client import device_lib
device_lib.list_local_devices()
ちゃんとGPU使えてますね!!!
やりたいこと
Podを動かすNodeは指定できるので、その方法を近々追記します。GPUの指定はできるのかな??
mysqlをk8s上で動かしたいですね〜。
Devlopmentとかingressも使ってみたいです。