はじめに

私は普段使いとしてArch Linuxを使っているのですが、ubuntuを触りたいときが稀にあります。そんなとき今まではVirtual Boxを利用していました。最近になって立て続けにVirtual Boxで作成した仮想マシンが不具合を起こしました。常用するものでもないので原因を究明して解決しようという気概もありません。前々からVirtual BoxでのOSインストール作業、起動停止の遅さやメモリの圧迫などが気になっていました。なので、これを機にdockerでデスクトップ環境を構築する方法を模索しました。

2018-03-26-003556_1366x768_scrot.png

Xephyr

dockerでGUIを使う方法はいくつかありますが、ホストがLinuxなので手軽にホストのX serverで描画します。Xephyr は X アプリケーションとして実行されるネストされた X serverです。
ubuntuならapt install xserver-xephyr、Archならpacman -S xorg-server-xephyrでインストールできます。
Xephyr -resizeable :1で可変ウィンドウでディスプレイ番号1のX serverを起動します。
イメージ作成時あるいはコンテナ起動時に環境変数でディスプレイ番号を指定します。
-e DISPLAY=:1 ENV DISPLAY=:1

サウンド

音の出力はホストのpulse audioのサーバーを使います。コンテナ起動時にホストのソケットファイルを共有します。cookieによる認証を行っているのでそれも共有しておきます。
-v /run/user/$UID/pulse/native:/tmp/pulse/native
-v $HOME/.config/pulse/cookie:/tmp/pulse/cookie
環境変数でpathなどを指定します。

ENV PULSE_SERVER=unix:/tmp/pulse/native \
    PULSE_COOKIE=/tmp/pulse/cookie

タイムゾーン

tzdataをインストール時にタイムゾーンを聞かれてビルドが止まるので、apt installする前にexport DEBIAN_FRONTEND=noninteractiveを実行しておきます。
ENV TZ=Asia/Tokyo

日本語入力

ENV GTK_IM_MODULE=fcitx \
    QT_IM_MODULE=fcitx \
    XMODIFIERS=@im=fcitx \
    DefalutIMModule=fcitx

CMDにデスクトップ環境やウィンドウマネージャを指定します。それと同時にfcitxのdaemonを起動したりfcitxの設定を変更するコマンドも指定します。

CMD fcitx-autostart > /dev/null 2>&1 && \
    fcitx-imlist -e fcitx-keyboard-jp > /dev/null 2>&1 && \
    fcitx-imlist -s fcitx-keyboard-jp,mozc > /dev/null 2>&1 && \
    jwm

あるいは、デスクトップ環境やウィンドウマネージャの設定ファイルで起動時に実行するコマンドを指定します。

#.jwmrc
<JWM>
  ...
  <StartupCommand>
    fcitx-autostart
    fcitx-imlist -e fcitx-keyboard-jp
    fcitx-imlist -s fcitx-keyboard-jp,mozc
  </StartupCommand>
  ...
</JWM>

原因は不明ですが一度変換キーを押さないと何故かIMEのON,OFFの変更ができないことが多々あります。

ユーザの作成

UIDはホストのUIDに合わせます。サウンド出力のときに使用するcookieを参照できるようにするためです。
--build-arg DOCKER_UID=$(id -u)

ARG DOCKER_USER=docker
ARG DOCKER_UID=1000
ARG DOCKER_PASSWORD=docker
RUN useradd -m --uid ${DOCKER_UID} --groups sudo --shell /bin/bash ${DOCKER_USER} && echo ${DOCKER_USER}:${DOCKER_PASSWORD} | chpasswd

デスクトップ環境,ウィンドウマネージャ

ホストではタイル型ウィンドウマネージャを使っています。使い慣れているので同じウィンドウマネージャを使おう考えましたが、X serverをネストしているのでキーバインドが重複します。なので、今回はスタック型ウィンドウマネージャのjwmを使用しています。gnomeやlxdeなどを使っていないのは余計なアプリケーションを可能な限り入れたくないからです。jwmはステータスバーが予め入っており、設定ファイルが分かりやすく、非常に軽量です。
画面をクリックするとmenuがでるのですが、そこにターミナルとブラウザを出せるようにする設定だけしています。

フォント

ターミナルで使うフォントをダウンロードしています。

RUN mkdir -p ./.local/share/fonts && \
    curl -L https://github.com/tonsky/FiraCode/raw/master/distr/ttf/{FiraCode-Regular.ttf} -o ./.local/share/fonts/#1 && \
    chown -R ${DOCKER_USER} ./.local && \
    fc-cache

ターミナル

ターミナルは設定ファイルで設定できるものなら何でもいいので、比較的軽いlxterminalにしています。フォントとカラースキームだけ設定しています。

DockerFile

FROM ubuntu:18.04

ENV DISPLAY=:1

RUN export DEBIAN_FRONTEND=noninteractive && \
    apt update && \
    apt install -y x11-xserver-utils \
                   xinit \
                   tzdata \
                   language-pack-ja-base \
                   language-pack-ja \
                   jwm \
                   sudo \
                   alsa-utils \
                   pulseaudio \
                   pulseaudio-utils \
                   fonts-ipafont-gothic \
                   dbus-x11 \
                   fcitx-mozc \
                   fcitx-imlist \
                   lxterminal \
                   vim \
                   chromium-browser \
                   curl

ENV PULSE_SERVER=unix:/tmp/pulse/native \
    PULSE_COOKIE=/tmp/pulse/cookie

RUN locale-gen ja_JP.UTF-8
ENV LANG=ja_JP.UTF-8

ENV TZ=Asia/Tokyo

ENV GTK_IM_MODULE=fcitx \
    QT_IM_MODULE=fcitx \
    XMODIFIERS=@im=fcitx \
    DefalutIMModule=fcitx

ARG DOCKER_UID
ARG DOCKER_USER=docker
ARG DOCKER_PASSWORD=docker
RUN useradd -m --uid ${DOCKER_UID} --groups sudo --shell /bin/bash ${DOCKER_USER} && echo ${DOCKER_USER}:${DOCKER_PASSWORD} | chpasswd

WORKDIR /home/${DOCKER_USER}

RUN mkdir -p ./.local/share/fonts && \
    curl -L https://github.com/tonsky/FiraCode/raw/master/distr/ttf/{FiraCode-Regular.ttf} -o ./.local/share/fonts/#1 && \
    chown -R ${DOCKER_USER} ./.local && \
    fc-cache

RUN cp /etc/jwm/system.jwmrc ./.jwmrc && \
    sed -i '/Program.*xterm.*/a <Program label="chromium">chromium-browser<\/Program>' ./.jwmrc && \
    sed -i 's/xterm\(<\/Program>\)/lxterminal\1/' ./.jwmrc

RUN mkdir -p ./.config/lxterminal && \
    cp /usr/share/lxterminal/lxterminal.conf ./.config/lxterminal/ && \
    sed -i 's/\(fontname=\).*/\1Fira Code 11/' ./.config/lxterminal/lxterminal.conf && \
    echo "bgcolor=rgb(253,246,227)\nfgcolor=rgb(101,123,131)\npalette_color_0=rgb(7,54,66)\npalette_color_1=rgb(220,50,47)\npalette_color_2=rgb(133,153,0)\npalette_color_3=rgb(181,137,0)\npalette_color_4=rgb(38,139,210)\npalette_color_5=rgb(211,54,130)\npalette_color_6=rgb(42,161,152)\npalette_color_7=rgb(238,232,213)\npalette_color_8=rgb(0,43,54)\npalette_color_9=rgb(203,75,22)\npalette_color_10=rgb(88,110,117)\npalette_color_11=rgb(101,123,131)\npalette_color_12=rgb(114,159,207)\npalette_color_13=rgb(108,113,196)\npalette_color_14=rgb(147,161,161)\npalette_color_15=rgb(253,246,227)\ncolor_preset=Custom" >> ./.config/lxterminal/lxterminal.conf && \
    chown -R ${DOCKER_USER} ./.config

USER ${DOCKER_USER}

CMD fcitx-autostart > /dev/null 2>&1 && \
    fcitx-imlist -e fcitx-keyboard-jp > /dev/null 2>&1 && \
    fcitx-imlist -s fcitx-keyboard-jp,mozc > /dev/null 2>&1 && \
    jwm

作成・起動

DOCKER_USER, DOCKER_PASSWORDを省略するとユーザ名,パスワードがdockerになる。

docker build \
    -t ubuntu-jwm \
    --build-arg DOCKER_UID=$(id -u) \
    --build-arg DOCKER_USER='ユーザ名' \
    --build-arg DOCKER_PASSWORD='パスワード' .

Xephyr -resizeable :1を実行後にdocker runを実行する。
--privilegedオプションをつけないとchromiumが起動しない。

docker run --privileged \
    -v /tmp/.X11-unix/:/tmp/.X11-unix/ \
    -v /run/user/$UID/pulse/native:/tmp/pulse/native \
    -v $HOME/.config/pulse/cookie:/tmp/pulse/cookie \
    -it --rm ubuntu-jwm

関数

毎回、長いコマンドを打ってubuntuを起動するのは面倒なので関数を作ります。

function ubuntu() {
  docker info > /dev/null 2>&1 || { echo 'Is the docker daemon running?' && return }
  [[ -e /tmp/.X11-unix/X1 ]] || Xephyr -wr -resizeable :1 &
  docker run \
    --privileged \
    -v /tmp/.X11-unix/:/tmp/.X11-unix/ \
    -v /run/user/$UID/pulse/native:/tmp/pulse/native \
    -v $HOME/.config/pulse/cookie:/tmp/pulse/cookie \
    -it --rm ubuntu-jwm
  killall Xephyr
}
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.