ConoHa VPSでbottle

前回

に引き続き、VALUE SERVERからConoHa VPSに移行して動かなくなってたところを直していきます。今回はコレですね。

bottleです。Hello, worldしただけなんですけどね。VALUE SERVERではpython3自体がインストールされていたので、Apacheのmod_cgiを使い、CGIでpythonを起動して動かしていました。

これを今回はdockerコンテナ上のnginxからWSGIで別のdockerコンテナ上のpythonに繋ぎ、bottleを動かします。まあ最近bottle聞かなくなりましたけど。。。

bottleの設置

サブドメインの追加

せっかくnginxのリバースプロキシ置いて、dockerコンテナで分離しているので、いつでもサーバーを動かせるようにサブドメインで動かします。ConoHaのDNSでpythonというCNAMEレコードを追加しました。ドメインはpython.elephantcat.workになります。

タイプ名称TTL
CNAMEpython3600elephantcat.work

関連記事

SSL証明書の取得

Let’s Encryptで先程追加したサブドメイン(python.elephantcat.work)のSSL証明書を取得しました。certbotのあるディレクトリで以下のファイルを作成して…

DOMAIN="python.elephantcat.work"
EMAIL="更新通知を受け取りたいメールアドレス"

登録用のシェルスクリプトを実行しました。

$ bash register.sh python

成功すると「Congratulations! Your certificate and chain have been saved at:」と表示されて、証明書の位置を教えてくれます。

関連記事

nginxの設定追加

コンテナの修正

nginx用のdocker-compose.ymlを以下のように修正し、hostにmountするディレクトリとファイルを追加しています。

...
services:
  nginx:
...
    volumes:
...
      - ./../python/html:/var/www/html_python
      - ./python.conf:/etc/nginx/conf.d/python.conf
...

./../python/htmlは、https://python.elephjantcat.work/用の静的ファイルのルートフォルダです。mkdir ./../python/htmlしておきます。
./python.confは、https://python.elephjantcat.work/bottle用のnginx設定ファイルです。

設定増えてきたので、そろそろconf.dからマウントした方がいいかもしれません。

nginxの設定追加

先ほど追加したpython.confの中身です。

server {
  listen 443 ssl; 
  server_name python.elephantcat.work; 
  ssl_certificate     /etc/letsencrypt/live/python.elephantcat.work/fullchain.pem;
  ssl_certificate_key   /etc/letsencrypt/live/python.elephantcat.work/privkey.pem;
  location / {
    root   /var/www/html_python;
    index  index.html index.htm;
  }
  location /bottle {
    resolver 127.0.0.11 valid=30s;
    include uwsgi_params;
    set $variable python;
    uwsgi_pass $variable:3031;
  }
}

/bottle以下のリクエストはpythonという名前のホストのポート3031にwsgiで転送しています。

resolverが設定されていたり、ホスト名が$variable経由になっていたりするのは、名前解決できないときにサーバーごと落とさないための配慮です。

起動確認

これだけの設定で、ホストpythonがいなくてもnginxは起動するので、確認しました。

$ docker-compose up -d

この時点でhttps://python.elephantcat.work/bottleにアクセスすると、502 Bad Gatewayを返します。

pythonコンテナ追加

docker-compose.yml

version: '3'
services:
  python:
    image: python
    volumes:
      - ./python:/home/python
      - ./initial_data:/home/initial_data
    networks:
      - frontend
    entrypoint: /home/initial_data/docker-entrypoint.sh

networks:
  frontend:
    external: true

イメージはpythonの公式最新イメージを使います。マウントは2箇所で、./pythonと./initial_dataです。./pythonは実行環境を実際に作成する場所で、最初は空です。./initial_dataにあるデータとスクリプトを使って、実行環境を構築します。実際に動かすスクリプトはdocker-entrypoint.shです。

docker-entrypoint.sh

./initial_data/docker-entrypoint.sh

#!/bin/sh
if [ ! -f /home/python/bottle/env/bin/uwsgi ]; then
        cd /home/python
        mkdir bottle
        cd bottle
        python3 -m venv env
        . env/bin/activate
        pip install -U pip
        pip install bottle uwsgi
        cp -p /home/initial_data/uwsgi.ini .
        cp -p /home/initial_data/app.py .
        cd ..
        chown -R 1000:1000 .
fi
exec /home/python/bottle/env/bin/uwsgi /home/python/bottle/uwsgi.ini

※このファイルは実行可能属性が必要です(chmod u+x initial_data/docker-entrypoint.sh)

/home/python/bottleにvenvの実行環境を作成し、pipでbottleとuwsgiをインストールしてuwsgiを起動しています。既にインストールされている場合はインストールがスキップされます。

uwsgiはWSGIなどのインターフェースを実装したサーバーで、pythonなどで書かれたWSGIアプリを動かせます。上のスクリプトで、uwsgi.iniがuwsgiの設定ファイルで、app.pyがpythonで書かれたWSGIアプリになります。既にインストールされている場合にvenvのactivateがされていませんが、venv環境のpipでインストールされたuwsgiを使っているので、activateしなくてもvenv環境が使用されます。

uwsgi.ini

https://uwsgi-docs.readthedocs.io/en/latest/WSGIquickstart.html

この辺を参考に、以下のような設定にしています。

./initial_data/uwsgi.ini

[uwsgi]
socket = :3031
uid = 1000
gid = 1000
chdir = /home/python/bottle
wsgi-file = app.py
#master = true

最初にポートの指定、次がユーザーとグループの指定(rootだと危険と怒られるため適当に設定)、実行ディレクトリとあとアプリの指定だけです。masterを指定すると、落ちたときなどに再起動などを期待できますが、その分余計にメモリを食うので、実験用のアプリしか動かさない今の環境では不要と判断してコメントにしています。

app.py

./initial_data/app.py

from bottle import route, default_app
@route('/bottle')
def hello():
    return 'Hello, World!'
application = default_app()

https://python.elephantcat.work/bottleにアクセスされたら、Hello, World!を返すだけのアプリです。bottleを使った今回のプログラム本体です。

起動

$ docker-compose up -d

確認

https://python.elephantcat.work/bottle

できてる模様。

まとめ

Apache -> CGI -> bottleからnginx -> WSGI -> bottle(かつdocker使用)に書き換えることが出来た。

次回は同様の作業をdjangoでやる予定。