1. 株式会社PALTEK
  2. TECHブログ
  3. 製品情報
  4. 業界最安値のGPUaaS「GPUSOROBAN」を実際に試してみた(3)~Dockerコンテナを使用し機械学習プロト環境を作る~【環境構築その2】

TECHブログ

業界最安値のGPUaaS「GPUSOROBAN」を実際に試してみた(3)~Dockerコンテナを使用し機械学習プロト環境を作る~【環境構築その2】

GPU
業界最安値のGPUaaS「GPUSOROBAN」を実際に試してみた(3)~Dockerコンテナを使用し機械学習プロト環境を作る~【環境構築その2】

皆さん、こんにちは。

本ブログは最新のGPUが使える上に、とても安いと噂の「GPUSOROBAN」がどんな感じのものなのか、Dockerコンテナを使用し機械学習プロト環境を作成し、最終的にはオンプレ環境とクラウド環境でリアルタイムに顔検出を行う工程を実際に試してみたブログです。

今回は前回のブログに続いて環境構築について紹介します。
本ブログでは以下の工程を進めます。

Dockerのインストール
CUDAが使えるコンテナを作るために必要な前準備
CUDA対応/非対応のDockerのコンテナの作成
作成したコンテナにOpenCV等のソフトウェアのインストール

早速インストールを進めます。それでは、始めましょう。

目次

Dockerのインストール

Dockerに必要なパッケージをインストールします。

左右にスクロールしてご覧ください
sudo apt update
sudo apt install apt-transport-https ca-certificates curl gnupg-agent software-properties-common

Docker公式のGPG公開鍵をインストールします。

左右にスクロールしてご覧ください
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

Dockerのリポジトリを追加します。

左右にスクロールしてご覧ください
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) stable"

Dockerをインストールします。

左右にスクロールしてご覧ください
sudo apt-get install docker-ce docker-ce-cli containerd.io

外部のネットワークへのアクセスにプロキシサーバを経由する必要がある場合は
http-proxy.confにHTTPS_PROXYを設定してください。今回は割愛します。

サイト Docker-docs-ja
タイトル systemdでDockerの制御(HTTP/HTTPSプロキシ)
URL https://docs.docker.jp/config/daemon/systemd.html

このままだとdockerコマンドの実行のたびにsudoが必要なので、ユーザをdockerグループに追加します。

左右にスクロールしてご覧ください
sudo usermod -aG docker $USER_NAME

インスタンスにインストールする場合は以下も行います。

左右にスクロールしてご覧ください
sudo usermod -aG docker $BARE_USER

shellを開きなおすとsudoなしでdockerコマンドを実行できるようになります。
Dockerのコンテナの作成と起動ができることを確認します。

左右にスクロールしてご覧ください
docker run --rm hello-world

実行結果は以下のようになります。

左右にスクロールしてご覧ください
kirin@xeon-e3:~$ docker run --rm hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:7d246653d0511db2a6b2e0436cfd0e52ac8c066000264b3ce63331ac66dca625
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/

Dockerのイメージにhello-worldが追加されています。

左右にスクロールしてご覧ください
kirin@xeon-e3:~$ docker images
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
hello-world   latest    feb5d9fea6a5   10 months ago   13.3kB

「--rm」オプションを指定しているので、コンテナは実行完了後に自動的に削除されているので、まだコンテナのリストには何もありません。

左右にスクロールしてご覧ください
kirin@xeon-e3:~$ docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

CUDAが使えるコンテナの作成準備

この手順はGPUを使用する場合に必要になります。
DockerのイメージはnVidiaが提供するnvidia/cuda:11.4.0-cudnn8-devel-ubuntu18.04を使用します。このイメージを取得します。イメージの取得が始まると以下のような進捗を表示します。私の環境では7分くらいかかりました。

左右にスクロールしてご覧ください
kirin@xeon-e3:~$ time docker pull nvidia/cuda:11.4.0-cudnn8-devel-ubuntu18.04
11.4.0-cudnn8-devel-ubuntu18.04: Pulling from nvidia/cuda
40dd5be53814: Pull complete
727501ebf16b: Pull complete
cac242494db3: Pull complete
648bcaa34440: Pull complete
942e9ab9aca4: Pull complete
cd95af8dbbe7: Downloading [===============================>                   ]  809.6MB/1.266GB
7834e91d8511: Download complete
f0cd23b28866: Downloading [======================>                            ]  749.8MB/1.67GB
4c98ca284304: Download complete
7f3ab65998d9: Downloading [======================>                            ]  841.3MB/1.898GB

イメージが追加されました。

左右にスクロールしてご覧ください
kirin@xeon-e3:~$ docker images
REPOSITORY    TAG                               IMAGE ID       CREATED         SIZE
nvidia/cuda   11.4.0-cudnn8-devel-ubuntu18.04   ce3d7d1c55a8   2 months ago    8.98GB
hello-world   latest                            feb5d9fea6a5   10 months ago   13.3kB

nvidia-container-runtimeをインストールします。

左右にスクロールしてご覧ください
cd $WORK_DIR/cuda
curl -s -L https://nvidia.github.io/nvidia-container-runtime/gpgkey | sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-container-runtime/$distribution/nvidia-container-runtime.list | \
    sudo tee /etc/apt/sources.list.d/nvidia-container-runtime.list
sudo apt-get update
sudo apt install nvidia-container-runtime

Dockerのサービスを開始します。

左右にスクロールしてご覧ください
sudo service docker restart

コンテナを起動し、コンテナ内でnvidia-smiを実行してGPUを認識しているか確認します。

左右にスクロールしてご覧ください
kirin@xeon-e3:/work/cuda$ docker run --rm --gpus all nvidia/cuda:11.4.0-cudnn8-devel-ubuntu18.04 nvidia-smi
Mon Aug 15 11:50:33 2022
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 470.42.01    Driver Version: 470.42.01    CUDA Version: 11.4     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  NVIDIA GeForce ... On | 00000000:01:00.0 Off |                  N/A |
| 40%   44C    P8     7W /  75W |    123MiB /  3909MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
+-----------------------------------------------------------------------------+

無事認識できました。
以上でCUDAが使えるコンテナを作る準備ができました。

コンテナの作成

オンプレ、クラウドのどちらでも共通に使えるものを作りますが、図1のようなクラウドのネットワーク構成を想定したコンテナにします。

図1 ホストPC/GPUクラウドとのネットワーク接続


オンプレで使う部分だけにすると図2のようにシンプルになります。RasPIとコンテナはまったく同じです。

図2 ホストPCとコンテナの関係


外部からDockerのコンテナ内部にアクセスするにはコンテナにポートフォワードの設定をする必要があります。
GPUクラウドに接続することを想定して設定します。

表1-1 Dockerコンテナのポートフォワード設定

  No. ホストPC側
ポート
コンテナ側
ポート
用途
No.1 1

40090

9090

検出結果映像の送信

No.2 2

8080

80

(将来LAMP環境等を
使用する場合を想定し)
外部からコンテナ内の
apacheへのアクセス

No.3 3

40022

22

ログイン用ssh


今回、映像送信がうまくいかなかったときにホストPCとコンテナ間の疎通確認にポート80(8080)でapachを使いましたが、本シリーズでは特に使用しません。

Dockerではsshは使わないのが通説のようですが、今回は以下の理由で使えるようにします。

コンテナへのデータコピーにscpを使用する
うまく動かないときの問題の切り分けや実験的な実装のためにX11を使用する

ではコンテナを作成します。
-hostnameオプションはコンテナのホスト名です。設定した名前がターミナルのコマンドプロンプトに表示されます。
ホストPC、クラウドのインスタンス、アクセスサーバ等、いろいろなものにsshで接続するのでプロンプトで分かりやすくしておきます。

ポートフォワードは-pオプションで設定します。

CUDAを使用するコンテナとそうでないコンテナではオプションが異なります。

CUDAを使用する場合

左右にスクロールしてご覧ください
docker run -p 40090:9090 -p 8080:80 -p 40022:22 \
-it -d \
--gpus all \
--hostname "docker_CUDA" \
--name kirin_cuda_test01 \
nvidia/cuda:11.4.0-cudnn8-devel-ubuntu18.04

コンテナができていることを確認します。

左右にスクロールしてご覧ください
kirin@xeon-e3:~$ docker ps -a
CONTAINER ID   IMAGE                                         COMMAND   CREATED          STATUS          PORTS                                                                                                                         NAMES
cd5916e1657e   nvidia/cuda:11.4.0-cudnn8-devel-ubuntu18.04   "bash"    36 seconds ago   Up 35 seconds   0.0.0.0:40022->22/tcp, :::40022->22/tcp, 0.0.0.0:8080->80/tcp, :::8080->80/tcp, 0.0.0.0:40090->9090/tcp, :::40090->9090/tcp   kirin_cuda_test01

CUDAを使用しない場合

左右にスクロールしてご覧ください
docker run -p 40090:9090 -p 8080:80 -p 40022:22 \
-it -d \
--hostname "docker_CPU" \
--name kirin_cpu_test01 \
ubuntu:18.04

コンテナができていることを確認します。

左右にスクロールしてご覧ください
kirin@xeon-e3:~$ docker ps -a
CONTAINER ID   IMAGE                                         COMMAND   CREATED          STATUS                      PORTS                                                                                                                         NAMES
f409d77c01de   ubuntu:18.04                                  "bash"    16 seconds ago   Up 16 seconds               0.0.0.0:40022->22/tcp, :::40022->22/tcp, 0.0.0.0:8080->80/tcp, :::8080->80/tcp, 0.0.0.0:40090->9090/tcp, :::40090->9090/tcp   kirin_cpu_test01
CUDAを使用するコンテナ、使用しないコンテナ両方を作成することができますが、同時に起動することはできません。理由はどちらのコンテナも同じポートを割り当てているためです。

docker runコマンドはコンテナを作成するとともに作成したコンテナを起動します。
コンテナ作成後にホストPCを再起動する等をしてコンテナが停止したときに再度起動する場合はdocker startコマンドで起動します。

左右にスクロールしてご覧ください
# CUDAを使用するコンテナの場合
kirin@xeon-e3:~$ docker start kirin_cuda_test01

# CUDAを使用しないコンテナの場合
kirin@xeon-e3:~$ docker start kirin_cpu_test01

停止はdocker stopコマンドを使います。

左右にスクロールしてご覧ください
# CUDAを使用するコンテナの場合
kirin@xeon-e3:~$ docker stop kirin_cuda_test01

# CUDAを使用しないコンテナの場合
kirin@xeon-e3:~$ docker stop kirin_cpu_test01

起動しているコンテナを調べるにはdocker psを使用します。
-aオプションを付与すると起動していないコンテナも含めたリストが表示されます。

この時点ではインストールしていませんが、後でインストールするsshはコンテナを再起動するたびに起動する必要があり、ホストPCで以下のコマンドを実行して起動します。

左右にスクロールしてご覧ください
# CUDAを使用するコンテナの場合
kirin@xeon-e3:~$ docker exec kirin_cuda_test01 service ssh start

# CUDAを使用しないコンテナの場合
kirin@xeon-e3:~$ docker exec kirin_cpu_test01 service ssh start

Dockerを使うときは集中的に使うので体で覚えていますが、長らく使わないと忘れてしまい、毎度思い出すのに時間がかかります。また忘れたときのために、思い出したときに頭に描いているイメージを図にしました。詳しい説明は省きますが、本シリーズで使用するコマンドはこれですべてです。

図3 よく使うdockerコマンドの関係図

コンテナの設定

CUDAを使用するか否かに関わらず必要な設定です。
コンテナにログインしてコンテナ内の環境を作っていきます。
コンテナが停止している場合はdocker startで起動してから行います。

左右にスクロールしてご覧ください
# CUDAを使用するコンテナの場合
kirin@xeon-e3:~$ docker exec -it  kirin_cuda_test01 /bin/bash
root@ docker_CUDA:/#

# CUDAを使用しないコンテナの場合
kirin@xeon-e3:~$ docker exec -it  kirin_cpu_test01 /bin/bash
root@ docker_CPU:/#

パッケージのインストール

コンテナにログインし、各種パッケージをインストールします。

左右にスクロールしてご覧ください
# パッケージのdbを更新
apt update

# ツールチェインとマルチメディア関係
apt install -y build-essential ccache cmake git libgtk2.0-dev pkg-config libavcodec-dev \
libavformat-dev libswscale-dev tesseract-ocr libtesseract-dev \
libavcodec-dev libavformat-dev libswscale-dev libv4l-dev \
libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev gstreamer1.0-plugins-good \
libgtk2.0-dev libgtk-3-dev libpng-dev libjpeg-dev libopenexr-dev libtiff-dev libwebp-dev

# python関係
apt install -y python3-dev python3-numpy python3-pip python-dev python-numpy

# X11、その他
apt install -y vim wget curl openssh-server xserver-xorg x11-apps iputils-ping \
net-tools sudo
# 上記でキーボードレイアウトを聞かれるので「54. Japanese」→「1. Japanese」を選択した。

# ここはお好みで
apt install -y emacs screen

# pythonのパッケージ関係
pip3 install --upgrade pip
pip3 install opencv-python opencv-contrib-python
pip3 install bottle

# この先の作業のために一旦sshdを起動しておきます
service ssh start 

ユーザの追加

コンテナ内にホストPCと同じユーザを追加します。
まずは追加するユーザID、グループIDをホストPCで調べます。ここではユーザ名がkirinの場合の例を記載します。

左右にスクロールしてご覧ください
kirin@xeon-E3:~$ whoami
kirin
kirin@xeon-E3:~$ id
uid=1000(kirin) gid=1000(kirin) groups=1000(kirin),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),116(lpadmin),126(sambashare),999(docker)

ユーザIDは1000、グループIDは1000となっていました。

次はコンテナにログインした状態でユーザの追加、及びsudo権限を付与します。
USER_NAME、USER_ID、GROUP_IDは環境に合わせて書き換えて実行します。

左右にスクロールしてご覧ください
root@docker__CPU:/# export USER_NAME=kirin # 追加するユーザID名
root@docker__CPU:/# export USER_ID=1000 # ホストPCで調べたkirinのID
root@docker__CPU:/# export GROUP_ID=1000 # ホストPCで調べたkirinのグループID
root@docker__CPU:/# groupadd $USER_NAME -g $GROUP_ID
root@docker__CPU:/# adduser $USER_NAME --uid $USER_ID --gid $GROUP_ID --shell /bin/bash
Adding user `kirin' ...
Adding new user `kirin' (1000) with group `kirin' ...
Creating home directory `/home/kirin' ...
Copying files from `/etc/skel' ...
Enter new UNIX password:パスワードを入力してエンター
Retype new UNIX password: パスワードを入力してエンター
passwd: password updated successfully
Changing the user information for kirin
Enter the new value, or press ENTER for the default
        Full Name []:エンター
        Room Number []:エンター
        Work Phone []:エンター
        Home Phone []:エンター
        Other []:エンター
Is the information correct? [Y/n] エンター
root@docker__CPU:/# gpasswd -a $USER_NAME sudo
Adding user kirin to group sudo

以上で追加したユーザIDでホストPCからコンテナにsshでログイン、X11を使用できるようになりました。
環境変数DISPLAYに直接操作しているPCのIPアドレスとディスプレイ番号を設定してxeyesを実行すると目玉が表示されます。
私のホストPCはヘッドレスなのでwindowsのMobaXtermからホストPCやコンテナにログインして使っています。
ホストPCのIPアドレス:192.168.0.90
windows PCのIPアドレス:192.168.0.126

コンテナ作成時にコンテナのポート22は外部のポート40022に割り当てたので、コンテナでsshを起動しておくと、ホストPCのポート40022でアクセスできます。

左右にスクロールしてご覧ください
ssh -Y -p 40022 $USER_NAME@$HOST_IP # コンテナにログイン
### 以下はsshでログインしたコンテナ内で実行します。
export DISPLAY=192.168.0.126:0 # IPアドレスとディスプレイ番号を設定
xeyes # xeyseを実行

図4 コンテナでX11の接続確認

OpenCVをインストール

OpenCVをインストールします。CUDAを使用する場合もしない場合も同じ手順でインストールできます。Dockerを使わない場合も同じです。
ここからはコンテナに追加したユーザ(kirin)でコンテナにsshでログインして進めます。ビルドにはGPUを使用する場合は40分、しない場合は20分ほどかかりました。

左右にスクロールしてご覧ください
### ホストPCからコンテナにsshでログイン
ssh -Y -p 40022 $USER_NAME@$HOST_IP

### 以下はsshでログインしたコンテナ内で実行します。
# 作業用ディレクトリを作成
export OPENCV_VER=4.5.5
export WORK_DIR=/work
export USER_NAME=kirin
export GROUP_NAME=kirin
sudo mkdir $WORK_DIR
sudo chown $USER_NAME.$GROUP_NAME $WORK_DIR

# OpenCVのソースコードを取得
mkdir $WORK_DIR/opencv_cuda/
cd $WORK_DIR/opencv_cuda/
time git clone https://github.com/opencv/opencv.git -b $OPENCV_VER --depth 1
time git clone https://github.com/opencv/opencv_contrib.git -b $OPENCV_VER --depth 1

# ビルド
mkdir build
cd  build

cmake -D CMAKE_BUILD_TYPE=RELEASE \
  -D CMAKE_INSTALL_PREFIX=/usr/local/lib/opencv$OPENCV_VER \
  -D OPENCV_EXTRA_MODULES_PATH=../opencv_contrib/modules \
  -D OpenBLAS_INCLUDE_DIR=/usr/include/x86_64-linux-gnu \
  -D OpenBLAS_LIB=/usr/lib/x86_64-linux-gnu/libopenblas.so \
  -D INSTALL_TESTS=ON \
  -D INSTALL_C_EXAMPLES=ON \
  -D WITH_PYTHON=ON \
  -D INSTALL_PYTHON_EXAMPLES=ON \
  -D BUILD_opencv_python2=OFF \
  -D BUILD_opencv_python3=ON \
  -D PYTHON_DEFAULT_EXECUTABLE=python3 \
  -D WITH_MKL=ON \
  -D WITH_CUDA=ON \
  -D CUDA_FAST_MATH=ON \
  -D WITH_CUBLAS=ON \
  -D WITH_CUDNN=ON \
  -D WITH_NVCUVID=OFF \
  -D OPENCV_DNN_CUDA=OFF \
  -D BUILD_opencv_cudaimgproc=OFF \
  -D BUILD_EXAMPLES=ON \
  ../opencv

time make -j8

# インストール
sudo make install

ビルドがうまくいかなかったときの比較のためにCUDAあり・なしそれぞれのcmakeのログを置いておきます。
CUDAを使用するコンテナ:
20220818a-opencv-cmake-cuda.log
CUDAを使用しないコンテナ:
20220818a-opencv-cmake-cpu.log

環境変数にインストールしたライブラリのパスを設定します。
私は以下のようにコンテナの~/.bashrcに追加しておきました。

左右にスクロールしてご覧ください
export OPENCV_VER=4.5.5
export PYTHONPATH=/usr/local/lib/opencv$OPENCV_VER/lib/python3.6/site-packages/cv2/python-3.6:$PYTHONPATH

インストールしたライブラリが使われるようになったか確認します。

左右にスクロールしてご覧ください
kirin@docker__CPU:/work/opencv_cuda/build$ python3 -c "import cv2; print( cv2.__version__ )"
4.5.5

正常にパスが設定されていると4.5.5が返ってきます。
4.6.0等になる場合は、標準でインストールされているライブラリが認識されていいます。PYTHONPATHに設定したパスの下にcv2.cpython-36m-x86_64-linux-gnu.soがあることを確認してください。

おわりに

いかがでしたでしょうか。
最後までご覧いただきありがとうございました!
次回もよろしくお願いします。


見積もり・無償評価などに関する
お問い合わせはこちら

このブログのシリーズ