Dockerの初歩と詰まったことへの備忘録


Dockerの初歩と詰まったことへの備忘録

はじめに

本記事は,私がUbuntu18.04とWindows上でDockerを学んだことの備忘録であるため,以下のとおりである.

  • Dockerについての環境構築について詳しく触れるものではない
  • Dockerのイメージを作成まで(Docker Hubへのアップはしていない)
  • DockerでホストのGPUを活用する方法
  • DockerでGUIを有効にする方法
  • Windows上でGUIを有効にするために必要なXserverについて

Dockerについて

まず初めに,簡単に学んだDockerの特徴だけ示しておく.

  • Dockerは隔離されたコンテナの中で作業するイメージであり,ホスト環境を壊すような心配がない.
    • コンテナ内が壊れてもすぐに廃棄して作り直せばよい
  • Dockerにはビルド -> 実行 -> 廃棄ライフサイクルがある.
    • 初めは意味が分からなかったが,作って使っていく中で更新があれば,更新内容を控えて古いものは廃棄して,作り直していくということだと理解した.
  • Dockerには基本Linuxが必要
    • WindowsやMacでも動くのは,あくまでホスト上に仮のLinuxがあり,そのうえで動いている.
  • Dockerは隔離されてはいるため,中は見えないとされているが,一部サーバやマウントにより,中身へアクセスすることも可能.
    • サーバであれば,ローカルホストの指定ポートにアクセスすることでコンテナ内を見て回ることができる.
    • マウントはホスト間でファイルの共有ができる.マウントにも種類があるが,Docker側での変更をホスト側で管理しておきたい場合や,必要なシステムファイルを共有するときなどに用いるようだ.

Dockerfile作成からイメージ作成まで

Dockerfileとは?

Dockerfileはコンテナを作るうえで必要なイメージを作成する.
コンテナを製品,イメージを鋳型と表現するならば,Dockerfileはその鋳型を作る設計図のようなものである.

Dockerfileの簡単な説明
FROM <ベースとするイメージファイル>:タグ

WORKDIR <ワークディレクトリを指定できる(shellに入ったときに始めにいるディレクトリ)>

COPY <ホスト側にあるファイルなど> <Docker内における移動先>

ENV <環境変数名> <変数に指定するもの(パスや値)>

RUN apt-get update && apt-get upgrade -y
RUN apt-get install <パッケージ> -y

CMD ["docker runしたときに実行するコマンド"]

他にも指定できるものはあるかもしれないが,現状,私が作成しているDockerfileはこれらで事足りている.必要に応じてまた調べると良いと思っている.

Dockerのイメージは他のイメージの上にどんどん作っていくことでより効率的に自分好みのイメージを作成していく.したがって,何をつくりたいのかと考えた時に一番近そうなものがないか,DockerHubを探索するのもおもろいかもしれない.

Dockerfileの作成例

ここで,Dockerfileの作成例として,noetic-desktop-full(ubuntu20.04上
にROSが構築されている)をベースとして,自分のワークスペースを適用できるところまで完了させるイメージファイルを作成するDockerfileを作ってみる.(毎回ワークスペースを作るのも面倒であるため.)

Dockerfile
FROM osrf/ros:noetic-desktop-full

WORKDIR /root/

RUN echo "source /opt/ros/noetic/setup.sh" >> .bashrc
RUN mkdir -p catkin_ws/src
RUN cd catkin_ws/src && . /opt/ros/noetic/setup.sh && catkin_init_workspace
RUN cd && cd catkin_ws && . /opt/ros/noetic/setup.sh && catkin_make
RUN echo "source ./catkin_ws/devel/setup.bash" >> .bashrc

ここでの気づきとしては,

. /opt/ros/noetic/setup.sh

がないと,catkin_init_workspaceがないと言われる.catkin_makeについても同様.

ここまででとりあえず,Dockerfile作成について整理することができた.

イメージファイルの作成

ビルドすることでイメージファイルを生成できる.

docker build -t <イメージファイル名>:<タグ名> .

Dockerfileの内容にもよるが,少し時間がかかる.

コンテナ操作

組み立て
docker run --name <コンテナ名> <イメージファイル名>:<タグ名>
  • 組み立て時には,いろんなオプションがあるようだ.主に使っているのは以下の4つ
    • -name
      • docker run --name <コンテナ名> <イメージファイル名>:<タグ名>とすることで,名前を付与したコンテナを作成できる.
    • -it
      • docker run -it <イメージファイル名>:<タグ名> /bin/bashとすることで,コンテナ内のターミナルに入ることができる.itはinteractiveオプションのようだ.
    • -p
      • docker run -p 6080:80 <イメージファイル名>:<タグ名>とすることで,80ポートをlocalhostの6080ポートに接続できる.つまりは,localhost:6080と適当なブラウザに打ち込めば,コンテナサーバにアクセスできる.
    • -v
      • docker run -v ./share <イメージファイル名>:<タグ名>とすることで,ホスト側にあるshareフォルダをdockerにマウントして,ホストとdocker間でファイルの共有が可能になる.
廃棄
docker rm <コンテナ名>

詰まったこと

背景

  • 機械学習系をdocker上でするにあたって,ホストのGPUを活用したい.
  • ROSの環境(Rvizなど)やmatplotlibなどを含めたGUIをdocker上でも使いたい.

DockerでホストのGPUを活用する方法

結論から言うと,以下のようなDockerfileと実行をすることで可能になる.

Dockerfile
FROM nvidia/cuda:11.0-devel-ubuntu20.04

RUN apt-get update
RUN apt-get install -y python3 python3-pip
RUN pip3 install torch torchvision

WORKDIR /work

COPY train.py /work/

ENV LIBRARY_PATH /usr/local/cuda/lib64/stubs

nvidiaが提供するイメージファイルをベースにPyTorchを構築している.
肝としては,ENVでLIBRARY_PATHという環境変数にcudaのパスを通す部分である.
しかしながら,これだけではうまくいかない.

コンテナ組み立て時に以下のようにする必要がある.

docker_run
docker run -it --runtime=nvidia --name pytorch_ubuntu2004_cuda pytorch_ubuntu2004_cuda:latest /bin/bash

もう一つの肝は**--runtime=nvidia**である.--gpus=allとするというような記事もよく見かけたが,私の環境ではうまくいかなかった.

参考

DockerでGUIを有効にする方法

GUIはホストでのGUIを扱う部分(Xserver)とdocker間でやり取りできるようにする必要がある.
色々とコンテナ組み立て時に指定する必要がある.
また,ターミナルコマンドもいくつか打つ必要があるため,シェルスクリプトが紹介されており,
それを以下に示す.

run.sh
# If not working, first do: sudo rm -rf /tmp/.docker.xauth
# It still not working, try running the script as root.
	
xhost +
XAUTH=/tmp/.docker.xauth
if [ ! -f $XAUTH ]
then
    xauth_list=$(xauth nlist :0 | sed -e 's/^..../ffff/')
    if [ ! -z "$xauth_list" ]
    then
        echo $xauth_list | xauth -f $XAUTH nmerge -
    else
        touch $XAUTH
    fi
    chmod a+r $XAUTH
fi

docker run -it \
    --env="DISPLAY=$DISPLAY" \
    --env="QT_X11_NO_MITSHM=1" \
    --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" \
    --env="XAUTHORITY=$XAUTH" \
    --volume="$XAUTH:$XAUTH" \
    --runtime=nvidia \
    --name=ros1_noetic \
    ros1_noetic \
    bash
echo "done"

xhost +が非常に大きな部分で,ホストのxserverに関わる権限をすべて解放するコマンドであるため,使い終わったときには,xhost -で権限を閉じたほうが良いと思う.

上記のようなシェルスクリプトをつくれば,コンテナ組み立ては以下のとおりにするだけである.

./ run.sh

Windows上でGUIを有効にするために必要なXserverについて

ubuntu上であれば,先ほどの手順でRvizなどは動くが,windows上では,xhostのような操作はできない.というのも,別でXserverを用意する必要があるようだ.

powershell上で以下のコマンドで,VcXsrvというXserverを提供するソフトをインストール.

winget install marha.VcXsrv

あとは,docker側で,必要なものをそろえる.

Dockerfile
FROM osrf/ros:noetic-desktop-full

WORKDIR /root/

ENV DISPLAY host.docker.internal:0.0

RUN apt-get update -y && apt-get upgrade -y
RUN apt-get install x11-apps -y

注目してほしいのは,ENVと最後のRUNである.

ENVでは,環境変数DISPLAYにxserverとつながるように指定している.0はディスプレイ番号を表す.

さらにRUNでは,x11-appsというソフトをインストールしている.詳しくは分からないが,これで,xserverとのやりとりが行えるようだ.

これで準備は整った.注意点としては,GUIを使いたいときには,ホスト側で先ほどインストールしたXserverを立ち上げておく必要がある.いたって簡単で,XLaunchというものを起動するだけである.特に設定とかはいじらずに指示に従っていけば,すぐに立ち上がる.

以下に実行例を示す.