16
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Jupyterを使ったハンズオンセミナーをdockerを使って開催する方法

Last updated at Posted at 2016-03-07

やりたいこと

  • Jupyterなどを使ったハンズオンセミナーを開催したいとします。
  • 実行環境は、dockerで用意することにします。
  • Tmpnbのように、受講者ごとに動的にdockerコンテナを立ち上げて利用できるようにします。

実現イメージ

arch.png

  • pythonのflaskを使って、webサーバを立ち上げます。
  • セミナーの受講者がアクセスすると、自動的にセミナーイメージからコンテナを起動して、そのアドレスをリダイレクトします。
  • 下記の説明では、Ubuntu(15.10)上の docker(1.10.2)で確認しています。

webサーバでは、pythonのflaskとdockerの両方を動かします。
これをdockerで提供するのですが、どうせ、ホストでdockerを動かすので、ホストの環境を利用しましょう。pythonもexeとdllを別イメージからvolumeにコピーして、使うことにします。

Step 1. Making volume for python

pythonとflaskの実行環境を持ったtsutomu7/py3flask(Dokcerfile)からファイルをコピーして、pythonという名前のvolumeを作成します。コンテナはコピー後、廃棄します。

bash
docker volume rm python
docker run -it --rm -v python:/usr/local tsutomu7/py3flask sh -c "\
    cp /usr/bin/python3.5 /usr/local/bin/python && \
    cp /lib/ld-musl-x86_64.so.1 /usr/local/lib && \
    ln -s /usr/local/lib/ld-musl-x86_64.so.1 /usr/local/lib/libc.musl-x86_64.so.1 && \
    cp /usr/lib/libpython3.5m.so.1.0 /usr/local/lib/ && \
    cp -r /usr/lib/python3.5/ /usr/local/lib/"

Step 2. Start server

tsutomu7/seminar(Dockerfile)を使ってwebサーバを起動します。

  • IMAGE環境変数で受講者に起動させたいdockerイメージを指定します
  • PORT環境変数でそのイメージの利用するポート番号を指定します。
  • CoreOSなどのように"/lib/x86_64-linux-gnu"がない場合は、その部分をとってください。
bash
docker run -it --rm \
   -v /lib/x86_64-linux-gnu/:/lib/x86_64-linux-gnu/:ro \
   -v /lib64:/lib64:ro \
   -v /usr/bin:/usr/bin:ro \
   -v /usr/lib:/usr/lib:ro \
   -v /var/run/docker.sock:/var/run/docker.sock:ro \
   -v python:/usr/local \
   -p 5000:5000 \
   -e IMAGE=tsutomu7/jupyter \
   -e PORT=8888 \
   tsutomu7/seminar

Step 3. Access

ネットワークにつながったPCから「webサーバのホストのアドレス:5000」にブラウザでアクセスしてください。自動的に新しい dockerコンテナが起動し、そのアドレスがリダイレクトされます。
同じPCからのアクセスは、1つのコンテナで対応します。

サーバプログラムの説明。

pythonもdockerも借り物なので、このサーバイメージは、5MBしかないです。中のプログラム(seminar.py)を説明します。

seminar.py
import os
from flask import Flask, request, redirect
from subprocess import run
app = Flask(__name__)
dct = {}

@app.route('/')
def hello_world():
    addr = request.environ['REMOTE_ADDR']
    if addr not in dct:
        img = os.environ.get('IMAGE', 'tsutomu7/jupyter')
        prt = os.environ.get('PORT', '8888')
        cid = 8001 + len(dct)
        run(['docker', 'run', '-d', '--name', str(cid), '-p', '%d:%s' % (cid, prt), img])
        srvr = request.environ['HTTP_HOST']
        if ':' in srvr:
            srvr = srvr[:srvr.index(':')]
        dct[addr] = 'http://%s:%d' % (srvr, cid)
    return redirect(dct[addr], 302)

if __name__ == '__main__':
    app.run('0.0.0.0', 5000)
  • 同じPCからのアクセスでは、同じコンテナを使うようにします。その対応関係(アクセス元アドレス→コンテナのアドレス)をdctという辞書で持ちます。
  • addrに、アクセス元アドレスを入れます。
  • addrが最初のアクセスの時、以下を実行します。
    • imgに、受講者用のイメージ名を環境変数IMAGEから取得します。
    • prtに、そのイメージで用いるポート番号を環境変数PORTから取得します。
    • cidに、受講者用コンテナに対し、サーバ側で用いるポート番号を計算します。(8001から通し番号)
    • 受講者用コンテナを起動します。
    • srvrに、サーバのアドレスを入れて、元のポート番号(5000)を消して、新しいコンテナのポート番号を足して、dct[addr]に設定します。
  • dct[addr]にリダイレクトします。

以上

16
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?