2015年04月09日

LINE を使い始めたら、あれだけ苦手だったワインをクジラ料理で克服できた話

僕 Wine(Unix 系 OS 向け Windows アプリケーション実行環境)は昔から苦手。 理由は、あの膨大な依存パッケージの数とそのサイズ。 ちょっとした Windows アプリケーションを使うためだけに OS のパッケージ管理を複雑にしても良いと思える程のボリュームでは無かったのです。 でも、僕がモバイル回線を格安 MVNO に乗り換え、家族間でのメッセージングを LINE へ統一することが決まると少し事情が変わってきました。 LINE 初心者(友達は一人だけ・・・)、かつ、ソフトウェア・キーボードを使って高速に文章を打ちこむスキルの無い僕は、どうしても Linux OS 上で Windows 版 LINE クライアントを動かし快適に標準入力したい、そう思うようになっていったのです。 では、どうしたら良いのでしょうか? 僕は少しだけ考えてからその解決を諦め、問題の全てをコンテナに詰め込みクジラ(Docker)の上でワインを飲むことにしたのです。

docker



Docker を使った Wine ベース・イメージの作成


Docker はコンテナ型と呼ばれる仮想化ソフトウェア。 KVM、Xen、VMware のような従来のサーバー仮想化技術と比べると省リソースで高速に起動することが出来るという特長があります。 Docker を全く知らないという人は、まず、こちらからどうぞ。


さて、僕のホスト OS は Ubuntu MATE 14.04 です。 まずここに Docker 実行環境をインストールしますが、標準で利用可能な docker.io パッケージ(1.0.x)で無く、新たにリポジトリを登録して 1.5 系を使います。

mate $ echo deb https://get.docker.com/ubuntu docker main | sudo tee /etc/apt/sources.list.d/docker.list
mate $ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
mate $ sudo apt-get update
mate $ sudo apt-get install lxc-docker lxc
mate $ docker -v
Docker version 1.5.0, build a8a31ef


仮想マシンに固定の MAC アドレスを割り当てる(理由は後述)ので、docker 環境設定を編集して DOCKER_OPTS で lxc ドライバを指定します。

mate $ sudo vi /etc/default/docker
# Docker Upstart and SysVinit configuration file # Customize location of Docker binary (especially for development testing). #DOCKER="/usr/local/bin/docker" # Use DOCKER_OPTS to modify the daemon startup options. #DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4" # -e, --exec-driver="native", Force the Docker runtime to use a specific exec driver DOCKER_OPTS="-e lxc" # If you need Docker to use an HTTP proxy, it can also be specified here. #export http_proxy="http://127.0.0.1:3128/" # This is also a handy place to tweak where Docker's temporary files go. #export TMPDIR="/mnt/bigdrive/docker-tmp"


設定を変えたら docker を再起動しておきましょう。

mate $ sudo service docker restart


よーし、準備はできました。 適当なディレクトリを作り、Wine のベース・イメージをビルドする為の Dockerfile を作ります。

$ mkdir -p ~/Docker/wine
$ vi ~/Docker/wine/Dockerfile


内容はこんな感じ。 「【翻訳】Dockerを用いたGUIアプリケーションの実行」も参考につつ、日本語及び Wine 環境を構築しています。

FROM ubuntu:14.04
MAINTAINER netbuffalo

RUN dpkg --add-architecture i386
RUN apt-get update -y
RUN apt-get install --no-install-recommends software-properties-common -y
RUN add-apt-repository -y ppa:ubuntu-wine/ppa
RUN apt-get update -y
RUN apt-get install wine1.7 winetricks winbind -y

# Japanese Localization
RUN cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
RUN apt-get install language-pack-ja -y && update-locale LANG=ja_JP.UTF-8
RUN apt-get install fonts-takao fonts-takao-gothic fonts-takao-pgothic fonts-takao-mincho
RUN sed -i -e 's/^XKBMODEL="pc105"/XKBMODEL="jp106"/g' /etc/default/keyboard
RUN sed -i -e 's/^XKBLAYOUT="us"/XKBLAYOUT="jp"/g' /etc/default/keyboard

RUN apt-get purge software-properties-common -y
RUN apt-get autoclean -y

# Replace 1000 with your user / group id
RUN export uid=1000 gid=1000 && \
    mkdir -p /home/wineuser && \
    echo "wineuser:x:${uid}:${gid}:Developer,,,:/home/wineuser:/bin/bash" >> /etc/passwd && \
    echo "wineuser:x:${uid}:" >> /etc/group && \
    echo "wineuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/wineuser && \
    chmod 0440 /etc/sudoers.d/wineuser && \
    chown ${uid}:${gid} -R /home/wineuser

USER wineuser
ENV HOME /home/wineuser
ENV LANG ja_JP.UTF-8
WORKDIR /home/wineuser
CMD /bin/bash


さあ、こいつをビルドして Docker イメージにしましょう(タグは wine:base)。

mate $ sudo docker build -t wine:base ~/Docker/wine
Step 0 : FROM ubuntu:14.04
 ---> d0955f21bf24
Step 1 : MAINTAINER netbuffalo
 ---> Running in 813fccd26121

... snip ...

Step 18 : ENV LANG ja_JP.UTF-8
 ---> Running in 9de94a611af3
 ---> 7768303336f7
Removing intermediate container 9de94a611af3
Step 19 : WORKDIR /home/wineuser
 ---> Running in 1202802eeda4
 ---> 6c522e3913f4
Removing intermediate container 792b181f5b9a
Successfully built 30331fd9268f


イメージのリストを見ると・・・、

mate $ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
wine                base                c23213cc6dad        35 seconds ago      1.4 GB
ubuntu              trusty              d0955f21bf24        2 weeks ago         188.3 MB
ubuntu              trusty-20150320     d0955f21bf24        2 weeks ago         188.3 MB
ubuntu              14.04               d0955f21bf24        2 weeks ago         188.3 MB
ubuntu              14.04.2             d0955f21bf24        2 weeks ago         188.3 MB
ubuntu              latest              d0955f21bf24        2 weeks ago         188.3 MB


お、できてますね。 ベースとなったイメージからの増加分 1 GB 強、その殆どが Wine パッケージ周りといっても過言では無いところが恐ろしい所以だヨ・・・。

このイメージを使ってコンテナを run すると、CMD で指定した /bin/bash シェルが起動します。

mate $ sudo docker run -ti --rm --lxc-conf="lxc.network.hwaddr = ac:ac:ac:11:22:33" \
  -e XMODIFIERS="@im=fcitx" -e GTK_IM_MODULE=fcitx -e QT_IM_MODULE=fcitx -e XIMPROGRAM=fcitx -e LC_CTYPE=ja_JP.UTF-8 \
  -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix \
  wine:base

wineuser@296237b7bdf0:~$


起動オプションについてはもう少し詳しい説明が必要ですよね。

lxc.network.hwaddr では LINE がコンピューターの識別子(又は、その一部)として利用する 仮想マシンの MAC アドレスを指定しており、常に同じアドレスを使うようにしています(指定しないとコンテナ起動毎に新たなコンピューターからログインしたと認識され、2段階認証が発生してしまいます)。
※ Docker 1.6 系では --mac-address="your hardware address" 書式で指定できます。 

fcitx に関わる環境変数たちは僕がホスト OS、つまり Ubuntu MATE 上で利用しているインプット・メソッドをコンテナに伝える為であり、これで日本語入力が出来るようになります(これが無いと日本語入力はコピー・ペーストのみ)。

fcitx input method


最後2つのオプション、DISPLAY と /tmp/.X11-unix はコンテナ上で起動したアプリケーションの描画をホスト OS 上の X サーバーで行うのに指定しているのです。

/tmp/.X11-unix の下には X サーバーとクライアント間で利用する、DISPLAY 番号に割り当てられた Unix domain socket があるのですが、

mate $ echo $DISPLAY
:0.0

mate $ ls -la /tmp/.X11-unix/
srwxrwxrwx  1 root root   0  4月  9 09:50 X0


これをコンテナと共有することでアプリケーション環境とその実行はコンテナ上、但し、その描画はホスト OS 上のデスクトップで行う、というサプライズを実現しています。


Wine コンテナへの LINE アプリケーションのインストールとイメージの commit


先程ログインした Wine ベース・コンテナ上で Windows 版 LINE インストーラをダウンロード、wine で実行してみましょう。

wineuser@296237b7bdf0:~$ wget http://cdn.line-apps.com/client/win/new/LineInst.exe
wineuser@296237b7bdf0:~$ wine LineInst.exe


ホスト OS 上に Mono(.NET 実行環境)、Gekko(HTML レンダリング・エンジン)に関する警告ダイアログが表示されるはずです。 LINE には必要無いので今回はパス(インストールするとストレージを数百 MB 消費します)。

Wine Mono installer


続いて LINE クライアントのインストールが始まります。

line installer


インストール先だけは覚えておきましょうね(シェルから LINE を起動するのに必要)。 

LINE install path


つ、ついに LINE クライアントがコンテナ上では無く僕のデスクトップで起動しました(実際には描画のみ)!

line login

※ lxc ではなくデフォルトの libcontainer ドライバを利用している場合、docker run に --privileged オプションを追加しておかないとコンテナがネットワーク・インタフェース情報(MAC アドレス)にアクセスできず、ログイン認証時にアプリケーションが停止するかもしれません。

2段階認証を終えたら忘れずに、フォントやウインドウ幅などを使い易いサイズ・塩梅に調整しておきましょう。

line 設定

え、何故かって? この状態・設定を保った LINE 用のイメージを新たに作る(commit する)からですよ!

Docker ではコンテナ上で行われた変更は永続化されず、シェルを exit してしまえば全てが無に帰るのです。

これはお好みなのですが、最後にホーム・ディレクトリ(/home/wineuser)下に main.sh を作り、

wineuser@296237b7bdf0:~$ vi main.sh


~/.wine/drive_c 下にインストールされた LINE.exe を wine で呼び出すようにしておくと docker の起動引数をシンプルにできます。

#!/bin/sh

wine ~/.wine/drive_c/Program\ Files\ \(x86\)/LINE/LINE.exe


このスクリプトに実行権を付けたらおしまい(不要になった LineInst.exe は削除)。

wineuser@296237b7bdf0:~$ chmod 775 main.sh


別の端末を開くかコンテナをデタッチ後(bash を exit するとデータが消えることに注意!)、起動中のコンテナ ID を指定して wine:line イメージを新たに作成(docker commit)。

# show running containers.
mate $ sudo docker ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
bbb5ffc7e181        wine:base           "/bin/sh -c /bin/bas   6 minutes ago       Up 6 minutes                            sleepy_hawking

# commit running container.
mate $ sudo docker commit bbb5ffc7e181 wine:line
edbed6aa4f471b007ae1797e0816c5d836b848cb5cfc622ec16c5064ef38073f

# show images.
mate $ sudo docker images
[sudo] password for netbuffalo:
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
wine                line                fc91e2e99000        5 hours ago         1.495 GB
wine                base                fd65d59108d1        17 hours ago        1.411 GB
ubuntu              14.04               d0955f21bf24        2 weeks ago         188.3 MB
...


wine:base と同じオプションで、シェルには /home/wineuser/main.sh を指定して wine:line を docker run するとダイレクトに LINE が起動、2段階認証無しにログインできるはずです。

mate $ sudo docker run -ti --rm --lxc-conf="lxc.network.hwaddr = ac:ac:ac:11:22:33" \
    -e DISPLAY=$DISPLAY -e XMODIFIERS="@im=fcitx" -e GTK_IM_MODULE=fcitx -e QT_IM_MODULE=fcitx \
    -e XIMPROGRAM=fcitx -e LC_CTYPE=ja_JP.UTF-8 \
    -v /tmp/.X11-unix:/tmp/.X11-unix wine:line \
    /home/wineuser/main.sh


動く動画はこちら。 コンテナ型仮想化技術の圧倒的な軽さ(オーバーヘッドの少なさ)がわかりますよね。




ホスト OS、コンテナ間で永続化・データ交換可能な場所を用意したいのであれば、 -v オプションでもう一つ別の共有ボリュームを追加するのが良いでしょう。

mate $ mkdir ~/Docker/wine/shared
mate $ sudo docker run -ti --rm --lxc-conf="lxc.network.hwaddr = ac:ac:ac:11:22:33" \
    -e DISPLAY=$DISPLAY -e XMODIFIERS="@im=fcitx" -e GTK_IM_MODULE=fcitx -e QT_IM_MODULE=fcitx \
    -e XIMPROGRAM=fcitx -e LC_CTYPE=ja_JP.UTF-8 \
    -v /tmp/.X11-unix:/tmp/.X11-unix wine:line \
    -v ~/Docker/wine/shared:/home/wineuser/shared \
    /home/wineuser/main.sh


もし、これが NetBeans や Eclipse のようなデスクトップで動くアプリケーション開発環境に応用できるのだとしたら、短い期間で複雑さやテクノロジーが変化していく現代のソフトウェア開発環境において小さなオーバーヘッドで過去・現在・プロジェクト間を行き来、共有できる興味深い手法なのかもしれませんね。

それでは、また今度。



Posted by netbuffalo at 20:00│Comments(0)TrackBack(0)Linux | ユーティリティ


この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/netbuffalo/5001669

コメントする

名前
URL
 
  絵文字