dockerコンテナ内でcolmap guiを動作させる方法
TL;DR
-
Xvfb, xfce4, VNCを使ってDockerコンテナ内に仮想ディスプレイを作成し、その中で
colmap gui
を動かす。 - noVNCを使うことで、ブラウザから仮想ディスプレイへアクセスできるようにする。
- 同様の手法で、Dockerコンテナ内でGUIが必要なソフトを動かすことができる。
起動イメージ
1. はじめに
Docker上でCOLMAPをビルドし、その中でcolmap gui
を動かしたいモチベーションがありました。(macでbrew install colmap
が失敗したりしたため)
しかし、Dockerコンテナ内でGUIを起動するにはそのままではうまく動きません。
そこで、Xvfb, xfce4, VNCを使ってDockerコンテナ内に仮想ディスプレイを作成し、その仮想環境内でcolmap gui
を起動できるようにしました。
VNCとは?
ネットワーク経由で別のコンピューターの画面を遠隔操作するための技術で、リモートデスクトップの一種です。
今回はxvfbで作成した仮想ディスプレイを、VNCで遠隔操作できるようにしています。
noVNCとは?
VNCクライアントを Webブラウザ上で動作させるためのソフトウェアです。
通常、VNC接続にはVNC Viewer等の専用クライアントが必要なのですが、これをブラウザからでもアクセスできるようにするのがnoVNCです。
2. Dockerfile等
VNCを起動する際は、GPU版,CPU版のどちらかのDockerfile
とstartup.sh
を同じディレクトリに配置し、Usageに従って実行してください。
Dockerfile (GPU版)
ARG UBUNTU_VERSION=22.04
ARG NVIDIA_CUDA_VERSION=11.8.0
#
# Docker builder stage.
#
FROM nvidia/cuda:${NVIDIA_CUDA_VERSION}-devel-ubuntu${UBUNTU_VERSION} AS builder
ARG COLMAP_GIT_COMMIT=main
ARG CUDA_ARCHITECTURES=native
ENV QT_XCB_GL_INTEGRATION=xcb_egl
# Prevent stop building ubuntu at time zone selection.
ENV DEBIAN_FRONTEND=noninteractive
# Prepare and empty machine for building.
RUN apt-get update && \
apt-get install -y --no-install-recommends --no-install-suggests \
git \
cmake \
ninja-build \
build-essential \
libboost-program-options-dev \
libboost-graph-dev \
libboost-system-dev \
libeigen3-dev \
libflann-dev \
libfreeimage-dev \
libmetis-dev \
libgoogle-glog-dev \
libgtest-dev \
libgmock-dev \
libsqlite3-dev \
libglew-dev \
qtbase5-dev \
libqt5opengl5-dev \
libcgal-dev \
libceres-dev \
libcurl4-openssl-dev
# Build and install COLMAP.
RUN git clone https://github.com/colmap/colmap.git
RUN cd colmap && \
git fetch https://github.com/colmap/colmap.git ${COLMAP_GIT_COMMIT} && \
git checkout FETCH_HEAD && \
mkdir build && \
cd build && \
cmake .. -GNinja -DCMAKE_CUDA_ARCHITECTURES=${CUDA_ARCHITECTURES} \
-DCMAKE_INSTALL_PREFIX=/colmap-install && \
ninja install
#
# Docker runtime stage.
#
FROM nvidia/cuda:${NVIDIA_CUDA_VERSION}-runtime-ubuntu${UBUNTU_VERSION} AS runtime
# Minimal dependencies to run COLMAP binary compiled in the builder stage.
# Note: this reduces the size of the final image considerably, since all the
# build dependencies are not needed.
RUN apt-get update && \
apt-get install -y --no-install-recommends --no-install-suggests \
libboost-program-options1.74.0 \
libc6 \
libceres2 \
libfreeimage3 \
libgcc-s1 \
libgl1 \
libglew2.2 \
libgoogle-glog0v5 \
libqt5core5a \
libqt5gui5 \
libqt5widgets5 \
libcurl4
# Copy all files from /colmap-install/ in the builder stage to /usr/local/ in
# the runtime stage. This simulates installing COLMAP in the default location
# (/usr/local/), which simplifies environment variables. It also allows the user
# of this Docker image to use it as a base image for compiling against COLMAP as
# a library. For instance, CMake will be able to find COLMAP easily with the
# command: find_package(COLMAP REQUIRED).
COPY /colmap-install/ /usr/local/
# ------------ VNC ------------
ENV DEBIAN_FRONTEND=noninteractive
ENV DISPLAY=:0
RUN apt-get update && \
apt-get install -y --no-install-recommends --no-install-suggests \
# Install VNC server.
x11vnc \
xvfb \
xfce4 \
xfce4-terminal \
# Install noVNC.
git \
xinit \
dbus-x11 && \
git clone https://github.com/novnc/noVNC.git /opt/noVNC
COPY startup.sh /root/startup.sh
RUN chmod +x /root/startup.sh
EXPOSE 6080
CMD ["/root/startup.sh"]
Dockerfile (CPU版)
ARG UBUNTU_VERSION=22.04
#
# Docker builder stage.
#
FROM ubuntu:${UBUNTU_VERSION} AS builder
ARG COLMAP_GIT_COMMIT=main
ENV QT_XCB_GL_INTEGRATION=xcb_egl
# Prevent stop building ubuntu at time zone selection.
ENV DEBIAN_FRONTEND=noninteractive
# Prepare and empty machine for building.
RUN apt-get update && \
apt-get install -y --no-install-recommends --no-install-suggests \
git \
cmake \
ninja-build \
build-essential \
libboost-program-options-dev \
libboost-graph-dev \
libboost-system-dev \
libeigen3-dev \
libflann-dev \
libfreeimage-dev \
libmetis-dev \
libgoogle-glog-dev \
libgtest-dev \
libgmock-dev \
libsqlite3-dev \
libglew-dev \
qtbase5-dev \
libqt5opengl5-dev \
libcgal-dev \
libceres-dev \
libcurl4-openssl-dev
RUN apt-get install -y ca-certificates gnupg
# Build and install COLMAP.
RUN git clone https://github.com/colmap/colmap.git
RUN cd colmap && \
git fetch https://github.com/colmap/colmap.git ${COLMAP_GIT_COMMIT} && \
git checkout FETCH_HEAD && \
mkdir build && \
cd build && \
cmake .. -GNinja \
-DCMAKE_INSTALL_PREFIX=/colmap-install && \
ninja install
#
# Docker runtime stage.
#
FROM ubuntu:${UBUNTU_VERSION}
# Minimal dependencies to run COLMAP binary compiled in the builder stage.
# Note: this reduces the size of the final image considerably, since all the
# build dependencies are not needed.
RUN apt-get update && \
apt-get install -y --no-install-recommends --no-install-suggests \
libboost-program-options1.74.0 \
libc6 \
libceres2 \
libfreeimage3 \
libgcc-s1 \
libgl1 \
libglew2.2 \
libgoogle-glog0v5 \
libqt5core5a \
libqt5gui5 \
libqt5widgets5 \
libcurl4
# Copy all files from /colmap-install/ in the builder stage to /usr/local/ in
# the runtime stage. This simulates installing COLMAP in the default location
# (/usr/local/), which simplifies environment variables. It also allows the user
# of this Docker image to use it as a base image for compiling against COLMAP as
# a library. For instance, CMake will be able to find COLMAP easily with the
# command: find_package(COLMAP REQUIRED).
COPY /colmap-install/ /usr/local/
RUN apt-get install -y ca-certificates gnupg
# ------------ VNC ------------
ENV DEBIAN_FRONTEND=noninteractive
ENV DISPLAY=:0
RUN apt-get update && \
apt-get install -y --no-install-recommends --no-install-suggests \
# Install VNC server.
x11vnc \
xvfb \
xfce4 \
xfce4-terminal \
# Install noVNC.
git \
xinit \
dbus-x11 && \
git clone https://github.com/novnc/noVNC.git /opt/noVNC
COPY startup.sh /root/startup.sh
RUN chmod +x /root/startup.sh
EXPOSE 6080
CMD ["/root/startup.sh"]
startup.sh
#!/bin/bash
Xvfb :0 -screen 0 1280x720x24 &
startxfce4 &
if [ -n "$VNC_PASSWORD" ]; then
echo -n "$VNC_PASSWORD" > /.password1
x11vnc -storepasswd $(cat /.password1) /.password2
chmod 400 /.password*
x11vnc -display :0 -rfbauth /.password2 -forever -usepw -shared -xkb -reopen -rfbport 5900 -bg
export VNC_PASSWORD=
else
# passwordless
x11vnc -display :0 -forever -shared -nopw -xkb -reopen -rfbport 5900 -bg
fi
/opt/noVNC/utils/novnc_proxy --vnc localhost:5900 --listen 0.0.0.0:6080
(任意) docker-compose.yml
services:
ubuntu-vnc-colmap:
build: .
container_name: ubuntu-vnc-colmap
ports:
# noVNC
- "6080:6080"
volumes:
- ./:/app/data
# VNCのパスワードを指定したい場合
# environment:
# - VNC_PASSWORD=xxxx
tty: true
エラー関連
nvcc
GPU版Dockerfileにて、colmapのビルド時に
nvcc fatal : Unsupported gpu architecture 'compute_'
というエラーが出る場合、11行目にある CUDA_ARCHITECTURES
を以下のように書き換えてください。
- ローカル環境でを実行し、GPU のアーキテクチャ(例:8.9 など)を確認。
nvidia-smi --query-gpu=compute_cap --format=csv,noheader
- その数値から「.」を除いた値を
CUDA_ARCHITECTURES
に指定- 例: GPU のアーキテクチャが 8.9 の場合、
CUDA_ARCHITECTURES=89
- 例: GPU のアーキテクチャが 8.9 の場合、
参考:
ninjaでのビルドエラー
> ninja
[1/259] Building CXX object src/colmap/controllers/CMakeFiles/colmap_controllers.dir/bundle_adjustment.cc.o
FAILED: src/colmap/controllers/CMakeFiles/colmap_controllers.dir/bundle_adjustment.cc.o
/usr/bin/c++ -DBOOST_ALL_NO_LIB -DBOOST_GRAPH_DYN_LINK -DBOOST_PROGRAM_OPTIONS_DYN_LINK -DBOOST_REGEX_DYN_LINK -DCERES_EXPORT_INTERNAL_SYMBOLS -DCOLMAP_CGAL_ENABLED -DCOLMAP_DOWNLOAD_ENABLED -DCOLMAP_GPU_ENABLED -DCOLMAP_GUI_ENABLED -DCOLMAP_LSD_ENABLED -DCOLMAP_OPENGL_ENABLED -DCOLMAP_OPENMP_ENABLED -DGFLAGS_IS_A_DLL=0 -DGLOG_VERSION_MAJOR=0 -DGLOG_VERSION_MINOR=4 -DGOOGLE_GLOG_DLL_DECL="" -DGOOGLE_GLOG_DLL_DECL_FOR_UNITTESTS="" -DPOSELIB_DEBUG=0 -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NO_DEBUG -DQT_OPENGL_LIB -DQT_WIDGETS_LIB -I/app/colmap/src -I/app/colmap/build/_deps/poselib-src -I/app/colmap/build/_deps/poselib-build/generated_headers -isystem /usr/include/eigen3 -isystem /usr/include/aarch64-linux-gnu/qt5 -isystem /usr/include/aarch64-linux-gnu/qt5/QtCore -isystem /usr/lib/aarch64-linux-gnu/qt5/mkspecs/linux-g++ -isystem /usr/include/aarch64-linux-gnu/qt5/QtOpenGL -isystem /usr/include/aarch64-linux-gnu/qt5/QtWidgets -isystem /usr/include/aarch64-linux-gnu/qt5/QtGui -Wno-maybe-uninitialized -Wall -O3 -DNDEBUG -fPIC -fopenmp -std=gnu++17 -MD -MT src/colmap/controllers/CMakeFiles/colmap_controllers.dir/bundle_adjustment.cc.o -MF src/colmap/controllers/CMakeFiles/colmap_controllers.dir/bundle_adjustment.cc.o.d -o src/colmap/controllers/CMakeFiles/colmap_controllers.dir/bundle_adjustment.cc.o -c /app/colmap/src/colmap/controllers/bundle_adjustment.cc
c++: fatal error: Killed signal terminated program cc1plus
ホスト側の性能が足りていないと、このエラーが出やすいです。
よほどのスペック不足でない限り、ninja install
をninja install -j1
に変更して、ビルドの並列処理を無効にすることで解決すると思います。
参考:
3. Usage
docker-composeを使用する場合
docker-compose up --build -d
を実行した後、ブラウザで http://localhost:6080/vnc.html にアクセスすると、noVNCが開きます。
その後、noVNC内のターミナルで
colmap gui
と打つとCOMAPのGUIが立ち上がります。
4. 最後に
COLMAP以外でも、Dockerコンテナ内でGUIが必要なソフトを動かしたい場面は多いと思います。
同様の手法でXvfb + xfce4 + x11vnc + noVNCを使うことで、手軽にブラウザ経由のリモートGUIが実現できるので、どなたかの参考になれば幸いです。
Dockerfile
, startup.sh
でやっていること
おまけ. Dockerfileの # ------------ VNC ------------
までは、COMLAP公式が公開しているマルチステージビルドをベースにしています。
ここでは、VNC周りの解説を中心に取り上げます。
Dockerfileでやってること
全体像
ENV DEBIAN_FRONTEND=noninteractive
ENV DISPLAY=:0
RUN apt-get update && \
apt-get install -y --no-install-recommends --no-install-suggests \
# Install VNC server.
x11vnc \
xvfb \
xfce4 \
xfce4-terminal \
# Install noVNC.
git \
xinit \
dbus-x11 && \
git clone https://github.com/novnc/noVNC.git /opt/noVNC
COPY startup.sh /root/startup.sh
RUN chmod +x /root/startup.sh
EXPOSE 6080
CMD ["/root/startup.sh"]
詳細
ENV DEBIAN_FRONTEND=noninteractive
これをしないと、apt-get installする際にtimezoneなどをインタラクティブに設定する必要があり、入力待ち状態になってビルドが途中で止まります。
ENV DISPLAY=:0
xvfbで生成する仮想ディスプレイの番号を指定。
RUN apt-get update && \
apt-get install -y --no-install-recommends --no-install-suggests \
# Install VNC server.
x11vnc \
xvfb \
xfce4 \
xfce4-terminal \
# Install noVNC.
git \
xinit \
dbus-x11 && \
git clone https://github.com/novnc/noVNC.git /opt/noVNC
VNCサーバーやnoVNCの依存関係をインストール。
startup.shでやってること
- xvfbで仮想ディスプレイを作成
- xfce4でデスクトップ環境を準備
- VNC/noVNCでGUIに外部からアクセスできるように設定
全体像
#!/bin/bash
Xvfb :0 -screen 0 1280x720x24 &
startxfce4 &
if [ -n "$VNC_PASSWORD" ]; then
echo -n "$VNC_PASSWORD" > /.password1
x11vnc -storepasswd $(cat /.password1) /.password2
chmod 400 /.password*
x11vnc -display :0 -rfbauth /.password2 -forever -usepw -shared -xkb -reopen -rfbport 5900 -bg
export VNC_PASSWORD=
else
# passwordless
x11vnc -display :0 -forever -shared -nopw -xkb -reopen -rfbport 5900 -bg
fi
/opt/noVNC/utils/novnc_proxy --vnc localhost:5900 --listen 0.0.0.0:6080
詳細
Xvfb :0 -screen 0 1280x720x24 &
Xvfbを起動し、仮想ディスプレイ番号0番で、サイズが1280x720、24bitカラーのディスプレイを仮想的に作成。
startxfce4 &
軽量デスクトップ環境のxfce4を起動。
if [ -n "$VNC_PASSWORD" ]; then
echo -n "$VNC_PASSWORD" > /.password1
x11vnc -storepasswd $(cat /.password1) /.password2
chmod 400 /.password*
x11vnc -display :0 -rfbauth /.password2 -forever -usepw -shared -xkb -reopen -rfbport 5900 -bg
export VNC_PASSWORD=
else
# passwordless
x11vnc -display :0 -forever -shared -nopw -xkb -reopen -rfbport 5900 -bg
fi
x11vncを起動し、VNCの有無やパスワード設定を行う。
x11vncのオプションの詳細は下記マニュアルを参照してください。
/opt/noVNC/utils/novnc_proxy --vnc localhost:5900 --listen 0.0.0.0:6080
noVNCを起動。
ポート5900で動作するVNCを、6080番から接続できるようにしています。
Discussion