Docker上の仮想環境でブラウザを動かしてみた

はじめに

こんにちは、テクノロジー本部の田中です。
アドベントカレンダー13日目です。
今回は、以前に個人的興味があってやってみた話「Docker上の仮想環境でブラウザを動かしてみた」を書きたいと思います。

よくあるパターン : NoVNC を利用したブラウザから動かす仮想環境

この手の話題でよくあるのが、ブラウザから動かす仮想環境の話です。
VNC は Virtual Network Computing というリモートデスクトップのソフトウェアで、NoVNCは、それの OSS です。
これを用いて、Docker上で仮想環境を動かしてブラウザを起動します。

どうやるか

以下が NoVNC を動作させる Dockerfile と docker-compose.yml です。 (謎に tor-browser を入れているのは個人的な趣味です...w)

  • Dockerfile
FROM ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive



RUN apt update -y && apt install --no-install-recommends -y xfce4 xfce4-goodies tigervnc-standalone-server novnc websockify sudo xterm init systemd snapd vim net-tools curl wget git tzdata
RUN apt update -y && apt install -y dbus-x11 x11-utils x11-xserver-utils x11-apps
RUN apt install software-properties-common -y
RUN add-apt-repository ppa:mozillateam/ppa
RUN apt update 
RUN apt -y install firefox-esr firefox-esr-locale-ja

RUN apt -y install vlc 
RUN apt update -y && apt install -y xubuntu-icon-theme

RUN apt update -y && apt install -y fonts-noto-cjk
RUN apt update -y && apt install -y locales
RUN locale-gen ja_JP.UTF-8
ENV LANG=ja_JP.UTF-8
ENV LANGUAGE=ja_JP:ja
ENV LC_ALL=ja_JP.UTF-8
RUN touch /root/.Xauthority

RUN apt update && apt install -y sudo

ARG USERNAME=user
ARG GROUPNAME=user
ARG UID=1000
ARG GID=1000
ARG PASSWORD=admin
RUN groupadd -g $GID $GROUPNAME && \
useradd -m -s /bin/bash -u $UID -g $GID -G sudo $USERNAME && \

echo $USERNAME:$PASSWORD | chpasswd && \
echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

USER $USERNAME
WORKDIR /home/$USERNAME/

RUN wget https://www.torproject.org/dist/torbrowser/13.5.2/tor-browser-linux-x86_64-13.5.2.tar.xz
RUN tar -Jxvf tor-browser-linux-x86_64-13.5.2.tar.xz

EXPOSE 5901
EXPOSE 6080

CMD ["bash", "-c", "vncserver -localhost no -SecurityTypes None -geometry 1920x1080 --I-KNOW-THIS-IS-INSECURE && openssl req -new -subj '/C=JP' -x509 -days 365 -nodes -out self.pem -keyout self.pem && websockify -D --web=/usr/share/novnc/ --cert=self.pem 6080 localhost:5901 && tail -f /dev/null"]
  • docker-compose.yml
services:
  tor-browser:
    build: 
      context: .
    tty: true
    container_name: 'tor-browser'
    ports:
      - 8080:6080

動作させると以下の画面が出てきます。

NoVNCの画面

問題点

日本語バグ

日本語がバグる!

こっちは早急に解決!
Locale を日本設定と日本語フォントを入れました。
余談ですが、日本語入力は未だできない...

音声が出ない!

こっちが割と根が深い問題でして...
Ubuntu の音声は PulseAudio というソフトウェアを用いています。
それが、ブラウザから取得できないという感じです。

ネットワーク越しに音声を出力するための解決策

  • PulseAudio を利用
    この場合は音声を出力する Port の設定とそれをブラウザに通す能力が必要です。
    速攻、あきらめました。 (解決策が、PulseAudio 内の javascript をいじるまでは、わかるがブラウザもいじらないといけないことに絶望)
  • Bluetooth 接続 または、それ以外の方法で音声を出力 ( Chrome の RDP 拡張機能を使うとか)
    これは選択肢として微妙でした... ( Bluetooth は Docker 周りが上記のやつ同様面倒だし、RDP は単純に利用が煩わしくなる)

結局どうしたか : Docker上で直にブラウザを呼び出してみる

色々、考えた結果....
xeyes を起動できるコンテナを作成してみる。

xeyes から Firefox や Google Chrome に置き換える。

音声や画面などは、WSL2 の bus 周りから取得すれば動作可能。

ということで、Chat-GPT などで壁打ちしながら完成しました...!

以下のファイルで $ docker-compose up -d をすると Firefox が起動します。

  • Dockerfile
FROM ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive

ARG UID=1000 # ホストのユーザーIDと一致させる

RUN sed -i.org -e 's|ports.ubuntu.com|jp.archive.ubuntu.com|g' /etc/apt/sources.list \
        && apt update \
        && apt install -y software-properties-common \
        && add-apt-repository ppa:mozillateam/ppa \
        && apt install -y \
        firefox-esr \
        firefox-esr-locale-ja \
        tzdata \
        dbus-x11 \
        fcitx-mozc \
        pulseaudio \
        fonts-noto-cjk \
        locales \
        libpci-dev \
        && ln -s -f /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
        && dpkg-reconfigure tzdata \
        && locale-gen ja_JP.UTF-8 \
        && touch /root/.Xauthority \
        && apt clean \
        && rm -rf /var/lib/apt/lists/* \
        && usermod -l user $(getent passwd ${UID} | cut -d: -f1) || useradd -m -u ${UID} user

ENV LANG=ja_JP.UTF-8
ENV LANGUAGE=ja_JP:ja
ENV LC_ALL=ja_JP.UTF-8
ENV XMODIFIERS=@im=fcitx
ENV GTK_IM_MODULE=fcitx
ENV QT_IM_MODULE=fcitx

RUN echo '#!/bin/bash\nfcitx &\nexec firefox-esr' > /usr/local/bin/start.sh \
        && chmod +x /usr/local/bin/start.sh

CMD ["/usr/local/bin/start.sh"]
  • docker-compose.yml
services:
  firefox:
    build:
      context: .  
    network_mode: bridge
    shm_size: '4096m'
    environment:
      - DISPLAY=${DISPLAY}
      - PULSE_COOKIE=/tmp/pulse/cookie
      - PULSE_SERVER=unix:/tmp/pulse/native
      - XMODIFIERS=@im=fcitx
      - GTK_IM_MODULE=fcitx
      - QT_IM_MODULE=fcitx
      - DefaultIMModule=fcitx
      - DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
    volumes:
      - /tmp/.X11-unix:/tmp/.X11-unix
      - /run/user/1000/pulse/native:/tmp/pulse/native
      - ~/.config/pulse/cookie:/tmp/pulse/cookie:ro
      - /run/user/1000/bus:/run/user/1000/bus
    user: "${UID:-1000}"
    tty: true

補足
コンテナ側の環境変数 DISPLAY をホスト側の DISPLAY をセットすることが必要です。
WSL2 だと $ echo $DISPLAY で値が出てくると思いますので、うまく調整してください。

成功すると...

Firefox起動画面

まとめ

ということで、無事に完成しました!
色々と最適化されていない問題とか音声がたまに流れないとかありますが...
ともあれ、やりたいことができたので無問題です。