コンテナ内のGUIアプリケーションのレンダリングをホスト側のXサーバーで実現させてみる


# はじめに

@GORO_Neko です。ご存知の方ご無沙汰してます。初めての方お初にお目にかかります。

最初にいつも通りのお断りをば。

自分、先年から仕事では開発業務に携わっておりません。記事に書いてる技術っぽい話は、個人的にアレヤコレヤやった結果から得た情報です（企業的に裏取りされた情報を期待してた各位、ごめんなさい…って僕の記事をいくつかなりとも読んでる方ならそんな期待はもってないはず）。

以下は、自分が所属する会社の意向を反映したものでもスタンスを示すものでもなく、単なる一個人の趣味の活動から産まれた記述です。

… はい。

# GUIアプリを詰め込んだコンテナの作り方に対してアイデアを頂いた！

数日前、[GUIアプリを詰め込んだコンテナの作成例](https://qiita.com/GORO_Neko/items/547222921a8e7287cabd)を書いてみました。
そうしたら嬉しいことにコメントと言うか「こんなやり方もあるんじゃない？」と言うアイデアをいただきました（コメントしてくださった @tenmyo さん、沢山沢山感謝です）。

私のやり方は「X Desktop」や「VNC Server」と言った比較的サイズのでかいものをコンテナに同梱させて、GUIアプリの表示を可能にするやり方でした。
対して頂いたコメントの案は「ホスト側のXサーバーに飛ばしてしまって、GUIアプリのレンダリングそれに任せちゃったら？」と言うもので、私のやり方よりコンテナを小さくできるのは明白な案でした。

コメントいただいた直後「え？　でもDockerエンジン動かしている側にXサーバーがなかったらだめじゃない？　純粋なCLIモードで動いているLinuxサーバとか。」などとも思ったのですが、そもそもそんな環境（CLIモードで動いているLinuxサーバ）上では、先に示した自分のやり方も、コンテナに接続するためのVNCクライアントが動くはずないので、どっちみち「おぢゃんのぱぁ」なのでした。

というわけで、
① Dockerエンジンが動いている所謂ホスト環境ではXサーバーが動いている（"/tmp/.X11-unix"にXクライアント、Xサーバー間のやり取りを仲立りするUNIXドメインソケットファイルが存在する）
② コンテナが内包するGUIアプリケーションのレンダリングはホストのXサーバーで実現する
設定で、なるべく軽い形のGUIアプリを詰め込んだコンテナの作成を試してみました。

# で、どうやって実現する？

ホスト側のと言うか、所謂Xクライアント、Xサーバーで構成されたXならば、両者間のやり取りを仲立つ存在としてにUNIXドメインソケットファイルが存在します。
自分の拙い記憶が間違っていなければ（と言うか、今回はありがたくも間違ってなかったっぽい）、それは、"/tmp/.X11-unix"のはずです。
なので、ホスト側のこのディレクトリをコンテナ側の"/tmp/.X11-unix"にマウントしてしまえば、コンテナ内で起動したGUIアプリケーションのレンダリングをホスト側におまかせ可能となるはず（なりました）。

お試しのコンテナは、以下のようなDockerfileを書いて作成しました


```
#
# Last Updete: 2022/12/18
#
# Author: Yoshihiko Hara
#
# Overview:
#   Dockerfile that creates a container that renders a GUI application using the host's X server.
#
# Example of Build command:
#   > docker build --build-arg uid=`id -u` --build-arg gid=`id -g` -t using_xserver_of_host:20221218 .
# Example of container initial start command:
#   > docker run -it --rm --name use_the_hosts_xserver -e DISPLAY=${DISPLAY} -v /tmp/.X11-unix:/tmp/.X11-unix using_xserver_of_host:20221218

# Specify the image (Ubuntu 22.04) to be the base of the container.
FROM ubuntu:22.04

# Define UID and GID for user "hoge".
ARG uid=1000
ARG gid=1000

# Modernize the container userland.
RUN apt-get update -y
RUN apt-get install -y --no-install-recommends sudo vim curl wget git ca-certificates cutecom
RUN apt-get clean

# Create the groups the user belongs to and the user itself.
RUN addgroup --gid ${gid} hoge
RUN adduser --disabled-login --gecos '' --uid ${uid} --gid ${gid} hoge
RUN usermod -G sudo hoge

# Set the user "hoge" to be able to use "sudo" command.
RUN echo "Defaults:hoge !requiretty" >> /etc/sudoers.d/hoge && \
    echo "hoge ALL=(ALL)      NOPASSWD: ALL" >> /etc/sudoers.d/hoge && \
    chmod 440 /etc/sudoers.d/hoge

# Change the user to "hoge".
USER hoge

CMD ["bash"]

```

上記のDockerfileが用意できたら以下のコマンドを実行して、まずイメージを作成します。

```
> docker build --build-arg uid=`id -u` --build-arg gid=`id -g` -t using_xserver_of_host:20221218 .

```

首尾よくイメージが作成できたら、以下のコマンドを実行して、実際にコンテナを作成・起動します。

```
> docker run -it --rm --name use_the_hosts_xserver -e DISPLAY=${DISPLAY} -v /tmp/.X11-unix:/tmp/.X11-unix using_xserver_of_host:20221218

```

この "docker run" コマンドが今回の試行のキモです。
"-v /tmp/.X11-unix:/tmp/.X11-unix" でホスト側の"/tmp/.X11-unix"をコンテナ側の同位置にマウントすることで、コンテナ内のGUIアプリのレンダリングもホスト側のXサーバーでうまいことさせるようにゴニョゴニョしているわけです。

うまくコンテナが起動できたら、シェル（bash）が起動状態のコンテナが操作できるはずです。

![00A.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89832/9575a82f-ff33-e33e-97e8-7c967092bc19.png)

コンテナ作成時にインストールしておいたGUIアプリ（cutecom）を起動すると、見事ホスト側のXデスクトップ上でGUIが表示されます。

![00C.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89832/eeae9457-bd55-7665-685a-68817300d938.png)

さて、コメントで頂いたやり方でもGUIアプリを詰め込み、表示できるコンテナが作れることを確認できました。
公開した Dockerfile やこの説明が誰かのお役立ちとなると良いなぁ。

では、また。