Vagrant + DigitalOcean + Ansibleで環境構築

ものすごく今更ながら、実践Vagrantを見ながら、Vagrantを試してる。

実践 Vagrant

実践 Vagrant

ついでに気になってたDigitalOceanも試したかったので、 VagrantとSSDなVPS(Digital Ocean)で1時間1円の使い捨て高速サーバ環境を構築する - Glide Note - グライドノート を参考に、DigitalOceanにVagrant+Ansibleで環境を構築する方法を試したので、メモ。

Vagrantのインストール

Download Vagrant - Vagrantからバイナリをダウンロード。

Ansibleのインストール

プロビジョニングには今回Ansibleを使用。インストールはpipから。

pip install ansible

DigitalOcean Pluginのインストール

標準のproviderではDigitalOceanは存在しないが、Pluginが既にあるので、インストール。

https://github.com/smdahlen/vagrant-digitalocean

vagrant plugin install vagrant-digitalocean

MacだとDigital OceanのAPIを叩くためには追加で下記をインストールする必要があるみたい。

 brew install curl-ca-bundle

インストール後、.zshrc等に環境変数をセット

export SSL_CERT_FILE=/usr/local/opt/curl-ca-bundle/share/ca-bundle.crt

DigitalOceanのアカウント作成

DigitalOceanからアカウントを作成。

アカウント作成後、管理画面からssh keyの登録とAPI keyの発行を行う。

ssh keyの登録

API keyの発行

Vagrantfileの作成

インスタンスは最小プラン(512MB)、RegionはSingaporeの構成で作成する想定。 注意点としては、「provider.client_id」、「provider.api_key」、「provider.ssh_key_name 」をssh keyの登録やAPI keyの発行で確認したものにきちんと設定すること。

# -*- mode: ruby -*-
# vi: set ft=ruby :


Vagrant.configure('2') do |config|

  config.vm.hostname = "digital-ocean-test"

  config.vm.provider :digital_ocean do |provider, override|
    override.ssh.private_key_path = '~/.ssh/id_rsa'
    override.vm.box = 'digital_ocean'
    override.vm.box_url = "https://github.com/smdahlen/vagrant-digitalocean/raw/master/box/digital_ocean.box"

    provider.client_id = 'API key発行時に確認したClient ID'
    provider.api_key = 'API key発行時に確認したAPI key'

    provider.region = 'Singapore 1'
    provider.size = '512MB'
    provider.ssh_key_name = 'ssh key登録時に登録したssh key name'
  end

  config.vm.provision :ansible do |ansible|
    ansible.playbook = "provision_vagrant.yml"  # playbookファイル名
    ansible.host_key_checking = false
  end
end

playbookの作成

ansibleでprovisionするためにplaybookを作成。 provisoningの内容は、実践Vagrantの例の通り。

  1. Apacheをインストール。
  2. /var/wwwを/vagrantのsymlinkにする

playbookのファイル名は「provision_vagrant.yml」で作成。

- hosts: default
  user: root
  tasks:
      - apt: pkg=apache2 update_cache=yes state=latest
      - file: path="/var/www" state=absent
      - file: src="/vagrant" dest="/var/www" state=link

DigitalOceanではユーザ名がrootで作成されるので、「user」を「root」にすること。

Ansibleでは通常provisoning先をINVENTORY FILEに記載する必要があるが、DigitalOcean等、ローカル以外の環境に作成する場合は、IPアドレスが作成後に決まる為、事前にINVENTORY FILEを用意することができない。

Vagrantではこの問題を解消するために、INVENTORY FILEを指定しない場合は、自動でINVENTORY FILEを作成し、それを使用してprovisioningを行ってくれる。*1

vm名をVagrantfileで指定しない場合は、「default」で生成されるので、「hosts」についても「default」を指定。

あと、実践Vagrantにならって、index.htmlも用意しておく。

<strong>Hello</strong>

インスタンスの作成

上記まで用意できたら、あとはVagrantを実行するだけ、providerとしてDigitalOceanを指定して起動。

vagrant up --provider=digital_ocean

起動後はsshでアクセス

vagrant ssh

後はブラウザでアクセスして下記のように表示されれば、OK

f:id:wkcrobin:20140310003616p:plain

使い終わったら、destroyでインスタンスを破棄。

vagrant destroy

参考

http://blog.glidenote.com/blog/2013/12/05/digital-ocean-with-vagrant

https://github.com/smdahlen/vagrant-digitalocean

https://docs.vagrantup.com/v2/provisioning/ansible.html

http://qiita.com/seizans/items/54da2077ac8e2dcf5d6f

http://docs.ansible.com/file_module.html

Erlang 17rc1をMacにインストールしてみた

R16B まではwxWidgetsの問題でMacでobserver等が動かず、悲しい思いをしていたが、17rc1で試して見たらあっさり動いたのでメモ*1

環境

Mac OSX 10.9.1 (Marvericks)

Erlang 17.0-rc1

wxWidgetsのインストール

wxWidgetsをhomebrewでインストール。現時点だと3.0.0が入るはず。

brew install wxmac

Erlangのインストール

Erlangのソースはerlang-users.jpがミラーを用意してくれているので、そちらからダウンロード。

erlang-users.jp

configure オプションもerlang-user.jpを参考に。違いはwxをオプションを有効にしているだけ。*2

./configure --enable-darwin-64bit --disable-hipe --enable-vm-probes --with-dynamic-trace=dtrace --with-wx --prefix=/opt/local/erlang/R17rc1

あとはそのままmake, make installするだけ。

make
sudo make install

observerの起動

erl -s observer start

でobserverを起動。

f:id:wkcrobin:20140309224422p:plain

*1:厳密にはR16B以前でも32bitsでErlangコンパイルすれば動いていたみたい

*2:最近はkerlを使うんだろうけど、とりあえずはpathの切り替えでバージョンを管理してる。

Bitbucket ミートアップ東京に行ってきた

以下メモ

How we use Bitbucket to build Bitbucket

  • Erik van Zijstさん

  • 英語だったので、全然聞き取れなかった。サーセン

  • 質問

    • githubに勝てる?

      • facebookgoogle+のように使い分けが大事
      • githubOSS等の大規模なものに適してる、小規模なチームの場合はBitbucketの方が使いやすいと思う
      • Bitbucketは標準でプライベートレポジトリが使える
      • もちろんmercurialが使用できるのもメリットの一つ
      • Atlassian製品との連携もあるよ
    • UIについて

      • 製品一つに対して、一人のデザイナーが付いている。そのデザイナーと相談してUIを決めてる
      • 他のAtlassian製品とできるだけデザインを併せている。またUI用のフレームワークがある。
    • 百を超えるプライベートレポジトリがある。レポジトリを簡単に検索・グルーピングできる機能ってある?

      • 他のユーザからも問い合わせがある
      • issueも上がっているけど、ラベルにするかマルチグルーピングにするか決定しかねてる
      • issueをwatchしてみて
    • bitbucketでgitをサポートし始めた理由は?

      • bitbucketを購入した時点では、mercurialだけだったけど、gitのユーザ数が多くなってきたので、自然にサポートしましょうという感じになりました。

co-meeting

  • 吉田パクえさん

  • co-meeting

    • 4人で運営
    • life hackerで取り上げられたよ
    • 会議のフロー

      • 通常:会議 -> 議事録 -> 承認 -> メール
      • co-meeting:
      • 2週間の会議が2日で終わる
      • RubyKaigiとかPHP Matsuriとかで使われてる
    • パクえ

      • ユーザやベンダーが言い難い事を代わりに代弁する。
    • 外部サービスを利用する作戦

      • 目的を理解、導入のプランニング、不安を払拭
      • 目的を理解
        • きちんと説明
        • 外注管理の観点
          • 社内のNWにアクセスさせるの?
        • 顧客との共有
        • 費用対効果
          • 社内で立てて、落ちたらどうするの?
      • 導入のプランニング
        • ロックインされないよ
      • 不安の払拭
        • IPAとかの情報をうまく使おう
        • 論理的に答える事、長く使って経験してもらう。
      • オススメの方法
        • 皆に良さを実感してもらう
          • GUIで導入
          • 管理系ドキュメントを対象に導入
      • 体感ポイント

        • 意味を教えない
        • 操作だけ教えよう
        • 失敗した時の準備
      • ボトムアップでの導入は諦めたら終わり

できる!Bitbucket Teams

  • @troterさん

  • TokyoMercurialを主催

  • BitBucket歴4年6ヶ月

  • 会社説明

    • ToLot
  • BitBucket Teams

    • グループでの作業をサポートする機能
    • チームにグループを作成

      • グループに権限
      • 外部公開が簡単
        • OSS, 社外の人と連携
        • 会社で必要な機能はBitBucket Teamにある
    • Step by StepでBitbucket Teamの使い方

      • チーム作成

        • 基本的に会社名をおすすめ
        • チームアカウントとは別に管理者アカウントが必要
        • チームにメンバー追加
          • メンバーを追加するのはグループに追加
          • Administrators: 開発のリーダー
          • Developers:社員の人?
      • 自社プロダクトのリポジトリを作成

        • チームリポジトリの権限
          • チームアカウントがowner
          • チームアカウント以外が作成した場合、creator
          • チームアカウントのグループの権限を変更すると、すべてのリポジトリに反映される。
      • 協力会社とのリポジトリ

        • Developersに追加する?個別に開発者を追加する?
          • 協力会社用のグループをチームに追加する
          • 製品ベースのレポジトリに協力会社のグループを追加する
          • 権限
          • チームアカウントにはアクセスしない、リポジトリの作成もできない
          • リポジトリにグループを追加
      • OSSで公開

        • パブリックで作成
        • 危険な情報(DBのパス、ssh-key)を消してからね。
      • インターン生を追加

        • 社員と一緒
          • Developersに追加
        • インターンインターンとして扱う
          • Studentsグループを作る
          • 協力会社と同じような扱い
          • 協力会社と同じようにグループを作成
    • 落穂拾い

      • Developersの権限を外したい
        • Developersを消して、協力会社のグループに個別にユーザを追加
      • リポジトリの移譲
      • 個人アカウントからチームへ
        • アカウントのタイプは変更はできるよ。
        • ただしチームから個人へは変換できないよ。
  • 質問

    • 会社がデカイ場合でも会社名でとったほうが良い?
      • 多分取らないほうがよい。プロジェクト名、グループ名から始めてみれば?
      • Team account登録時のメールアドレスはどうしたらよい?
        • gmailだと+機能使えば、専用のメールアドレスを使えば?
        • 会社のアドレス使ったほうが良い?
          • 会社のメールの方が良いよ。アカウントに対して複数のメールアドレスを登録できるので、プライマリも会社のほうが良い。
            • mergeした時はプライマリのメールアドレスが使用されるから
          • メーリングアドレスを登録してnotificationが飛びすぎるとまずくない?
            • うーん。まぁ、とんだ方ほうがよくない?
          • パスワードのリセットメールが飛ぶと良くないよね。
            • じゃあ、管理者のメールアドレスで良いんじゃない?

BitBucketを会社で2年間使って

  • @methaneさん

  • Bazaar contributor

  • Bazaarの良さ

    • ファイル名でUnicodeを使用できた
    • Bazaar to Git
      • Pull Request based workflow
    • Github, Bitbucket
      • Bitbucketのメリット
      • $200/月で使い放題
      • admin権とwrite権のようにアクセス権限管理ができた。
    • GithubとBitbucketの使い分け
      • github
        • プロジェクトで使う
      • Bitbucket
        • 自由なコード置き場
    • 現在の状況

      • Github Enterpriseに移行中
    • BitBucket Pro

      • 良い点
        • 費用対効果が良い
        • アクセス管理
        • diffがとても綺麗
        • Online edit機能
          • githubだとコミット権をもってると意図しないコミットをしちゃうときがある。
        • Branch SyncとかHistory Graphとか
      • あんまり良くない点
    • 会社で使うポイント

      • 会社のID管理とできるだけ連携する
        • 会社のemailでアカウントを作成してもらう
        • 退職時会社のemailで引っ張って削除
      • 個人アカウントへのFork対応

Python: Mock

unittestでは基本的にassert等を用いてテストする為,動作の度にランダムに返す値が変わったり,外部サービスと連携するようなメソッドはテストが難しい. Pythonでは,Mockライブラリを使用することで,上記のようなケースでも比較的簡単にテストすることができる.

Mockって?

もしテストしたい対象が内部で下記のようなランダムな値を返す関数を利用している場合,単体テストが非常に面倒臭い.

import random

def randfunc():
    return random.randint(0, 10)

randfunc()
# => 0から10の値

def somefunc():
    if 5 > randfunc():
        return True
    else:
        return False

# assert ? == somefunc()
# 実行の度にTrueかFalseどちらを返すか分からないので,assertでテストできない.

上記のような場合,ダミーなクラスや関数を作って,置き換えることで,テストがしやすくなる. Mockでは,Mockオブジェクトを作り,置き換えたい関数に代入することで使用する. ダミーの関数の戻り値はreturn_valueで指定できる.

from mock import Mock

randfunc = Mock()
randfunc.return_value = 10
randfunc()
# => 10
# Mockで作ったダミーの関数は常に10を返す.

動的な置き換え

上記ではMockで置き換えた関数はそれ以降ずっとダミーの関数のままになってしまう. Mockでは,patchデコレータやwith構文を使ったコンテキストマネージャーが用意されており,テスト中のみダミー関数に置き換えることができる.

# some.py
class SomeClass(object):
    # some process

    # 外部サービスと連携するメソッド
    def service():
        # some process
        return "hogehoge"


# tests.py
from mock import patch

#testItの実行中のみダミー関数に置き換わる
#置き換えたいメソッド,ダミーの関数の戻り値をpatchに指定する
@patch("some.SomeClass.service", return_value=100) 
def testIt():
    import some
    result = some.SomeClass.service()

    assert result == 100

またwith構文を使った場合は下記のようになる.

def testIt():
    # withブロックの間のみダミー関数に置き換わる
    with patch("some.SomeClass.service", return_value=100) as m:
        import some
        result = some.SomeClass.service()
        assert result == 100

    # 以降は元の関数が使用される
    ...

その他

Mockライブラリは非常に機能が豊富で,上記のような基本的な使い方以外にも異なった値や例外を返すことができるside_effectや mockが呼び出された回数をチェックできるassert_called_once_with()等色々と便利な機能があるので,少しずつ調べて使っていきたい.

蛇足

「Python プロフェッショナル プログラミング」 でもMockが紹介されているが一部誤植っぽいのを見つけたのでメモ

書籍でのmockのpatchを使ったサンプルコードは下記だが

@patch("myviews.SomeService")
def test_it(MockSomeService):
    mock_obj = MockSomeService.return_value

    # 再度return_valueが呼ばれている
    mock_obj.return_value = 10

    # patchではSomeServiceを置き換えているのに,MyViewが呼ばれている
    from myviews import MyView
    result = Myview()

    # 書籍では代入になっていたけど,sphinxで通らない事もあり,正しいと思われる比較に修正
    assert result == 10

実際には下記が正しいと思われる.

@patch("myviews.SomeService")
def test_it(MockSomeService):
    MockSomeService.return_value = 10

    from myviews import SomeService
    result = SomeService()

    assert result == 10

まぁ,myviews.pyでのMyViewが下記なら元のコードでも問題ないけれど,ちょっとそこまでは読み取れなかった*1

# myviews.py
def SomeService():
    #some process
    return "hogehoge"

def MyView():
    return SomeService

参考

*1:書かれた当時とmockのversionが変わってる可能性もあるかもしれない.

Django : crash log

DjangoはDEBUGモード(DEBUG=True)では,クラッシュ時にデバッグの為の詳細なスタックトレースをブラウザに表示してくれる. だけど,プロダクション環境でDEBUGモードをFalseに設定した途端,requestの処理中に何か例外が発生し,クラッシュしてもログに何も出力してくれなくなる.さすがにログがないと,何か問題が発生した際に原因を追いようがないので,対処をメモ.

検索するといくつか解決策がでてくるけれど,一番分かりやすかった下記で,今回は対処することにした.

Note that using logging.exception('Some message') with python's standard logging module works just fine in a sginal handler for got_request_exception, if all you are looking to do is log out stack traces. In other words, the traceback is still available in got_request_exception. – TM. Feb 14 '11 at 23:02

python - How do you log server errors on django sites - Stack Overflow

上記を実装したコードが下記になる.signalを使うので,適当なmodels.pyに追加した.

from django.core.signals import got_request_exception
import logging

logger = logging.getLogger("app")

def exception_logging(sender, **kwargs):
    logger.exception("[%s]" % kwargs["request"].get_full_path())

got_request_exception.connect(exception_logging)

上で何をしているか簡易に説明すると

django.core.signals.got_request_exception

はrequestの処理中に例外が発生した際に送信され *1

Logging.exception

スタックトレースをログに出力する *2 だけなので,上のコードは例外が発生した際のスタックトレースをログに出力していることになる. スタックトレースがそのままログに出力されるので,あまり綺麗とは言えないけれど,当面の目的としては十分なので,今のところは上記で様子を見ようと思う.

本当はDjango側で用意して貰えると,一番なんだけれど.