Edited at

Dockerでuid/gid指定可能かつsudo使用可能なデスクトップ環境を構築する(XRDP編)

2019/9/23 追記

この記事の内容を基にしたメージを、docker hubに登録しました。

https://hub.docker.com/r/yama07/docker-ubuntu-lxde

以下のタグが付いているので、pullして使ってみてください。

Dockerfile等はGitHubの方を参照してください。

https://github.com/yama07/docker-ubuntu-lxde/tree/master/xrdp

なお、この記事自体の内容は多少古いですが、このまま残します。


以下の記事の続編です。

Dockerでuid/gid指定可能かつsudo実行可能なユーザとしてコンテナを起動する


はじめに

以前の記事では、Dockerコンテナ上のCUIの快適な環境を構築しました。

今回は、GUIの快適な環境を構築します。

ここでいう快適とは、以下の条件を満たす環境のことを指しています。(あくまで私にとっての快適です。)


  • uid/gidを指定して起動できる。(コンテナ<->ホスト間でファイル共有しやすい)

  • sudoが使える。(パッケージを自由に追加できる)

要するに、ちょっとパッケージを試しに入れて、データを加工して取り出して、いらなくなったら環境を捨てるということを、デスクトップ環境においてもお手軽にできるようにします。

スクリーンショット 2017-09-02 23.16.43.png

デスクトップ環境は、Docker + XRDP + XLDEで構成しています。

リモートデスクトップとしてXRDPを選択した理由は以下2点です。


  • クライアントソフトの追加インストールが不要(主にWindowsを使うので)

  • VNCよりもサクサク動く

なお、気が向いたら「VNC編」も書く予定です。


背景

最近、Androidアプリの開発をしているのですが、会社から支給されたノートパソコンでAndroidStudioを動かすのがキツくなってきました:disappointed_relieved:

色々と負荷を下げる設定を試みましたが、メールアプリケーションとAndroidStudioを同時に動かしている状態でメモリ使用率90%を超え、全体的に動作がモッサリしています。

さらに最近では、サブ画面にAndroidStudioを表示させると画面が表示されなくなるという現象が発生し始めました。

幸いなことに、個人のノートパソコンとは別に、それなりのスペックの共用サーバが提供されており、そこでは勝手にパッケージを追加したりはできませんが、dockerが使用可能です。

こういった事情から、コンテナでデスクトップ環境を立てて、手元のノートパソコンからアクセスするというところに行き着きました。

なお、この記事では汎用的なデスクトップ環境の構築について書いているので、AndroidStudioのインストールについては書いていません。

(気が向けば、あるいは需要があれば記事を書くかもしれません。)


Dockerホストの環境

$ cat /etc/lsb-release 

DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.2 LTS"

$ docker --version
Docker version 1.13.1, build 092cba3


Dockerイメージの作り方


Dockerfileとか

Dockerfileと、endpointとなるシェルスクリプトの2つから成ります。


Dockerfile

FROM ubuntu:16.10

RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y \
lxde \
xrdp \
ibus \
ibus-mozc \
language-pack-ja-base \
language-pack-ja \
fonts-ipafont-gothic \
fonts-ipafont-mincho \
&& apt-get clean \
&& rm -rf /var/cache/apt/archives/* \
&& rm -rf /var/lib/apt/lists/*

# RDPのポートを公開する
EXPOSE 3389

RUN echo "startlxde" > /etc/skel/.xsession

# 日本語ロケールを設定する
RUN cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
&& echo 'Asia/Tokyo' > /etc/timezone
RUN 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:ja \
LC_ALL=ja_JP.UTF-8

# デフォルトのユーザ名とパスワード
ENV DEFAULT_USER=developer \
DEFAULT_PASSWD=xrdppasswd

# sudoを使用できるようにする
RUN echo "ALL ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/ALL

# 一般ユーザがユーザ/グループを追加できるようにする
RUN chmod u+s /usr/sbin/useradd \
&& chmod u+s /usr/sbin/groupadd

# XRDPのendpointスクリプトを配置する
COPY endpoint.sh /opt/
RUN chmod +x /opt/endpoint.sh
CMD ["/opt/endpoint.sh"]



endpoint.sh

#!/bin/bash -e

USER_ID=$(id -u)
GROUP_ID=$(id -g)
PASSWD=${PASSWD:-${DEFAULT_PASSWD}}
USER=${USER:-${DEFAULT_USER}}

# グループを作成する
echo "GROUP_ID: $GROUP_ID"
if [ x"$GROUP_ID" != x"0" ]; then
groupadd -g $GROUP_ID $USER
fi

# ユーザを作成する
echo "USER_ID: $USER_ID"
if [ x"$USER_ID" != x"0" ]; then
export HOME=/home/$USER
useradd -d ${HOME} -m -s /bin/bash -u $USER_ID -g $GROUP_ID $USER
fi

# パーミッションを元に戻す
sudo chmod u-s /usr/sbin/useradd
sudo chmod u-s /usr/sbin/groupadd

# ログインユーザ名を設定する
USER=$(whoami)
echo "USER: $USER"

# ログインパスワードを設定する
echo "PASSWD: $PASSWD"
echo ${USER}:${PASSWD} | sudo chpasswd

[ ! -e ${HOME}/.xsession ] && cp /etc/skel/.xsession ${HOME}/.xsession

echo "#############################"

# XRDPサーバを起動する
sudo bash -c "/etc/init.d/xrdp start && tail -F /var/log/xrdp-sesman.log"


やっていることは、以前の記事で書いていることと基本同じです。

xrdpやlxdeのインストールや、日本語環境設定が追加されています。

ubuntu:16.10をベースイメージとしていますが、ubuntu:14.04や16.04も同様に使用することができます。しかし、ubuntu:16.04以前はxrdpがv0.6のため日本語キーボード配列に対応しておりませんので、ここを参考にキーマップを変更してください。なお、ubuntu:16.10のxrdpはv0.9なので、追加手順なしで日本語キーボードを使用できます。

xrdpの設定は見ての通り、デフォルトのままです。

好みに合わせてxrdpサーバの設定(xrdp.iniやsesman.iniに記述)をおこなってください。


docker build

普通にdocker buildをおこないます。

## Dockerfileを作成

$ vi Dockerfile

## endpointスクリプトを作成
$ vi endpoint.sh

$ docker build -t lxde_xrdp:ubuntu16.10_ja .


Dockerコンテナの使い方


docker run

XRDPサーバのコンテナを立ち上げます。

$ docker run --rm -it \

--privileged \
-p 3389:3389 \
-u $(id -u):$(id -g) \
-e USER=yama \
-e PASSWD=yamapasswd \
lxde_xrdp:ubuntu16.10_ja

オプションは以下の通りです。



  • -p port:3389
    クライアントから接続されるポートをportに設定してください。


  • -u user:group
    コンテナを起動するUIDをuserに、GIDをgroupに設定してください。
    指定しない場合は、rootユーザ(UID=0,GID=0)として起動します。
    なお、rootユーザとして起動した場合は、日本語入力(mozc)が利用できません。


  • -e USER=loginUser
    RDPによるログインユーザをloginUserに設定してください。
    指定しない場合は、“developer”となります。ただし、rootユーザとしてコンテナを起動した際は“root”となります。


  • -e PASSWD=loginPasswd
    RDPによるログインパスワードをloginPasswdに設定してください。
    指定しない場合は、“xrdppasswd”となります。

--privilegedオプションは動作環境によっては不要です。

mozcで「変換エンジンプログラムの起動に失敗しました。」とエラーが発生した場合は、このオプションをつけてください。


クライアントから接続

Windowsを利用する場合は、付属の「リモートデスクトップ」があれば追加でクライアントソフトをインストールする必要はありません。

Macの場合は「Microsoft Remote Desktop」、Linuxの場合は「FreeRDP」や「rdesktop」、「Remmina」などで接続してください。

接続方法は、リモートデスクトップクライアントを起動し、DockerホストのIP、およびdocker runで設定した接続ポート、ログインユーザ/パスワードでログインします。

ユーザ/パスワードの情報は、コンテナを起動した際に以下のように出力されますので、そこでも確認できます。

-dオプションでバックグラウンド実行した場合は、docker logsで確認できます。)

$ docker run ...オプション省略...

GROUP_ID: 1000
USER_ID: 1000
USER: yama
PASSWD: yamapasswd
#############################
* Starting Remote Desktop Protocol server
...

ログインに成功すると、「No session for pid (プロセスID)」とエラーダイアログが出てくるかもしれませんが、特に問題ない(と思う)ので、「OK」をクリックしてください。(今のところ動作に問題ないので、深く原因調査をしていません。すみません:sweat:

スクリーンショット 2017-09-02 23.58.43.png

また、クリップボード管理ソフト「Clipit」が履歴保存を有効化するのか訊いてきます。

「履歴データは、パスワードのようなセンシティブなデータであっても平文で保存するけどいい?」みたいなことを言っています。構わなければ「Yes」をクリックしてください。

スクリーンショット 2017-09-02 23.59.02.png


使い道

背景のところでも述べていますが、個人的な開発環境として使えます。

また、突然の開発メンバ増員の際も、Dockerイメージを使いまわして、即座に開発環境を提供することもできます。

今回のDockerイメージは汎用的なので、そのままだとできることが限られています。なので、別途必要なパケージをインストールしたイメージを作成する必要があると思います。私の場合は、今回のイメージをベースイメージ(DockerfileのFROM)として、JDKやAndroidStuioなど開発に必要なソフトをインストールしたイメージを作成し、使用しています。


その他


Dockerホストのバージョンについて

Docker version 17.06.0-ceとubuntu:16.10(ホストOSではなくベースイメージ)の組み合わせは、私が用意した検証環境において、動作しなかったです。XRDPサーバの起動でエラーが発生します。

どうやら、IPv6周りの設定の相性が悪いようで、Dockerホストの設定次第でうまく動くのかもしれません。

私の普段使用しているサーバがDocker version 1.13.1だったこともあり、めんどくさくてあまり深く調査していません。

なお、xrdpのバージョンがv0.6であるubuntu:14.04やubuntu:16.04であれば、Docker version 17.06.0-ceであっても動作します。


私の普段の使い方

以下のようにコンテナ起動の際に-vオプションを付与し、ホームディレクトリをマウントして使用しています。

$ docker run --rm -it \

--privileged \
-p 3389:3389 \
-u $(id -u):$(id -g) \
-e USER=yama \
-e PASSWD=yamapasswd \
-v ${HOME}/container_home:/home/yama \
lxde_xrdp:ubuntu16.10

コンテナ内のデスクトップ環境において、ほとんどの個人設定はホームディレクトリに保存されるので、ホームディレクトリをマウントしておけば、コンテナを停止&起動しても個人の設定が維持されます。

また、コンテナ内で永続化したいデータもホームディレクトリ配下に置いておけば、コンテナを停止しても問題ありませんし、ホストとのデータのやり取りにも便利です。

もちろん、ホストのuid/gidを引き継いでいるので、ファイルパーミッションのせいでファイル/ディレクトリが削除できないといったような問題もありません。