機械学習ではじめるDocker
目次とお断り
この資料をまとめるに当たって、実際に開発したり運用したりという経験のスニペットから、できるだけ編集して、自分なりに体系化したものです
様々な角度のデータが乱雑なっててわかりにくいかもしれませんが、ご了承いただけると幸いです
- "1. Dockerとは"
- "2. Dockerを用いるメリット"
- "3. docker.ioのインストール"
- "4. dockerでコンテナの起動"
- "5. 基本的な操作"
- "6. Dockerコンテナにsshdなどの必須ソフトウェアをインストールする"
- "7. dockerコンテナのexportとimport"
- "8. 機械学習ように調整したコンテナの利用"
- "9. 実際に使用している例"
- "10. Docker Hub連係"
- "11. Docker Compose"
- "12. Dockerのコンテナとホストマシン間でファイルの共有をする"
- "13. 便利なチートシート"
- "14. まとめ"
1. Dockerとは
- 仮想化コンテナで、VMWare、VirtualBoxのようなsystemdやシステムのサービス管理サービスが稼働するような重いものではない
- chrootみたいなものだが、immutable architectureを前提とするので、docker commitするまで状態は保存されない
- vmware, virtualboxみたいな完全なOSを乗っけるイメージよりアプリレベルの簡単な仮想化を想定(指定したバイナリしか動かないのでsystemd通常動作させない)
2. Dockerを用いるメリット
開発と分析するいう側面
- 依存の多い分析ライブラリと開発環境を簡単にどこでも好きな場所で再現できる
- XGBoost, LightGBM, LibSVM, RedisやAerospikeのような微妙な環境じゃないと動かなかったりするものを封じ込めて、安定運用版のスナップショットとしていつでも利用できる
運用という側面
- Dockerで構築したアプリをそのままデプロイ用に加工して、DevOpsに渡すことで、運用に回してもらう
- DevOpsは開発レイヤーが強いので、なんなら機械学習とエンジニアリング専門の私でも、運用ルールを策定できる
3. docker.ioのインストール
手法1. dockerのrepositoryからのインストール
$ sudo apt install docker.io $ sudo usermod -aG docker $USER LOGOUTしてLOGINか、再起動
手法2. docker公式が提供する公式のインストールスクリプトからインストール
$ curl -fsSL get.docker.com -o get-docker.sh $ sh get-docker.sh $ sudo usermod -aG docker $USER LOGOUTして、LOGINか再起動
4. dockerでコンテナの起動
最小サイズのubuntuをインストール
$ docker pull ubuntu $ docker run -it ubuntu bash
5. 基本的な操作
dockerにはなぜか名前がつかないことがあって、docker tagで名前をつける
$ docker tag ${ID} ${NAME}
run(内容が保存されない)
$ docker run -it ${NAME} /bin/bash
すでに起動済みのDockerにCONTAINER IDでログイン
$ docker exec -it ${CONTAINER_ID} /bin/bash
恒久化(Commit)
作業した内容は保存されないないので、commitすることで、状態が差分として保存される
$ docker commit ${CONTAINER_ID} ${NAME}/${TAG}
Dockerでportをホストのportとバインドして起動
docker内でportを起動して、ホストマシンにつなげてサービスを公開するときなど、利用できる
$ docker run -it -p ${PORT}:${PORT} bash
6. Dockerコンテナにsshdなどの必須ソフトウェアをインストールする
DockerコンテナにSSHでアクセスする
sshdなどはdockerの性質上、systemdなどで管理なので、dockerにbashなどでログインして、手動やdocker-composeなどで起動する必要があります
$ apt install openssh-server
sshdのインストール(ArchLinux)
$ sudo pacman -S openssh
sshdサーバの起動
$ /usr/bin/sshd
sshへのアクセス
IPアドレスなどをnet-toolsのifconfigなどで確認して、ホストマシンからclientのマシンに接続する
$ ssh ${USER}@172.17.0.2
.bashrcのロード
通常の環境変数のローディングと異なるので、.bashrcから読み取る
$ source .bashrc
これをしないとlocaleがja_JP.UTF-8にならずにtmuxなどが使えないっぽい
7. dockerコンテナのexportとimport
諸々をインストールして、安定して運用できるようになったらば、tar形式にexportできます
export
tarファイルで出力することができます
$ docker export ${PID} > alice-bob.tar
import
$ docker import ./hogehoge.tar
インポートした状態では、最初は
REPOSITORY:<none> TAG:<none>
となるので、tagコマンドで適切に名前をつける
$ docker tag ${NAME}/${TAG} ${NEWTAGNAME}
8. 機械学習ように調整したコンテナの利用
ArchLinux(Official)
$ docker pull archlinux/base
Debian(Official)
$ docker pull debian
私のDocker Hubのレポジトリ
機械学習専用のコンテナを作りました!
sshd, python3, pip3, mecab, neologd, lightgbm, xgboost, neovim, tmux, git, JVM, Kotlin, leveldb, rocksdbなどをインストールしてすぐ使えるようにしたイメージです。docker hubで公開しているので、docker pullでダウンロードしてすぐ利用できます
すぐに機械学習できますね!!
$ docker pull nardtree/oppai:latest $ docker run -it nardtree/oppai bash (sshd serverモードではこうして、表示されたipaddressにssh oppao@${IP_ADDR}とします) $ docker run -p 1022:22 -it nardtree/oppai server.py
server.pyでは、ifconfigとsshdが非同期で実行されて、このDockerのsshdにアクセスできるようになります
**ここからコンテナ内部です** # sudo su oppai #passwordはoppaiです $ cd ~ $ source .bashrc $ python3 Python 3.6.3 (default, Oct 24 2017, 14:48:20) [GCC 7.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> $ sudo pip3 install mecab-python3 Requirement already satisfied: mecab-python3 in /usr/lib/python3.6/site-packages $ echo "艦これ" | mecab 艦これ 名詞,固有名詞,一般,*,*,*,艦これ,カンコレ,カンコレ EOS $ which lightgbm /usr/local/bin/lightgbm $ which xgboost /usr/bin/xgboost $ which nvim /usr/bin/nvim $ which javac /usr/bin/javac $ which kotlin /usr/bin/kotlin
9. 実際に使用している例
開発、分析環境として利用する例
本番に投入するサービスとして利用する例
分析機にはUbuntu, Debian or ArchLinuxを使うことが多く、本番環境ではRHELやCentOSを使う運用が多い構成なのですが、バイナリや微妙なディストリビューション間の差を人間が吸収するのはやめて、Dockerの出力を利用してどこでも再現してもらえば、問題ないよね、好きな構成でアプリとして機能すればDevOpsでよろしく組み合わせるよ、というスパースな設計ができます
このように一つの機能を持ったアプリとして動作させるには、docker composeやkubernetesを用いてDockerの断片をつなぎ合わせて、巨大なシステムを編纂します。
ローカルでserverの機能をもつアプリをDockerでラップした一つのアプリの粒度として動作させるには、このようにします。
$ docker run -p ${PORT1}:${PORT2} -it ${APPLICATION_NAME}
10. Docker Hub連係
DockerというgithubのようなコンテナのイメージのSNSみたいなのがあります
nardtree/archのようなtag名をつけるとスラッシュの先のユーザ名のレポジトリにpushできて再現性が確保で来ます
$ docker tag ${IMAGE_ID} ${USER_NAME}/${SOME_NAME} $ docker push ${USER_NAME}/${SOME_NAME}
11. Docker Compose
Dockerの一連の複雑なオペレーションを自動化した状態で、取り扱うのが、Docker Composeです
$ git clone https://github.com/GINK03/docker-compose-templates $ cd docker-compose-templates/minimal-machine-learning-oppai $ docker-compose up
これをやると、一連のめんどくさいセットアップコマンド各種をすっ飛ばして、port 1022でlocalhostにsshdできるArchLinuxが仕上がります
$ ssh -p 1022:22 oppai@localhost # password:oppai
12. Dockerのコンテナとホストマシン間でファイルの共有をする
Dockerコンテナでは状態を持たないイミュータブルアーキテクチャになっており、あまり状態を持つことを期待されて居ません しかし、RDBやKVSなどを利用する際は、当然ながら、ファイルに書き出したりして状態を保存しなければいけません
DockerfileではVOLUMEオプションをつけることで、マウントするディレクトリを指定し、作ることができます
FROM nardtree/oppai EXPOSE 22 EXPOSE 1022 EXPOSE 4567 VOLUME ["/data"] CMD ["server.py"]
Docker-compose.ymlでホストの$HOME/dataとコンテナの/dataを結び、片方で書き込まれたらもう片方にも反映されるようになります
version: '3' services: ml-app: build: . ports: - "4567:4567" - "1022:22" volumes: - ~/data:/data
13. 便利なチートシート
noneの一括削除
$ docker images | awk '/<none/{print $3}' | xargs docker rmi
肥大化するvarを別のポイントに移動
ホストマシンのデフォルトのdockerのコンテナの保存を別の場所にする
SSDでパフォーマンスが大きく変わるサービスである、KVSなどを利用する際は、こっちの方がいいよ
方法1. /etc/default/dockerを編集します
DOCKER_OPTS="-g $HOME/sda/docker/data"
方法2. /var/lib/dockerをssdやnvmeからリンクする
$ sudo mv /var/lib/docker ${nvme_dir} $ sudo ln -s ${nvme_dir} /var/lib/docker
docker containerのIPや詳細を調べる
$ docker inspect ${PID}
docker composeで一括アプリの実行
$ docker-compose run ml-app
14. まとめ
私の所属しているいくつかの組織では、インフラエンジニアが十分に確保できなく、慣れないインフラオペレーションにイライラしていたのですが、時代はDevOpsということでソフトウェアエンジニアや私のような機械学習エンジニアがインフラの管理をしなくてはいけないことが、まま発生するようになりました
最近はもう諦めて、Dockerや最近のDocker-Compose、より上位のKubernetesなどを勉強し始めて、依存や環境を丸めて機能のみを取り出すDockerの粒度が一つのアプリの粒度として優れていると、思うようになり、運用と開発の面で導入するようになりました。実際便利であり、オンプレでサーバを持たなくていいので楽です