読者です 読者をやめる 読者になる 読者になる

devproxyをWebアプリケーション開発で使う

Linux 開発環境

devproxyというのを開発時に使っているのですが、便利なので紹介します。

GitHub - moriyoshi/devproxy: A swiss army knife of forward HTTP proxies

devproxyは、Webアプリケーション開発向けのHTTPフォワードプロキシです。次のような点で便利です。

  • /etc/hostsの編集やDNSの設定をしなくても、開発サーバーにドメイン名を指定してでアクセスできる
    • そのため、個々の開発環境に差(VMを使ってたりローカル環境だったり)があっても、概ね同じ手順でツールを利用できる
  • 設定を保存、共有するのが簡単(YAMLファイル)
  • クロスプラットフォームで動作し、実行に必要なファイルも1つなので容易に導入できる
  • HTTPSに対応しているため、開発時にHTTPSスキームでの動作確認などが容易にできる

作者はmoriyoshiさんです(弊社の代表)。

動作環境

Goで書かれていて、LinuxMacWindowsで動作します。手元ではLinux(Ubuntu)とWindows(Windows10)で問題なく使えています。

導入

英語ですがREADMEに書いてあるとおりにすれば、特にハマりませんでした。Goで作られたツールをビルドできる環境があればすぐに試せるかと思います。

私はGo言語には詳しくないので、ビルド方法などいい手順があれば指摘ください。

$ cd /path/to/temorary/
$ export GOPATH=$PWD
$ go get github.com/moriyoshi/devproxy
$ bin/devproxy --help
Usage of bin/devproxy:
  -l string
        "addr:port" on which the server listens (default ":8080")
  -v    verbose output

一度バイナリをビルドしてしまえば、あとはコピーして他の環境でも使えるあたりは、Goで書かれたツールの利点ですね。依存ライブラリもなくポータビリティも高くていい感じです。

go getを実行する際に環境変数を指定すればWindows用のバイナリをクロスコンパイルできました。

$ GOOS=windows GOARCH=amd64 go get github.com/moriyoshi/devproxy
$ ls bin/windows_amd64/
devproxy.exe

使ってみる

動作確認用にPHPでホスト名を表示するだけのスクリプトを用意して、ビルトインサーバーで動かしておきます。

$ cat index.php 
<?php
header("Content-type: text/plain; charset=utf-8");
echo "テスト用コンテンツ\nHost: " . $_SERVER['HTTP_HOST'];
$ php -S 127.0.0.1:8000

今回はHTTPとHTTPSを試すので、SSL証明書(いわゆるオレオレ証明書)を用意します。devproxyのREADMEにかかれている通りにopensslコマンドを実行すれば、できました。

x509.ini:

[CA]
basicConstraints=critical,CA:TRUE,pathlen:1
keyUsage=digitalSignature,keyCertSign,cRLSign

SSL証明作成:

$ openssl genrsa 2048 > testca.rsa.key.pem
$ openssl req -new -key testca.rsa.key.pem -out testca.rsa.csr.pem
$ openssl x509 -req -in testca.rsa.csr.pem -signkey testca.rsa.key.pem -days 3650 -sha256 -extfile x509.ini -extensions CA -out testca.rsa.crt.pem

devproxyの設定ファイルとして、config.yml(ファイル名は何でもいい)を次のように書きます。

tls:
  client:
    verify: true
  ca:
    cert: testca.rsa.crt.pem
    key: testca.rsa.key.pem

hosts:
  http://example.com:
    - ^(/*)$: http://127.0.0.1:8000$1
  https://example.com:
    - ^(/*)$: http://127.0.0.1:8000$1

devproxyを起動します:

$ devproxy config.yml

Webブラウザのプロキシ設定で、HTTPとHTTPSのプロキシをdevproxyのアドレスとポートに設定します。

プロキシ設定の切り替えは、例えばChromeならProxy SwitchySharpなどを使えば手軽にできます。

ブラウザで https://example.com/ にアクセスしてみると、オレオレ証明書なので警告は出ますが、テスト用のコンテンツが表示されます。ドメイン名もアプリケーション側のHOSTヘッダで参照できています。

f:id:nullpobug:20170326135612p:plain

HTTPSの際に追加ヘッダを要求する場合は、devproxyでヘッダを追加するようにも設定できます。最近だと、ワイルドカードサブドメインに対応したWebアプリの動作確認や、OAuthプロバイダの動作確認などで活躍しました。

Dockerで使う

Dockerイメージを作ってDockerHubに置いときました。

https://hub.docker.com/r/tokibito/devproxy/

まとめ

便利なので使っていきたいと思います。

SphinxでPDFをビルドするためのDockerイメージを作った

Python Sphinx Docker

Sphinxでlatexpdfjaコマンドを使ってPDFをビルドするには、latexのインストールされた環境が必要になります。

Ubuntuだとtexlive-fullパッケージで必要なパッケージをインストールできるっぽいというのを把握しました。

texlive-fullは依存パッケージがたくさんありサイズが大きいので、Dockerイメージにして使い捨てすると良さそうだと思いました。

調べたらすでに同じようなことをやってる人がいたんですが、Sphinx拡張などいくつか欲しいものが足りなかったので、自分で作ってみました。

DockerHubに置いときました。

tokibito/sphinx-texlive - Docker Hub

使い方

イメージのサイズが圧縮状態で3GBぐらいあって大きいので、試す際はご注意ください。

Sphinxのプロジェクトのディレクトリに移動して以下のコマンドを実行すると、make latexpdfjaが実行されます。

$ docker run --rm -v $PWD:/docs/ tokibito/sphinx-texlive:latest

make htmlの場合は末尾にコマンドを指定すればできます。

$ docker run --rm -v $PWD:/docs/ tokibito/sphinx-texlive:latest make html

sphinx-quickstartを使いたい場合はdocker runコマンドのほうに -it オプションを指定するといいです。

$ docker run -it --rm -v $PWD:/docs/ tokibito/sphinx-texlive:latest sphinx-quickstart

*diagシリーズのsphinxcontribも入ってます。詳しくはリポジトリのDockerfileを見てください。

github.com

2017年

雑記

年が明けて1月はもう後半になってしまいましたが、今年もちょっとずついろいろなことをやっていきたいです。

  • ブログの更新頻度をもう少し高めにしたい
  • ここ1~2年、技術的に新しいことに手を出せていなくて危機感高まっているので、入門的なことからでもメモを残しつつやっていこう
  • 積みあげてしまっているプライベートなタスクを整理しつつ、しっかりこなしていきたい
  • 車の運転を練習したい(オートバイは7年ぐらい乗ってるけど、車はペーパードライバー。今後のためにも慣れておきたい)
  • 運動していこう(1~2年で増えてしまった体重を減らしたい)
  • 畑は継続して知見ためつつやっていこう
  • 睡眠時間の調整をもう少しうまくしていきたい(早寝早起きに寄せたい)
  • お金の運用は継続してうまくやっていきたい

こんな感じで...

畑を借りたり農作業したり

雑記

この記事はpyspa Advent Calendar 2016の7日目として投稿しています。 http://www.adventar.org/calendars/1435

今年、畑を借りました

うちの近所には、市民が趣味で農作物を育てたりできる市民農園がいくつかあり、市営、民営で貸し出されています。

私が借りたのは民営のもので、4m×5mの大きさ、使用料は年間1万円程度のものです。自宅から自転車で10分程度の場所(もっと近いところが良かったけど、空きがない)。

今年の春頃に市から募集要項が出ており、7月から使えることになりました。 f:id:nullpobug:20160910100606j:plain うちの地域は、市民農園の人気がそこそこあって、この農園だと40区画程度に対して倍率が1.5倍ぐらい。元々抽選で落ちていたのですが、辞退者が出て補欠繰り上がりにより、借りられることになりました。

借りる期間は3年間で、3年経過後は返却し整備された上で次回の募集という形でした。機会を逃すと中々借りれない。

動機

元々、農作業というか野菜を育てることに興味がありました。料理するのも好きなので、食材から自分で用意してみるのも面白そうだなーとか思ってました。

自宅マンションのベランダでプランターにて育てたりもしてますが、南向きでも野菜を育てるには日当たりがイマイチで、畑で育ててみたいと思ってました。 f:id:nullpobug:20160605141742j:plain f:id:nullpobug:20160703173029j:plain

所感

  • 自分で作った野菜おいしい。無農薬野菜。
  • 野菜の育つ過程を見るの楽しい
  • 野菜が育ちすぎるとおいしくなくなるというのを体感
  • 手間がかかる。毎日世話をするには時間をとるのが難しい
  • 明るい時間しか作業できないので、平日は早朝に限られてしまう
  • 雨の日や雨の直後など土が湿っていて作業できない。
  • 雑草育つの早い
  • 虫が多い。雑草をしっかり取らないと、どんどん増える
  • 天候や害虫などコントロール不可能な要素の影響を受けやすい。予防とか対策はある程度できるけども、どうしようもないことがある。
  • 土を耕すの時間かかる、機械化、自動化が効果絶大なのよくわかる
  • 水やり大変。
  • プランターより畑のほうが圧倒的に育てやすい。水やり多少サボっても何とかなることが多い。
  • 野菜づくりの話題で会話に参加できるようになった

やってみていろいろありましたが、普段のエンジニア仕事に比べると、制約がかなり多くて知らなかった感覚、世界観を知れたなーという感じです。

今のところ楽しいので今後も続けられたらいいなと思います。 f:id:nullpobug:20160910100621j:plain

育てたもの

いろいろ育ててみたいけど、時期的なものがあってまださほどは。基本的に無農薬。

  • きゅうり
    • 夏に植えて1ヶ月ほどで収穫。植えて旅行の間放置してたら、大変良く育ちました。豊作。
  • はつか大根
    • 虫に食われてしまってあまり育たず。失敗
  • にんじん
    • 秋頃種を蒔いて、先月から食べる分だけひっこ抜いて収穫してます。豊作。
  • ピーマン
  • トマト
    • プランターで育ててましたが日照不足で実は大きくならず。ミニトマトサイズで収穫。その後アブラムシにやられて全滅。

f:id:nullpobug:20161123145544j:plain f:id:nullpobug:20160709181317j:plain

今育ててる

  • ほうれん草
    • 時期が遅すぎたかもしれない。失敗かも?
  • はくさい
    • 作業してたら近くの畑のおじさんに苗を貰ったので植えた。
  • スナップエンドウ
    • 時期が遅すぎたかもしれない。失敗かも?
  • パセリ
    • プランターで育てているものは順調。畑の方はまだ芽が出たところ。

dogpile.cacheでpickleシリアライズせずにRedisに値を保存する

Python Redis

Python用のキャッシュフレームワークでdogpile.cacheというモジュールがあります。

Welcome to dogpile.cache’s documentation! — dogpile.cache 0.6.2 documentation

Redisに保存するバックエンドも提供されているんですが、そのまま使うと値はpickleシリアライズされて保存されます。

この方法でRedisに保存された値を、Python以外で作られたシステムから利用するのはちょっと面倒です。

pickleシリアライズをさせたくない場合は、dogpile.cacheのバックエンドクラスを作成する必要があります。

GitHub - tokibito/dogpile_cache_native_redis: backend for dogpile.cache with reading and writing the native value

pypi.python.org

作成してPyPIに登録しておきました。

ThriftPy+gunicorn_thriftでRPCサーバーを動かす

Python

ThriftPyを使って作ったサーバーを動かすのに、thriftpy本体が持ってるサーバークラスを使ってもいいのだけど、タイムアウト処理やマルチプロセス動作だとかやるのが少し面倒だなーと考えてました。

githubでサーバークラスを差し替えるpull requestを出してたら、コメントでgunicorn_thriftというパッケージがあるから試すといいよと教わりました。ThriftPyと同じOrganization。

github.com

ThriftPyで作ったサービスの場合は、TProcessorのインスタンスをgunicorn_thriftコマンドに指定して起動する。

Python3.5、Ubuntu 16.04で試した。

main.py:

import thriftpy
from thriftpy.thrift import TProcessor


class AppServiceHandler:
    def echo(self, message):
        return message


main_thrift = thriftpy.load("main.thrift")
app = TProcessor(main_thrift.TIAppService, AppServiceHandler())

起動コマンド:

$ gunicorn_thrift -w 4 main:app

裏では、gunicornをカスタムのワーカークラスが動作している。gunicornのコマンドオプションも使えてうれしいです。

thrift_syncクラスを使った場合、単純なロードのパフォーマンスはmake_serverのほうがほんの少し良いみたいですが、気にするほどではなさそう。

以下、パフォーマンス試験に使ったコードと結果

thriftpy performance test

ありがたい。

Procfileを扱う

Ruby Python Go

Procfileというのを使ったのでメモを残す。

Procfileという名前のファイルを作って、アプリケーションの起動コマンドをまとめておくと、Procfileを扱うツールから簡単に実行できる。

Procfile:

web: gunicorn -w 4 main:app 0.0.0.0:$PORT
test: py.test .

起動(honchoの場合):

$ honcho start web
22:55:01 system | web.1 started (pid=53633)
22:55:02 web.1  | [2016-11-21 22:55:02 +0900] [53635] [INFO] Starting gunicorn 19.6.0
22:55:02 web.1  | [2016-11-21 22:55:02 +0900] [53635] [INFO] Listening at: http://0.0.0.0:5000 (53635)
22:55:02 web.1  | [2016-11-21 22:55:02 +0900] [53635] [INFO] Using worker: sync
22:55:02 web.1  | [2016-11-21 22:55:02 +0900] [53638] [INFO] Booting worker with pid: 53638
22:55:02 web.1  | [2016-11-21 22:55:02 +0900] [53639] [INFO] Booting worker with pid: 53639
22:55:02 web.1  | [2016-11-21 22:55:02 +0900] [53640] [INFO] Booting worker with pid: 53640

環境変数を.envファイルに記述し、Procfile内で使うことができる。こうすると、起動コマンドはProcfileで共有し、利用する各環境では.envに設定を記載するといったこともやりやすい。

Procfileを扱うモジュールはRubyだとForeman、PythonだとHoncho、GoだとGoremanといった感じで色々あるようだ。

HerokuではProcfileを記述してプロセスを起動できるようだ。