kubernetes
Jupyter

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のチュートリアルなどを作るのに良さそうと感じました。

参考