バイナリログ転送ツール bingo

前回のエントリから相当間が空いてしまいました。
ネタがあればちゃんと書いていきたい所です。

で、タイトルの通り bingo というアプリケーションをリリースしました。

何をするアプリケーションかと言いますと、
MySQLのバイナリログ(更新差分)を簡単にリアルタイム転送するツール、です。

MySQL to MySQLであればMySQLのレプリケーションでいいじゃん、となるのですが
例えばBigQuery等にリアルタイムでデータ転送しようと思うと結構面倒くさいと思います。
(トリガーを使ったり、短時間毎に差分を取得したり。。)

bingo はMySQLのレプリケーション技術で更新データを読み取りますので、
非同期ではありますが、ほぼリアルタイムに更新データを取得できます。
現状はfluentdにhttp postする事しか出来ませんが、色々と応用できるとは思います。

使い方(詳しくはREADMEへ)

bingoは起動するとすぐにMySQLに接続します。

$ bingo
2016/09/02 01:19:10 connected to mysql(root@127.0.0.1:3306)
2016/09/02 01:19:10 start reading binlog
2016/09/02 01:19:10     Binlog Version:  4
2016/09/02 01:19:10     Server Version:  5.7.14-log

MySQLに何かしらデータを書き込みます。

$ mysql -u root -e 'create database testdb default character set utf8mb4'
$ mysql -u root -e 'create table testdb.testtable (id bigint, name varchar(32))'
$ mysql -u root -e 'insert into testdb.testtable (id, name) values (1, "hello world")'
$ mysql -u root -e 'insert into testdb.testtable (id, name) values (2, "はろーわーるど")'

localhost:8888 で待ち受けるfluentdにはこんな感じでデータがpostされます。

2016-09-02 01:23:28 -0400 bingo.data: {"database":"testdb","table":"testtable","columns":["1","hello world"]}
2016-09-02 01:23:36 -0400 bingo.data: {"database":"testdb","table":"testtable","columns":["2","はろーわーるど"]}

余力があればカラム名つきでpostするような実装を入れたいところですが、ひとまずはここまで。
テストも途中からほとんど書けていないのでこれもIssueですね。。

Asepriteのマウスポインタを固定する

個人的にドット絵を描くならAsepriteが一番使いやすいと思っているのですが、
マウスポインタがよく消えたり見えにくかったりするのが難点だと感じていました。
つい最近ソースが公開されている事を知ったので、ソースに手をいれて強制的に固定するようにしてみました。

まずは普通にcloneして最新のv1.1.1のタグに切り替えます

git clone --recursive https://github.com/aseprite/aseprite.git
cd aseprite
git checkout v1.1.1

そして、下記の2ファイルを変更します

  • src/ui/system.cpp 109行目付近
       case ui::kSizeWCursor: nativeCursor = she::kSizeWCursor; break;
       case ui::kSizeNWCursor: nativeCursor = she::kSizeNWCursor; break;
     }
+    nativeCursor = she::kArrowCursor;
   }
  • src/ui/window.cpp 411行目付近
           case HitTestBorderS: cursor = kSizeSCursor; break;
         }

+        cursor = kArrowCursor;
         set_mouse_cursor(cursor);
         return true;
       }

これでasepriteをビルドします。(INSTALL.mdをご参考ください)
Visual Studioの開発者用コマンドプロンプトから、下記の通り実行します。

mkdir build
cd build
cmake .. -G "NMake Makefiles"
nmake aseprite

Visual Studio 2015 Community (Update 1) をインストールした Windows 10 でビルド成功を確認しました。
成果物として build/bin/aseprite.exe が出力されるので、これを起動して動作確認します。
メニューバーに “WARNING” と表示される場合は、設定ファイルとバイナリのバージョン差異があるため、src/config.h の25行目付近を書き換えます。

 // General information
 #define PACKAGE "Aseprite"
-#define VERSION "1.1.1-dev"
+#define VERSION "1.1.1"

 #ifdef CUSTOM_WEBSITE_URL
 #define WEBSITE                 CUSTOM_WEBSITE_URL // To test web server

マウスポインタの切り替えがなくなり、見えなくなる事もなくなってより使いやすくなった気がします。
ただ、見ての通り無理矢理固定するので、ドット絵なマウスポインタと切り替えたりはできなくなります。
また、拡大縮小ツールを使った時や、アプリ内ウィンドウの端っこをつかむときもカーソルが変化しなくなる為、部分的には使いにくくなります。
それでも個人的にはこの方が作業ストレスが減るので、しばらくこのまま使ってみようと思います。

chef-soloからchef-zeroへ

長らくchef-solo+knife-soloと連れ添ってきたのですが、
そろそろzeroの学習をしておこうと色々とchef-zero移行を解説なさっているサイトを見て回りました。
たくさん解説されていらっしゃるサイトがあるのですが、一応自分なりにもまとめてみます。

環境の準備

とりあえずrbenv,ruby,bundler、とインストールして、いつもの環境を作ります。
Gemfileはこんな感じの最小構成。こいつでbundle installします。

source "https://rubygems.org"

gem "chef"
gem "knife-zero"

テスト用のレシピを書く。

とりあえずテストとして、apacheをインストールするレシピと、それを適用するjsonファイルを用意します。

$ mkdir -p cookbooks/httpd/recipes
$ echo 'package "httpd" do
>   action :install
> end' > cookbooks/httpd/recipes/default.rb

$ echo '{ "run_list": "recipe[httpd]" }' > web.json

local_mode でプロビジョニングする

chef-soloであれば、cookbook_pathを記述したsolo.rbを用意してchef-soloを実行するところですね。

sudo bundle exec chef-solo -c solo.rb -j web.json

chef-zeroのlocal_modeを使うと、このような感じになるようです。solo.rbが不要になり、少しだけ楽になりましたね。

sudo bundle exec chef-client -z -j web.json

実行後、nodes/(hostname).json ができていました。
内部的にはchef-serverが動いているわけですから、このノード(localhost)の状態がchef-serverの管理下に置かれているということですね。
(Node Objectと言うそうです)

このあたりはchef-server的な仕組みで動いていると思うので、chef-serverを学習した方が理解がはさそうな気がします。

knife-zeroでリモートホストをプロビジョニングする

ローカルにあるレシピを使って、リモートホストをプロビジョニングする場合はknife zeroを使います。

仕組みやチュートリアル含め、開発者様のQiitaを一読すると理解が早いと思います。

先ほど作ったレシピを使って、knifeしてみましょう。

まずはリモートホストをknife zeroの管理に追加します。
mkdir で “許可がありません” とエラーになる場合は、sudoできる権限をつけてあげて –sudo を追加します。

bundle exec knife zero bootstrap remote.com --sudo

nodes/(hostname).jsonが作成されていると思います。
また、node showすると、ノードが管理されている事がわかります。

$ bundle exec knife node show remote.com --local-mode
Node Name:   remote.com
Environment: _default
FQDN:        remote.com
IP:          10.0.2.15
Run List:
Roles:
Recipes:
Platform:    centos 7.0.1406
Tags:

ローカルモードは今後常に有効にするので、設定ファイルを作成して省略できるようにしておきます。
環境によってはsudoを省略するオプションも記述しておいた方が捗りそうです。

mkdir .chef
echo 'local_mode true' > .chef/knife.rb
echo 'knife[:use_sudo] = true' >> .chef/knife.rb
bundle exec knife node show remote.com

それではレシピを適用してみましょう。
knife soloの場合は、nodes/(hostname).json のrun_listを記述してknife solo cookしていました。

bundle exec knife solo cook (hostname)

knife zeroの場合も、nodes/(hostname).json のrun_listを記述して、以下のコマンドを実行するだけです。

bundle exec knife zero converge '(query)' 

knife soloと違い、queryにマッチするホストをすべてプロビジョニングできるようです。
これはかなり便利そうです。

今回の用に単一ホストをプロビジョニングする場合は、このような感じで書きます。

$ bundle exec knife zero converge 'name:remote.com'

remote.com Starting Chef Client, version 12.5.1
remote.com resolving cookbooks for run list: ["httpd"]
remote.com Synchronizing Cookbooks:
remote.com   - httpd (0.0.0)
remote.com Compiling Cookbooks...
remote.com Converging 1 resources
remote.com Recipe: httpd::default
remote.com   * yum_package[httpd] action install
remote.com     - install version 2.4.6-31.el7.centos.1 of package httpd
remote.com
remote.com Running handlers:
remote.com Running handlers complete
remote.com Chef Client finished, 1/1 resources updated in 06 seconds

ちゃんとapacheがインストールされましたね。
knife node show してみるとレシピが追加されている事がわかります。

$ bundle exec knife node show remote.com

Node Name:   remote.com
Environment: _default
FQDN:        remote.com
IP:          10.0.2.15
Run List:    recipe[httpd]
Roles:
Recipes:     httpd, httpd::default
Platform:    centos 7.0.1406
Tags:

細かい点では変わったところもありますが、今までのレシピが全く使えなくなるという事はなく、
確かにchef-solo+knife-soloからの移行は問題なさそう。

EBSのスナップショット作成スクリプト

EBSのスナップショットを作成し、古いスナップショットを自動削除するスクリプトを書いたのでメモがてら残します。
このスクリプトを実行するインスタンスのすべてのボリュームに対して、EXPIRE_DAYS日数経過したスナップショットを削除し、EBSスナップショットを作成します。
あ、credentials は ~/.aws/credentials にある前提です。

#!/bin/sh

# ------------------------------------------
# configuration
EXPIRE_DAYS=4
INSTANCE_ID=`curl -s http://169.254.169.254/latest/meta-data/instance-id`
EXPIRE_DATE=`date +%Y-%m-%dT%H:%M:%S.0000Z -d "-${EXPIRE_DAYS}day"`

# ------------------------------------------
# script start

STATUS=0

for VOL_ID in `aws ec2 describe-volumes --filters "Name=attachment.instance-id,Values=${INSTANCE_ID}" | grep -e '^VOLUMES' | awk '{ print $9 }'`
do
  # delete old snapshots
  for SNAPSHOT in `aws ec2 describe-snapshots --filters "Name=volume-id,Values=${VOL_ID}" | grep ${VOL_ID} | awk '{ print $8","$9 }'`
  do
    SNAPSHOT_ID=`echo $SNAPSHOT | awk -F"," '{ print $1 }'`
    CREATE_DATE=`echo $SNAPSHOT | awk -F"," '{ print $2 }'`

    # delete expired snapshot.
    if [[ "$EXPIRE_DATE" > "$CREATE_DATE" ]]; then
      aws ec2 delete-snapshot --snapshot-id $SNAPSHOT_ID > /dev/null
      RESULT=$?
      if [ $RESULT -ne 0 ]; then
        echo "delete for snapshot failed... ($SNAPSHOT_ID, $CREATE_DATE, ${RESULT})"
        STATUS=1
      fi
    fi
  done

  # create snapshot.
  aws ec2 create-snapshot --volume-id ${VOL_ID} --description "`date +%Y-%m-%d` snapshot instance-id:${INSTANCE_ID}" > /dev/null
  RESULT=$?
  if [ $RESULT -ne 0 ]; then
    echo "create for snapshot failed... (${RESULT})"
    STATUS=2
  fi
done

exit $STATUS

next HTML

w3cのwikiに、次世代HTMLのアイデアリストがまとめられているのを眺めてみました。
http://www.w3.org/wiki/HTML/next

面白いのがいくつかあったのでピックアップしてみます。

Advanced Anchors

<a href="w3.org/page.html$section>div>p"> go there </a>

おそらく「そのページのsection > div > pへのアンカー」という意図のURLで、CSSセレクタでアンカー指定できるようにするアイデアですね。
アンカーIDが振られていないページなどへのリンクに使えそうです。

ComboBox

<select name="age" inputable="inputable">
<option value="11"></option>
<option value="12"></option>
</select>

自由入力できるプルダウン、コンボボックス。ローカルアプリケーションでは一般的に使えるのに、むしろなぜ実装されていないのか。
確かに欲しいですね。JSとCSSで頑張って実装しているケースが多いですが、ブラウザでサポートしてくれるのがやっぱり一番安心。

おまけ

目次化されていませんでしたが、目を引いたので。

BR
{
   breakline:right;
}

breakline: none | left | right  ;
none : = default
left : = insert a breakline before the element
right : = insert a breakline after the element

近年で、HTMLタグは文章を意味づけするものであり、
スタイルを適用するものではないという考え方が大分進んできたにもかかわらず、
相変わらずBRタグだけは改行する為に使われ続けているので、これもスタイルにしちゃおうという提案ですね。
最近はもうBRタグを記述する事は減りましたが、デザイン的にどうしてもpを使わず改行を入れたい場合にBRタグを使っているので、
どうせならそこもcssで解決できるようにはして欲しいですね。

vagrantでansible

vagrantイメージのプロビジョニングにansibleを使う方法をメモメモ。

  • playbook.ymlを作成する
---
- hosts: all
  tasks:
    - name: step1 (install docker)
      shell: curl -sSL https://get.docker.com/ | sudo sh

    - name: step2 (install libselinux-python)
      yum: name=libselinux-python state=present

    - name: step3 (disable selinux)
      selinux: policy=targeted state=permissive
      sudo: yes
  • Vagrantfile
    Vagrant.configure(2) do |config|
      ...
      config.vm.provision "ansible" do |ansible|
        ansible.playbook = "playbook.yml"
      end
    end
    

golangでツールを一つ作ろうと思ってるので、ついでにansibleにも勉強しようかなーと。
chefやpuppetよりもシンプルで取っつきやすいよね。

VisualOpsいいですね

AWSの構成図をGUIで作成し、そのままCloudFormationのようにStackを構成します。
非常に完成度が高く、CloudFormationのJSONをエクスポートすることもできるため、JSONの手書きから解放されます。

ありそうで無かったので個人的に非常に助かります。