walkingmask’s development log

IT系の情報などを適当に書いていきます

MENU

Home Mackerel with GPU-TensorFlow

(walkingmask/HomeMackerel - GitHub からの転載です)

自作 PC を組み立てて機械学習計算用自宅鯖 (サーバー) にする計画。なぜなら

  • 自由に使い倒せる計算用の鯖が無性に欲しい
  • PC自作は簡単ガンダム組み立てる並に余裕3時間くらいでできる
  • スペック考えてパーツを調べたり選んだりに時間がかかる>数日
  • それが楽しい
  • 学生なら時間あるし余裕だし楽しい

から。このドキュメントは、自分の作業ログとして、また、同じようなことをしようとしている方の参考になればと思い作成しました。

How to

主に利用するものとしては、NVIDIA グラフィックボード、Docker(nvidia-docker)、anaconda(Python3)、TensorFlow、DDNS となります。

  1. パソコンを組み立ててる
  2. Ubuntu インストール & 基本設定
  3. ドライバ, Docker, nvidia-docker, anaconda, tensorflow をインストール
  4. 外部から接続するためのセキュリティ設定
  5. DDNS で外部から SSH 接続

あとは、ソースコードなどを鯖に上げて走らせるだけ。

ここからは、実際にどのように作っていくかをできるだけ細かく説明していくのですが、二度手間や必要のない情報も含まれます。Ubuntu 側の設定をつらつらっと書いたファイルを walkingmask/HomeMackerel に置いておきます。説明をすっ飛ばしてこのファイルを参考に自分で進めても良いと思います。

パソコンを組み立てる

自作 PC を作っていきます。この辺は個人の好みがとても強く出ると思うので、参考になりそうなことを適当に書いておきます。

参考構成

今回使用した PC の構成を書いておきます。4 年くらい前の構成です。

最初は低価格でとりあえず組めればいいと思い、マザボCPUメモリディスプレイケースだけを買ってHDD周辺機器はあり合わせを使ったので、当時 3 万円くらいで作ったと思います。その後、この計画を思いついてグラボを追加したのですが、それを含め小規模構成です。しかし、それでも MacBookPro などのノートに比べると GPU のおかげでより早い学習が可能になると思うので作る価値はあるかなと思います。また、今回の作業中に良いパーツを手に入れることができたので、一部変更になっています。

HowTo 本を手に入れる

上記の PC パーツ構成はほんの一例で、しかも古く手に入りにくいと思うので、新たに構成を考えることになると思います。

また、組み立てることも考えると、簡単なものでいいので PC 自作関連書籍 or 雑誌を手に入れて、組み立ての概要をつかむといいでしょう。

規格を合わせる

パーツ選びで重要なのは規格を合わせることだと思います。例えばマザーボードのメモリスロット、CPUソケットなどの規格が合うように気をつけましょう。

その辺についても入門本や Web ページを参照するといいかと思います。

また、Ubuntu を OS としてインストールする場合で、無線 LAN の利用を想定している場合は、無線LAN子機の相性を先に確認しておくといいでしょう。

電源供給の計算

PC を組む時に気にしないといけないことの1つに電源容量がどれくらいあればいいかということがあります。次のようなページで計算しておくと楽かと思います。

組み上げる

パーツを壊さないように組み上げていきます。静電気防止のためにゴム手袋などをつけるといいかもしれません。埃防止に全裸に風呂場でヤる人もいるみたいです。エアクリーナーがあると便利です。

参考ページ

グラフィックボードのデュアルブート

追記: GPU を計算リソース専用に使うために、オンボードのグラボをディスプレイ用にするためにデュアルブート設定をしたかったのですが、dmesgにエラーが出ててどうやらうまくいってないようで、断念しました。

オンボード(CPUについている)とグラフィックボード(Nvidiaなど)のデュアルブートBIOS 設定をやる方法を記しておきます。

通常、マザーボードPCI スロット(グラボを刺すスロット)にグラボを刺すと、そちらが優先されてオンボードの方は使われなくてなってしまうようです。そこで設定が必要になります。

BIOS の設定手順が少し違いますが、ほぼ同じ感じでやります。私のマザボの場合は、

Advanced
-> North Bridge Configuration
-> IGPU Multi-Monitor
-> Enabled

これでデュアルブート設定

Primary Graphic Adapter -> Onboard

これでプライマリグラフィックボード(ディスプレイ接続用)が設定できました。

Ubuntu と基本ソフトのインストール

Ubuntu と基本的なソフトウェアをインストールしていきたいと思います。

Ubuntu Server

ささっと Ubuntu Server をインストールします。適当に用意したインストールメディア(.iso の入った CD か USBメモリ)を PC に接続します。

iso ファイルについては 公式サイト からダウンロードしてきますが、サイズが大きいので uTorrent を使うことを推奨します。ダウンロードしたら適当なメディアに書き込みます。

インストールメディアを接続して PC の電源を入れるとインストーラが起動します。あとは

  1. 言語を選択して “Install Ubuntu” ボタンをクリック
  2. 次の Update や third-party などは好みに応じて選択
  3. Installation type は特に問題がなければ “Erase disk and install Ubuntu” を選択
  4. 地域を選択
  5. ユーザ情報を入力

したらインストールが開始します。

ネットワークの基本設定

IP 固定設定などを設定します。

lshw -short -class network

で、ネットワークインターフェースを確認します。enpXxx のようなものが有線 LAN の ID であるはずなので、これをメモしておいて /etc/network/interfaces を編集します。

sudo vim /etc/network/interfaces
cat /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

#
auto enp3s0
iface enp3s0 inet static
address 192.168.0.100/24
gateway 192.168.0.1
dns-nameservers 8.8.8.8 192.168.0.1

これでネットワークに繋がるはずです。適当に curl などで外部との疎通を確認してみてください。無線については今回は省略します。

参考ページ

SSH

外部から接続して操作しやすくするように SSH の設定をします。まずはインストール

sudo apt install -y openssh-server

この時点で SSH 接続は可能になっていると思うので、ip aifconfig などで IP アドレスを調べて ssh user@hostname で、ノート PC などから接続しておくと後の作業が楽ちんです。

Update

OS インストール後は、とりあえずこれ。

sudo apt -y update
sudo apt -y upgrade

基本ソフトのインストール

好みに応じて、使うであろうソフトをインストールします。

sudo apt -y install zsh vim git

zsh をデフォルトシェルにするには

chsh -s /usr/local/zsh

を実行します。初回実行時は 2 を選択して zshrc のテンプレートを作成しておくといいでしょう。

apt の掃除

新しいパッケージをインストールした後はとりあえずやってます。

sudo apt -y autoremove
sudo apt -y autoclean

TensorFlow 環境の構築

nvidia-driver、Docker、nvidia-docker、pyenv、annaconda、tensorflow を入れていきます。

ここがメインになるところですが、先人方の知恵と記録のおかげであっという間に終わります。

しかしnvidia-docker にたどり着くまでに driver を入れたり消したり CUDA や cuDNN を入れたり tensorflow を入れたり消したりかなり苦労しました。特別な理由がない限り nvidia-docker を利用することを強くお勧めします (現時点で Windows 対応はしていないようです)。

グラフィックボードの設定

まずは、グラボ用ドライバをインストールしていきます。nvidia-378 の部分は apt search nvidia-* の結果次第で適当に変更してください。

sudo add-apt-repository ppa:graphics-drivers/ppa
sudo apt -y update
sudo apt -y install nvidia-378
sudo apt -y install ubuntu-drivers-common

インストールが完了したら、再起動 (sudo reboot now) して、下記のコマンドでグラフィックボードとドライバが正常に動いているか確認します。

nvidia-smi

こんな感じで出力されていればうまくいっていると思います。

Mon Jan 23 00:36:47 2017       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 367.57                 Driver Version: 367.57                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GT 730      Off  | 0000:01:00.0     N/A |                  N/A |
| 33%   35C    P8    N/A /  N/A |    146MiB /   979MiB |     N/A      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|    0                  Not Supported                                         |
+-----------------------------------------------------------------------------+

Note

ubuntu-drivers-common をインストールすると、スムーズにドライバが入るのですが、果たして必要なのか…。また、これを入れた後に、GUI が有効になってしまっていました。Tips に GUICUI の切り替え方法が書いてあるので、GUI の必要がなければ CUI に変更しておきましょう。

参考ページ

Docker のインストール

次は Docker を Ubuntu に入れます。公式ページ 通りに進めます。

sudo apt update
sudo apt -y install curl \
  linux-image-extra-$(uname -r) \
  linux-image-extra-virtual
sudo apt -y install apt-transport-https \
  ca-certificates
curl -fsSL https://yum.dockerproject.org/gpg | sudo apt-key add -
apt-key fingerprint 58118E89F3A912897C070ADBF76221572C52609D
sudo add-apt-repository \
  "deb https://apt.dockerproject.org/repo/ \
  ubuntu-$(lsb_release -cs) \
  main"
sudo apt update
sudo apt -y install docker-engine

Docker は、次のコマンドで動作確認ができます。

sudo docker run hello-world

この時、イメージやコンテナが生成されると思うので、気になる方は Docker コマンドを調べて削除するといいでしょう。

参考ページ

nvidia-docker のインストール

こちらも 公式 GitHub のページに沿って進めます。

wget -P /tmp https://github.com/NVIDIA/nvidia-docker/releases/download/v1.0.0/nvidia-docker_1.0.0-1_amd64.deb
sudo dpkg -i /tmp/nvidia-docker*.deb && rm /tmp/nvidia-docker*.deb

次のコマンドで動作確認をします。

sudo nvidia-docker run --rm nvidia/cuda nvidia-smi

先ほどの Nvidia ドライバのインストールの時と同じ結果が表示されれば OK です。

tensorflow のインストール

nvidia-docker を利用して tensorflow を インストールした Docker イメージを作ります。cuDNN が必要なので、cuDNN 入りのイメージを走らせます。

sudo nvidia-docker run -it --name tensorflow nvidia/cuda:cudnn /bin/bash

次に Docker 上で pyenv を使って annaconda を入れます。

# Docker上で
apt-get update
apt-get install -y --no-install-recommends wget git
apt-get clean
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
source ~/.bashrc
pyenv install -l | grep ana
# ここで最新のものをコピペ
pyenv install anaconda3-4.2.0
pyenv rehash
pyenv global anaconda3-4.2.0
echo 'export PATH="$PYENV_ROOT/versions/anaconda3-4.2.0/bin/:$PATH"' >> ~/.bashrc
source ~/.bashrc
conda update conda

あとは tensorflow 公式ページ に従って tensorflow をインストールするだけです。

# Docker 上で
export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-0.12.1-cp35-cp35m-linux_x86_64.whl
pip install --ignore-installed --upgrade $TF_BINARY_URL

注意: TensorFlow 1.0.0 がリリースされています。

インストールがうまくいってるか確認しましょう。

# Docker 上で
python
# python 上で
import tensorflow as tf
sess = tf.Session()
hello = tf.constant('hello, tensorflow!')
print(sess.run(hello))
a = tf.constant(10)
b = tf.constant(32)
print(sess.run(a + b))

次のような出力があれば成功しているはずです。

I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcublas.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcudnn.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcufft.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcuda.so.1 locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcurand.so locally
I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
I tensorflow/core/common_runtime/gpu/gpu_device.cc:885] Found device 0 with properties: 
name: GeForce GT 730
major: 3 minor: 5 memoryClockRate (GHz) 1.006
pciBusID 0000:01:00.0
Total memory: 979.56MiB
Free memory: 921.12MiB
I tensorflow/core/common_runtime/gpu/gpu_device.cc:906] DMA: 0 
I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 0:   Y 
I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GT 730, pci bus id: 0000:01:00.0)
b'hello, tensorflow!'
42

これだけで終わりです。あの苦しい CUDA や cuDNN のインストール、ドライバとの戦いはなんだったんだって感じです。

MNIST のサンプルを使って他の環境と比較してみるといいかもしれません。

参考ページ

セキュリティ設定

外部から SSH 接続できるようにするためには、まずセキュリティ設定をしておく必要があります。設定項目として、ユーザの切り分け、ファイアーウォール、アンチウィルスなどになります。主に こちら を参考にさせていただきました。その後、DDNS を使って外部からグローバルドメインを利用して SSH 接続可能にします。

ユーザの設定

まずはユーザを設定していきたいと思います。この辺は自由にやって OK

ユーザをどうやって切り分けて行ったらいいかよくわからないので、よくわからないなりに 作業用、ssh 用の 2 つのユーザを Ubuntu 上に作ります。

作業用はインストール時に作ったユーザとして、それとは別に ssh 用を作ります。

# ssh ユーザの追加 パスワード設定後基本空エンター
adduser sshuser

ユーザ間のディレクトリの権限を変更します。

# root ユーザの umask 変更
sudo sed -i -e "s/^UMASK\(\t*\)022/UMASK\1027/g" /etc/login.defs
# 作業用ユーザのディレクトリを ssh ユーザから見えなくする
chmod 750 ~

気分で passprompt を変更しておきます。

# エディタを 3 の vim に変更
sudo update-alternatives --config editor
sudo visudo
# visudo 画面で次の行を追加
Defaults passprompt = "%u@%h PaSsWoRd: "

参考ページ

SSH のセキュリティ強化

SSH のセキィリティを強化しておきます。これはセキィリティ上ほぼ必須です。

まずは公開鍵でログインできるようにしましょう。

何度も修正するのは面倒なので、環境が完全に出来上がるまではローカルの .ssh/config は設定は後回しにした方がいいかもしれません。以下は設定例。

# ローカルで
scp ~/.ssh/ssh_rsa.pub sshuser@192.168.0.100:~
# リモートの ssh 用ユーザのホームディレクトリで
mkdir ~/.ssh
chmod 700 ~/.ssh
cd ~/.ssh
touch ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
cat ~/ssh_rsa.pub >>authorized_keys
rm ~/ssh_rsa.pub

次に /etc/ssh/sshd_config の設定例です。数値は好みで。

sudo sed -i -e "s/Port 22/Port 56789/g" \
-e "s/LogLevel INFO/LogLevel VERBOSE/g" \
-e "/^LoginGraceTime/i MaxAuthTries 3" \
-e "s/LoginGraceTime 120/LoginGraceTime 30/g" \
-e "s/prohibit-password/no/g" \
-e "s/#PasswordAuthentication yes/PasswordAuthentication no/g" \
/etc/ssh/sshd_config
# ssh 接続を許可するユーザの限定
sudo sed -i -e '$ a AllowUsers sshuser' /etc/ssh/sshd_config

参考ページ

UFW の設定

UFW は Uncomplicated Firewall のことで、Linux のファイアーウォールである iptables の複雑な設定を簡単に行うためのもののようです。簡単なだけに、国外からのパケットフィルタやポートスキャンを始めとした攻撃対策のような複雑な設定はできません。以下に設定の一例を挙げておきます。

sudo ufw default DENY
sudo ufw limit from 216.58.0.0/16 to any port 56789 proto tcp
sudo ufw limit from 192.168.0.0/24 to any port 56789 proto tcp
sudo ufw enable

この設定では、特定の IP アドレスから指定のポート (22 番ポートから変更した SSH ポート) へのパケットを制限付きで許可しています。

参考ページ

iptables の設定

iptablesLinux のファイアーウォールです。複雑は設定ですが、設定項目が多くて面白くもあり、Web 上のドキュメントも多いです。しかし、しっかり設定するとなると結構な労力を要するようです。

ここでは、参考になるページを紹介するにとどめたいと思います。以下の二つは特に、そのまま利用してもいいのではないでしょうか。

また、Ubuntu 16.04 では iptables の設定は PC を終了させると消えてしまうようなので、iptables-president などを導入するといいです。他にも 複数の IP アドレスをまとめてホワイトリストブラックリストに登録できる ipset といったツールもあります。ただ、こちらも設定を永続化させるには工夫が必要なようです。登録の際はシェルスクリプトを書くと楽です。

参考ページ

ClamAV の設定

CalmAV はオープンソースのアンチウィルスソフトです。念のため入れます。導入は次のページに従っていけば OK です。

freshclam の更新が上手くいかない場合は

定期実行のために次のページのスクリプトを参考に、virusscan といったような名前で実行権限をつけて /etc/cron.daily に置いておきます。

参考ページ

Rootkit Hunter の設定

rkhunter は様々な悪意のあるツールやファイルの改竄を検出してくれるソフトです。一応導入しておきます。導入は次のページに従っていけば OK です。

参考ページ

mail の設定

上記のセキュリティ用のソフトで、mail を使ってアラートを送るというコードがいくつかあるのですが、そのために一応 mail コマンドを内部でのやり取りだけに使えるように設定をします。ただ、難しくない割に色々と必要なので、setupall.sh を参照してもらって、ここでは参考にしたページを紹介するにとどめたいと思います。

参考ページ

DDNS を使って外部 SSH 接続

外部から自宅鯖に接続するには、まず自宅のグローバル IP アドレスを知っていないといけません。しかし、固定 IP アドレスは結構な料金がかかりますし (学生にとってはつらみ) 、色々と手続きをしなければなりません。そこで、DDNS (Dynamic Domain Name System) というサービスを利用します。具体的には、グローバルドメインと自宅の IP アドレスを紐付け、自宅の IP が変わった時に鯖からその変更を DDNS に登録することで、グローバルドメインを通していつでも自宅鯖に接続できるようにします。

注意

この方法を利用するにあたって、以下の点が要求されます。

  1. 世帯にグローバル IP アドレスがあること (アパートなど建物内の各部屋にプライベート IP が振られている場合は 2 へ)
  2. ネットワーク管理者である、または、ネットワーク管理者に色々お願いできる
  3. 常時起動可能な PC がある

1、3 は言わずもがなですが、2 は、グローバル IP 宛に届いたパケットをポートフォワーディングで鯖に送ってもらう必要があるため、ルータの設定をしなければなりません。

DDNS の登録

今回は、"ieServer" という日本の DDNS サービスを利用させてもらいました。

登録は非常に簡単で、左サイドバーの「新規ユーザー登録」から、利用規約・注意事項をよく読んで、サービス (通常接続) に申し込みます。登録には、「ユーザ名 (サブドメイン名)」「ドメイン名」「メールアドレス」「パスワード」が必要になります。この「サブドメイン名」「ドメイン名」から、ieserver_no_subdomain.dip.jp のようなグローバルドメインを取得することができます。

ユーザ登録が完了したら、左サイドバーの「ログイン/IPアドレス登録」から、自宅の IP アドレスを登録します。ログインして、ドメインieserver_no_subdomain.dip.jpIPアドレスを xxx.xx.x.xx に更新 をクリックすると、現在利用しているグローバル IP アドレスが、そのドメインに紐づけられます。ゆえに、この作業は自宅から行う必要があります。

ルータのポートマッピング設定

DDNS の登録が済んだら、ルータのポートマッピングの設定をします。ここでは、例として我が家のルータの設定を紹介しておきます。ルータの型は

です。まず、マッピングするプライベート IP が固定されていないと困るので、「DHCP固定割当設定」から、鯖で利用している NICMAC アドレスをメモってきて、ネットワークの基本設定 で設定した IP アドレスと共に登録します。

次に、「ポートマッピング設定」から、「LAN 側ホスト」に固定 IP アドレス、プロトコルTCP、ポート番号を SSH で設定したポートにして設定を追加します。

これで、ルータ側の設定はできたと思うので、

ssh sshuser@ieserver_no_subdomain.dip.jp -i ~/.ssh/ssh_rsa.pub

といった具合で SSH して、接続できれば成功です。この時、接続できない場合もあると思いますが、頑張って解決してください!

ヒント

  • アドレスの設定がどこか間違っている・タイポ (~/.ssh/config, /etc/ssh/sshd_config, ufw, DDNS, ルータなど)
  • プライベートアドレス内からグローバルドメイン宛に SSH すると断られることがある (vpnテザリングを利用するといいかも)
  • ufw で許可していないアドレスからの接続 (自宅の IP は可変なので登録してないはず)

DDNS の自動アップデートスクリプトの設定

これで、どこからでも接続できるようになったとは思うのですが、それは一時的です。継続的に接続できるようにするには、自宅のグローバル IP アドレスが変更された時に DDNS を更新してくれるような機構が必要になります。ここでは、例として、今作成した鯖を常時起動するものとして cron にアップデートスクリプトを登録し、自動で更新してくれるようにしたいと思います。

と言ってもスクリプトは公式で配布されているので、それを利用すれば早いです。

私は、慣れたシェルスクリプトに変更して実行権限を与えて cron に登録しました。詳しくは を見てみてください。

ここまで設定できれば、DDNS で外部から SSH 接続して、Docker の上に乗った TensorFlow を利用し、GPU を用いた学習スクリプトを回すことができるはずです!

jupyter の利用と Docker のセキュリティ

DDNS の設定までが、鯖を作り始めてからの目標だったのですが、色々と欲が出てしまい、jupyter lab を利用してブラウザから TensorFlow および tensorboard を使う設定までしたので、それを少しだけ紹介したいと思います。

jupyter lab とは

ざっくり言うと、ブラウザから Python を色々できる jupyter notebook のパワーアップバージョンです。これを利用すると「いちいちターミナルを開かなくても、ブラウザから色々できちゃうじゃん!」と思い、導入してみました。

作業用ディレクトリを作っておく

jupyter lab をインストールする前に、実行するスクリプトなどを入れておく作業用ディレクトリを、SSH ユーザのホームディレクトリ上に作っておきます。jupyter lab は、指定されたディレクトリをルートとして実行されるので、作業用ディレクトリを指定しておくと何かと楽です。

mkdir /home/sshuser/Workspace
chmod 777 /home/sshuser/Workspace

共有するため、権限を変えてます。

httpsドメインを取っておく

jupyter lab を SSL を使って利用するために、ieServer で SSL・暗号化接続用のドメインを取得します。ieServer では、5つまでドメインを登録することができます。手順は先ほどとさほど変わらないのでサクッと取っちゃいます。

ルータのポートマッピングに設定を追加

jupyter lab と tenosrboard で使用するポート用に 2 つ設定を追加しておきます。追加項目は、IP アドレスは先ほどと同じで、ポートを適当に設定しておきます。ここでは、例として jupyter lab 用に 56790、tensorboard 用に 56791 を設定しておきます。

jupyter lab のインストール

インストールはとても簡単です。Docker 上にインストールするのですが、Anaconda がインストールしてあるので jupyter notebook はすでに使える状態です。これに少し加えるだけで良いです。

しかし、先ほど作成した Docker 上に、このままインストールしていっても、Docker のポートフォワードの設定をしていないので、ブラウザから jupyter lab や tensorboard にアクセスができません。また、作業用ディレクトリを共有したいので、手間ですがコンテナを作り直します。ただ、コンテナ内でもユーザの切り分けを行いたい (jupyter lab は、ブラウザ上からターミナルを操作できるため、root ユーザのまま設定してしまうと、ブラウザ上から特権ユーザとしてコンテナにアクセスできてしまう) ため、そのため Dockerfile を作りました。

このファイルを使って… (DOCKERUSER は適当に変更してください)

(注意: 後で説明しますが、DDNS を設定した状態でこれを実行すると、世界中のブラウザからアクセスできてしまう可能性があります。心配な場合は、ルータのポートフォワーディングの設定を切っておくなどしておいてください。)

sudo nvidia-docker build -t DOCKERUSER:latest .
sudo nvidia-docker run \
-p 56790:8888 \
-p 56791:6006 \
-v /home/sshuser/Workspace:/home/DOCKERUSER/Workspace \
--name DOCKERUSER \
-u DOCKERUSER \
-d DOCKERUSER:latest /usr/local/bin/jl

とやると、これだけで設定できているはずです。ブラウザを開いて https://192.168.0.100:56790 といった登録してある固定 IP アドレスにアクセスできれば成功です。この時、SSL 証明書がオレオレ証明書なため警告が出ると思いますが、自分の鯖に自分で作った証明書なので気にせず ADVANCED から Proceed しちゃってください。

また、TensorFlow が正しく動いているかも確認してみてください。特に、tensorboard を利用できるようなサンプルを動かして、jupyter lab 上からターミナルを起動し、tensorboard を動かして http://192.168.0.100:56791 から見れれば大成功です。

Docker のポートフォワーディング設定時のセキュリティ

Docker でポートフォワーディングの設定をすると、どうやら UFW をすり抜けてしまうようです。そうすると、すべての IP アドレスからブラウザで jupyter lab にアクセスできてしまいます。これはさすがにまずい気がします。

そのため、上記の記事に書かれた解決法などがあるようですが、いろいろとうまくいかなかったため、最もいい感じだったルータのパケットフィルタを設定して解決を図ることにしました。パケットフィルタの設定は、in パケットを指定の IP アドレスからの特定のポートへのみ通過させ、それ以外は全て捨てるといった 2 つの設定を追加しました。

iptables を駆使するか Docker をもっと勉強すれば、もっとスマートなソリューションを得られるかもしれませんが、現時点では力不足ゆえに力技で解決してしまいました。

ここまで設定して、https://ieserver_no_subdomain.dip.jp:56790 にアクセスできれば成功です。

その他

書き洩らしたことなど。

Docker の自動起動設定

鯖を起動した時に systemctld に Docker を自動起動してもらうようにします。

sudo sh -c 'cat << EOF > /etc/systemd/system/docker_autostart.service
[Unit]
Description=auto start of docker containers
After=docker.service
Requires=docker.service

[Service]
ExecStart=/bin/bash -c "/usr/bin/docker start DOCKERUSER"

[Install]
WantedBy=multi-user.target
EOF'
sudo systemctl enable docker_autostart.service

docker コマンドと nvidia-docker コマンドの違い

ちょっと気をつけた方が良いポイント。

Dockerfile を作る時に参考にした記事

初 Dockerfile でした。

openssl で オレオレ証明書を作るワンライナー

VirtualBox 上でテスト

いきなり本番環境で作ってもいいのですが、失敗すると一から再インストールしないといけない上に家でしか作業できないので、VirutalBox 上に Ubuntu 16.04 LTS Server を作って Docker を入れてほぼ同じ環境でテストしていました。ただし、もちろん GPU は使えません。Anaconda がサイズ大きいので、ストレージは 16GB にしていました。

ipv6 を無効にする

今時 ipv6 を無効にするのはどうなのだろうとは思いますが。

sed -i -e "$ a net.ipv6.conf.all.disable_ipv6 = 1" /etc/sysctl.conf
sed -i -e "$ a net.ipv6.conf.default.disable_ipv6 = 1" /etc/sysctl.conf
sudo sysctl -p

参考ページ

nmap でポートの状態を確認

ufw や ルータの設定ができているのか確認するために nmap を使って調べていました。netcat でもできたかもしれません。

nmap -Pn -p 56789 ieserver_no_subdomain.dip.jp

参考ページ

sshuser に docker コマンドを一部許可する

docker start tensorflow のようなコマンドは sshuser に許可してもいいと思うので、次のように設定しておきます。

sudo visudo
sshuser    ALL=(ALL) NOPASSWD: /usr/bin/docker ps -a
sshuser    ALL=(ALL) NOPASSWD: /usr/bin/docker start tensorflow
sshuser    ALL=(ALL) NOPASSWD: /usr/bin/docker restart tensorflow
sshuser    ALL=(ALL) NOPASSWD: /usr/bin/docker stop tensorflow
sshuser    ALL=(ALL) NOPASSWD: /usr/bin/docker logs -ft tensorflow

また、このような設定は別ファイルに保存することもできます。

HDD をマウントする

バックアップ用に HDD を PC に増設した場合の設定です。まずは、デバイス名を調べてフォーマットし、マウントします。

バックアップするには、簡単に cron に rsync してもらうようにしてます。

sudo sh -c 'cat << EOF >>/etc/cron.hourly/workspace-backup 
#!/bin/bash
set -eu
/usr/bin/rsync -a --delete /home/sshuser/Workspace/ /mnt/hdd1/backup/sshuser/Workspace
exit 0
EOF'
sudo chmod +x /etc/cron.hourly/workspace-backup
sudo /etc/cron.hourly/workspace-backup

Wake On LAN

DDNS の自動更新が必要なため、常時起動を余儀なくされたわけですが、この構成の PC をずっと起動しておくと電気代がそこそこかかってしまうと思います。そこで、リモートから鯖の電源管理をするべく Wake On LAN (WOL) の設定をしてみます。もちろん、DDNS の自動アップデートはされなくなってしまうので、本来なら Raspberry Pi のようなずっと消費電力の少ないパソコンに DDNS の更新をやってもらいたいところです。

注意: ハードウェア (マザーボードNIC) 側が WOL に対応していないと、利用できません。

簡単に紹介すると、次の設定をすることで WOL できます。

  • BIOS (or UEFEI)
    • “Boot From Onboard LAN” などの設定を Enable にする
    • “Deep Sleep” などを Disabled にする
    • PCI Devices Power on” などを Enabled にする
  • 鯖上で sed -i '$ a up ethtool -s enpXXX wol g' /etc/network/interfaces
  • ルータに WOL を許可してもらう
  • クライアント PC に WOL ツールをインストールする
    • Mac であれば brew install wakeonlan

あとは、クライアント PC で

wakeonlan -i ieserver_no_subdomain.dip.jp 12:23:56:78:90:ab

のように鯖の NICMAC アドレス宛にマジックパケットを送り、鯖が起動したら成功です。

参考ページ

Ubuntu の自動セキュリティアップデート

Tips

関係あることもないことも。

sudo apt -y remove --purge libreoffice*
sudo apt -y remove --purge unity-webapps-common
sudo apt autoclean
sudo apt -y autoremove

参考ページ