Dream Driven Development。夢を形にしよう!

Kubernetesで jupyterlab環境構築 (buildah + dockerfile)

Kubernetesで
jupyterlab環境構築
(buildah + dockerfile)


前回、Kubernetes環境でociイメージ(open container initiative image)のローカルレジストリの環境を構築しました。

Kubernetesの
ローカルイメージレジストリを
dockerlessで作る-Dream Driven Development(夢駆動開発)
Kubernetesの ローカルイメージレジストリを dockerlessで作る-Dream Driven Development(夢駆動開発)
先日、クラウド環境の勉強と開発環境のセットアップを兼ねてKubernetesのセットアップを行いました。 %%BlogCard https://dream.drivendevelopment.jp/dev-environment/k8s-:Kubernetesの ローカルイメージレジストリを dockerlessで作る

せっかく環境ができたのでjupyterlab + pytorchのDeeplearning環境を構築してみましょう。

dockerを使わず(cri-o環境なので)に、でもdockerfileを使って構築していきます。

buildahとdockerfile

OCIイメージの構築を行うためにbuildahを利用します。

$ sudo apt install buildah
$ buildah images
REPOSITORY   TAG   IMAGE ID   CREATED   SIZE
$ buildah containers
CONTAINER ID  BUILDER  IMAGE ID     IMAGE NAME                       CONTAINER NAME

 前回の記事のようにbuildahのコマンドを使ってimageを作成することもできるのですが、今回は楽をしたいので”dockerfile”を使って構築してみます。

dockerfile

準備したdockerfileは以下のようになります。

FROM ubuntu
LABEL maintainer="hassyheisaku"

ENV USER_NAME heisaku
ENV UID 1000
RUN useradd -m -u ${UID} ${USER_NAME}

ENV HOME /home/${USER_NAME}

ENV TZ Asia/Tokyo
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

ENV PATH ${HOME}/anaconda3/bin:${PATH}
WORKDIR ${HOME}

RUN apt-get update \
 && apt-get install -y curl \
    wget \
    git \
    unzip \
    imagemagick \
    bzip2 \
    vim \
    libsm6 \
    libgl1-mesa-dev \
    build-essential \
    libssl-dev

RUN wget https://repo.anaconda.com/archive/Anaconda3-2020.02-Linux-x86_64.sh -P ${HOME} \
 && bash ${HOME}/Anaconda3-2020.02-Linux-x86_64.sh -b -p ${HOME}/anaconda3  \
 && rm ${HOME}/Anaconda3-2020.02-Linux-x86_64.sh \
 && ${HOME}/anaconda3/bin/conda build purge-all

RUN ${HOME}/anaconda3/bin/conda update -y --all
RUN ${HOME}/anaconda3/bin/conda install -y -c conda-forge opencv
RUN ${HOME}/anaconda3/bin/conda install -y -c intel tensorflow
RUN ${HOME}/anaconda3/bin/conda install -y keras
RUN ${HOME}/anaconda3/bin/conda install -y -c pytorch pytorch torchvision
RUN ${HOME}/anaconda3/bin/conda install -y jupyterlab
RUN ${HOME}/anaconda3/bin/conda install -y pandas matplotlib scipy scikit-learn scikit-image h5py seaborn numpy Pillow tqdm
RUN ${HOME}/anaconda3/bin/conda install -y -c conda-forge nodejs

USER ${USER_NAME}

必要そうなライブラリをひたすらインストールするような中身になってます。。。

イメージのビルド

構築はbuildah budオプションを使います。

$ buildah bud --tag pytorch-jupyter -f dockerfile .
:
Writing manifest to image destination
Storing signatures
--> b73156b381d
b73156b381deed36a54730b7be3152a2088c78a289baf6ea8d570ddd59be9fc5
$ buildah images
REPOSITORY                  TAG      IMAGE ID       CREATED          SIZE
localhost/pytorch-jupyter   latest   b73156b381de   11 minutes ago   14.3 GB
docker.io/library/ubuntu    latest   f643c72bc252   6 days ago       75.3 MB

いろいろ突っ込んだせいか14.3GBという巨大なイメージになってしまいました。

ローカルレジストリへの登録

 前回作成したローカルレジストリに登録します。

$ buildah --tls-verify=false push pytorch-jupyter docker://<local registry ip>:5000/heisaku/pytorch-jupyter:latest

kubernetesでのjupyterlabコンテナ作成

pv/pvc向けディスクの準備

jupyterlabのデータはpermanent volumeに保存したいので、先にpv/pvc向けのディスクを作成します。
 前回の記事と同様にnfsのボリュームを準備します。

マスターノード(nfs提供側)

$ sudo apt install nfs-kernel-server
$ sudo mkdir -p /var/nfs/exports
$ sudo mkdir /var/nfs/exports/jupyter # local registry用
$ sudo chown 1000.1000 /var/nfs/exports/jupyter
$ echo "/var/nfs/exports <ローカルドメイン 192.168.0.0/24>(rw,sync,no_root_squash) 127.0.0.1/32(rw,sync,no_root_squash)" | sudo tee -a /etc/exports
$ sudo systemctl restart nfs-server rpcbind
$ sudo systemctl enable nfs-server rpcbind

ワーカーノード全部(nfs client側)

$ sudo apt install -y nfs-common;	

pv/pvc向けマニフェスト

jupyter-persistentvolume.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
    name: jupyter-pv
    labels:
        k8s-app: my-jupyter
spec:
    capacity:
        storage: 50Gi
    accessModes:
        - ReadWriteMany
    nfs:
        path: /var/nfs/exports/jupyter
        server: <nfs提供側サーバーIP>
    persistentVolumeReclaimPolicy: Retain
    storageClassName: sc-jupyter

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
    name: jupyter-pvc
    namespace: my-jupyter
    labels:
        k8s-app: my-jupyter
spec:
    accessModes:
        - ReadWriteMany
    resources:
        requests:
            storage: 50Gi
    storageClassName: sc-jupyter

name space “my-jupyter”を作成してpv/pvcを作成します。

$ kubectl create ns my-jupyter
namespace/my-jupyter created
$ kubectl apply -f jupyter-persistentvolume.yaml
persistentvolume/jupyter-pv created
persistentvolumeclaim/jupyter-pvc created
$ kubectl get pv
NAME         CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                              STORAGECLASS   REASON   AGE
jupyter-pv   50Gi       RWX            Retain           Bound    my-jupyter/jupyter-pvc             sc-jupyter              98s
$ kubectl get pvc -n my-jupyter
NAME          STATUS   VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS   AGE
jupyter-pvc   Bound    jupyter-pv   50Gi       RWX            sc-registry    12m

jupyterデプロイメント向けマニフェスト

jupyter-deployment.yaml

kind: Service
apiVersion: v1
metadata:
  name: my-jupyter-nodeip
  namespace: my-jupyter
  labels:
      app: my-jupyter
spec:
  type: NodePort
  ports:
  - name: http
    port: 8888
    targetPort: 8888
  selector:
    app: my-jupyter
  externalIPs:
    - <jupyterアクセス向け外部IP>
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: jupyterlab-config
  namespace: my-jupyter
data:
  jupyterlab-pass: "heisaku"
  jupyterlab-user-name: "heisaku"
  jupyterlab-user-id: "1000"
  jupyterlab-base-url: "/heisaku/"
  jupyterlab-home-dir: "/jupyter-pvc"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: jupyterlab-deployment
  namespace: my-jupyter
  labels:
    app: my-jupyter
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-jupyter
  template:
    metadata:
      labels:
        app: my-jupyter
    spec:
      containers:
      - name: my-jupyter
        image: <local registry ip>:5000/heisaku/pytorch-jupyter:latest
        ports:
        - name: http
          containerPort: 8888
        env:
        - name: JUPYTERLAB_PASS
          valueFrom:
            configMapKeyRef:
              name: jupyterlab-config
              key: jupyterlab-pass
        - name: UID
          valueFrom:
              configMapKeyRef:
                name: jupyterlab-config
                key: jupyterlab-user-id
        - name: USER_NAME
          valueFrom:
              configMapKeyRef:
                name: jupyterlab-config
                key: jupyterlab-user-name
        - name: BASE_URL
          valueFrom:
              configMapKeyRef:
                name: jupyterlab-config
                key: jupyterlab-base-url
        - name: HOME_DIR
          valueFrom:
              configMapKeyRef:
                name: jupyterlab-config
                key: jupyterlab-home-dir
        command:
        - "sh"
        - "-c"
        - |
            PASSWORD=$(python -c 'from notebook.auth import passwd;print(passwd("'${JUPYTERLAB_PASS}'"))')
            jupyter-lab --port=8888 --ip=0.0.0.0 --no-browser --NotebookApp.token='' --NotebookApp.base_url=${BASE_URL} \
            --NotebookApp.password=${PASSWORD} --NotebookApp.notebook_dir=${HOME_DIR}
        volumeMounts:
          - mountPath: "/jupyter-pvc"
            name: jupyter-pvc
      volumes:
        - name: jupyter-pvc
          persistentVolumeClaim:
              claimName: jupyter-pvc
              readOnly: false

デプロイします。

$ kubectl apply -f jupyter-deployment.yaml
service/my-jupyter-clusterip created
configmap/jupyterlab-config created
deployment.apps/jupyterlab-deployment created
$ kubectl get po -n my-jupyter
NAME                                     READY   STATUS    RESTARTS   AGE
jupyterlab-deployment-846585dc59-qs5dc   1/1     Running   0          25m

ブラウザでアクセスしてみる

https://<external IP>:8888/heisaku/

動いたでしょうか?

まとめ

buildahでイメージを作成して、ローカルレジストリに登録して、k8sにデプロイして
と一通りの流れを試すことができましたね。

ただ、機械学習するには僕の”herobox”は非力過ぎるようで学習が一向に進まないことがわかりました。
今の環境は、もっと軽いウェブサービスの開発などに活用したほうが良さそうです。

enjoy!

|

お気に入りサイト