これは、なにをしたくて書いたもの?
Dockerコンテナ内で動かしたアプリケーションの描画内容を、ホスト側に持ってこれないかな?と思いまして。
どうやらできそうです。
Dockerを用いたGUIアプリケーションの実行 | POSTD
試してみましょう。
環境
今回の環境は、こちらです。
$ docker version Client: Docker Engine - Community Version: 20.10.2 API version: 1.41 Go version: go1.13.15 Git commit: 2291f61 Built: Mon Dec 28 16:17:43 2020 OS/Arch: linux/amd64 Context: default Experimental: true Server: Docker Engine - Community Engine: Version: 20.10.2 API version: 1.41 (minimum version 1.12) Go version: go1.13.15 Git commit: 8891c58 Built: Mon Dec 28 16:15:19 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.4.3 GitCommit: 269548fa27e0089a8b8278fc4fc781d7f65a939b runc: Version: 1.0.0-rc92 GitCommit: ff819c7e9184c13b7c2607fe6c30ae19403a7aff docker-init: Version: 0.19.0 GitCommit: de40ad0
Dockerfileを用意する
まずは、Dockerfile
を用意します。こんな感じで作成。
Dockerfile
FROM ubuntu:20.04 ARG uid=1000 ARG gid=1000 RUN apt-get update -y && \ apt-get install -y --no-install-recommends \ sudo \ vim \ curl \ ca-certificates \ && \ apt-get clean RUN addgroup --gid ${gid} myuser && \ adduser --disabled-login --gecos '' --uid ${uid} --gid ${gid} myuser && \ usermod -G sudo myuser RUN echo "Defaults:myuser !requiretty" >> /etc/sudoers.d/myuser && \ echo "myuser ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/myuser && \ chmod 440 /etc/sudoers.d/myuser USER myuser CMD ["bash"]
ビルドします。
$ docker image build --build-arg uid=`id -u` --build-arg gid=`id -g` -t kazuhira/ubuntu:20.04 .
Dockerfile
はいろいろ書いていますが、ポイントはここだけです。
RUN addgroup --gid ${gid} myuser && \ adduser --disabled-login --gecos '' --uid ${uid} --gid ${gid} myuser && \
指定のuid
、gid
でユーザーを作成します。
あとは操作しやすいようにvim
やcurl
を入れたり、sudo
を実行できるようにしました。
コンテナを起動して、ホスト側で描画を行う
では、作成したコンテナを起動します。
$ docker container run -it --rm --name ubuntu \ -e DISPLAY=${DISPLAY} \ -v /tmp/.X11-unix:/tmp/.X11-unix \ kazuhira/ubuntu:20.04
この時、ホスト側の/tmp/.X11-unix
ディレクトリをコンテナ側にマウントします。
-v /tmp/.X11-unix:/tmp/.X11-unix
${DISPLAY}
環境変数も指定します。ホストの値を引き継ぐようにしています。
-e DISPLAY=${DISPLAY}
コンテナ内で起動するアプリケーションとしては、geditにしましょう。インストールします。
$ sudo apt install -y gedit
インストールが完了したら、起動してみます。
$ gedit &
すると、ホスト側でアプリケーションが描画されます。
成功しました。
どうなっているのか?
Dockerコンテナの起動時の設定を、もう1度見返します。
$ docker container run -it --rm --name ubuntu \ -e DISPLAY=${DISPLAY} \ -v /tmp/.X11-unix:/tmp/.X11-unix \ kazuhira/ubuntu:20.04
ホスト側の/tmp/.X11-unix
ディレクトリをマウントしていました。
-v /tmp/.X11-unix:/tmp/.X11-unix \
このディレクトリには、Xクライアント、Xサーバー間でのやり取りに使われるUNIXドメインソケットファイルが配置されています。
これをコンテナ側に持ってきたわけです。
$ ll /tmp/.X11-unix total 8 drwxrwxrwt 2 root root 4096 Jan 15 22:56 ./ drwxrwxrwt 1 root root 4096 Jan 15 23:52 ../ srwxrwxrwx 1 myuser myuser 0 Jan 15 22:56 X0= srwxrwxr-x 1 121 125 0 Jan 15 22:55 X1024= srwxrwxr-x 1 121 125 0 Jan 15 22:55 X1025=
そして、$DISPLAY
環境変数はホスト側から引き継ぎましたが、:0
を指しています。
$ printenv DISPLAY :0
この設定だと、/tmp/.X11-unix/X0
というUNIXドメインソケットファイルでXクライアント、Xサーバー間でやり取りします。
あとは、現在のユーザーでこのファイルを扱う権限が必要です。
このため、ホスト側とコンテナ側のuid
、gid
を合わせる目的でuid
、gid
をコンテナイメージ作成時に指定し
$ docker image build --build-arg uid=`id -u` --build-arg gid=`id -g` -t kazuhira/ubuntu:20.04 .
Dockerfile
内でのユーザー、グループ作成時のuid
、gid
に反映させ、コンテナ内からUNIXドメインソケットファイルを
操作できるように調整した、というわけです。
RUN addgroup --gid ${gid} myuser && \ adduser --disabled-login --gecos '' --uid ${uid} --gid ${gid} myuser && \
なるほどなぁ、と。