Dockerコンテナ上にDesktop環境(IntelliJ IDEA)を構築する


この記事は「[Dockerコンテナ上に開発環境一式を構築する](http://qiita.com/hakaicode/items/5522a5ad1c280b9cf757)」の一部です。

## 現在のステータス

* [VPSにホストにUbuntuを入れる](http://qiita.com/hakaicode/items/5522a5ad1c280b9cf757)
* [dnsを構築する](http://qiita.com/hakaicode/items/478ba39055c101d6197d)
* [nginxを構築する](http://qiita.com/hakaicode/items/38cbed889a03a33cdfcf)
* [GitBucket環境を構築する](http://qiita.com/hakaicode/items/4fb257c8e05727a8abf5)
* [Selenium用のJenkins環境を構築する](http://qiita.com/hakaicode/items/9a4ccf9faf63a4d9d3e4)
* Desktop環境(IntelliJ IDEA)を構築する <-イマココ

## Dockerfile

頑張ってデスクトップ環境を入れます。development+desktopでdevtopと呼ぶことにします。LXDEだとコンポーネントがかっこ悪いのでMATEを入れてみました。mate-desktop-environmentだけだとレイアウト崩れまくりでubuntu-desktopも必要でした。

```docker:Dockerfile
# Devtop Dockerfile

# Pull base image.
FROM ubuntu:14.04

# Install from jp
RUN sed -e 's;http://archive;http://jp.archive;' -e  's;http://us\.archive;http://jp.archive;' -i /etc/apt/sources.list

ENV DEBIAN_FRONTEND noninteractive
# ENV http_proxy=http://host:port
# ENV https_proxy=http://host:port

# apt-get install
RUN apt-get update && apt-get -y upgrade \
 && apt-get install -y build-essential \
 && apt-get install -y software-properties-common \
 && apt-get install -y byobu git subversion bc iotop htop man zip unzip curl wget locate tree \
 && apt-get install -y vncviewer vnc4server shutter gedit gnote \
 && apt-get install -y language-pack-ja fonts-vlgothic ibus-mozc \
 && apt-get install -y ruby ruby-dev exuberant-ctags vim-gtk gnote dnsutils telnet \
 && apt-get install -y traceroute bash-completion subversion \
 && apt-get install -y libreoffice \
 && apt-get install -y firefox \
 && apt-add-repository ppa:ubuntu-mate-dev/ppa -y \
 && apt-add-repository ppa:ubuntu-mate-dev/trusty-mate -y \
 && apt-get update && apt-get -y upgrade \
 && apt-get install -y mate-desktop-environment \
 && apt-get install -y ubuntu-desktop \
 && apt-get install -y nautilus-open-terminal \
 && rm -rf /var/lib/apt/lists/*

# Install java 8.
RUN add-apt-repository ppa:webupd8team/java -y && apt-get update \
 && (echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections) && apt-get install -y oracle-java8-installer oracle-java8-set-default \
  && rm -rf /var/lib/apt/lists/*

# Copy files.
COPY apps/*deb apps/*tar.gz /tmp/

# Install chrome.
RUN \
  wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
  echo "deb http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list && \
  apt-get update && apt-get install -y google-chrome-stable

# Install skype.
RUN dpkg --add-architecture i386 \
 && dpkg -i --force-depends /tmp/skype-install.deb \
 && apt-get update \
 && apt-get -y -f install \
 && rm -rf /var/lib/apt/lists/*

# Install scala & sbt.
RUN dpkg -i  /tmp/sbt*.deb
RUN dpkg -i  /tmp/scala*.deb

# Install IntelliJ IDEA.
RUN tar zxvf /tmp/idea*.tar.gz -C  /usr/local/
RUN ln -s /usr/local/idea-* /usr/local/idea

# Copy skeleton home directory.
# COPY skel /home/skel

# Setup Japanese environment.
RUN cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
    echo 'Asia/Tokyo' > /etc/timezone && date
RUN sed -e 's;UTC=yes;UTC=no;' -i /etc/default/rcS
RUN echo 'LC_ALL=ja_JP.UTF-8' > /etc/default/locale && \
    echo 'LANG=ja_JP.UTF-8' >> /etc/default/locale && \
        locale-gen ja_JP.UTF-8

ENV LC_CTYPE ja_JP.UTF-8

# sudo
RUN echo 'ALL ALL=NOPASSWD:   ALL' >> /etc/sudoers
RUN echo 'Defaults env_keep+="http_proxy https_proxy no_proxy"' >> /etc/sudoers

# For locate command
RUN updatedb

# Define default command.
CMD ["bash"]
```

appsディレクトリを作ってインストールするアプリケーションを`COPY`で`/tmp`に送っています。IntelliJ IDEA等はバージョンアップした時に入れ替えが面倒なので$HOME配下に置いた方が良かったかもしれません。バージョンアップは今後の課題ですね。
appsでは下記のスクリプトで取得しました。

```apps.sh
#/bin/sh

# scala & IDEA
wget http://www.scala-lang.org/files/archive/scala-2.11.7.deb
wget http://dl.bintray.com/sbt/debian/sbt-0.13.9.deb
wget https://download.jetbrains.com/idea/ideaIC-15.0.3.tar.gz

wget -c https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
wget -c -O skype-install.deb http://www.skype.com/go/getskype-linux-deb
```


デスクトップ環境なので困った時にrootで色々できるようにsudoersに足してます。rootとられても/sbinとか/usr/binとかは再起動すれば元に戻りますが、ある程度環境構築が落ち着いたらこの部分は削除します。

vnc4server, libreoffice, mozcなどを入れて一通り作業環境を整えます。

このイメージをdevtopとして作成します。

```build.sh
#/bin/sh

. ../../setenv.sh
PROJECT=devtop

cd $DOCKER_HOME/$PROJECT/docker
docker build -t "$PROJECT:latest" .
```

## ユーザー用Docker

このdevtopを複数のユーザーで使いまわします。

```docker:Dockerfile-users
 # Devtop Dockerfile for users.
FROM devtop:latest

# Add users
RUN /usr/sbin/useradd -p xxx -u 1000 megumin -s /bin/bash
RUN /usr/sbin/useradd -p xxx -u 1001 yuiyui -s /bin/bash
RUN /usr/sbin/useradd -p xxx -u 1002 hyoizaburo -s /bin/bash

CMD ["bash"]
```

我が名はめぐみん！GUI環境へはVNCでアクセスするのでパスワード無しで運用してたのですが、うっかりXをロックしたりすると復帰できないので適当に設定してました。一度パスワードを設定してから`/etc/passwd`からコピペしました。

これをdevtop-usersとしてビルドします。

```bash:build-users.sh
#/bin/sh

. ../../setenv.sh
PROJECT=devtop-users

cd $DOCKER_HOME/$PROJECT/docker
docker build -f Dockerfile-users -t "$PROJECT:latest" .
```

## ユーザー用コンテナの作成

ユーザー用のディレクトリを作ります。ConoHaのVPS 1GBプランでは1ユーザーが限界ですが、複数作る場合はそれぞれのユーザーごとにchownでオーナーを変えておきます。ホスト側のユーザーとは関係ないので注意が必要です。

```shell-session
$ cd /home/docker
$ mkdir megumin
$ sudo chown 1000:1000 -R megumin
$ mkdir yuiyui
$ sudo chown 1001:1001 -R yuiyui
...
```

それぞれのディレクトリに起動スクリプトを作ります。

```bash:run.sh
#/bin/sh

. ../setenv.sh
USER=megumin

docker run -v $DOCKER_HOME/$USER:/home/$USER -u $USER -h devtop-$USER -d \
  -w /home/$USER -e HOME=/home/$USER --dns=$IP --name $USER -p 127.0.0.1:5901:5901  --privileged \
  devtop-users bash -c "sudo umount /dev/shm; \
   sudo mount -t tmpfs -o rw,nosuid,nodev,noexec,relatime,size=512M tmpfs /dev/shm; \
   vncserver :1 -geometry 1200x800 ; tail -f /dev/null"
```
```bash:kill.sh

```

vncサーバーを立ち上げるので-p 5901:5901を指定するのですが、そのまま外部にさらすと暗号化されません。ここはローカルホストのみにバインドしておいて、クライアントからアクセスするときはsshポートフォワーディングを使います。

```bash:.ssh/config
Host dev
Hostname dev.example.jp
User docker
LocalForward   5901 localhost:5901
```

このように`.ssh/config`を設定しておけば`ssh dev`と打つだけでポートフォワードしてくれるので、vncクライアントでlocalhost:1に繋ぐと接続できます。configを使わない場合は`ssh -L 5901:dev.example.jp:5901 -l docker`のように打つ必要があります。

`--privileged`はコンテナに特権を与えます。これがないとchromeの起動に`--no-sandbox`オプションが必要になるのですが、「このオプションはサポートされていません」と出るのでうざいです。

起動コマンドはbashで、sudoのところは共有メモリをマウントしているのですが`docker run -v /dev/shm:/dev/shm`で置き換え出来るかもしれません。あとはvncserverの立ち上げと、このままではプロンプトに戻ってコンテナが死んでしまうので無駄にtailしてます。

vncserverのパスワードファイルはバイナリなので、まず一回bashで立ち上げて設定してあげます。

```shell-session
$ docker run -v /home/docker/megumin:/home/megumin -u megumin -it --name megumin devtop-users bash
```

```shell-session
$ vncserver

You will require a password to access your desktops.

Password:
Verify:
xauth:  file /home/megumin/.Xauthority does not exist

New 'c773bac95718:1 ()' desktop is c773bac95718:1

Creating default startup script /home/megumin/.vnc/xstartup
Starting applications specified in /home/megumin/.vnc/xstartup
Log file is /home/megumin/.vnc/c773bac95718:1.log
```

xstartupを日本語入力&MATEデスクトップ環境用に書き換えます。

```bash:xstartup
#!/bin/sh

[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup
[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources
xsetroot -solid grey

# Japanese input method.
export XMODIFIERS="@im=ibus"
export GTK_IM_MODULE="xim"
export QT_IM_MODULE="xim"
ibus-daemon -d -x

#x-session-manager &
vncconfig -iconic &
#/usr/bin/lxterminal -e /bin/bash &
gnome-terminal &

mate-session&
```

## 実行

あとはいつもの通り`run.sh`して、ローカルからsshポートフォワーディング後にvncで繋ぐだけです。

TODO ss

IntelliJ IDEAを実行してみます。

TODO メモリ使用量など