Edited at

Jupyter NotebookからKubernetesを操作する

最近流行りのJupyter Notebook( http://jupyter.org/ )でkubectlコマンドを呼び出すことで、生きている手順書が作れるのでは?と思ったので、試してみることにしました。

このドキュメントではKubernetesクラスタの中にJupyter Notebookをデプロイし、そこから自身がデプロイされている、Kubernetesクラスタを操作する方法を紹介します。


前提条件


  • minkube

  • kubectl

はインストール済みとします。


minikubeによるKubernetesクラスタの作成

$ minikube start

Starting local Kubernetes v1.10.0 cluster...
Starting VM...
Getting VM IP address...
Moving files into cluster...
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.
Loading cached images from config file.


python kernelをつかってみる

まずはシンプルな普通の機能を試してみます。


Jupyter Notebookのデプロイ

まずは公式で用意しているminimal-notebookのコンテナイメージを使ってみることにします。


jupyter.yaml

apiVersion: apps/v1

kind: Deployment
metadata:
name: jupyter-notebook
labels:
app: jupyter-notebook
spec:
replicas: 1
selector:
matchLabels:
app: jupyter-notebook
template:
metadata:
labels:
app: jupyter-notebook
spec:
containers:
- name: minimal-notebook
image: jupyter/minimal-notebook:latest
ports:
- containerPort: 8888
command: ["start-notebook.sh"]
args: ["--NotebookApp.token=''"]
---
kind: Service
apiVersion: v1
metadata:
name: jupyter-notebook
spec:
type: NodePort
selector:
app: jupyter-notebook
ports:
- protocol: TCP
nodePort: 30040
port: 8888
targetPort: 8888

$ kubectl apply -f jupyter.yaml


デプロイしたサービスの確認

$ kubectl get svc

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jupyter-notebook NodePort 10.100.161.148 <none> 8888:30040/TCP 5m
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 25d


ブラウザからアクセス

まずminikubeのIPを確認します。

$ minikube ip

192.168.99.100

サービスのNodePortは30040なのでこの場合は下記のアドレスをブラウザで開きます。

http://192.168.99.100:30040


notebookの作成

WebUIからPython 3の形式のNotebookを作成します。

image.png


試しに書いてみる

Jupyter NotebookはドキュメントをCellという単位で記述します。CellにはMarkDownのモードとコードのモードなどがあります。

コードのモードの時に普通にプログラムを書くとPythonとして解釈され、!を前置するとシェルスクリプトとして解釈されます。

Shift+Enterを押すことでそのコードを実行することができます。

image.png


kubectlを呼び出す

!を前置することでシェルスクリプトが動くのでwgetコマンドでkubectlのバイナリをダウンロードして、実行してみます。

実行したコマンドは下記です。

!wget https://storage.googleapis.com/kubernetes-release/release/v1.12.0/bin/linux/amd64/kubectl

!chmod 755 kubectl
!./kubectl get pod

image.png

権限は無いが、一応動いていることがわかります。

このシェルスクリプトはKubernetesにデプロイされたPodの中で動作しており、権限としてはデフォルトで作成されるdefaultという名前のServiceAccountの権限で動作します。(これらは環境変数によって設定されています。気になる方は!envをNotebookで実行するとわかります)


権限を付与する

defaultのServiceAccountに権限を与えます。下記コマンドはviewという標準で用意されているRoleをdefaultというServiceAccountに紐づけています。

$ kubectl create rolebinding default-sa --clusterrole=view --serviceaccount=default:default

rolebinding.rbac.authorization.k8s.io/default-sa created

再度実行すると、実行できました!

これがやりたかったことです!

image.png


一度全て削除する

次のステップに行く前に一度デプロイしたjupyter notebookを削除します。

$ kubectl delete -f jupyter.yaml

deployment.apps "jupyter-notebook" deleted
service "jupyter-notebook" deleted


bash kernelをつかってみる

ここまでで、Jupyter Notebookでkubectlが実行できることがわかりましたが、実行する時に先頭に!をつけるのがどうにも煩わしいです。

これはPython kernelを使っているためデフォルトとしてPythonのコードとして動作しているからです。

そこで、Bash kernelを使うことでもっと素直にシェルスクリプトが実行できるようにしてみましょう。


Dockerイメージの作成

bash kernelの入ったDockerイメージが見当たらなかったので自分で作ります。

また出力を等幅フォントにすることで、出力結果が綺麗に表示されるようにしています。

FROM jupyter/minimal-notebook

USER jovyan

# Make sure not to create a cache dir else NB_UID switching
# will hit issues.
RUN /opt/conda/bin/pip install --no-cache-dir bash_kernel
RUN /opt/conda/bin/python -m bash_kernel.install
RUN mkdir -p ~/.jupyter/custom && echo '.CodeMirror pre, .output pre { font-family: Monaco, monospace; }' > ~/.jupyter/custom/custom.css

USER root

minikubeのDockerを使ってビルドします。

$ eval $(minikube docker-env)

$ docker build -t bash-notebook:v1.0 .

Sending build context to Docker daemon 3.584kB
Step 1/6 : FROM jupyter/minimal-notebook
---> 400c44c4a7a7
Step 2/6 : USER jovyan
---> 858a23692f3d
Step 3/6 : RUN /opt/conda/bin/pip install --no-cache-dir bash_kernel
---> 33313772919f
Step 4/6 : RUN /opt/conda/bin/python -m bash_kernel.install
---> 6ce76d215977
Step 5/6 : RUN mkdir -p ~/.jupyter/custom && echo '.CodeMirror pre, .output pre { font-family: Monaco, monospace; }' > ~/.jupyter/custom/custom.css
---> ebbcec57eea2
Step 6/6 : USER root
---> feb1400abc10
Successfully built feb1400abc10
Successfully tagged bash-notebook:v1.0


デプロイ

下記のようにマニフェストを変更してデプロイします。


jupyter-bash.yaml

apiVersion: apps/v1

kind: Deployment
metadata:
name: jupyter-notebook
labels:
app: jupyter-notebook
spec:
replicas: 1
selector:
matchLabels:
app: jupyter-notebook
template:
metadata:
labels:
app: jupyter-notebook
spec:
containers:
- name: minimal-notebook
image: bash-notebook:v1.0 # イメージ名を変更
imagePullPolicy: IfNotPresent # minikube内のイメージを使う
ports:
- containerPort: 8888
command: ["start-notebook.sh"]
args: ["--NotebookApp.token=''"]
---
kind: Service
apiVersion: v1
metadata:
name: jupyter-notebook
spec:
type: NodePort
selector:
app: jupyter-notebook
ports:
- protocol: TCP
nodePort: 30040
port: 8888
targetPort: 8888

 $ kubectl apply -f jupyter-bash.yaml

deployment.apps/jupyter-notebook created
service/jupyter-notebook created


ブラウザからアクセス

アドレスは前と同じです。

Bashが選べるようになっています。

image.png


遊んでみる

!を書かずにシェルスクリプトが実行できました

image.png


感想

kubernetesのチュートリアルなどを作るのに良さそうと感じました。


参考