CV・NLPハマりどころメモ

画像認識と自然言語処理を研究する上でうまくいかなかったことと,その対策をまとめる自分用のメモが中心.

空のAWS EC2にnvidia-docker2をインストールするまで[AWS EC2][nvidia-docker2]

f:id:Vastee:20180618174144p:plain

空のEC2インスタンスUbuntuをインストールし, nvidia-docker2のインストールまで行った. 手順は多いが, 簡単な内容だ. しかし, 後で振り返ると手順を部分的に忘れてしまうので, ここに全ての手順を残すことにした. インスタンスの種類やAMI, Nvidiaドライバは, 私がインストールしたバージョンをそのまま載せて説明するので, もしかしたらバージョン違いにより, インストールがうまくいかないことがあるかもしれない. エラー承知の上で参考にしてください.

EC2インスタンスの作成

AWSのマネジメントコンソールからInstancesのタブを開き, Launch Instanceボタンを押す. Launch Instanceボタンは, 下の画像で言うと画面左上にある青いボタンのこと.

f:id:Vastee:20181113193300p:plain

Launch Instanceのボタンを押すと, Amazon Machine Image(AMI)を選択する画面がでてくるので, Ubuntu Server 16.04 LTS (HVM), SSD Volume Type を選択.

f:id:Vastee:20181113194818p:plain

次にインスタンスの種類を選ぶ画面が出てくるので, g3.4xlargeを選択.

f:id:Vastee:20181113194522p:plain

後は, 案内通りに進めば, インスタンスが作成できる.

EC2インスタンスにElastic(静的) IPを付与

AWSのマネジメントコンソールのElastic IPのタブを選択.

選択後IPのリストが表示されるので, 任意のIPを選択し, Actionボタンを押し,さらに Associate addressボタンを押す.

Associate addressボタンを押した後, Elastic IPを関連付けるインスタンスとElastic IPを選択後, Associate(関連付け)ボタンを押すと, インスタンスにElastic IPを付与することができる.

EC2インスタンスに接続

AWSのマネジメントコンソールからInstancesのタブを開き, その中から先ほど作成したインスタンスを探す. 作成したインスタンスの横にある, Public IPの欄の中にあるアドレスをメモする.

接続元のLinux PCで, vim ~/.ssh/config を打ち込み, 以下の内容をconfigに書き込む.

Host hoge # 好きな名前を書く
  HostName xx.xx.xx.xx # 先ほどメモしたインスタンスのPublic IPを書く
  Port 22
  User ubuntu
  ProxyCommand connect -H proxy.xxx.co.jp:xxxx %h %p # プロキシがある場合は書く
  Identityfile ~/.ssh/hoge.pem # 秘密鍵の場所を書く

configファイルにインスタンスの情報を書き込んだ後, ssh hogeインスタンスに接続できる.

EC2インスタンスにdockerをインストール

まず, aptをアップデート.

$ sudo apt update

次に必要なパッケージのインストール

$ sudo apt install \
    apt-transport-https \
    ca-certificates \
    curl \
    software-properties-common

Docker公式のGPGキーを取得・追加

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

aptリポジトリにdockerのリポジトリを追加

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

再度, aptをアップデート

$ sudo apt update

Docker CEのインストールを実行

$ sudo apt install docker-ce

以上でDockerのインストール作業は終了

dockerの動作確認

Docker動作確認の定番であるhello-worldを実行. Hello from Docker! が表示されれば正常にインストールが完了.

ubuntu@ip-xxx-xx-xx-xxx:~$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
: Pull complete 
Digest: 
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

sudo無しでdockerを使う為の設定

以下のコマンドを入力し, 自分のユーザをdockerグループに所属させれば, sudo無しでもdockerが使えるようになる.

$ sudo gpasswd -a ubuntu docker

ubuntuは自分のユーザー名.

nvidiaのドライバをインストール

もし以下のコマンドを叩いてnouveauが表示された場合は, 無効化する必要がある.

$ lsmod | grep nouveau

また,過去にnvidia-driverをインストールした,もしくはインストールに失敗してことがある場合は,念の為,下のコマンドで削除しておく.

sudo apt-get --purge remove nvidia-*
sudo apt-get --purge remove cuda-*

GPUの型番を確認

ubuntu@ip-xxx-xx-xx-xxx:~$ lspci | grep VGA
00:02.0 VGA compatible controller: Cirrus Logic GD 5446
00:1e.0 VGA compatible controller: NVIDIA Corporation GM204GL [Tesla M60] (rev a1)

GPUに合ったドライバをインストールする.

$ sudo add-apt-repository ppa:xorg-edgers/ppa

$ sudo apt update

NVIDIAドライバダウンロードサイト(http://www.nvidia.co.jp/Download/index.aspx?lang=jp) から, 見つけたGPUの型番に合うドライバのインストーラーを確認する.

下の画面から選択すると,

f:id:Vastee:20181114103841p:plain

以下のようにドライバ情報が出てくる. 最新のドライバのバージョンは384であることが分かった. 今回はコマンドからインストールするので, runファイルをダウンロードする必要は無い.

f:id:Vastee:20181114123406p:plain

ドライバのバージョン情報を確認後, インスタンスに戻り, ドライバ一覧を表示し, インストールするドライバを選ぶ.

ubuntu@ip-xxx-xx-xx-xxx:~$ apt-cache search 'nvidia-[0-9]+$'
nvidia-331 - Transitional package for nvidia-331
nvidia-346 - Transitional package for nvidia-346
nvidia-352 - Transitional package for nvidia-361
nvidia-304 - NVIDIA legacy binary driver - version 304.135
nvidia-340 - NVIDIA binary driver - version 340.104
nvidia-361 - Transitional package for nvidia-367
nvidia-367 - Transitional package for nvidia-375
nvidia-375 - Transitional package for nvidia-384
nvidia-384 - NVIDIA binary driver - version 384.130

ここでは, 先ほどのリストからnvidia-384を選び, 以下のコマンドでインストールした. インストールには少し時間がかかる.

$ sudo apt install nvidia-384

nvidia-docker2のインストール

ここでインストールするnvidia-dockerはバージョン2.0である. もしもnvidia-dockerのバージョン1.0がインストールされている場合, 一旦バージョン1.0をアンインストールする必要がある.

バージョン2.0のインストールで問題なければ次に進む.

以下のコマンドでaptリポジトリに必要なパッケージリポジトリパスを追加

$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -

$ curl -s -L https://nvidia.github.io/nvidia-docker/ubuntu16.04/amd64/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

リポジトリをアップデート

$ sudo apt-get update

nvidia-docker2をインストール

$ sudo apt-get install -y nvidia-docker2

dockerのデーモン設定をリロード

$ sudo pkill -SIGHUP dockerd

nvidia-docker2の動作確認

最後に, dockerコンテナ内でnvidia-smiを実行し, 動作確認を行う.

ubuntu@ip-xxx-xx-xx-xxx:~$ sudo docker run --runtime=nvidia --rm nvidia/cuda nvidia-smi
Wed Nov 14 03:36:25 2018       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 384.130                Driver Version: 384.130                   |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla M60           Off  | 00000000:00:1E.0 Off |                    0 |
| N/A   26C    P0    38W / 150W |      0MiB /  7613MiB |     94%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

ここまで来れたらnvidia-docker2のインストールは完了だ.

EC2インスタンスのストレージを増設する

dockerイメージの格納場所を外部ストレージにしたいので, インスタンスにストレージをアタッチし, そこを格納場所にする.

手順としては大まかに2つあり, ひとつはAWS マネジメントコンソール上でストレージをアタッチすること, もうひとつが任意のフォルダにストレージをマウントすることである.

では早速手順にはいる.

EC2 Management Console > ELASTIC BLOCK STORE > Volumes を選択

Create Volume で所望の容量でストレージを作成

この時, ストレージの接続場所をメモしとくと良い(例 /dev/sdf)

ストレージが作成されたことを確認したら, Actions > Attach Volume でストレージを接続したいEC2インスタンスを選択.

選択後, インスタンスを再起動.

ここからは公式のドキュメント(https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ebs-using-volumes.html)に沿って作業を行う.

再起動後, インスタンスコマンドプロンプト上でlsblkコマンドを使用し, 使用可能なディスクデバイスとマウントポイント (該当する場合) を表示.

ubuntu@ip-xxx-xx-xx-xxx:~$ lsblk
NAME    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
xvda    202:0    0    8G  0 disk 
└─xvda1 202:1    0    8G  0 part /
xvdf    202:80   0  300G  0 disk 
loop0     7:0    0 12.7M  1 loop /snap/amazon-ssm-agent/495
loop1     7:1    0 87.9M  1 loop /snap/core/5328
loop2     7:2    0 16.5M  1 loop /snap/amazon-ssm-agent/784
loop3     7:3    0 87.9M  1 loop /snap/core/5742

xvdfに先ほど作成したストレージが確かにあることがわかった.

ボリュームにファイルシステムを作成する必要があるかどうかを確認. 下記コマンドを打って, 出力にデバイスのdataだけ表示されるはず. dataだけ表示された場合は, ボリュームにファイルシステムを作成する必要がある.

ubuntu@ip-xxx-xx-xx-xxx:~$ sudo file -s /dev/xvdf
/dev/xvdf: data

ボリュームに ext4 ファイルシステムを作成.

$ sudo mkfs -t ext4 /dev/xvdf

任意の場所マウントポイントディレクトリを作成し, 作成した場所にストレージをマウント.

$ sudo mkdir ~/disk
$ sudo mount /dev/xvdf ~/disk

次に, システムブート時に常に, このストレージをマウントする為の設定を行う.

バイスの UUID を見つける為, dfコマンドを使う.

ubuntu@ip-172-31-19-116:~$ df
Filesystem     1K-blocks    Used Available Use% Mounted on
udev            62901564       0  62901564   0% /dev
tmpfs           12582728    8996  12573732   1% /run
/dev/xvda1       8065444 5171944   2877116  65% /
tmpfs           62913636       0  62913636   0% /dev/shm
tmpfs               5120       0      5120   0% /run/lock
tmpfs           62913636       0  62913636   0% /sys/fs/cgroup
/dev/loop0         13056   13056         0 100% /snap/amazon-ssm-agent/495
/dev/loop1         90112   90112         0 100% /snap/core/5328
/dev/loop2         16896   16896         0 100% /snap/amazon-ssm-agent/784
/dev/loop3         89984   89984         0 100% /snap/core/5742
tmpfs           12582728       0  12582728   0% /run/user/1000
/dev/xvdf      309506048   64344 293696680   1% /home/ubuntu/disk

次に, 2 つのコマンドのいずれかの出力を調べて, /dev/xvdf の UUID を見つける.

$ sudo file -s /dev/xvdf
$ ls -al /dev/disk/by-uuid/

fstabにエントリを追加

$ sudo vim /etc/fstab

見つけたUUIDを下のように追加

UUID=d7216092-b9d1-4df8-a714-b4626a229bd5   /home/ubuntu/disk   ext4   defaults,discard    0 0

sudo mount -a コマンドを実行し, /etc/fstabにすべてのファイルシステムをマウントする.

$ sudo mount -a

上のコマンドでエラーが出なければ, 増設が完了.

増設したストレージをdockerのイメージ・コンテナの格納場所にする

デフォルトでは docker のイメージやコンテナは標準設定だと /var/lib/docker に格納される. しかし, それでは容量が膨らんでしまったときに収集がつかなくなってしまうので, サブのストレージに格納したい.

まずはdockerを止める

$ sudo service docker stop
$ sudo systemctl stop docker

docker.serviceファイルをコピーし, Unitファイルを編集

$ sudo cp /lib/systemd/system/docker.service /etc/systemd/system/

/etc/systemd/system/docker.service から以下の行を探して --data-root オプションをつける

ExecStart=/usr/bin/dockerd -H unix:// # 編集前
ExecStart=/usr/bin/dockerd -H unix:// --data-root /home/ubuntu/disk/docker # 編集後

docker再起動

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

増設したストレージの動作確認

まず, Hello worldでエラーが出ないかを確認.

$ docker run hello-word

次に/home/ubuntu/disk/docker の中をみて, 下のようなファイルツリーが構成されていることが確認できれば完了. /var/lib/dockerは邪魔なので消しておこう.

ubuntu@ip-xxx-xx-xx-xxx:~/disk/docker$ ll
total 56
drwx--x--x 14 ubuntu ubuntu 4096 Nov 14 07:27 ./
drwx--x--x  3 ubuntu ubuntu 4096 Nov 14 07:27 ../
drwx------  2 root   root   4096 Nov 14 07:27 builder/
drwx------  4 root   root   4096 Nov 14 07:27 buildkit/
drwx------  3 root   root   4096 Nov 14 07:27 containers/
drwx------  3 root   root   4096 Nov 14 07:27 image/
drwxr-x---  3 root   root   4096 Nov 14 07:27 network/
drwx------  6 root   root   4096 Nov 14 07:27 overlay2/
drwx------  4 root   root   4096 Nov 14 07:27 plugins/
drwx------  2 root   root   4096 Nov 14 07:27 runtimes/
drwx------  2 root   root   4096 Nov 14 07:27 swarm/
drwx------  2 root   root   4096 Nov 14 07:27 tmp/
drwx------  2 root   root   4096 Nov 14 07:27 trust/
drwx------  2 root   root   4096 Nov 14 07:27 volumes/

以上で全工程が終了. お疲れ様でした.