Dockerを導入してGUI操作可能なLinux(Ubuntu)コンテナを作成する

# 概要
Docker for MacでGUI操作可能なLinux(Ubuntu)環境を作成してみたので、方法を紹介します。下記の例のように、ホスト側からdockerコンテナ内のGUIアプリケーションを動かせる想定です。

#### 例1:ホスト(Mac)の画面からコンテナ(Ubuntu)内のデスクトップを操作
![nautilius.png](https://qiita-image-store.s3.amazonaws.com/0/100027/a1ccf097-546e-296f-3b08-0280ee9da1a3.png)


#### 例2:ホスト(Mac)の画面からコンテナ(Ubuntu)内のブラウザ(FireFox for Ubuntu)を操作
![ubuntu-firefox.png](https://qiita-image-store.s3.amazonaws.com/0/100027/77c729c1-9be3-9a80-7eec-f8b63f473317.png)

# 構成
作成に入る前に、構成を先に説明しておきます。大雑把なイメージとしては、下記の図のようになります。Dockerコンテナは、GUIのディスプレイをホストOSに対して投影し、ホストOS側から操作を受け付けます。ホストOSでは、X11(X windows SystemのmacOS版)というUnix系をGUI操作する仕組みで、Dockerコンテナ内のアプリケーションをGUIインターフェースに描画し、ユーザの操作を受け付けてDockerコンテナ内のアプリケーションに伝えます。また、portとx11の間でのプロキシサーバとしての役割を担います。

![dockerGUIの仕組み.png](https://qiita-image-store.s3.amazonaws.com/0/100027/417679be-a834-d4f3-f887-b3939519eba4.png)


# 環境
macOS High Sierra(10.13.3)

# 手順

## 1. Dockerの導入
Dockerを初めて触る方向けにDockerの導入方法から説明します。下記コマンドでDocker for Macを導入します。

```console
$ brew install docker
$ brew cask install docker #docker for macのクライアントアプリを導入
```

なお、下記からも導入できます。
[DOCKER FOR MAC](https://www.docker.com/docker-mac)

## 2. Socatの導入・起動
Socatは、簡単なプロキシサーバを建ててソケット通信を実施するものです。つまり、ここでは、port6000番(コンテナのGUI操作を行うx11用のボート)を通して、ホスト側の画面がコンテナ内と通信できるようにするために使用します。

まずは、導入から。

```console
$ brew install socat
```

下記コマンドで、port6000番(UnixのGUI操作を行うxquartz用のポート)への通信をホスト側のディスプレイで表示するようにします。
`fork`は複数のコネクションを管理できるようにするオプションで、`reuseaddr`はポートを再利用可能にするオプションです。

```console
$ socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"
```

## 3. Xquartzの導入・起動
Xquartz(X11.app)は、macOS用のX Window Systemとなります。X Window Systemとは、Unix系OSでGUI操作を可能にするものです。
最近のmacOSではデフォルトでは入っていないので、導入・起動します。

```console
$ brew cask install xquartz
$ open -a XQuartz #起動
```

ちなみに、xquartzは下記から導入することもできます。
[Quartz](https://www.xquartz.org/)

## 4. Dockerイメージの導入
今回はubuntuを使用してみます。

```console
$ docker pull ubuntu
```

## 5. Dockerコンテナの作成・起動
いよいよDockerコンテナの作成・起動になります。
先にdockerコンテナ側からMacにアクセスする際のホスト側のIPアドレスを取得します。


```console
# ホストのIPアドレスを取得
$ ifconfig en0 | grep inet | awk '$1=="inet" {print $2}'
```

上記で取得したIPアドレスを`xxx.xxx.xxx.xxx`の部分に置き換えて、下記`docker run`コマンドを実行し、コンテナを作成・起動します。
`e`オプションでコンテナ内の環境変数DISPLAYをホストのIPアドレスに設定して、ホスト側にディスプレイされるようにします。なお、ホストのIPアドレスの後ろの`:0`は、ホスト内のx windowsサーバの番号を指し、1番目のx windowサーバという意味です。

```console
# Dockerコンテナの作成・起動
# 下記xxx.xxx.xxx.xxxをホストのIPアドレスに変更して実行
$ docker run -it -e DISPLAY="xxx.xxx.xxx.xxx:0" ubuntu
```

## 6. ホストにXサーバへの接続権限を付与
上記のコマンドを実行すると、Xterm(Xquartzのターミナル)のウィンドウが開くと思います。開かなかった場合は、`⌘+N`、またはXquartzのGUIアプリのメニューバーから「Applications」→「Terminal」から開いてください。
![xtermの開き方.png](https://qiita-image-store.s3.amazonaws.com/0/100027/0bbc3518-4d4e-d0c4-61f3-7bdbfae743db.png)

そして、xterm上で下記のコマンドを実行し、ホストにXサーバーへの接続権限を与えます。ちなみに、`xhost +`としても、接続制限が一切なくなるのでここでの目的は達成されます。ただし、セキュリティ的に好ましくないです。

```console
# xterm上から実行
$ xhost XXX.xxx.xxx.xxxホストのIPアドレス
```


###ここまでで、Dockerの導入とGUI操作可能なLinuxコンテナ作成は完了となります。

以下では、実際に、作成したコンテナ上にGUIアプリケーションを導入して、起動してみます。

## 7.Dockerコンテナ内にGUIアプリを導入・起動
ここでは、Ubuntuのコンテナであるという前提で進めます。
※下記のどちらもディスク容量を消費します。また、多少時間もかかるので、お気をつけください。

### デスクトップクライアント・ファイルマネージャの導入
```console
# コンテナ内で実行
root@xxxxxxx:/# apt-get update
root@xxxxxxx:/# apt-get install ubuntu-desktop
root@xxxxxxx:/# exit #コンテナを再起動するためexit
```
```console
# ホスト側でコンテナを再起動
$ docker restart CONTAINER_ID
```

```console
# 再起動したコンテナ内からファイルマネージャーを起動
root@xxxxxxx:/# nautilus
```

そうすると、冒頭の画像のようにUbuntuのデスクトップとファイルマネージャー(nautilus)が開き、操作ができます。
![nautilius.png](https://qiita-image-store.s3.amazonaws.com/0/100027/a1ccf097-546e-296f-3b08-0280ee9da1a3.png)


### ブラウザ(Firefox)の導入

```console
root@xxxxxxx:/# apt-get update
root@xxxxxxx:/# apt-get install firefox
root@xxxxxxx:/# firefox #起動
```
![firefox起動.png](https://qiita-image-store.s3.amazonaws.com/0/100027/215ecfb1-7927-adf4-94db-42fb90619731.png)


以上のように、作成したコンテナをGUI操作できます。


# 参考
[Docker for Macで作ったUbuntuコンテナ内のGUIプログラム（spyder）を使う](https://ur.edu-connect.net/archives/29091)
[DockerコンテナのGUIをMac側に飛ばして表示させよう。](https://qiita.com/akiko-pusu/items/e42aab2df1a5772f9585)