DNS and Jupyter Notebook Using Docker - シリーズ投稿2/7
Series Top: Dockerで作るおうちLAN遊び場
この投稿はシリーズ第二弾で、Dockerを使ってDNSとJupyter Notebookを動かします。
自分のDNSサーバがあるとシリーズで今後立ち上げていく各サービス用に、自由にDNSレコードを用意できます。
具体例があるとどういうことか分かりやすいので、この投稿ではwebサービスとDNSサーバ、両方ともカバーします。
Accessing service with and without DNS
まずは机上の例として。あるwebサーバが192.168.1.250:80
でサービス提供しているとして、「YAHOO!」というサービス応答をするとします。ブラウザでhttp://192.168.1.250/
へアクセスすると「YAHOO!」という応答が表示されます。ここでさらにyahoo.example.net
というDNSレコードがあり、それが192.168.1.250
へと名前解決されるとします。すると、ブラウザなどでhttp://yahoo.example.net
へとアクセスすると「YAHOO!」という応答が表示されます。
Jupyter Notebook on Docker
それでは実際に構築を始めていきましょう。まずwebサービス、Jupyter Notebookを走らせます。走らせるマシンは192.168.1.56
というIPアドレスで、Jupyter Notebookというサービスは8888ポートでサービス提供させます。すると先の例の通り、ブラウザでhttp://192.168.1.56:8888
へアクセスするとJupyter Notebookにアクセスできます。また、このサービスをjupyter.mylan.local
と名付けたとして、そのDNSレコードが192.168.1.56
で名前解決されるようDNSサーバとDNSレコードも用意すると、今度はブラウザでhttp://jupyter.mylan.local:8888
でもサービスにアクセスできます。
なおサラッと触れていますが、シリーズを通してLANで利用するドメインはmylan.local
とします。
マシンに接続して手を動かし始めましょう。先の投稿でインストールしたdocker compose
が確かにインストールされていることを確認します。
$ docker compose version
Docker Compose version v2.12.0
ディレクトリを用意し、Docker Composeに何をやらせるかの指示書、docker-compose.yml
というファイルを用意します。ディレクトリは$HOME/mylan/jupyter
とします。
$ mkdir -p $HOME/mylan/jupyter
$ cd $HOME/mylan/jupyter
# and then create a docker-compose.yml file here
以下がdocker-compose.yml
ファイルの中身です。ここではjupyter/base-notebook
というDockerイメージを使います。
services:
jupyter:
container_name: jupyter
image: jupyter/base-notebook:notebook-6.5.1
ports:
- "8888:8888"
command: "start-notebook.sh --ServerApp.password='' --ServerApp.token='' --ip=0.0.0.0 --no-browser"
ファイルができれば実行準備完了です。docker compose up -d
で実行、docker compose ps
でステータス確認、docker compose down
で停止できます。実行するとLAN内の別の端末からhttp://192.168.1.56:8888
へブラウザでアクセスすることでJupyter Notebookサービスにアクセスできます。
$ docker compose up -d
[+] Running 13/13
⠿ jupyter Pulled 97.2s
⠿ cf92e523b49e Pull complete 16.1s
⠿ d122d224d8ab Pull complete 36.9s
⠿ da0342913a35 Pull complete 37.0s
⠿ 4f4fb700ef54 Pull complete 37.1s
⠿ c2f2efbb391f Pull complete 37.2s
⠿ 291238b4cf86 Pull complete 37.3s
⠿ 47fcc7e93076 Pull complete 37.4s
⠿ 8c8e1d8f7987 Pull complete 37.5s
⠿ 3c19a726ce99 Pull complete 92.8s
⠿ 442a90c0da0a Pull complete 92.9s
⠿ e511a84b0db8 Pull complete 93.0s
⠿ 44bce5cd969a Pull complete 93.1s
[+] Running 2/2
⠿ Network jupyter_default Created 0.2s
⠿ Container jupyter Started 2.4s
$ docker compose ps
NAME COMMAND SERVICE STATUS PORTS
jupyter "tini -g -- start-no…" jupyter running (healthy) 0.0.0.0:8888->8888/tcp, :::8888->8888/tcp
docker compose down
した場合の出力です。
$ docker compose down
[+] Running 2/2
⠿ Container jupyter Removed 0.8s
⠿ Network jupyter_default Removed 0.4s
$ docker compose ps
NAME COMMAND SERVICE STATUS PORTS
Unbound DNS on Docker
上と同様に、次はDNS用にディレクトリとdocker-compose.yml
ファイルを用意していきます。
$ mkdir -p $HOME/mylan/dns
$ cd $HOME/mylan/dns
# create a docker-compose.yml file here
ファイルの中身は以下で、Dockerイメージとしてはmvance/unbound
を使います。
services:
dns:
image: mvance/unbound:1.16.2
container_name: dns
ports:
- '53:53/udp'
- '53:53'
早速docker compose up -d
で実行しdocker compose ps
でステータスを確認しましょう。
$ docker compose ps
NAME COMMAND SERVICE STATUS PORTS
dns "/unbound.sh" dns running (starting) 0.0.0.0:53->53/tcp, 0.0.0.0:53->53/udp, :::53->53/tcp, :::53->53/udp
先のセクションではサービス実行状態の確認としてブラウザでJupyter Notebookにアクセスしました。同様にDNSサービスの確認としては名前解決をしてみましょう。LAN上のどの端末、どのシステムからでも確認できますが、実行コマンド例は以下です。
host www.google.com. 192.168.1.56
nslookup www.google.com. 192.168.1.56
dig www.google.com. @192.168.1.56
ちなみに利用するDockerイメージバージョンによっては、このDNSサーバは普通にインターネット上のルートネームサーバへ名前解決にいっているかもしれませんし、TLS越しにCloudflare DNSへ名前解決しにいっているかもしれません。ここで私が利用しているバージョンは後者です。
Configure DNS server
Dockerで実行させているDNSサービスが機能していること確認できたと思います。次に、設定を編集してjupyter.mylan.local
を名前解決できるようにします。
どのディレクトリに置いてあるどのファイルを変更すればサーバの設定を変更できるのかは、サービスによってまちまちです。利用するDockerイメージのドキュメントないしサービスの公式ドキュメントを確認しにいく必要があるでしょう。
またDockerで実行しているサービスの設定変更をしたいという場合、実行しているコンテナ内で設定ファイルの更新をするのでは、マシンの再起動、そしてDockerのup/downだけでも設定変更は巻き戻ってしまいます。実行コンテナ内でどうこうする代わりに、Dockerを実行しているマシン上に設定ファイルを用意し、Dockerにそのファイルを実行コンテナにも利用してもらうよう持っていってもらいます。
実際にどうすればよいのかやっていましょう。
今回利用しているイメージmvance/unbound:1.16.2
の場合、設定ファイルのサンプルがあるのでそれを利用します。設定ファイルを置くためのディレクトリを用意し、実行しているコンテナ内よりサンプルファイルをローカルにコピーしてきます。
# you are at $HOME/mylan/dns
mkdir config
cd config
# copy a-records.conf configuration file from "dns" docker container
docker cp dns:/opt/unbound/etc/unbound/a-records.conf .
コンテナ内よりコピーしてきたa-records.conf
ファイルの中身は以下のとおりです。
$ cat a-records.conf
# A Record
#local-data: "somecomputer.local. A 192.168.1.1"
# PTR Record
#local-data-ptr: "192.168.1.1 somecomputer.local."
例に習って行を追加します。先頭の#
があると一行丸ごとコメントアウトされるので除いておきましょう。
$ cat a-records.conf
# A Record
#local-data: "somecomputer.local. A 192.168.1.1"
local-data: "jupyter.mylan.local. A 192.168.1.56"
# PTR Record
#local-data-ptr: "192.168.1.1 somecomputer.local."
local-data-ptr: "192.168.1.56 jupyter.mylan.local."
次に$HOME/mylan/dns
配下に作ったdocker-compose.yml
ファイルも更新します。カスタムの設定ファイルは./config/a-records.conf
にあり、それをコンテナ内の/opt/unbound/etc/unbound/a-records.conf
ファイルとしてローカルから持ち込むようDockerに指示します。volumes:
以下のセクションがその設定で、ちなみに末尾の:ro
はread-onlyモードの指示です。
こういったファイルやディレクトリのマッピング、マウント関連オペレーションについて、公式ドキュメントに更に情報があります。
$ cat docker-compose.yml
services:
dns:
image: mvance/unbound:1.16.2
container_name: dns
ports:
- '53:53/udp'
- '53:53'
volumes:
- './config/a-records.conf:/opt/unbound/etc/unbound/a-records.conf:ro'
コンテナをリスタートすると追記されたdocker-compose.yml
に従ってカスタム設定ファイルが実行コンテナに載ります。
# run `cd $HOME/mylan/dns` first if you are not there
docker compose restart
# or docker compose down, and then docker compose up -d
スマホ、ラップトップ、LAN上のどの端末でもよいですが、DNS設定を変更して192.168.1.56
をDNSサーバとして使うようにしましょう。そうするとようやく、ブラウザでhttp://jupyter.mylan.local:8888
とアクセスすることでJupyter Notebookサービスに接続できます。
❯ curl jupyter.mylan.local:8888 -v
* Trying 192.168.1.56:8888...
* Connected to jupyter.mylan.local (192.168.1.56) port 8888 (#0)
Files created on Jupyter Notebook
DNSサーバの設定のところで触れたとおり、Dockerを実行しているホストマシンを再起動したり、Jupyter Notebookのコンテナを停止して改めて立ち上げると、Jupyter Notebookで作ったファイルなどが毎回失くなっています。Docker Volumeを利用することでこの問題が解決できます。
早速以下に用意しましたが、更新版のdocker-compose.yml
ファイルです。今度はjupyter_volume
というボリュームを作成し、今回の例で利用しているJupyter NotebookのDockerイメージのワーキングディレクトリ、/home/jovyan
にマウントするよう指示します。
services:
jupyter:
container_name: jupyter
image: jupyter/base-notebook:notebook-6.5.1
user: root
ports:
- "8888:8888"
command: "start-notebook.sh --ServerApp.password='' --ServerApp.token='' --ip=0.0.0.0 --no-browser"
environment:
- "CHOWN_EXTRA=/home/jovyan"
- "CHOWN_EXTRA_OPTS=-R"
volumes:
- type: volume
source: jupyter_volume
target: /home/jovyan
volume:
nocopy: true
volumes:
jupyter_volume: {}
ボリューム以外にも増えている行がありますが、Jupyter Notebookのドキュメントで触れられている通りユーザと権限の問題があり追加されている行となります。
Cleaning up Docker
以上でシリーズ投稿第二弾でカバーすべき主なアイテムは全てです。
最後にDocker環境のクリーンアップ方法について触れておきます。
jupyter
とdns
用のディレクトリへ移動し、それぞれでdocker compose down
を実行して停止させます。そしてdocker system prune --volumes
を実行することでイメージ、ボリュームなどあれこれがクリーンアップされます。なお、DNS用に用意したカスタム設定ファイルは影響を受けませんが、Jupyter Notebookで新規追加したファイルなどがあれば、ボリュームがクリーンアップされることですべて消されます。すでにJupyter Notebookであれこれ遊び始めているようであれば実行しないでおきましょう。
$ docker system prune --volumes
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all volumes not used by at least one container
- all dangling images
- all dangling build cache
Are you sure you want to continue? [y/N] y
Deleted Volumes:
5f9710e79b0e3478c1faf63ba85c8f584cddc264cf82ffe912daf4396b164f12
e80bd0c29be5882802c488061f824402965cc7d0bced938ee59ad4d2a9907551
ee0cd42517800cf647cd7ac371e88544ba67c6cdc7448fdecfea7a52e00c1345
...
f443285371dff464c127e1430dc64e41df86675f8b11f7b1ccc80b57a41f7047
994da20fd1461980079a343d20d0326307d421869b955e5f8874c1391ec701d6
Deleted Images:
untagged: redis@sha256:4bed291aa5efb9f0d77b76ff7d4ab71eee410962965d052552db1fb80576431d
deleted: sha256:3900abf4155226f3f62401054b872ce0c85b5c3b47275cae3d16a39c8646e36b
deleted: sha256:8ba2d28fdd3729dec59c7e11c3c99b5df826f7d4fc63c358ae54833e27a16e92
...
deleted: sha256:3779241fda7b1caf03964626c3503e930f2f19a5ffaba6f4b4ad21fd38df3b6b
deleted: sha256:bacd3af13903e13a43fe87b6944acd1ff21024132aad6e74b4452d984fb1a99a
Deleted build cache objects:
l8z524ebp7tmuvmusjxc4jn2b
rp9mtdw4y51kgjuferu1khdzv
Total reclaimed space: 2.925GB
今後様々なイメージ、バージョンを試していったり、ボリュームを作っていったりすると次第にホストマシンのディスク容量を逼迫していくかもしれません。あるいはあちこちに用意されているチュートリアルやクイックスタート手順を試すために環境をクリーンアップしたいという場面が出てくるかもしれません。そういうときにはクリーンアップしましょう。
ちなみにあちこちでdocker compose up -d
を実行しすぎて何がどこに置いてあったかわからなくなった場合は、docker ps
で実行しているコンテナ名を確認し、そのコンテナ名でdocker container inspect コンテナ名 -f '{{ index .Config.Labels "com.docker.compose.project.working_dir"}}'
と実行することでそのコンテナのワーキングディレクトリがわかります。
$ docker ps --format '{{.Names}}'
dns
jupyter
$ docker container inspect jupyter -f '{{ index .Config.Labels "com.docker.compose.project.working_dir"}}'
/home/{username}/mylan/jupyter
Closing
この投稿は以上です。次回はリバースプロキシサーバを用意し、Jupyter Notebookなどのサービスへのアクセスの仕方を変えていきます。
Discussion