stylesheet

2018-08-25

HerokuのDocker Deployで機械学習APIを5ステップで作成

HerokuでDockerが使えるようになっていたので、遅まきながら、機械学習を使ったAPIを5ステップで作成してみた。

STEP1: 事前準備

herokuへサインアップし、APPを作成。
また、herokuコマンドとdockerをインストールして使えるようにしておく。

STEP2: サンプルコードを入手

heroku公式のminicondaイメージのサンプルコードがあるので、コレをベースに使用。

$ git clone https://github.com/heroku-examples/python-miniconda.git

ざっと中身を確認すると、

  • python 2.7
  • miniconda環境構築済み (condaコマンドが使える)
  • scikit-learn導入済み
  • webフレームワークはflask
  • gunicornでwsgi
  • ポート番号は環境変数PORTで指定

となっていた。

STEP3: APIを実装

heroku用だろうと特に変わることはないので、いつものようにサクッと実装する。

開発中にライブラリを追加した場合は、Dockerfileへの反映も忘れずに。

pandas等condaで追加するもの -> Dockerfile内のconda installに追記
pipでインストールするもの -> requirements.txt

STEP4: ローカルで動作チェック

Dockerコンテナを起動して動作を確認する。

引数指定がめんどうなので、docker-compose.ymlを作成してdocker-composeを使用することにする。

# docker-compose.yml
version: "2"
services:
  app:
    build: .
    ports:
      - "8100:8100"
    environment:
      PORT: "8100"

コンテナ起動とブラウザで動作チェック。

$ docker-compose up
$ xdg-open http://localhost:8100

STEP5: herokuへデプロイ

ここからがherokuで行う操作となるが、いくつかコマンドを打つだけで本番反映まで行える。素晴らしい。

$ heroku login
Email: nobody@somewhere.com
Password: ********
$ heroku container:login
$ heroku container:push web -a アプリ名
$ heroku container:release web -a アプリ名

以上で完了。

終わり

Heroku の Docker Registry & Runtime (Docker Deploy)は、ほぼストレスフリーで簡単に使用できる完成度の高いプラットフォームと思う。

詰まったところといえば、サンプルコードのREADME.md記載の手順が少し古かったところぐらい。
container-registry用のpluginをインストールするよう書かれていたが、現在は不要。

作ったもの

結局、何を作ったかというとIPO銘柄の初値予想APIを作った。
過去のIPOデータを学習させてRidge回帰で暴騰率を予測させている。スコア的には残念だが、雰囲気はでていると思う。

ブラウザの場合は、http://ipo-cal.herokuapp.comへアクセスするとGUIで試せる。

API本体はhttp://ipo-cal.herokuapp.com/api/predictで公開している。
curlだと以下のように呼び出す。

$ curl -X POST \
  -H "Content-type: application/json" \
  -d '[{"code":"4385", "market":3, "sector":25, "price": 3000.0, "fund":122142.9, "kobo":18159.5, "uri":22554.8}]' \
  http://ipo-cal.herokuapp.com/api/predict

{"data":[{"code":"4385","inflation":189.6046720498996,"price":5700,"rank":3}],"status":"success"}

json文字列をhttp://ipo-cal.herokuapp.com/api/predictへpostするだけでOK。
配列にして一度に50件までまとめて実行できる。

レスポンスはJsendに概ね準拠している。

レスポンスがなかなか返ってこない時は、サーバーがスリープしている。コンテナが起動するまでしばらくかかるので、10秒ほど待機してからリトライしてみて欲しい。

2018-08-03

arm64版armbianでpuppeteerを使う

puppetterはnodejsからheadless-chromeを使用するためのライブラリ。
こちらもarm64環境では素直に動かなかったのでメモ。

環境

  • Orange Pi Win Plus
  • ARMBIAN 5.41 stable Ubuntu 16.04.5 LTS 3.10.107-pine64
  • nodejs v8.11.3

問題点

  • npmインストール時にchromeバイナリが自動ダウンロードされるがarm64版ではないので起動しない。
  • 手動でarm64版をダウンロードして置き換えようにも、そもそもarm64版のスナップショットは公式で提供されていない。
  • armbian(ubuntu)がarm64版のchromiumを提供しているが少しバージョンが古い。Chromium 68.0.3440.75
  • 最新のpuppeteer v1.6.1が対応するchromeはChromium 69.0.3494.0 (r575458)。
  • chromiumのような大きなアプリケーションをセルフビルドするのは嫌だ。

対処

  • 古いのを承知でaptパッケージのchromium-browserをインストール。
  • 対応chromeのバージョンが近いpuppetter v1.4.0で妥協。
  • aptパッケージのchromiumを使う。(executablePath/usr/bin/chromium-browserを指定)
$ sudo apt install chromium-browser
$ npm install puppeteer@1.4.0 
const puppeteer = require('puppeteer')

(async () => {
    const browser = await puppeteer.launch({
      executablePath: '/usr/bin/chromium-browser'
    })
    ...
})()

以上の対処で今回のケースでは一応動作した。
早くarm64もメジャーなアーキテクチャになって欲しいところ。

2018-06-07

Alertmanager (prometheus) の Webhookレシーバーを調べる

AlertmanagerPrometheusでのアラート管理を行うコンポーネント。
現状で以下のレシーバー(通知先)をサポートしている。

  • SMTPメール
  • Hipchat
  • PagerDuty
  • Pushover
  • Slack
  • OpsGenie
  • VictorOps
  • WeChat
  • Webhook

今後はレシーバーの追加は積極的に行わないそうで、Webhookを使って自身で作成して欲しいとのこと。

Webhookレシーバー

設定で指定したエンドポイントに対して、JSONでPOSTリクエストを送出するレシーバー。
POSTリスエストを送るだけなので、その後の処理は利用者側で用意する必要がある。

なんでもできるけど、なんにもできない、そんな感じ。

使用するにはAlertmanagerの設定にwebhookレシーバーを追加してやる。

receivers:
- name: "myreceiver"
  webhook_configs:
  - url: 'http://127.0.0.1:3001/alerts'
    send_resolved: true

Prometheus側のアラートルールでlabelsとannotationsとして受け取るプロパティを追加出来る。

- alert: InstanceDown
    expr: up == 0
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "Instance {{ $labels.instance }} down"
      description: "{{ $labels.instance }} of job {{ $labels.job }} has bennd down for more than 5 minutes"

Prometheusのアラートはpendingfiringresolvedと状態が遷移する。
この内、webhookで送出されるイベントはfiringresolvedの2つ。

firing状態では次のような構造になる。
同じグループのアラートは配列としてまとめて送られてくる。

{ receiver: 'duino-klutch-webhook-receiver',
  status: 'firing',
  alerts:
   [ { status: 'firing',
       labels:
        { alertname: 'InstanceDown',
          instance: 'localhost:9100',
          job: 'node_exporter',
          severity: 'critical' },
       annotations:
        { description: 'localhost:9100 of job node_exporter has bennd down for more than 5 minutes.',
          summary: 'Instance localhost:9100 down' },
       startsAt: '2018-06-06T18:03:58.765899704+09:00',
       endsAt: '0001-01-01T00:00:00Z',
       generatorURL: 'http://orange:9090/graph?g0.expr=up+%3D%3D+0&g0.tab=1' } ],
  groupLabels: { alertname: 'InstanceDown' },
  commonLabels:
   { alertname: 'InstanceDown',
     instance: 'localhost:9100',
     job: 'node_exporter',
     severity: 'critical' },
  commonAnnotations:
   { description: 'localhost:9100 of job node_exporter has bennd down for more than 5 minutes.',
     summary: 'Instance localhost:9100 down' },
  externalURL: 'http://orange:9093',
  version: '4',
  groupKey: '{}:{alertname="InstanceDown"}' }

設定でsend_resolvedを無効にしていない場合はresolved状態でもPOSTリクエストが送出される。
スキーマはfiringの場合と違いはない。

{ receiver: 'duino-klutch-webhook-receiver',
  status: 'resolved',
  alerts:
   [ { status: 'resolved',
       labels:
        { alertname: 'InstanceDown',
          instance: 'localhost:9100',
          job: 'node_exporter',
          severity: 'critical' },
       annotations:
        { description: 'localhost:9100 of job node_exporter has bennd down for more than 5 minutes.',
          summary: 'Instance localhost:9100 down' },
       startsAt: '2018-06-06T18:03:58.765899704+09:00',
       endsAt: '2018-06-06T18:07:58.765932428+09:00',
       generatorURL: 'http://orange:9090/graph?g0.expr=up+%3D%3D+0&g0.tab=1' } ],
  groupLabels: { alertname: 'InstanceDown' },
  commonLabels:
   { alertname: 'InstanceDown',
     instance: 'localhost:9100',
     job: 'node_exporter',
     severity: 'critical' },
  commonAnnotations:
   { description: 'localhost:9100 of job node_exporter has bennd down for more than 5 minutes.',
     summary: 'Instance localhost:9100 down' },
  externalURL: 'http://orange:9093',
  version: '4',
  groupKey: '{}:{alertname="InstanceDown"}' }

アラートの状態がpendingからfiringに変化しても、実際にリクエストが送出されるまでは多少時間が掛かる。
即応性が必要なものは不向き。

実装例

上記を踏まえて手抜き実装してみたwebhookがこちら

arduinoに繋いだ8x8マトリクスLEDへサマリーをメッセージ表示するもの。
firing状態のアラートを保持してresolvedで破棄するようにしてみた。

2018-06-03

node-red + influxdb + prometheus + grafanaでorange-pi-winへダッシュボードを作る

orangepi-win(armbian x64)を監視用ダッシュボードにするために色々とインストールを行う。
arm64用のパッケージが古かったり提供されてなかったりで色々と面倒。

監視用ダッシュボード

grafanaを使用してウェブブラウザで各種メトリクスデータをグラフ表示するもの。

メトリクスデータは以下のものを収集。

  1. システムのメトリクスデータ
  2. 外部Webサービスの応答速度
  3. websocketやweb apiで収集したセンサー値など

1番、2番に関してはprometheusを使用して収集する。それぞれnode_exporter、blackbox_exporterが追加で必要になる。
3番は、node-redを使用してデータフローを作成して対応する。メトリクスデータの保存にはinfluxdbを使用。

以下、必要となるソフトウェアのインストール方法をメモしていく。
node-redデータフローの内容やgrafanaダッシュボードの作り方は記載しない。

※センサーデータの配信サーバーデバイスを自作してやろうという変人は著作のこちらも参考にどうぞ。 esp8266向けのhttp/websocket apiサーバーです。

influxdb

https://www.influxdata.com/

influxDBは時系列データの扱いに特化したデータベース。
時系列データベースとして採用例が多いgraphiteより後発のもの。

インストールはaptで素直に入る。
ついでにnode-redからの書き込み用のデータベースを作成しておく。

$ sudo apt install influxdb influxdb-client
$ influx
> create database things

http apiで更新可能のためか、簡易なWebUIが付属している。

http://127.0.0.1:8083

prometheus

https://prometheus.io/

prometheusはpull型のサーバー監視ツール。k8s環境で使われることが多い印象。

arm64版のパッケージがレポジトリに登録されていないのでインストールは少し面倒。
公式サイトからバイナリを入手してインストールする必要がある。

$ wget https://github.com/prometheus/prometheus/releases/download/v2.2.1/prometheus-2.2.1.linux-arm64.tar.gz
$ sudo tar xvfz prometheus-2.2.1.linux-arm64.tar.gz -C /opt
$ cd /opt
$ sudo ln -s prometheus-2.2.1.linux-arm64/ prometheus
$ sudo vi /etc/systemd/system/prometheus.service

  [Unit]
  Description=Prometheus
  Wants=network-online.target
  After=network-online.target

  [Service]
  User=root
  Group=root
  Type=simple
  ExecStart=/opt/prometheus/prometheus --config.file /opt/prometheus/prometheus.yml

  [Install]
  WantedBy=multi-user.target

$ sudo systemctl daemon-reload
$ sudo systemctl enable prometheus

また、prometheusではメトリクスデータの収集に各種exporterが必要。
システムメトリクスの収集はnode_exporter、外部サービスの死活監視はblackbox_exporterを使用する。

これらも同じようにインストール。手順はほぼ一緒なので省略。

インストールが完了したら、/opt/prometheus/prometheus.ymlを編集してjobを登録する。

...
scrape_configs:

  ...

  - job_name: 'node_exporter'
    static_configs:
    - targets: ['localhost:9100']

  - job_name: 'blackbox_http'
    metrics_path: /probe
    params:
      module: [http_2xx]
    static_configs:
      - targets:
        - http://example.com
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: 127.0.0.1:9115

最後にsystemdで自動起動を有効にする。

$ sudo systemctl daemon-reload
$ sudo systemctl enable prometheus
$ sudo systemctl enable node_exporter
$ sudo systemctl enable blackbox_exporter

node-red

https://nodered.org/

node-redはビジュアルデータフロープログラミングツール。
"mqttでセンサーデータを受信、influxdbへ保存"みたいなことがマウスでポチポチするだけで出来あがる。

nodejs製のWebアプリなので、インストールにはnpmを使用する。また、daemon化にはpm2を使用した。

$ sudo npm install -g --unsafe-perm node-red
$ sudo npm install -g pm2

プロセス構成を作成してsystemdへ登録する。

$ sudo su
$ pm2 start node-red
$ pm2 save
$ pm2 startup

WebUIはポート1880番を使用。

http://127.0.0.1:1880

WebUIにアクセスし、node-red-contrib-influxdbを設定から追加。

その後、マウスでポチポチしてデータフローを組み上げる。
例えば、以下のようなデータフローを作成する。

websocket接続 -> 受信データのフィルタと成形 -> influxdbへ追加
定期実行 -> httpリクエスト -> レスポンスデータのフィルタと成形 -> influxdbへ追加

grafana

https://grafana.com/

grafanaはwebブラウザ向けのデータビジュアライゼーションツール。kibanaからフォークして誕生した。
ストレージにinfluxdbやprometheusが使用可能。

aptリポジトリ版はUIが壊れた(アイコンが表示されない)不具合のある旧版なので公式パッケージを使用。

$ wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.0.4_amd64.deb
$ sudo dpkg -i grafana_5.0.4_amd64.deb

一旦、homepathを指定して起動してやる。

$ sudo grafana-server -homepath /usr/share/grafana

自動起動を有効にする。

$ sudo systemctl enable grafana-server

WebUIはポート3000番を使用。

http://127.0.0.1:3000

初期アカウントはユーザー、パスワード共にadmin
メニューのData Sourcesからinfluxdbとprometheusを追加しておく。

Type: InfluxDB
Url: http://localhost:8086

Type: Prometheus
Url: http://localhost:9090

その後、こちらもマウスでポチポチしてダッシュボードを作成していく。
公開されているものをインポートしてから調整していくと少しは楽できる。

結構大掛かりになったが、以上でセットアップは完了。

メトリクスデータが僅かなこともあって、非力なorange-piでも一応は動作しているが、それなりに負荷はかかっているよう(特にinfluxdb)なので、そのうち破綻しそうな気はする。

都会派のカメはヒキガエルと言うそうです

2018-05-19

IP直打ちやhosts編集が面倒になったのでmDNSを設定しまくる

BonjourだとかzeroconfだとかmDNSの話。
閉じたネットワークで`ホスト名.local`でサーバーマシンにアクセスできれば満足。Service Discoveryとかはスルーの方向性で。

Linux (Debian系)

最初から入っているディストリも多いが、ホスト名を設定してavahi-daemonlibnss-mdnsを入れるだけ。

avahi-daemonがresponderでlibnss-mdnsのほうがクライアントとして動作する。 ラズパイやオレンジパイも同じ。

$ sudo -e /etc/hostname
$ sudo apt install avahi-daemon libnss-mdns

Windows10

ネイティブサポートされているようだがファイアーウォールで止められている。UDPポート5353を開放すると使えるようになる。

面倒であれば、Bonjourをインストールするとファイアウォールが自動で構成されるので手っ取り早い。

ホスト名はコンピュータ名を使う。

MacOS, iOS

最初から使用可能。設定のローカルホスト名とか名前とかそこらへんでホスト名を決める。

esp8266

Arduinoスケッチの場合は、ESP8266mDNSライブラリをインクルードしてMDNS.beginをコールするだけ。

この類のマイコンでmdnsはかなり有用。

#include <ESP8266mDNS.h>
MDNS.begin("superhost");

Android

SDKでAPIは提供されているが、アプリ側で対応が必要。そして現状、chromeでは使えない。

スマホは公共ネットワークに接続することも多いだろうから、セキュリティ的に使えなくて正解かもしれない。

2018-03-31

OnePlus3Tのシステム更新メモ

op3tのシステムを新しくしたのでメモ。
stable版で固めたのでandroidは8.0(sdk26)と少し古めの構成。

システム構成:

  • Device: OnePlus3T (A3010)
  • ROM: oxygen v5.0.1
  • Kernel: blu_spark r215
  • Recovery: twrp_blu_spark v8.61
  • Root: magisk v16.0

ファイルの入手先:

Downloads - OnePlus.net
  • - OnePlus3TOxygen_28_OTA_062_all_1712272248_d28093577f324959.zip
[KERNEL] [blu_spark r32 unified] [OOS 4.0.* … | OnePlus 3T
  • twrp-3.2.1-x_blu_spark_v8.61-op3_op3t.img
  • blu_spark_r215-oos-oreo_op3-op3t_bc9e869.zip
[2018.3.18] Magisk v16.0 - Root & Universal Systemless Interface [Android 5.0+]
  • Magisk-v16.0.zip
  • MagiskManager-v5.6.3.apk

手順:

  1. oemロック解除
  2. recoveryからoxygen(zip)をインストール ※リカバリーがOxygenのものに上書きされてしまう
  3. fastbootモードにしてtwrp(img)をフラッシュ
    $ fastboot flash recovery twrp-3.2.1-x_blu_spark_v8.61-op3_op3t.img
  4. recoveryでmagisk(zip)、次にblu_spark(zip)をインストール
  5. MagiskManager(apk)をインストール

以上。

2018-03-27

Windowsは文字キーを押している間、タッチパッドやボタンでクリックできない

久々にWindowsを使用していると、「文字キーを押している間はタッチパッドやボタンでクリックできない」現象に遭遇したのでメモ。

この現象、Microsoft Supportによると不具合でも何でもなくて期待された振る舞いとのこと。

文字入力中にタッチパッドに手が触れてクリック暴発、カーソルが飛んであらぬところに文字入力。
そんな悲しい事故を防ぐために、キー入力中はOS側でクリックを一時的に無効にしてくれるという親切機能。

Accidental Activation Prevention (AAP)という御大層な名前がついており、Windows8.1で強制導入された。

邪魔なので無効にする

Windows10の場合、設定 > デバイス > タッチパッド から「タッチパッドの感度」を「最大の感度」にすると無事クリックできるようになる。

詳しくはMicrosoft Supportで

Microsoftが忘れ去ってしまったもの、この機能によって完全に失われてしまったもの

そう。
射撃しつつ前進だ。

2018-02-20

ansibleのインストール

PC初期化の毎に調べてる気がするので、ansibleのインストール方法をメモしておく。
OSはUbuntuを使用。

2018-01-14

Hなこと始めました

すぐに仕事で使えそうなKotlin、熟練者から最強との呼び名が高いRust。 どちらにしようか迷ってたはずなのに、なぜか、2018年度のお勉強はHaskellに決まりました。

関数型言語はEmacsの設定ファイルをコピペ位しかしたことがないド素人です。

2017-12-30

OnePlus3TをTWRP/OxygenOS(oreo)/SuperSU構成でクリーンインストール

年の瀬なので、Android端末のOnePlus3Tも年末大掃除。 全てリセットして、Android8(Oreo)ベースのOxygenOSへ移行する。

  • osはoreo版のOxygenOS
  • リカバリーはTWRP
  • rootはSuperSU

全データを消去して端末のセットアップから始めるので事前にバックアップやメモは必要。しっかりNANDroid Backupしておく。

2017-12-12

60%レイアウトのBluetoothメカニカルキーボード Anne Pro

最近老化が進んでいるのか、Thinkpadのパンタグラフキーボードでもキー入力が重いと感じることが多くなったので キーボードを新調してみた。

60%から75%サイズのキーボードを比較検討した結果、最終的にAnne Proを購入。
昨年発売の製品となるが、機能的に見劣りするものではない。

Anne ProはGateron赤軸を採用した60%サイズのキーボード。主な特徴は以下の通り。

  • 標準的な60%レイアウト
  • Bluetooth/USB両対応
  • Gateronキースイッチ 赤軸
  • PBTキーキャップ
  • RGBバックライト
  • プログラマブル (専用アプリ使用)
  • ファームウェア更新対応

同セクターのメカニカルキーボード代表機種Pokerから外観をパクり、様々な機能をてんこ盛りにした、 「ミニマリスト向けなのに全部入り」というブレまくったコンセプトが素敵。それでいてお値段控えめがうれしい中華キーボードの決定版。

2017-11-24

GKEでPython WSGIアプリケーションをクラスタ化してみる

Google Cloud Platform (GCP) の無料クレジットがまだ余っているものの、有効期限が迫っているので Google Kubernetes/Container Engine (GKE) で遊んでみる。

実使用ではyamlファイルを作成してInfrastructure as Codeまで行うのだろうけど、 今回はチュートリアルのDeploying a containerized web application に倣って、全てコマンドラインオプションで指定する。

アプリケーションはnginxとwsgiコンテナをシングルイメージに詰め込んだものを使用。 Dockerfileはこんな感じ。

FROM tiangolo/uwsgi-nginx:python2.7

COPY ./docker/nginx.conf /etc/nginx/conf.d/default.conf

# install MeCab
RUN apt update && apt install -y mecab mecab-utils mecab-ipadic-utf8 libmecab-dev

# install app
COPY ./app /app
COPY ./docker/uwsgi.ini /app/uwsgi.ini
WORKDIR /app
RUN pip install -r requirements.txt

2017-11-13

CSS: transform-styleを用いた3D視差回転アニメーション

transform-styleプロパティへpreserve-3dを設定すると子要素を3D空間に配置することができる。 これを使用すると簡単なcssとスクリプトで視差回転アニメーションが実現できるので試してみた。

デモはこちら
対応ブラウザでマウスかタッチしてぐりぐりしてみて欲しい。

transform-style - CSS | MDN