オッサンはDesktopが好き

自作PCや機械学習、自転車のことを脈絡無く書きます

今更だけど,Dockerで開発環境を分離してみる

1. はじめに

 こんにちは.changです.

 新年度を迎え,新たな研究や開発に着手している方も多いと思います. 僕自身も,コーディング環境やレポジトリを一新しようとしています. こんな折に気にしなければならないのが,古い開発環境を如何に残すかです. Python系の開発において,ソース管理以上に重要になるのが開発環境の維持管理です. 新プロジェクトからPythonNVIDIAの資源をいじった結果,古いソースが動かなくなるという事が容易に起き得るからです. Windows.Net Frameworkが統合環境として動作したのは過去の話で,プロジェクト毎に開発環境(実行環境も)を分離するのが近年の常識です.

 開発環境を分離するベストな方法はストレージの差し替えだ,と今でも思っています. ドライバレベルから環境を分ける唯一の方法だからです. ところが,M.2 SSDの普及に伴って採用が難しくなってきました. そこで代替案になるのが,virtualenvやvenv等の仮想環境と,dockerによるコンテナの活用です*1. 僕自身は長年virtualenvを使ってきました*2. 手軽に使えて重宝していますが,分離出来る資源は限られます. virtualenvに関して言うと,分けられるのはpipでインストールするPythonライブラリだけで,aptでインストールしたり,ソースからcmakeでビルドしたライブラリは分離出来ません.

 個人的な事情を言うと,去年度の開発環境を論文の査読が終わるまでは触りたくないのです. そこで今回,dockerを試す事にしました. 僕の事情はさておき,pipの範囲を超えて,つまりPythonを主体としつつも,C言語などの別資源を併用する様な開発を,環境を安全に分離して行いたい方向けの記事になります

基本方針としては:
・ホストはUbuntu 20.04LTS
・コンテナ(分離先の環境)もUbuntu 20.04
・仕事絡みで行ったGaussian-splatting*3のビルドを題材に

2. 前準備(ホストマシン)

2. 1 NVIDIA Driver & CUDA

ホストマシンに元々入っていたものをそのまま使いました.

NVIDIA Driver ver. 550.14
・CUDA ver. 11.7

NVIDIA Driverはver. 550.14

CUDAはver. 11.7

2. 2 Gaussian-splatting

githubからソースを取得しておきます

$ cd /home/username
$ mkdir src *1
$ cd src
$ git clone https://github.com/graphdeco-inria/gaussian-splatting.git --recursive *2

*1 /home/username/src下にソースを置くこととします
*2 今回,Gaussian-splattingについての詳細は書きません(業務中にやった内容でもあるので)

2. 3 NVIDIAの自動更新を無効化

dockerの構築とは直接関係無いのですが,NVIDIA DriverやCUDAのver.が変わってコンテナが動かなくなる事がある様なので,更新を無効化しておきます

$ sudo nano /etc/apt/apt.conf.d/50unattended-upgrades

・ここ*4を参考にしました

NVIDIA DriverとCUDAの自動更新を停止

3. インストール

3. 1 Docker Engine

Docker Engineを動かす為に必要なツールをインストールします
ここ*5を参考にしました

$ sudo apt update
$ sudo apt install ca-certificates curl gnupg
$ sudo install -m 0755 -d /etc/apt/keyrings *1
$ sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
$ sudo chmod a+r /etc/apt/keyrings/docker.asc
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt update
$ sudo groupadd docker *2
$ sudo usermod -aG docker username *3

*1 aptレポジトリを追加
*2 dockerグループを作成
*3 sudo 無しでdockerコマンドを実行出来るようにする(PC再起動が必要かも).usrnameはご自身に合わせて下さい

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

$ sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
$ docker --version *1
$ docker compose version *2
$ docker run hello-world *3

*1 ver.確認
*2 docker composeのver.確認
*3 サンプルイメージで動作確認

docker ver. 28.1.1

docker compse ver. 2.35.1

動作確認.イメージhello-worldを取得&起動

3. 2 Ubuntu 20.04コンテナを作成

結果的には使わないのですが,ここ*6を参考にUbuntu 20.04のdocker環境を作ります

イメージを取得

$ docker pull ubuntu:20.04
$ docker images

Ubuntu 20.04イメージを取得

コンテナを作成

$ cd /home/username/src/gaussian-splatting
$ docker run -it -v $PWD:/share/gaussian-splatting -d --name g-splatting ubuntu:20.04 *1
$ docker exec -it g-splatting bash
root@containerid:/# ls share/gaussian-splatting *2

*1 g-splattingはコンテナ名で,任意に設定します."-v $PWD:/share"がポイントで,下記Noteで解説します
*2 ここからコンテナの中です.以後もコンテナの中で実行するコマンドには"root@containerid:/# "を表記します

Note:
ソースファイル用の共有設定です*7.これをしないと,コンテナを消した時にソースも一緒に消えてしまいます.virtualenvで仮想環境用のフォルダを消したらソースが無くなってしまうようなものです.共有設定によってホスト側にもソースを保存します.こうする事で,同じソースをライブラリのver.を変えて動作検証する事も可能になります.

ちゃんとGaussian-splattingのソースが/share下に入っています

ホスト側で取得したGaussian-splattingのソースが,コンテナ内から見えています

ここで一度挫折しました. 当初,CUDA等を個々のコンテナに自分で入れるのだと思っていたのですがそうではなく,ホストに入っているNVIDIA DriverとCUDAをコンテナ内*8で使う様です. 次節でNVIDIAが提供している連携ツールを入れていきます.

その前に,今作ったコンテナは要らないので消しておきます

@containerid:/# exit
$ docker stop g-splatting
$ docker rm g-splatting

3. 3 NVIDIA連携(NVIDIA Container Toolkit)

NVIDIA Container Toolkitをインストール

$ curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \
    sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
    && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
        sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
        sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
$ sudo apt update
$ sudo apt install -y nvidia-container-toolkit
$ sudo nvidia-ctk runtime configure --runtime=docker
$ sudo systemctl restart docker

コンテナを作り直す

$ docker run -it --gpus all -d --name test-gpu ubuntu:20.04 *1
$ docker exec -it test-gpu bash
root@containerid/:# nvidia-smi
root@containerid/:# nvcc -v

*1 "--gpus all"でGPUを有効化.ここも失敗するので,コンテナ名は"test-gpu"としています

ドライバは見えるようになりましたが,,,

コンテナ内でnvidia-smiを実行

nvccが見つかりません

コンテナ内でnvccのver.確認を試みますが,失敗します

ここで再度挫折です. どうやら,さらのubuntuイメージでは駄目で,nvidia用に用意されたdevelを使う必要がある様です*9*10

cuda 11.7 + Ubuntu20.04用のイメージをpullしてコンテナを作り直します

$ docker pull nvidia/cuda:11.7.1-cudnn8-devel-ubuntu20.04
$ docker run -it --gpus all -d --name g-splatting nvidia/cuda:11.7.1-cudnn8-devel-ubuntu20.04
$ docker exec -it g-splatting bash
root@containerid/:# nvcc -V

nvccが使える用になりました

コンテナの中から,ホストに入っているCUDAを使える様になりました

因みに,cuda用のコンテナにはC言語用のビルド環境が入っていました

CUDA 11.7 + Ubuntu20.04イメージには,gcc/g++ 9.4.0が入っていました

3. Gaussian-splattingを動かしてみる

ビルド手順は(業務中にやったので)公開を控え,実行手順のみを書きます

コンテナの外から必要フォルダを作って,入力画像をコピー

$ cd /home/username/src/gaussian-splatting
$ mkdir target
$ mkdir target/input
$ mkdir target/output
$ mkdir target/images
$ cp /home/username/images/entrance/*.JPG target/input/ *1

*1 ホスト内のentranceフォルダから画像をコピーしています.entranceというフォルダ名は,勤め先の玄関の写真で試したからです

コンテナの中でSfMを実行

root@containerid:/# python3 convert.py -s /share/gaussian-splatting/target

ホスト側から,SfM実行で作成されたファイルを確認できます

学習を実行

root@containerid:/# python3 train.py -s /share/gaussian-splatting/target -m /share/gaussian-splatting/target/output

4. むすび

 出来たんですが,,,正直微妙というか,思った程には環境を分けられないと感じました. 今回に関しては,aptで入れたboostとソースから入れたブーストがぶつかってたりしたので導入効果がありましたが,virtualenv(またはvenv)で十分なケースも多い筈です. また,Gaussian-splatting(正確に言うとCOLMAP)のビルドに際して,GUIを無効(有効)化するという,docker内でビルドするが故の問題も発生しました. 環境分離=docker一択という程のものでは無く,用途によってvirtualenvと使い分けるのが良いと思いました.

 とは言え,近年は(Gaussian-splattingは該当しませんが)githubにDockerfile付きで公開されるソースも多いので,避けては通れないというか,使いこなしておいて損はないでしょう.

 改めて,ストレージの差し替えが最強の環境分離だと確信しましたwww