EurekaMoments

This is my studying logs about Autonomous driving, Machine learning technologies and etc.

Dockerコンテナ上のPythonスクリプトから出力したmatplotlibのグラフをホストPC側で表示する方法

試して学ぶ Dockerコンテナ開発

試して学ぶ Dockerコンテナ開発

目次

背景・目的

DockerコンテナのPythonを
インタプリタにスクリプトを
実行する環境を構築できる
ようになったのですが、

www.eureka-moments-blog.com

input関数によるキー入力操作や、
matplotlibによるグラフ表示といった
GUI関連の処理が全然動かない
問題にぶつかりました。
いろいろハマりながらもなんとか
解決する事が出来たので、今回は
その方法について紹介します。

1. ホストPC側にVcXsrvをインストールする

DockerコンテナのLinuxでGUIアプリを
動かす一般的なやり方として、
Xサーバ(X Window System)を使う
というものがあります。

www.atmarkit.co.jp

ただし、普通にDockerコンテナを作成
するだけでは、Xサーバがインストール
されていないので、CUIコンソールしか
機能せず、GUIのウィンドウの描画や
キーボードやマウスからの入力といった
ものは出来ません。
なので、まずは上の記事に従って、ホスト
PC側(今回はWindows 10)にVcXsrvという
Xサーバソフトウェアをインストール
します。

sourceforge.net

2. コンテナ作成の準備をする

それぞれのファイルについては後述します
が、今回はこのようなフォルダ構成として
います。

f:id:sy4310:20200229174715p:plain

また、今回のサンプルコードとして、
matplotlibのグラフを描画する簡単な
Pythonスクリプトをcodeフォルダに
置いています。

import math
import numpy as np
import matplotlib.pyplot as plt

pi = math.pi

x = np.linspace(0, 2*pi, 100)

y = np.sin(x)

plt.plot(x, y)

plt.show()

3. コンテナからXサーバへの接続設定をする

コンテナ側で実行されたアプリが、
自動的にホスト側のXサーバに接続
して、GUIの描画を行う仕組み
なので、コンテナ側にホストの
IPアドレスを教えてやる必要が
あります。
この仕組みについては、こちらの
記事にある図が分かりやすいです。

ameblo.jp

f:id:sy4310:20200229221810p:plain

まずは、ホスト側のIPアドレスが
どうなっているかを「ipconfig」
コマンドで調べましょう。

f:id:sy4310:20200229214455p:plain

この赤枠で囲ったIPv4アドレスが、
コンテナ側に教えてやるIPアドレス
になります。

laboradian.com

次にこれを、ホスト側とコンテナ側
それぞれのDISPLAYという環境変数に
セットする事で、お互いの接続が
可能になります。
こういった環境変数の設定は、
docker-compose.ymlファイル
に記述するのですが、コンテナ側
設定をホスト側と共有するために
.envファイルというものを
作成する必要があります。

docs.docker.com

この.envファイルにコンテナ側の
DISPLAY変数への設定を記述し、

DISPLAY=192.168.3.3:0.0

docker-compose.ymlと同じ場所
に置いておきます。

f:id:sy4310:20200229224016p:plain

そして、docker-compose.yml
ファイルの中で、

environment:
      - DISPLAY=${DISPLAY}

と記述する事で、コンテナ側の
変数設定をホスト側と共有する
事が出来ます。
以上を踏まえて、今回はこの
ようなdocker-compose.ymlを
作成しました。

version: '3'
services:
  python_env:
    build:
      context: '.'
      dockerfile: 'Dockerfile'
    image: ubuntu:18.04
    container_name: ubuntu1804_python37
    environment:
      - DISPLAY=${DISPLAY}
    volumes:
      - ../:/var/ubuntu1804_python37
    tty: true
    working_dir: /var/ubuntu1804_python37

4. Xサーバ側の接続許可設定をする

ホスト側にあるVcXsrvの
インストール場所を見ると、
「X0.hosts」というファイル
があります。

f:id:sy4310:20200229234930p:plain

VcXsrvは、このファイルに
記述されたアドレスからの
接続のみを許可するように
なっています。
そのため、コンテナ側と
接続されるIPアドレスを
このファイルに追記しておく
必要があります。ただし、
このファイルは基本的に編集
不可であるため、編集する
にはエディタを管理者権限で
起動しなければなりません。

f:id:sy4310:20200229235430p:plain

5. イメージをビルドしてコンテナを作成する

ここまでで下準備は揃ったので、
あとはDockerfileを作成して
イメージをビルドします。

# pull base image
FROM ubuntu:18.04

# update packages
RUN set -x && \
    apt update && \
    apt upgrade -y && \
    apt install -y apt-utils && \
    apt install -y x11-apps

# installation
RUN set -x && \
    apt update && \
    apt install -y wget && \
    apt install -y sudo

# anaconda
RUN set -x && \
    wget https://repo.anaconda.com/archive/Anaconda3-2019.10-Linux-x86_64.sh && \
    bash Anaconda3-2019.10-Linux-x86_64.sh -b && \
    rm Anaconda3-2019.10-Linux-x86_64.sh
ENV PATH $PATH:/root/anaconda3/bin

# python requirements
WORKDIR /var/ubuntu1804_python37
ADD requirements.txt /var/ubuntu1804_python37
RUN pip install -r requirements.txt

ここで忘れてはいけないのが、

apt install -y x11-apps

によってXサーバ対応の基本アプリを
インストールする事です。これは
Xサーバ対応アプリやツールの
パッケージなのですが、これを入れて
おかないとGUIが描画されません。

docker-compose.ymlを使うので、
こちらのコマンドでビルドします。

$ docker-compose up -d --build

6. コンテナに接続してサンプルコードを実行する

前回の記事で紹介した手順で、PyCharm
からコンテナに入り、今回のサンプル
コードであるtest.pyを実行してみます。

f:id:sy4310:20200301143021p:plain

このようにグラフが表示されれば成功です。
ここまで長い闘いだった。。

f:id:sy4310:20200301142916p:plain