やること
- 公式のAnacondaイメージをベースに自前のイメージをつくります。
- コンテナを立ち上げ、Jupyter Labを起動します。
- ブラウザから、コンテナ内で立ち上げたJupyter Labを操作します。
- VSCodeでコンテナに接続します。
- VSCodeからもコンテナ内部を編集できることを確認します。
なにがうれしいの??
- Anacondaをホストマシンにインストールすることのリスク回避(Homebrewやpipとの衝突)
- 複数人で開発環境を共有できる
環境
- MacOS X 10.14.5 (Mojave)
- VSCode 1.35.1
- Docker 18.09.2
Dockerイメージをつくる
Dockerfile
Anaconda公式イメージをベースにします。
https://hub.docker.com/r/continuumio/anaconda3
# ベースイメージ名:タグ名
FROM continuumio/anaconda3:2019.03
# pipをアップグレードし必要なパッケージをインストール
RUN pip install --upgrade pip && \
pip install autopep8 && \
pip install Keras && \
pip install tensorflow
# コンテナ側のルート直下にworkdir/(任意)という名前の作業ディレクトリを作り移動する
WORKDIR /workdir
# コンテナ側のリッスンポート番号
# 明示しているだけで、なくても動く
EXPOSE 8888
# ENTRYPOINT命令はコンテナ起動時に実行するコマンドを指定(基本docker runの時に上書きしないもの)
# "jupyter-lab" => jupyter-lab立ち上げコマンド
# "--ip=0.0.0.0" => ip制限なし
# "--port=8888" => EXPOSE命令で書いたポート番号と合わせる
# ”--no-browser” => ブラウザを立ち上げない。コンテナ側にはブラウザがないので 。
# "--allow-root" => rootユーザーの許可。セキュリティ的には良くないので、自分で使うときだけ。
# "--NotebookApp.token=''" => トークンなしで起動許可。これもセキュリティ的には良くない。
ENTRYPOINT ["jupyter-lab", "--ip=0.0.0.0", "--port=8888", "--no-browser", "--allow-root", "--NotebookApp.token=''"]
# CMD命令はコンテナ起動時に実行するコマンドを指定(docker runの時に上書きする可能性のあるもの)
# "--notebook-dir=/workdir" => Jupyter Labのルートとなるディレクトリを指定
CMD ["--notebook-dir=/workdir"]
イメージビルド
Dockerfileが置いてあるディレクトリで以下を実行
docker build -t ANATA_NO_IMAGE_NAME .
-t
ビルドしたイメージに名前(:タグ名)をつけるオプションです。
. (最後のドット)
ビルドコンテキストの指定。
Dockerfileのあるディレクトリを指定します。
ここでは.
なのでカレントディレクトリを指定しています。
docker buildコマンドではビルドコンテキスト内にあるDockerfileを自動で読みにいきます。
コンテナ起動
① docker runコマンドで起動する場合
docker run -it \
-p 8080:8888 \
--rm \
--name ANATA_NO_CONTAINER_NAME(任意) \
--mount type=bind,src=`pwd`,dst=/workdir \
ANATA_NO_IMAGE_NAME(上でビルドしたもの)
このコマンド何してるの??
docker run
docker pull
と docker create
と docker start
を1発で行うやつ。
イメージがホストマシン上になければDocker Hubからpullしてきて、コンテナつくって、コンテナを起動します。
-it
-i
と -t
をまとめて書いてるものです。
-i
or--interactive
=> ホスト側のシェルからコンテナ内を操作できるようにする。-t
or--tty
=> 仮想ttyの割当て。キーバインドを使用したり、色を出力したりシェル操作を便利に行うために指定。
こちらが非常にわかりやすいです。
https://teratail.com/questions/121780
https://teratail.com/questions/19477
https://teratail.com/questions/100044
-p 8080:8888
ホスト側のポート番号
:コンテナ側のポート番号
をひも付けます。
ローカルのブラウザからlocalhost:8080
でコンテナ内で立ち上げたjupyterをひらけるように。
--rm
コンテナを停止したときに自動で削除(docker rm)までしてくれます。
--name ANATA_NO_CONTAINER_NAME
任意のコンテナ名をつける。
なくても動きます。
これを指定しない場合、自動でコンテナ名が付与されます。
--mount type=bind,src=`pwd`,dst=/workdir
ホスト側のディレクトリとコンテナ側のディレクトリを同期させる。
- type=bind => マウントタイプにbindを指定(他にvolume,tmpfsの指定が可能)
- src=`pwd` => ホスト側のディレクトリにカレントディレクトリを指定(任意のディレクトリでOK)
- dst=/workdir => コンテナ側のディレクトリにルート直下のworkdir/を指定(任意のディレクトリでOK)
※-v
でも --mount
と同じことができます。
-
-v
=> ホスト側に存在しないディレクトリをマウントしようとすると新規作成 -
--mount
=> ホスト側に存在しないディレクトリをマウントしようとするとエラー
--mount
を使った方が誤って空のディレクトリをマウントしてしまう事故などを防げます。
例えば空のディレクトリをマウントしてしまうと、必要なファイルが覆い隠されてしまうためコンテナが正常に動作しなくなる場合がある。
(見た目上は上書きされたように見えるが、マウント元のディレクトリの中身でマウント先のディレクトリの中身が隠れているだけで削除されるわけではない)
公式でも以下のように --mount
オプションでの書き方が推奨されているようです。
ヒント: はじめて利用する方は --mount を利用してください。 上級ユーザーは -v や --volume を用いることに慣れているかもしれませんが、--mount を利用するように心がけてください。 --mount の方が簡単に利用することができるとの調査もあります。
ANATA_NO_IMAGE_NAME
先程docker buildで作ったイメージ名を指定します。
② docker-composeで起動する場合
上記docker run 〜
コマンドをコード化したようなものです。
docker-compose.yml
version: '3' # docker-composeファイルの書式バージョン。最新の’3’を指定(2019/6/27現在)
services:
dev: # 任意の名前(ディレクトリ名 + dev がコンテナ名となります)
build:
context: .
dockerfile: Dockerfile
image: ANATA_NO_IMAGE_NAME
ports:
- "8080:8888"
volumes:
- .:/workdir
コンテナ起動
docker-compose.ymlが置いてあるディレクトリで以下を実行
docker-compose up
Jupyter Labを開く
ブラウザのアドレスバーに localhost:8080
を入力しEnter。
=> Jupyter Labが開きます。マウントさせたディレクトリと同じものが入っていればOK。
同期されるか確認
ローカルのディレクトリで新しくファイルを作ってみます。
touch test.ipynb
再読込ボタンでJupyter Labのエクスプローラを更新して、test.ipynb
が追加されていれば成功です。
コンテナ停止
docker runで起動した場合
docker stop ANATA_NO_CONTAINER_NAME
docker-compose up で起動した場合
docker-compose stop
コンテナ削除
docker runで起動した場合
docker rm ANATA_NO_CONTAINER_NAME
docker-compose up で起動した場合
docker-compose down
コンテナの中でもVSCodeつかいたい人
拡張機能のインストール
表示 > コマンドパレット > 拡張
と打つ > ビュー:拡張機能を表示する
サイドバーの入力欄にremote
と打つ > Remote - Containers
を選択 > インストール
もう一回コンテナ起動
- コンテナ名 =>
test_container
- 使用イメージ =>
anaconda_test_image
として起動してみます。
docker run -it -p 8080:8888 --name test_container \
--mount type=bind,src=`pwd`,dst=/workdir anaconda_test_image
コンテナに接続
左下のボタンを押して、
Remote - Containers: Attach to Running Container…
を選択
起動中のコンテナ一覧が出てくるので、接続したいコンテナを選択します。
新しいウィンドウが開きます。
左下のボタンがAttached Container ~
となります。
以下の手順で、マウント先(コンテナ側)のディレクトリを選択します。
マウント元(ホスト側)のディレクトリと同じ内容が表示されればOK。
Jupyterで新規ファイル作成してみます。
Untitled.ipynb
がVSCode側にも即反映されるのが確認できるかと思います。
コンテナ側に拡張機能インストール
ローカルでVSCodeにインストールされている一部の拡張機能が、コンテナ側には入っていません。
必要に応じでインストールします。
最後に
ここまで読んで頂きありがとうございました。
VSCodeでJupyterのように実行結果を表示させる方法も書いたので、もしよろしければ。
=> 【画像で説明】VSCodeをJupyter化する
参照
ありがとうございました!
- https://www.udemy.com/docker-k/
- https://www.qoosky.io/techs/0a0bd52cd3
- http://onoz000.hatenablog.com/entry/2018/02/11/142347
- https://qiita.com/shibukawa/items/0daab479a2fd2cb8a0e7
- https://qiita.com/hgsgtk/items/0fc14802c3234e95427f
- https://teratail.com/questions/121780
- https://teratail.com/questions/19477
- https://teratail.com/questions/100044
- https://qiita.com/yoskeoka/items/01c52c069123e0298660
- https://code.visualstudio.com/docs/remote/containers