CUBE SUGAR CONTAINER

技術系のこと書きます。

リモートサーバ上の Docker コンテナで Jupyter Notebook を使う

今回は、以下のエントリの続き。

blog.amedama.jp

上記の記事でやったことを Docker コンテナにしてみる。

使った環境は次の通り。 まずは Docker ホストとして使う Ubuntu 18.04 のマシンから。 こちらも前回と同じように Vagrant で構築している。

vagrant $ cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.1 LTS"
vagrant $ uname -r
4.15.0-29-generic

そこに接続するクライアントは次の通り。

client $ sw_vers 
ProductName:    Mac OS X
ProductVersion: 10.13.6
BuildVersion:   17G65
client $ ssh -V
OpenSSH_7.6p1, LibreSSL 2.6.2

Docker をインストールする

まずは Docker ホストとして使う Ubuntu に Docker をインストールする。 やり方については以下の公式サイトに記載がある。

docs.docker.com

まずは、すでに Docker 関連のパッケージがインストールされているようであればアンインストールする。

vagrant $ sudo apt-get remove docker docker-engine docker.io

続いて作業に必要なパッケージをインストールしておく。

vagrant $ sudo apt-get update
vagrant $ sudo apt-get -y install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common

Docker の公式リポジトリを検証するための GPG 鍵をインストールする。

vagrant $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

Docker の公式リポジトリを登録する。

vagrant $ sudo add-apt-repository \
    "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) \
    stable"

あとは Docker 本体をインストールするだけ。

vagrant $ sudo apt-get update
vagrant $ sudo apt-get -y install docker-ce

これで Docker を使えるようになった。

vagrant $ sudo docker version
Client:
 Version:           18.06.1-ce
 API version:       1.38
 Go version:        go1.10.3
 Git commit:        e68fc7a
 Built:             Tue Aug 21 17:24:51 2018
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.06.1-ce
  API version:      1.38 (minimum version 1.12)
  Go version:       go1.10.3
  Git commit:       e68fc7a
  Built:            Tue Aug 21 17:23:15 2018
  OS/Arch:          linux/amd64
  Experimental:     false

Jupyter Notebook が使える Docker イメージを用意する

Jupyter Notebook は公式が Docker のリポジトリを持っている。

https://hub.docker.com/u/jupyter/

元になっている Dockerfile などは以下にあるようだ。

github.com

最初、上記を使ってやろうかと思ったんだけど、ちょっと不都合があってやめることにした。 具体的には Jupyter Notebook が Bind する IP アドレスがループバックアドレスになっている。 もしかすると環境変数なんかで変更できるのかもしれないけど、それだと単なる特定のイメージ紹介になってしまうので。

そこで、自分で Docker イメージを作ることにした。 準備した Dockerfile が以下の通り。

vagrant $ cat << 'EOF' > Dockerfile 
FROM ubuntu:18.04

# Install prerequisite packages
RUN apt-get update \
 && apt-get install -yq --no-install-recommends \
      jupyter-notebook

# User configuration
ARG USERNAME=jupyter
RUN useradd -m -s /bin/bash ${USERNAME}
USER ${USERNAME}

# Jupyter configuration
RUN jupyter notebook --generate-config \
 && mkdir -p /home/${USERNAME}/jupyter-working \
 && sed -i.back \
    -e "s:^#c.NotebookApp.token = .*$:c.NotebookApp.token = u'':" \
    -e "s:^#c.NotebookApp.ip = .*$:c.NotebookApp.ip = '*':" \
    -e "s:^#c.NotebookApp.open_browser = .*$:c.NotebookApp.open_browser = False:" \
    -e "s:^#c.NotebookApp.notebook_dir = .*$:c.NotebookApp.notebook_dir = '/home/${USERNAME}/jupyter-working':" \
    /home/${USERNAME}/.jupyter/jupyter_notebook_config.py

# Expose container ports
EXPOSE 8888

# Boot process
CMD jupyter notebook
EOF

基本的に実行しているコマンドは前回のエントリと同じようなものになっている。 一点違うとすれば、前述した通り Bind する IP アドレスをループバックアドレスではなく任意のもの (*: アスタリスク) になっている。

Docker イメージをビルドする。 タグには example/jupyter という名前をつけた。

vagrant $ sudo docker image build -t example/jupyter .
...
Step 8/8 : CMD jupyter notebook
 ---> Using cache
 ---> 0d2915a8d871
Successfully built 0d2915a8d871
Successfully tagged example/jupyter:latest

あとは上記を起動するだけ・・・の前にアクセス制御をかけておこう。 SSH に使うポート以外は閉じておく。

vagrant $ sudo ufw allow 22
vagrant $ sudo ufw default DENY
vagrant $ yes | sudo ufw enable
vagrant $ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22                         ALLOW       Anywhere                  
22 (v6)                    ALLOW       Anywhere (v6)           

ビルドしたイメージをコンテナとして起動する コンテナの TCP/8888 を Docker ホストのループバックアドレスにマッピングする。 こうすることでインターネットからは疎通がない状態でコンテナとポートをマッピングできる。

vagrant $ sudo docker container run --rm -p 127.0.0.1:8888:8888 -it example/jupyter
[I 23:45:00.610 NotebookApp] Writing notebook server cookie secret to /home/jupyter/.local/share/jupyter/runtime/notebook_cookie_secret
[W 23:45:00.778 NotebookApp] WARNING: The notebook server is listening on all IP addresses and not using encryption. This is not recommended.
[W 23:45:00.781 NotebookApp] WARNING: The notebook server is listening on all IP addresses and not using authentication. This is highly insecure and not recommended.
[I 23:45:00.788 NotebookApp] Serving notebooks from local directory: /home/jupyter/jupyter-working
[I 23:45:00.789 NotebookApp] 0 active kernels
[I 23:45:00.790 NotebookApp] The Jupyter Notebook is running at:
[I 23:45:00.792 NotebookApp] http://[all ip addresses on your system]:8888/
[I 23:45:00.793 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).

確認すると、たしかにループバックアドレスで Listen している。

vagrant $ ss -tlnp | grep 8888
LISTEN   0         128               127.0.0.1:8888             0.0.0.0:*            

あとは、前回のエントリと同じように SSH Port Forwarding するだけ。

client $ vagrant ssh-config > ssh.config
client $ ssh -L 8888:localhost:8888 -F ssh.config default

ブラウザでクライアントのループバックアドレスの 8888 ポートを開いてみよう。

client $ open http://localhost:8888

いつもの画面が見えるはず。

f:id:momijiame:20181014022447p:plain

Docker Compose を使う場合

一応 Docker Compose を使うパターンについても紹介しておく。 Docker Compose を使えばコンテナの起動オプションなんかを覚えておく必要がなくなる。

まずは Docker Compose をインストールする。

vagrant $ sudo apt-get -y install docker-compose
vagrant $ docker-compose version
docker-compose version 1.17.1, build unknown
docker-py version: 2.5.1
CPython version: 2.7.15rc1
OpenSSL version: OpenSSL 1.1.0g  2 Nov 2017

続いて Docker Compose の設定ファイルを用意する。

vagrant $ cat << 'EOF' > docker-compose.yml 
version: "3"
services:
  jupyter:
    build: .
    image: example/jupyter
    ports:
      - "127.0.0.1:8888:8888"
EOF

あとは、上記の設定ファイルを使ってイメージをビルドする。 さっきビルドしたキャッシュが残っていればすぐに終わるはず。

vagrant $ sudo docker-compose build

設定ファイルを元にコンテナを起動する。

vagrant $ sudo docker-compose up jupyter

起動したコンテナの Jupyter Notebook を使う方法については Docker をそのまま使うときと同じ。

めでたしめでたし。

Docker/Kubernetes 実践コンテナ開発入門

Docker/Kubernetes 実践コンテナ開発入門