ujunのブログ

packer buildしてできたamiだけ取得(packerの出力変わると使えない)

#!/usr/bin/env python

import subprocess
import re

def run(cmd):
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    stdout = []
    while True:
        line = p.stdout.readline()
        stdout.append(line)
        if not line and p.poll() is not None:
            for text in stdout:
                match = re.search('ap-northeast-1:\s{1}(.*)', str(text.decode("utf-8")))
                if match:
                    print(match.group(1), end = "")
            break
    return ''.join(str(stdout))

if __name__ == '__main__':
    run("packer build -var-file=var.json template.json") 

プレースホルダを含んだtfを使うなど

python exec_packer.py | xargs -I{} sed -e 's/{{AMI_ID}}/{}/g' test.tf > test_e.tf

Executable JAR を作る

Treasure Data の Embulk(http://www.embulk.org/docs/) をインストールして気になったので、メモ。

Embulkがなんなのかはドキュメントを読むとして、インストールするには以下のコマンドを叩くだけではいった。

curl --create-dirs -o ~/.embulk/bin/embulk -L "https://dl.embulk.org/embulk-latest.jar"
chmod +x ~/.embulk/bin/embulk
echo 'export PATH="$HOME/.embulk/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

これはjarをローカルに保存してそこにパスを通してるだけなんだけど、jarを直接指定して実行できるというのが妙にかっこいい。

普通jarファイルを実行するときは、 java -jar hoge.jar みたいな感じですると思う。

でも、以下の方法でexecutableな jarを作成することができる。

coderwall.com

手順としては、

#!/bin/sh
MYSELF=`which "$0" 2>/dev/null`
[ $? -gt 0 -a -f "$0" ] && MYSELF="./$0"
java=java
if test -n "$JAVA_HOME"; then
    java="$JAVA_HOME/bin/java"
fi
exec "$java" $java_args -jar $MYSELF "$@"
exit 1

を、executableにしたいjarの先頭に追加するだけ。

上記をstub.shなどとして保存して、 cat stub.sh hoge.jar > hoge.run とすると良い。

ちなみに、embulkのjarは、その先頭の END_OF_EMBULK_SELFRUN_BATCH_PART というセクションにMS-DOSのコマンドも書いてあり、 さすがですねと思った。

PackerでAMIを作ると流れるようにできるしChefの確認も流れるようにできた

HashiCorpのPackerの使い勝手の良さはすごくいい。

AWS環境でしか使っていないが、とても手軽にAMIをbakeできる。(bakeという単語を公式で使っていた)。 特に、Windows機のAMIをbakeするのに威力を発揮してくれた。

そもそも、Windowsに限らずだが、後のインスタンス構築の手間を省く目的でpre-bakedなAMIを作るとき、 本当にとっかかりの段階ではだいたい以下のようなサイクルを手元で回したくなるはずである(自分だけ?)。

Chefなどのプロビジョニングツールのレシピを書く
↓
( Chef Serverにレシピをupload ) 
↓
EC2インスタンス再作成して適用 
↓
失敗。。。調査。。
↓
Chefなどのプロビジョニングツールのレシピを書く
↓
( Chef Serverにレシピをupload ) 
↓
EC2インスタンス再作成して適用 
↓
失敗。。。調査。。
↓
・・・
・・・
↓
成功
↓
AMI化して完了

この時、Windowsだと圧倒的に困るのが、とにかくterminate/startが遅いことで、インスタンス再作成だけで数分とか数十分とか必要なことも。 せめて、terminateくらいは素早くやらせてほしい。

すばやく環境を構築/破棄するという観点では、Terraformを使っていると環境の構築/破棄がコマンド1つでとても簡単に行えるが、それでもapplyとdestroyを繰り返すのは、ずっと続けているとなんかアホらしくなってくる。

あと、applyしている途中で誤りに気づいてCtrl-cとかしたくても怖くてできない。 だいたい、applyのログ追ってれば、こりゃダメだって途中で気づくことも経験上よくある。しかし、Ctrl-cしたくてもterraformだと少し怖いし変にリソースが残るのが嫌なので、それはできない。

Packerだとこうだ。

簡単なtemplate(example.json)を用意する。

{
  "variables":{
    "home": "{{env `HOME`}}"
  },
  "builders": [
    {
      "type": "amazon-ebs",
      "region": "ap-northeast-1",
      "access_key": "{{user `aws_access_key`}}",
      "secret_key": "{{user `aws_secret_key`}}",
      "source_ami": "ami-d34f47b4",
      "instance_type": "t2.small",
      "ami_name": "hoge {{timestamp}}",
      "communicator": "winrm",
      "winrm_username": "Administrator"
    }
  ],
  "provisioners": [
    {
      "guest_os_type": "windows",
      "type": "chef-client",
      "server_url": "https://chef-server",
      "chef_environment": "production",
      "run_list": "recipe[example]",
      "encrypted_data_bag_secret_path": "/path/to/secret",
      "validation_client_name": "client",
      "validation_key_path": "/path/to/key"
    },
    {
      "type": "powershell",
      "inline": [
        "C:\\PROGRA~1\\Amazon\\Ec2ConfigService\\Ec2Config.exe -sysprep"
      ]
    }
  ]
}

これで、 packer build example.json を実行する。

Packer Builderというなぞのインスタンスがおもむろに立ち上がり、それに対しprovisionerが適用されていく。

よくあることだが作成途中にダメだと気づいたら、Ctrl-cすれば以下のようにちゃんと後始末してくれる。そしたらレシピを修正するなりpackerのログを見るなりして、またbuildすればよい。

・・・
^C==> amazon-ebs: Terminating the source AWS instance...
==> amazon-ebs: Cleaning up any extra volumes...
==> amazon-ebs: No volumes to clean up, skipping
==> amazon-ebs: Deleting temporary security group...
==> amazon-ebs: Deleting temporary keypair...
Build 'amazon-ebs' finished.
Cleanly cancelled builds after being interrupted.

terraformとの些細な違いは、自分でdestroyしなくて済むということだが、試行錯誤してる時には、これが体感として非常に利いてくる気がしている。 なんというか、カジュアルさが違う。terraformのように重おもしくない。

さらに、packerには、このように環境構築に対する圧倒的カジュアルさのほかに、非常に便利な機能がある。 それが、ステップ実行である。

packer build -debug example.json だけでそれは起動する。

まさにコードをデバッグするときのあの挙動そのままであり、breakpointは打てないが、各種provisionerとかoptionとかの実行直前でbreakしてくれて、 プロンプトが返るようになっている。

break中に例えば対象のインスタンスssh/rdpして中を確認したりできる。あたかも、コード実行中にデバッガで特定の変数の値を確認しているかのよう。 ターミナルに戻ってEnterすれば後続の処理がされていく。

ちなみにこの時点でCtrl-cしても、やはり先ほど同様後始末して終わってくれる。使いやすさ。

このように、Packerには、個別のインスタンスを作ってプロビジョニングして壊すのに最適な機能がたくさんあることに最近気づいた。

いままで考えもしなかったけど、 Packerは手元でのユニットテストに、TerraformはbakeしたAMIやその他クラウドリソース等の結合テストにというように、テスト工程に無理やりマッピングすると意外としっくりくるように思う。

そう考えると、それぞれにそれぞれの役割の機能がちゃんと備わっているように見えてきた。

すごいぜ、HashiCorp。

しかし、軽くググっても、Chef Server、しかもPackerとかTerraform + Cher Serverという例が全然ないよな。 そもそもChef Serverって世の中的に使われてるのかな。。

ALBログのためのInput Plugin

ALB (https://aws.amazon.com/jp/blogs/aws/new-aws-application-load-balancer/) がリリースされてから半年以上経っているけれど、 明示的にサポートしているfluendプラグインがあまりないようなので書くことにした。

先人には、id:yomon8 さんのここのような記事があったけど、 自分の環境ではこれではなく以下のプラグインをずっと使っているため、こちらを修正することになる。

GitHub - winebarrel/fluent-plugin-elb-access-log: Fluentd input plugin for AWS ELB Access Logs.

とにかくテストが書けていないのであれだけど、一応動くものとしては以下のforkにpushしている。

github.com

ポイントとしては、id:yomon8 さんのを参考に、multiple_files_gzip_reader を使っている点だ。 あと、CLBとALBではログのフォーマットが変わっているのでそこの細かい対応をしている。

テストまで書ければ完璧なのだけど、pluginディレクトリに置いて起動し問題なく稼働しているしとりあえずOK。

簡単な修正で済んだ。

Elasticsearch + Kibana 5.0のDockerImage

www.elastic.co

ここ最近、会社のログ収集基盤周りばかりと向き合っているので、 上記エントリを参考に手元のKitematicで5.0-betaを起動するところまでの記録です。

環境: MacOS El Capitan 10.11.6, VirtualBox 5.0.16, Docker Kitematic 0.10.0, boot2docker 1.10.3

エントリ通り、以下のdocker-compose.ymlを用意。

---
version: '2'
services:
  kibana:
    image: docker.elastic.co/kibana/kibana
    links:
      - elasticsearch
    ports:
      - 5601:5601

  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch
    cap_add:
      - IPC_LOCK
    volumes:
      - esdata1:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    environment:
      - -Xms2g
      - -Xmx2g

volumes:
  esdata1:
    driver: local  

できたら、コマンド一発で起動するはずが、Elasticsearch側コンテナでエラー

 % docker-compose up
・・・
elasticsearch_1 | max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least [262144]
elasticsearch_1 | [2016-09-24T13:34:47,265][INFO ][o.e.n.Node               ] [RaJ4T2F] stopping ...
elasticsearch_1 | [2016-09-24T13:34:47,343][INFO ][o.e.n.Node               ] [RaJ4T2F] stopped
elasticsearch_1 | [2016-09-24T13:34:47,344][INFO ][o.e.n.Node               ] [RaJ4T2F] closing ...
elasticsearch_1 | [2016-09-24T13:34:47,383][INFO ][o.e.n.Node               ] [RaJ4T2F] closed
・・・

docker-machineのカーネルパラメータを変更する必要があります。(https://github.com/elastic/elasticsearch-docker)

docker-machine ssh
sudo sysctl -w vm.max_map_count=262144

デフォルト設定としたいなら、/etc/sysctl.confに書いときます。

再度起動コマンドを実行。

% docker-compose up
・・・
elasticsearch_1 | [2016-09-24T14:05:07,637][WARN ][o.e.d.s.g.GroovyScriptEngineService] [groovy] scripts are deprecated, use [painless] scripts instead
・・・
kibana_1        | {"type":"log","@timestamp":"2016-09-24T14:05:21Z","tags":["status","plugin:elasticsearch@5.0.0-beta1","info"],"pid":6,"state":"green","message":"Status changed from red to green - Kibana index ready","prevState":"red","prevMsg":"Elasticsearch is still initializing the kibana index."}
kibana_1        | {"type":"log","@timestamp":"2016-09-24T14:05:21Z","tags":["status","ui settings","info"],"pid":6,"state":"green","message":"Status changed from red to green - Ready","prevState":"red","prevMsg":"Elasticsearch plugin is red"}
kibana_1        | {"type":"log","@timestamp":"2016-09-24T14:05:21Z","tags":["license","info","xpack"],"pid":6,"message":"Imported license information from Elasticsearch: mode: trial | status: active | expiry date: 2016-10-23T17:22:33+00:00"}
kibana_1        | {"type":"log","@timestamp":"2016-09-24T14:05:21Z","tags":["status","plugin:xpack_main@5.0.0-beta1","info"],"pid":6,"state":"green","message":"Status changed from red to green - Ready","prevState":"red","prevMsg":"Elasticsearch is still initializing the kibana index."}
kibana_1        | {"type":"log","@timestamp":"2016-09-24T14:05:21Z","tags":["status","plugin:graph@5.0.0-beta1","info"],"pid":6,"state":"green","message":"Status changed from red to green - Ready","prevState":"red","prevMsg":"Elasticsearch is still initializing the kibana index."}
kibana_1        | {"type":"log","@timestamp":"2016-09-24T14:05:21Z","tags":["status","plugin:reporting@5.0.0-beta1","info"],"pid":6,"state":"green","message":"Status changed from red to green - Ready","prevState":"red","prevMsg":"Elasticsearch is still initializing the kibana index."}
kibana_1        | {"type":"log","@timestamp":"2016-09-24T14:05:21Z","tags":["status","plugin:security@5.0.0-beta1","info"],"pid":6,"state":"green","message":"Status changed from red to green - Ready","prevState":"red","prevMsg":"Elasticsearch is still initializing the kibana index."}
kibana_1        | {"type":"log","@timestamp":"2016-09-24T14:05:21Z","tags":["status","plugin:monitoring@5.0.0-beta1","info"],"pid":6,"state":"green","message":"Status changed from red to green - Ready","prevState":"red","prevMsg":"Elasticsearch is still initializing the Monitoring indices"}
・・・

groovyはdeprecatedで、painlessを使っていきましょうよというメッセージが。

先日のElastic社のブログで触れられていたPainlessというElasticsearch組み込みスクリプトのこと。

www.elastic.co

あとは、上記起動メッセージから、5.0から標準内臓のX-Packプラギンがロードされていることが確認できます。

ともかく正常に起動できてそうなので、http://192.168.99.100:5601にアクセス(192.168.99.100はdocker-machineのipアドレス)

すると、Shieldの認証フォームが。デフォルトの認証情報でログインします。

f:id:ujun:20160924232704p:plain

おお、なんかKibana4までしか触ったことがないとちょっと感動するくらい様変わりしたUIだ。。

せっかくなので、Painless書いてみるかと思っているところ。

mruby-hibariとmruby-rack-r3でWeb API フレームワークを書いた

まだ表現力は乏しいですが、一応mrubyのWeb APIフレームワークのfirst commitを書きました。

github.com

書き味は、CRubyのGrapeやその他のRESTライクなAPIを書くフレームワークのような感じになっています。mruby-hibarimuby-rack-r3など巨人の肩の上に乗ってる感が満載ですが。

試しにmod_mrubyで使ってみます。 まず、インストールは通常のようにbuild_config.rbに依存mrbgemを追記します。

MRuby::Build.new do |conf|

    # ... (snip) ...

    conf.gem :github => 'ujun/mruby-webapi'
end

そして、mod_mrubyをビルド => インストール。

cd /path/to/mod_mruby
sh build.sh
make && make install

例えば、以下のようなフックの設定を書き、mrubyスクリプトを参照します。

そして、参照先スクリプトは以下のように書きます。 Rack::WebAPIを継承して、応答する内容をmruby-rack-r3のDSLで書きます。

Apacheを起動して、定義したエンドポイントにアクセスしてみます。

curl http://localhost/fuga
#=> "Fuga World!"
curl http://localhost/hoge/22
#=> your id is 22

以上のように、直感的にmrubyでWebAPIを書けるようになりました。

mrubyでがっつりWebアプリケーションを書くことはあまりないかも知れませんが、WebAPIサーバならアリなんじゃないかと思えてきました。これと同じようなことが、以下のエントリの最後のほうにも書いてありました。

mod_mruby を使った Web アプリ - Qiita

mrubyでWebAPI、楽しそうなネタです。

NorikraのAPIを叩くmrbgemを書いて、mod_mrubyで使う

FluentdからNorikraにサーバの各種ログを流し込んで解析する、というのは、 割とよくあるNorikraのユースケースかと思います。

Norikra+FluentdでDoS攻撃をブロックする仕組みを作ってみた | Developers.IO

Fluentd + Elasticsearch + Kibana + Norikra+ Zabbixを使ってOpenStackのログ解析してみた | テクノロジーコラム | コラム・ブログ | NTTソフトウェア株式会社

ログ解析にNorikraを使ってみた - hase log

FluentdとNorikraで異常アクセス検知を行う | ピコもん開発ブログ

これらは、テキストとして出力されているログファイルをFluentdで取り込んで送信となりますが、 ApacheやNginxのアクセスログをNorikraに溜め込むのなら、 以下のmrbgemをmod_mrubyやnginx_mrubyに組み込んでおけばできますよ!

READMEにも書いていますが、CRuby版からのポートなので詳しいAPI情報はそちらをご参照ください。

github.com

インストール

インストールは、通常通りbuild_config.rbに依存gemを追記します。

git clone https://github.com/matsumoto-r/mod_mruby
cd mod_mruby
vim build_config.rb

sh test.sh
sh build.sh
make && make install

使ってみる

まずは、Norikaraサーバのほうに、アクセス時間メソッドURIを受け取る簡単なTargetおよびそれらをselectするQueryをていぎします。

f:id:ujun:20151008064126p:plain

次に、以下のような感じのmod_mrubyの設定を書いて、Apacheを立ち上げます。 情報を投げる先のNorikraサーバのホスト名とポート番号を指定して、アクセス時間/メソッド/URIをNorikraに投げています。

このように、イベントを投げる際にmod_mrubyで取れる種々の情報を利用することができるので、 様々な側面から分析する際に役立つように思っています。

あとは、なんらかの手段でApacheにアクセスしてみます。

curl http://localhost/

このあと、Norikraのコンソールからイベント数を確認!!

アクセス数分増加していました!

(以下のスクリーンショットでは、50。)

f:id:ujun:20151008071237p:plain

mod_mrubyは本当に多くのサーバ情報が手軽に取れますので、 mruby-norikra-clientと組み合わせて、工夫次第で興味深い分析ができるかも。