Webサービス」カテゴリーアーカイブ

Jupyter Notebook をコマンドラインで作成して Jupyter kernel をテストする方法

Jupyter Notebook のカーネルを自動でテストする方法はいくつかあるようだけど、ユーザが使うことを想定しているような実装には見えない。今回は、nbformat を使って Python プログラムから notebook(.ipynb ファイル)を作って実行し結果を確認する方法について記録しておく。

Notebook の作成

import nbformat

nb = nbformat.v4.new_notebook()
title = "Python3 Test Notebook"
code = """
import sys
print(sys.version)
"""
nb["cells"] = [
    nbformat.v4.new_markdown_cell(title),
    nbformat.v4.new_code_cell(code)
]

with open("/notebook/Python3Test.ipynb", "w") as f:
    nbformat.write(nb, f)

こんな感じにすると、1つ目のセルに Python のバージョンをチェックするコードが入った notebook が Python3Test.ipynb の名前で保存される。

Notebook の実行

$ jupyter nbconvert --ExecutePreprocessor.kernel_name=<kernel> --to notebook --execute --inplace /notebook/Python3Test.ipynb

このようにすると、notebook を実行して結果を同ファイルに上書きしてくれる。

Notebook の中身の確認

import sys
import nbformat

with open(sys.argv[1]) as f:
    nb = nbformat.read(f, as_version=4)

for cell in nb['cells']:
    if 'outputs' in cell:
        for output in cell['outputs']:
            print(output['text'])

スクリプト実行するときに第一引数に notebook のファイル名を指定する。notebook 内の結果部分だけがすべて標準出力に出る。

HedgeDoc を Docker compose で動かす(SSL + リバースプロキシ)

概要

HedgeDoc というマークダウンでメモを書けるサービスが便利そうだったので自分用に立ち上げてみた。
サクッと閲覧のみで公開できるのはすごく便利そうに思える。

  • フロントエンドの nginx をリバースプロキシとして使っているので、そこからプロキシされるように設定。
  • サブディレクトリ /hedgedoc/ で運用。
  • 外部とは SSL でやり取りさせる。

HedgeDoc 提供コンテナ群

HedgeDoc を提供するためのコンテナ群はこのようにした。
shared はフロントエンドの nginx から hedgedoc:3000 でアクセスできるようにするために接続している。

version: '3.1'

services:

  database:
    image: postgres:13.4-alpine
    environment:
      - POSTGRES_USER=hedgedoc
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=hedgedoc
    volumes:
      - ./database:/var/lib/postgresql/data
    restart: always

  app:
    container_name: hedgedoc
    image: quay.io/hedgedoc/hedgedoc:latest
    environment:
      - CMD_DB_URL=postgres://hedgedoc:password@database:5432/hedgedoc
      - CMD_DOMAIN=www8281uo.sakura.ne.jp
      - CMD_HOST=hedgedoc
      - CMD_PORT=3000
      - CMD_URL_PATH=hedgedoc
      - CMD_URL_ADDPORT=false
      - CMD_ALLOW_ANONYMOUS=false
      - CMD_ALLOW_EMAIL_REGISTER=false
      - CMD_PROTOCOL_USESSL=true
    volumes:
      - ./uploads:/hedgedoc/public/uploads
    restart: always
    depends_on:
      - database

networks:
  default:
    external:
      name: shared

リバースプロキシの設定

リバースプロキシにしている nginx の設定はこんな感じ。
socket.io の項目をどうしたらいいか少し難しかったけど以下の内容でうまくいくようだ。

location /hedgedoc/ {
    proxy_set_header Host \$host;
    proxy_set_header X-Real-IP \$remote_addr;
    #proxy_set_header X-Forwarded-Host \$host;
    #proxy_set_header X-Forwarded-Server \$host;
    proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto \$scheme;
    proxy_pass http://hedgedoc:3000/;
}
location /hedgedoc/socket.io/ {
    proxy_set_header Host \$host;
    proxy_set_header X-Real-IP \$remote_addr;
    #proxy_set_header X-Forwarded-Host \$host;
    #proxy_set_header X-Forwarded-Server \$host;
    proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto \$scheme;
    proxy_set_header Upgrade \$http_upgrade;
    proxy_set_header Connection \$connection_upgrade;
    proxy_pass http://hedgedoc:3000/socket.io/;
}

参考サイト

VPS を再構築した話

VPS の OS が古くなってしまったので作り直した。

作りこんでいたサービスのほとんどはもはや使っていなかったので、とりあえずこの wordpress だけを持ってきた。
次回以降のことを考えて、docker で構築。

はじめに

外部 ↔ フロントエンドコンテナ(nginx) ↔ WordPress コンテナ群(nginx, php-fpm, mysql)という構成。
これだと、サーバ内にリバースプロキシが二つもあって無駄な処理をすることになるが、管理しやすさを考えてこうしてみた。問題があれば変更しよう。

コンテナ間通信ネットワークの作成

まずはコンテナ間通信のためのネットワークを作成し、

$ sudo docker network create --driver bridge shared

WordPress 用コンテナ群の作成

WordPress を提供するためのコンテナ群を作成。
これは nginx + php-fpm で動くようにした。
WordPress をサブディレクトリで動かすために working_dir: を設定するのだが、これに気が付くのに時間を費やした。

version: '3.1'

services:

  rproxy:
    container_name: wp-rproxy
    build:
      context: ./mynginx
      dockerfile: Dockerfile
    restart: always
    volumes:
      - ./wordpress:/var/www/html/blog
      - ./nginx-log:/var/log/nginx
    depends_on:
      - wordpress

  wordpress:
    image: wordpress:6.4.2-php8.3-fpm-alpine
    restart: always
    working_dir: /var/www/html/blog
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wp
      WORDPRESS_DB_PASSWORD: mywordpress
      WORDPRESS_DB_NAME: wp
    volumes:
      - ./wordpress:/var/www/html/blog
      - ./wordpress-log:/var/log
    depends_on:
      - db

  db:
    image: mysql:8.0
    restart: always
    environment:
      MYSQL_DATABASE: wp
      MYSQL_USER: wp
      MYSQL_PASSWORD: ***
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - ./db:/var/lib/mysql
      - ./db-log:/var/log

この mynginx は以下の Dockerfile で作成。

FROM nginx:alpine


COPY <<EOF /etc/nginx/conf.d/default.conf
server {
    listen 80;
    server_name localhost;

    root /var/www/html;
    index index.php;

    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;

    location /blog/ {
        try_files \$uri \$uri/ /index.php?\$args;
    }

    location ~ \.php\$ {
        include fastcgi_params;
        fastcgi_pass wordpress:9000;
        fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
        fastcgi_param PATH_INFO \$fastcgi_path_info;
    }
}
EOF

フロントエンドコンテナの作成

今後別のサービスを動かしたくなるかもしれないので、wordpress を提供しているコンテナ群とは独立に一つ nginx を立ててフロントエンドにする。
これは基本的には / にあるファイルの提供と、サブディレクトリに配置したサービスへのリバースプロキシにする。
なので、サービスを追加した際にはこのコンテナ(の default.conf)を適宜更新する。

version: '3.1'

services:

  rproxy:
    container_name: rfront
    build:
      context: ./mynginx
      dockerfile: Dockerfile
    ports:
      - 80:80
    restart: always
    volumes:
      - ./html:/var/www/html
      - ./nginx-log:/var/log/nginx

networks:
  default:
    external:
      name: shared

この mynginx は以下の Dockerfile で作ります。

FROM nginx:alpine

COPY <<EOF /etc/nginx/nginx.conf
user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '\$remote_addr - \$remote_user [\$time_local] "\$request" '
                      '\$status \$body_bytes_sent "\$http_referer" '
                      '"\$http_user_agent" "\$http_x_forwarded_for"';

    log_format upstreamlog '[\$time_local] \$remote_addr \$host \$upstream_addr '
                           '\$upstream_cache_status \$upstream_status '
                           '\$upstream_http_location \$request';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}
EOF

COPY <<EOF /etc/nginx/conf.d/default.conf
server {
    listen 80;
    server_name www8281uo.sakura.ne.jp;

    root /var/www/html;
    index index.html index.htm;

    access_log /var/log/nginx/access.log main;
    access_log /var/log/nginx/upstream.log upstreamlog;
    error_log /var/log/nginx/error.log;

    location /blog/ {
        index index.php;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-Host \$host;
        proxy_set_header X-Forwarded-Server \$host;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_pass http://wp-rproxy:80/blog/;
        proxy_redirect default;
    }
}
EOF

おわりに

WordPress くらい有名なサービスだとたくさん情報があるので調べればすぐにいろいろ出てくる。
Docker を使うことで、php-fpm を使った高速なサイト構築が簡単に出来るというのはすごいことだ。

Redmine に checklist 機能をつけたらとても便利

研究や家族行事の ToDo 管理に一人 Redmine を使っている。
一人で使うにはオーバスペックで、Redmine の操作自体に時間がかかっちゃうなーと思っていたのだけど、後から振り返れるのがいいと思ってる。

RedmineUP checklist plugin を入れたらかなり快適になった。これまで子イシューを作ってもいいけど、そこまででもないなってことをどうするか悩ましかったけど、これで結構カバーできる。

インストール方法は難しくない。だけど、Redmine にログインするユーザに権限を与えないと利用できないところで少しはまった。

Basecamp API の events.json で時刻が GMT で返ってくる

仕様・・・なんだとおもうけど。

問題

${PROJECT_ID}/api/v1/events.json で取得したイベントのアクションに時刻が含まれる場合、タイムゾーンが GMT で返ってくるみたい。

対策

  1. アクションのメッセージをパースして(GMTと仮定し)タイムゾーンを変更
  2. 返ってくる url から詳細情報を取得してタイムゾーンの情報も含んだ時刻情報を取得、利用

今回は 2. を選択。