GUIアプリケーションを格納したコンテナを作ってみた


# はじめに

この記事は Fujitsu Advent Calendar の 17 日目の記事となります。

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

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

自分、先年から仕事では開発業務に携わっておりません（いやぁ技術調査してレポート出す以外の仕事最後にしたのいつダロ？）。

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

… はい。

# コンテナに関する自分的なおさらい

ここに書いた記事でも、散々Dockerfileだの書き散らしてきましたが、みなさんVMだのコンテナだの所謂仮想化手段をどんな目的で利用されています？

以下、無茶苦茶荒っぽい話をしてると思って読まれたし…デス。

自分的にはVMは、（物理筐体としての）サーバーからOSを分離する手段、例をあげれば1台のPCサーバの上で、あるときはLinuxを、そしてまたあるときはWindowsを動作させる、場合によっては、その両方を（どころかVersion違いのものも複数同時とか！）動かすための手段と理解しています。

で、コンテナ。
コンテナはOSからアプリケーションを分離させる手段、例をあげれば、あるOS上に同時にインストールすれば必ずコンフリクトする、Version違いのソフトウェアだったりアプリケーションだったり、そいつらが依存するライブラリだったりをコンテナの中に封じ込め、コンテナの外には影響を出さないで、中に封じ込めたものを稼働させる手段、そんなふうに理解しています（異論は認めます）。

# おさらいを踏まえて今回やりたくなったこと

とまぁ「コンテナってソフトウェアだったりアプリケーションだったり、そいつらが依存するライブラリだったりを格納し封じ込めるもんだよなぁ。」みたいなことをぬぼぉっと思い返していたところでふと思ったんですよ「アプリケーションってGUIアプリもあるよなぁ。そう言やここに書いた記事例も含め、GUIアプリ格納したコンテナって作ったことあったけ？」

GUIアプリケーションを表示しようと考えると、最低限でもXWindowsの一部の機能がいるわけで（自分としては最低XDesktop機能はいるかなと…ここも異論は認めます）、依存機能としてそんなのまで格納したコンテナ作るかぁ？　と言うわけで、ここまで一度もGUIアプリ格納コンテナを作らず参りました。

で、ここまで書けばわかりますよね？　今回は酔狂と言うか興味ただ一言で、GUIアプリ格納コンテナが作れるかどうかチャレンジしてみました。

# GUIアプリ格納コンテナのDockerfile

GUIアプリ格納コンテナは作れるものか？　結論だけ言えば、出来ます（出来ました）。

GUIアプリケーション（今回はcutecomと言うシリアルターミナルソフト）と一緒に以下を突っ込んでコンテナ化してやることで、GUIアプリを格納した且つ、起動したコンテナにVNCクライアントでアクセスできるコンテナが作成できました。

【一緒に突っ込んだもの】
① X Desktop（Xfce desktop）
② VNC Server

Dockerfile は[こちら](https://github.com/YoshihikoHara/Dockerfile_for_Xfce_desktop)で公開してますが、そこそこいろんな設定（主なものとしては、VNCクライアントからのログインに利用する、USER/Passwordの作成とか）をやっていますので、以下ちょっと解説しようと思います。

# Dockerfile について

Dockerfile の中ではめんどくさいことはしていますが特に難しいことは（多分）していません

上から見ていくと

```
#
# Last Updete: 2022/12/13
#
# Author: Yoshihiko Hara
#
# Overview:
#   A Dockerfile to create a container running "Xfce desktop environment that can be connected using a VNC client and has CuteCom and ESP32-IDF installed".
#
# Example of Build command:
#   > docker build --no-cache -t ub2204_vncxfce_cutecom_esp32idf:20221213 .
#
# Example of container initial start command:
#   > docker run -it -v `pwd`:/home/hoge/data -p 5901:5901 -u hoge --name ESP32_Xfce --privileged ub2204_vncxfce_cutecom_esp32idf:20221213
# 

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

# Change the settings so that interactive operations that may cause waiting for input, etc., do not occur while building the container.
ENV DEBIAN_FRONTEND=noninteractive

# Specify working directory (/root).
WORKDIR /root

# Modernize the container userland.
# For the "upgrade" command, specify the options "--force-confdef" and "--force-confold" to automatically update packages non-interactively.
run apt-get update \
  && apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" upgrade
```

① Ubuntu 22.04 のコンテナを作る
② コンテナ構築時に入力待ち等が発生するような対話操作が発生しないように設定を変更（環境変数 DEBIAN_FRONTEND=noninteractive）
③  "/root" ディレクトリに移動して（ここが開発ディレクトリの起点）
④ OS（というかコンテナのユーザランド）を最新化

```
# Install "language-pack" to be able to use Japanese.
run apt-get install -y language-pack-ja-base language-pack-ja

# Set the time zone and locale ("Asia/Tokyo", "ja_JP.UTF-8").
run ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
  && echo 'Asia/Tokyo' > /etc/timezone \
  && locale-gen ja_JP.UTF-8 \
  && echo 'LC_ALL=ja_JP.UTF-8' > /etc/default/locale \
  && echo 'LANG=ja_JP.UTF-8' >> /etc/default/locale
env LANG=ja_JP.UTF-8 \
    LANGUAGE=ja_JP.UTF-8 \
    LC_ALL=ja_JP.UTF-8
```

⑤ ロケール"ja_JP.UTF-8"が使えるように設定（タイムゾーンも"Asia/Tokyo", "ja_JP.UTF-8"で設定）

```
# Install the "expect" command for interactive processing.
run apt-get -y install expect
```

⑥ シェル内で対話的にコマンド実行できるように、"expect"コマンドを導入

```
# Install a set of things necessary to make "Xfce desktop environment".
run apt-get -y install \
  xubuntu-desktop \
  xfce4-terminal \
  fcitx-mozc \
  fonts-ipafont-gothic \
  fonts-ipafont-mincho \
  xdg-utils
```

⑦ Xfce デスクトップ環境を作るために必要なもの一式を導入

```
# Install VNC Server.      
run apt-get -y install tigervnc-standalone-server
```

⑧ VNC Server を導入

```
# Install "CuteCom" to communicate with the microcomputer board connected to the PC with "Serial-USB".
run apt-get -y install cutecom

# Install "vim" for text editing.
run apt-get -y install vim
```

⑨ 今回コンテナに格納を目論んでいた GUI アプリ「cutecom」とCUIアプリ「VIM」を導入

```
# Remove "Light-locker" and install "gnome-screensaver" instead.
# This measure is a combination of "Xfce + Light-locker", and there is a possibility
# that the screen will remain black when resuming from suspend.
run apt-get -y remove --purge light-locker \
  && apt-get -y install gnome-screensaver
  
# Start "im-config" with "fcitx" specified for Japanese input.  
run im-config -n fcitx

# Delete unnecessary caches, etc.
run apt-get clean \
  && rm -rf /var/cache/apt/archives/* \
  && rm -rf /var/lib/apt/lists/*
```

⑨ Xfce との組み合わせで問題がある事が既知な「Light-locker」を削除し、代わりに「gnome-screensaver」を導入
⑩ 日本語入力用に「fcitx」を指定して「im-config」を起動
⑪ 不要なキャッシュなどを削除

```
# Create a user "hoge" for operation and make settings for VNC execution in the home of "hoge".
run groupadd -g 1000 hoge \
  && useradd -d /home/hoge -m -s /bin/bash -u 1000 -g 1000 hoge \
  && echo 'hoge:fugafuga' | chpasswd \
  && echo "hoge ALL=NOPASSWD: ALL" >> /etc/sudoers \
  && echo 'spawn "tigervncpasswd"' >> /tmp/initpass \
  && echo 'expect "Password:"' >> /tmp/initpass \
  && echo 'send "fugafuga\\r"' >> /tmp/initpass \
  && echo 'expect "Verify:"' >> /tmp/initpass \
  && echo 'send "fugafuga\\r"' >> /tmp/initpass \
  && echo 'expect "Would you like to enter a view-only password (y/n)?"' >> /tmp/initpass \
  && echo 'send "n\\r"' >> /tmp/initpass \
  && echo 'expect eof' >> /tmp/initpass \
  && echo 'exit' >> /tmp/initpass \
  && sudo -u hoge -H /bin/bash -c '/usr/bin/expect /tmp/initpass' \
  && mkdir -p /home/hoge/.vnc \
  && chown hoge:hoge /home/hoge/.vnc \
  && echo '#!/bin/sh' >> /home/hoge/.vnc/xstartup \
  && echo 'export LANG=ja_JP.UTF-8' >> /home/hoge/.vnc/xstartup \
  && echo 'export LC_ALL=ja_JP.UTF-8' >> /home/hoge/.vnc/xstartup \
  && echo 'export XMODIFIERS=@im=fcitx' >> /home/hoge/.vnc/xstartup \
  && echo 'export GTK_IM_MODULE=fcitx' >> /home/hoge/.vnc/xstartup \
  && echo 'fcitx -r -d &' >> /home/hoge/.vnc/xstartup \
  && echo 'exec startxfce4' >> /home/hoge/.vnc/xstartup \
  && chmod +x /home/hoge/.vnc/xstartup \
  && mkdir -p /home/hoge/data \
  && chown -R hoge:hoge /home/hoge/data

# Make settings so that the USB can be recognized from the container.
run usermod -a -G dialout hoge
```

⑫ Userとしてhoge（UID: hoge、Password: fugafuga）を作成
⑬ USB にアクセスできるように User hoge を dialout グループに追加

```
# Create a user "hoge" for operation and make settings for VNC execution in the home of "hoge".
# Prepare to mount the host side directory to "/home/hoge/data" in the container.
volume ["/home/hoge/data"]

# Publish port 5901 of the container as a communication port for VNC.
expose 5901

# Start VNC server
cmd /usr/bin/vncserver :1 -localhost no -geometry 1152x864 -alwaysshared -fg
```

⑭ コンテナと外部との共有用ディレクトリとして"/home/hoge/data"を作成
⑮ VNC Server の通信ポートとして 5901 を確保
⑯ VNC Server を起動

この Dockerfile を使ってイメージを作り、更にコンテナを作って VNC クライアントでアクセスするとこんな感じになります。

※　余談ですが、コンテナを起動させたサーバ上でVNCクライアントを動かすなら、接続先として"localhost:5901"を指定すればコンテナに接続できるはずです。

![001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89832/39542946-1cb3-0c95-a658-18ca0d3a10ce.png)

Password（fugafuga）でログインするとこんなデスクトップに入れます（発色がおかしくなっているのは御愛嬌）。

![003.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89832/f34cd68e-49a3-e360-4d7e-53c88469d2a5.png)

コンテナへの格納対象としたGUIアプリのcutecomもちゃんと起動します。

![004.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89832/1cc48bb9-698d-f3d0-3176-974b2192809d.png)

さて、自分のやりたいことはできることが確認できました。
公開した Dockerfile やこの説明が誰かのお役立ちとなると良いなぁ。

では、また。