TOLOTを支える技術(2)

開発部の tsuyukimakoto です。

今回はシステムの思想と実装について少しお話ししたいと思います。
タイトルは TOLOTを支える技術(1) を引きずっています。

2種類のスケールアウト

商品の提供価格から、TOLOTのシステムはスケールしなければならないことにお気づきのエンジニアも多いと思います。
通常のWebサービスはスケールしなければいけないのは対象のシステム自体ですが、 TOLOTは生産設備もスケールする必要があり、1生産拠点内でのスケールは当然のこととして、複数の生産拠点という視点でもスケールを意識しています。

デプロイに関すること

工場の生産に関わるシステムは、弊社の開発拠点から物理的にもネットワーク的にも離れた場所で設置・メンテナンスを行う可能性があります。
この可能性に気づいた時、次のことについては期待をせずにデプロイできることを目標としました。
  • デプロイする場所からVPNでソースコードに辿り着けること
  • 開発拠点からVPNでデプロイする場所にリモート接続できること
  • デプロイする場所からTCPで好きな場所に接続できること

つまり、ネットワーク的に閉じた世界であっても管理用サーバに、メンテナンス時に持ち込むマシンがあればシステムのインストールやメンテナンスが可能でなければなりません。
結果、すこしやりすぎて、変な実装となった箇所が有りますので紹介します。

Fabricという選択

Fabricはn個のサーバに対してsshをし、サーバでコマンドを実行するシンプルなサーバ管理ツールです。
capistranoやchef(-solo)、Buildbotやらといったソリューションが有るのも知っていますが、Fabricを利用しています。

理由は察してください。

さて、サーバOSのパッケージやプログラミング言語のライブラリは、http等でパッケージリポジトリにアクセスをして必要なもののインストールを行います。
必要なものを持ち運ぶことを考慮しているので、当然オレオレリポジトリを用意するのですが、インストール先にリポジトリを立てたいのにそのリポジトリを使ってhttpdを用意しなければならないという摩訶不思議な状況が発生します。

以下は、その状況を無理矢理解決したコードです。
Python2.6から標準となったwithステートメントを利用します。withステートメントはRubyのブロックのようなもので、スコープ&開始・終了処理を記述できるものです。
今回は、開始・終了処理を使って、withステートメントの中でだけhttpサーバを起動するものを作ってみました。

# -*- coding: utf-8 -*-
from __future__ import with_statement #Python2.5でもwithステートメントが使えるように
from fabric.api import run, sudo, local, cd

class _httpserver():

  def __init__(self):
    pass
  
  def __enter__(self):
    '''withのブロックに処理がはいる時に呼び出されます。
    Pythonは標準モジュールにHTTPサーバクラスを持っています。
    モジュールを指定してPythonインタプリタを起動すると、
    カレントディレクトリをドキュメントルートとするHTTP1.0サーバが起動します'''
    run("nohup python -m SimpleHTTPServer 8888 &")
  
  def __exit__(self, exc_type, exc_value, traceback):
    '''withブロックから処理が抜ける時に呼び出されます。
    SimpleHTTPServerという文字を含むプロセスを検索して終了しています'''
    sudo("kill `ps -ef | grep 'SimpleHTTPServer' | grep -v 'grep' | awk '{print $2}'`")

@hosts(TARGET_SERVER)
def install_packages():
  with cd('/var/www/html'): #cdはFabricが提供する関数で、カレントディレクトリを移動します
    with _httpserver():
      sudo(パッケージを利用するコマンド)

Fabricのrun関数はリモートサーバでコマンドを実行しますが、代わりにlocalという関数を利用するとFabricを実行しているクライアント上でコマンドを実行できます。
DSLではなく、完全にPythonのコードで表現するFabricなら、動的に現在のIPアドレスを取得してリモートからFabricを実行しているクライアント側へパッケージの取得に来るといったことも容易です。
拠点に一つだけ必要で同一拠点の別サーバから参照されるリポジトリを構築する場合はrunで、拠点にはインストール時以外不要なリポジトリはlocalでといった使い分けが適しているでしょう。

We need you!

TOLOT開発チームは、クライアントアプリの見た目からは気づかないシステムの改良も日々行っています。
今回紹介したような少しおかしな実装も転がっていますが、お客様の想い出が詰まったTOLOTをお届けするシステムの開発がメインです。
様々なバックグラウンドを持つエンジニアが在籍しておりますので、興味をお持ちになった方は私を捜し出してコンタクトを取ってみてください。

※Ruby、Pythonときたので、TOLOTを支える技術(3)は…
Update:2012/06/22

TOLOTをご存知ですか?

スマホやパソコンでオリジナルのフォトブックを作れるアプリです。。