Rundeckをクラスターモードで構築する

こんにちはmatsです。

最近、更新サボってましたが久しぶりの投稿です。

 

今回は前に下の記事でご紹介していたジョブスケジューラー「Rundeck」について書こうかと思います。

http://tech.im-dmp.net/archives/1681

最近、2.6.0がリリースされたのでアップデートを行ったのですが、改めてドキュメントを見なおしてみるとクラスター構成が組めるみたいだったのでチャレンジしてみました。

そんなに難しくはないのですが、ドキュメントがあまり綺麗にまとまっていなかったりするので、参考になれば幸いです。

 

Rundeckとは

rundeck-logotype-512

オープンソースで開発されているJava製のジョブスケジューラーです。

SSHで対象サーバに接続し、決められた処理を行えるのが基本機能になるのですが、EC2連携のプラグインを使うことでEC2側のタグやインスタンスタイプ、AZなどで対象サーバをフィルタリング出来のが非常に強力です。

rundeck1

IMではバッチ処理等の他にデプロイ処理や覚えにくいREST APIコールなども登録して運用しています。

 

Rundeckのクラスター構成

全体構成はこんな感じです。

rundeck_infra

設定やログを外出しできるので、構成的にはオートスケール出来るのですが、さすがにジョブの最中にライフサイクルが走ると困るのでやっていません。

EC2のインスタンスはそれほど強くなくて大丈夫なのですが、javaのout of  memoryが怖いのでt2.medium(RAM:4GB)を使っています。

また、クライアント証明書による認証を行う関係でnginxを挟んでいますが、ELB→Rundeck(jetty)の様に直接受けてもいいかもしれません。

 

設定まわり

 

基本的には yum や apt-get でインストールすればすぐに動くのですが、クラスターを組む際はいくつか設定を変更する必要があります。

 

設定をMySQLに持たせるようにする

デフォルトの設定だと下記のようになっていて、サーバ内に設定を保持してしまうのでMySQL内に持つように変更します。

/etc/rundeck/rundeck-config.properties

dataSource.url = jdbc:h2:file:/var/lib/rundeck/data/rundeckdb;MVCC=true;TRACE_LEVEL_FILE=4

これを下記のように書き換えます。

dataSource.url = jdbc:mysql://{{ mysql_host }}/{{ mysql_database }}?autoReconnect=true
dataSource.username = {{ mysql_user }}
dataSource.password = {{ mysql_password }}

# Enables DB for Project configuration storage
rundeck.projectsStorageType = db

# Encryption for project config storage
rundeck.config.storage.converter.1.type = jasypt-encryption
rundeck.config.storage.converter.1.path = projects
rundeck.config.storage.converter.1.config.password = mysecret

# Enable DB for Key Storage
rundeck.storage.provider.1.type = db
rundeck.storage.provider.1.path = keys

# Encryption for Key Storage
rundeck.storage.converter.1.type = jasypt-encryption
rundeck.storage.converter.1.path = keys
rundeck.storage.converter.1.config.password = mysecret

 

ログをS3に出力するようにする

下記設定を追加し、rundeck-s3-log-pluginを有効化します。

/etc/rundeck/rundeck-config.properties

rundeck.execution.logs.fileStoragePlugin = org.rundeck.amazon-s3

 

また、下記のようにログの出力先を設定します。

/etc/rundeck/framework.properties

#name of the bucket
framework.plugin.ExecutionFileStorage.org.rundeck.amazon-s3.bucket = {{ s3_bucket }}

#path to store the logs
framework.plugin.ExecutionFileStorage.org.rundeck.amazon-s3.path = logs/${job.project}/${job.id}/${job.execid}.log

#  AWS region name
framework.plugin.ExecutionFileStorage.org.rundeck.amazon-s3.region = ap-northeast-1

 

クラスターモードの有効化

下記設定を追加し、クラスターモードを有効化します。

/etc/rundeck/rundeck-config.properties

rundeck.clusterMode.enabled = true

 

また、個々のサーバを識別するためのserverUUIDを設定します。

値のフォーマットのバリデーションがあるみたいなので、uuidgen などで生成するのがいいかと思います。

/etc/rundeck/framework.properties

rundeck.server.uuid = 00000000-0000-0000-0000-000000000000

 

IMの場合は起動時に読まれるシェルスクリプト(/etc/rundeck/profile)内で生成するようにしています。

sed -i -e "/^rundeck.server.uuid/c\rundeck.server.uuid = $(uuidgen)" /etc/rundeck/framework.properties

 

ELBのスティッキーセッションを設定する

Rundeckはjettyというアプリケーションサーバが発行するCookieでセッション情報を管理しているので、ELBのセッション維持にこのCookieを用いるように設定します。

Cookie名は JSESSIONID です。

jsessionid

ちなみにこの設定をしないと別のサーバにバランシングされた瞬間にログアウトします。。。

 

 

あとはRundeckのプロセスを起動するだけでクラスターに参加します。楽ちんですね(´∀`)

 

 

おすすめプラグイン

大したものは入れてませんが、一応紹介しておきます。

rundeck-ec2-nodes-plugin

RundeckからEC2のAPIをコールして、インスタンス情報を取得することが出来るプラグインです。

 

rundeck-s3-log-plugin

ジョブの実行ログをS3におくプラグインです。

 

rundeck-slack-incoming-webhook-plugin

ジョブの通知をSlackのIncomming Webnoohに送るプラグインです。

↓こんな感じです。

Slack

 

 

Rundeckのクラスタリングについて日本語で書いてあるドキュメントはあまりないみたいなので、参考にして頂ければ幸いです。

(本家のドキュメントはこちら → http://rundeck.org/docs/administration/scaling-rundeck.html

 

 

AnsibleのPlaybookも公開しているので、Vagrantで試す際は使って頂ければと。

https://github.com/mats116/ansible-playbook-rundeck

Elasticsearch勉強会でLTしてきました

こんにちはmatsです。

 

昨日行われていた「第11回elasticsearch勉強会」でLTをしてきました。

今回は来日していたElasticsearchのCTO向けに英語スライドで事例紹介をとのオーダーがあったので、全編英語になっています。(さすがに日本語でしゃべりましたが)

内容的にはESというよりかはDMPとは?みたいな話が中心になりますが、世界的に見てもリアルタイムに検索クエリを投げることが出来るDMPはほぼ無い気がするのでいい事例なんじゃないかなと思います。

 

ちょっと失敗したのは、オーディエンスの特徴が出やすい(興味、関心が反映されやすい)デモ用のキーワードを用意していなかったことですね。。

参考までに「薄毛」で検索した時のキャプチャを載せておきます。

 

audiencesearch_demo

次があるのであればヘビーなAggregationに対応するためのチューニングの話とかをしたいですね。

 

おしまい。

 

Aerospikeのスケールアウト

こんにちはmatsです。

 

先日、「Aerospike Deep Dive」に登壇したのですが、その際にスケールアウト(ノードの追加)について聞かれる方が多い様に思いました。

http://tech.im-dmp.net/archives/3971

今回はそのスケールアウトの手順と注意事項について書こうかと思います。

 

スケールアウトの手順

0. 環境について

今回の環境は下記の想定です。

既存のノード

aerospike1 10.0.0.1
aerospike2 10.0.0.2
aerospike3 10.0.0.3

追加するノード

aerospike4 10.0.0.4

追加するノードのハードウェア構成は同じもので、既存のノードと同様の手順で aerospike-server がインストールされているものとします。

 

1. 設定の編集

基本的には既存のノードと全く同じになりますが、注意点があります。

AWSなどマルチキャスト通信が出来ない環境では、aerospike.confの設定が全ノードで同じにならず、追加を繰り返す毎に差分が増えていきます。

IMでは全ノード分のIPをconfに書き、自ノードのIPはコメントアウトする形でansibleで管理しています。ノード追加の際に既存のノードの設定も修正しますが、読み込みには再起動が伴うのであくまで形式上の変更になります。

また、この設定はオンラインでは変更不可のため設定の非対称性は残り続けます。(運用上問題ありませんが・・・)

aerospike.conf 設定例

network {
    service {
        address any
        port 3000
    }

    heartbeat {
        mode mesh
        address any
        port 3002
        mesh-seed-address-port 10.0.0.1 3002 # aerospike1
        mesh-seed-address-port 10.0.0.2 3002 # aerospike2
        mesh-seed-address-port 10.0.0.3 3002 # aerospike3
        #mesh-seed-address-port 10.0.0.4 3002 # aerospike4

        interval 150
        timeout 20
    }

    fabric {
        port 3001
    }
    info {
        port 3003
    }
}

 

2. 書き込み処理の停止

公式のドキュメントには記載がありませんが、書き込みは停止しておくのが推奨な様です。

 

3. 新規追加ノードの起動

asdのサービスを起動します。clusterへの参加は自動で行われます。

 

4. マッピングテーブルの生成を待つ

マッピングテーブルの生成が完了するまで1〜5分ほど待ちます。この間、無応答になりAMCなどでステータスを確認することが出来ません。

データ量に依存して時間が伸びることがあります。(IMでの実績ベースなので未確認)

 

5. マイグレーション完了まで待つ

一応、マッピングテーブルの生成が完了していれば、動作上は正常な状態に戻るので書き込み処理を再開しても問題は無いかと思います。

ただ、推奨的にはマイグレーションの完了まで待ったほうが良いとのことです。

 

6. 書き込み処理の再開

aerospikeへの書き込みを再開します。

 

気になる点

  • 無停止で行うことが出来ません
  • データ量の増加に伴い、無応答時間が伸びるなど不安程度が増します
  • マイグレーション中はレプリカの数が0になります

 

設定変更の際などローリングで全ノードを入れ替えたいと言っていた方もいらっしゃいましたが、個人的にはノードの数はあまり変更しないことをオススメしています。(作業は簡単なのですが、毎回挙動が違うのでドキドキします。。)

 

おしまい

「Data Connector for Amazon S3」でELBのログを取り込む

こんにちは。matsです。

 

トレジャーデータからこんなサービスがリリースされました。

http://blog-jp.treasuredata.com/entry/2015/06/22/125518

たまたま社内でELBのログを調査する機会があったので、「Data Connector」でELBのアクセスログをTDに送るのに使用してみました。

今回は「Data Connector」を使う時の手順について書こうかと思います。

 

TreasureData ToolBeltのインストール

公式サイトから落としてインストールします。

私は自分のMacbookにインストールしました。

 

TreasureData ToolBeltの設定

アカウント認証

下記コマンドでアカウント認証をします。(対話形式です)

$ td -e https://api.treasuredata.com account -f

Enter your Treasure Data credentials.
Email: kazuki.matsuda@intimatemerger.com
Password (typing will be hidden):
Authenticated successfully.
Use 'td -e https://api.treasuredata.com db:create <db_name>' to create a database.

 

APIエンドポイントの登録

下記コマンドでコールするAPIを設定します。(切り替えるとYBIでもいけるのかな?)

$ td server:endpoint https://api.treasuredata.com

 

設定ファイルの作成

基本的にはembulkの設定と同じようです。

ELBのログファイルを読み込む設定はこんな感じになりました。

elb.yml

config:
  in:
    type: s3
    bucket: <bucket_name>
    path_prefix: [prefix]/AWSLogs/[account_id]/elasticloadbalancing/ap-northeast-1/[YYYY]/[MM]/[DD]/
    endpoint: s3-ap-northeast-1.amazonaws.com
    access_key_id: XXXXXXXXXXXXXXXXXXXXXX
    secret_access_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    parser:
      charset: UTF-8
      newline: CRLF
      type: csv
      delimiter: ' '
      skip_header_lines: 1
      allow_extra_columns: true
      allow_optional_columns: true
      columns:
        - name: time
          type: timestamp
          format: "%Y-%m-%dT%H:%M:%S"
        - name: elb_name
          type: string
        - name: client:port
          type: string
        - name: backend:port
          type: string
        - name: request_processing_time
          type: double
        - name: backend_processing_time
          type: double
        - name: response_processing_time
          type: double
        - name: elb_status_code
          type: string
        - name: backend_status_code
          type: string
        - name: received_bytes
          type: long
        - name: sent_bytes
          type: long
        - name: request
          type: string
        - name: user_agent
          type: string
        - name: ssl_cipher
          type: string
        - name: ssl_protocol
          type: string
  out:
    mode: append

 

ログフォーマットはこちらを参考にしました。が、実際にはかれているログをよく見ると

  • user_agent
  • ssl_cipher
  • ssl_protocol

といった項目があるので、注意が必要です。(これ公式のドキュメントに書いてほしいな。。)

embulk使用時とちがうのは、outの書き方ぐらいかと思います。デフォルトの出力先がTDになっているので、アウトプットプラグインの指定が必要ない感じです。

 

今回は特定の日のログが目当てだったので、path_prefixで日にちまで指定して取り込みました。

階層を上げれば月別とかで取り込むことができるので便利ですね。

 

ジョブの登録

次のコマンドでTDにジョブを登録します。

$ td connector:issue elb.yml --database embulk --table elb_accesslog --time-column time

Job 27708303 is queued.
Use 'td job:show 27708303' to show the status.

databaseとtableをあらかじめ作っていないと、ジョブを登録できないようなので注意が必要です。

 

実行するとTDの画面上からはこんな感じで「RUNNING」のジョブに積まれます。

 

td_bulk

 

ジョブの定期実行

ジョブをタスクスケジューラーで定期的に動かす場合は、下記コマンドで登録することができます。

 

$ td connector:create 
  daily_import 
  "10 0 * * *" 
  embulk 
  elb_accesslog 
  elb.yml 
  --time-column time

 

が、定期的に出力されるログを取り込む場合は、取り込む際に対象ファイルの削除か、path_prefixの動的な変更が出来ないと正直使いにくいです。。

 

定期実行とは相性が悪いみたいなので、Lambdaを絡めてファイルの生成と同時にTDに取り込むというのをそのうちやってみようかと思います。

 

おしまい

 

 

AWSでAerospikeをインストールする

こんにちは。matsです。

 

ちょうどAerospikeを増強する機会があったので、インストールについてまとめてみました。

基本的にはこちらのリファレンスを参考にしています。

 

サーバの起動

下記の構成で立ち上げます。

起動したら次のコマンドで拡張ネットワーキングが有効になっていることを確認します。

「driver: ixgbevf」とあれば大丈夫です。

# ethtool -i eth0

driver: ixgbevf
version: 2.14.2+amzn
firmware-version: N/A
bus-info: 0000:00:03.0
supports-statistics: yes
supports-test: yes
supports-eeprom-access: no
supports-register-dump: yes
supports-priv-flags: no

 

Aerospikeのインストール

rpmパッケージを落としてきてインストールするだけです。楽ちん。

(ここまで楽ならyumリポジトリあってもいいのに。。)

# wget --output-document=aerospike.tgz http://www.aerospike.com/download/server/3.5.14/artifact/el6
# tar -xzvf aerospike.tgz
# cd aerospike-server-community-*-el6
# ./asinstall

 

ネットワーク(NIC)の最適化

Amazon Linux (HVM)の各NICは、毎秒約250Kパケットを処理することができますが、より高いパフォーマンスを求める場合は、以下のどちらかの対応が必要な様です。

(これは一つのNICから受けるパケットは一つのCPUで受けて処理する仕様に起因しているようです)

 

ENI(仮想NIC)を追加する

NICを追加し、それぞれに対応するCPUを分けることで対応します。

が、結構設定が面倒くさいので、私のオススメは次のやつです。

 

RPSを使う

Linux kernelの2.6.35以降で利用できる機能にRPSというものがあります。

詳細な仕様は私も分かっていないのですが、簡単な設定をすることで特定のNICのパケットを処理するCPUの個数を指定することができる様です。

設定方法は下記コマンドになります。

echo ffffffff > /sys/class/net/eth0/queues/rx-0/rps_cpus

AMIに固めるときなどは /etc/rc.local の最後に書いています。

 

Ephemeral Diskのアンマウント

Aerospikeはファイルシステムを介さず、直接ブロックデバイスに書き込むのでマウントは不要です。

EC2ではデフォルトでマウントされてしまうので外しておきます。

# umount /media/ephemeral0
# sed -i -e '/ephemeral0/d' /etc/fstab

 

Aerospikeの起動

あとは起動するだけです。

ちなみに、自動起動は設定していません。(サーバが落ちた時などは予期しないことが起こっている事が多いので)

# service aerospike start

 

 

おわり

Airbnbの「Airflow」を試す

こんにちは。最近pythonと戯れているmatsです。

 

6月の頭にこんなリリースがありました。

http://japan.cnet.com/news/service/35065498/

今回はこの「Airflow」を試してみようかと思います。

 

Airflowとは

「Airflow」はAirbnbオープンソースとして公開したワークフロー管理プラットフォームです。

データパイプラインを規模に応じてタイムリーにオーサリング、スケジューリング、モニタリングすることができ、過去数年間で爆発的に成長したAirbnbにとっては不可欠な存在とのこと。

 

ソースコード: https://github.com/airbnb/airflow/

ドキュメント: http://pythonhosted.org/airflow/

 

Airflowのインストール

Airflowはpython製で2.7系のみの対応です。今回はAmazon Linuxにインストールを行いました。

 

準備

コンパイルに必要なパッケージをインストールします。

$ sudo yum -y groupinstall "Development Tools"

 

Airflow本体のインストール

pythonのライブラリとして公開されているので、pipコマンドで導入可能です。(結構時間がかかります)

$ pip install airflow

 

データベースの初期化

次のコマンドでデータベースの初期化を行います。

デフォルトがSQLiteになっていてサクッとはじめられるのはいいですね(^^)

$ airflow initdb

DB: sqlite:////home/ec2-user/airflow/airflow.db
Done.

 

Airflowの起動

webserverを起動します。

$ airflow webserver

 ____________ _____________
 ____ |__( )_________ __/__ /________ __
____ /| |_ /__ ___/_ /_ __ /_ __ _ | /| / /
___ ___ | / _ / _ __/ _ / / /_/ /_ |/ |/ /
 _/_/ |_/_/ /_/ /_/ /_/ ____/____/|__/

2015-06-28 16:34:20,376 - root - INFO - Filling up the DagBag from /home/ec2-user/airflow/dags
2015-06-28 16:34:20,376 - root - INFO - Importing /usr/local/lib/python2.7/site-packages/airflow/example_dags/example_python_operator.py
2015-06-28 16:34:20,377 - root - INFO - Loaded DAG <DAG: example_python_operator>
2015-06-28 16:34:20,378 - root - INFO - Importing /usr/local/lib/python2.7/site-packages/airflow/example_dags/example_bash_operator.py
2015-06-28 16:34:20,378 - root - INFO - Loaded DAG <DAG: example_bash_operator>
2015-06-28 16:34:20,378 - root - INFO - Importing /usr/local/lib/python2.7/site-packages/airflow/example_dags/tutorial.py
2015-06-28 16:34:20,379 - root - INFO - Loaded DAG <DAG: tutorial>
Running Tornado server on host 0.0.0.0 and port 8080...

 

worker等を起動する場合は別途MySQL等が必要です。(初期設定ではceleryのバックエンドにMySQLを使用することになっています)

$ airflow worker

 -------------- celery@ip-192-168-4-67 v3.1.18 (Cipater)
---- **** -----
--- * *** * -- Linux-3.14.44-32.39.amzn1.x86_64-x86_64-with-glibc2.2.5
-- * - **** ---
- ** ---------- [config]
- ** ---------- .> app: airflow.executors.celery_executor:0x7f270bd6dd90
- ** ---------- .> transport: sqla+mysql://airflow:airflow@localhost:3306/airflow
- ** ---------- .> results: db+mysql://airflow:airflow@localhost:3306/airflow
- *** --- * --- .> concurrency: 16 (prefork)
-- ******* ----
--- ***** ----- [queues]
 -------------- .> default exchange=celery(direct) key=celery


[2015-06-28 15:09:19,033: WARNING/MainProcess] celery@ip-192-168-4-67 ready.
Starting flask
 * Running on http://0.0.0.0:8793/ (Press CTRL+C to quit)

 

$ airflow flower

[I 150628 15:09:45 command:114] Visit me at http://localhost:5555
[I 150628 15:09:45 command:116] Broker: sqla+mysql://airflow:airflow@localhost:3306/airflow
[I 150628 15:09:45 command:119] Registered tasks:
 ['celery.backend_cleanup',
 'celery.chain',
 'celery.chord',
 'celery.chord_unlock',
 'celery.chunks',
 'celery.group',
 'celery.map',
 'celery.starmap']
[I 150628 15:09:45 mixins:225] Connected to sqla+mysql://airflow:airflow@localhost:3306/airflow

 

ブラウザから http://:8080 にアクセスすると・・・

Airflow_-_DAGs

お、でた!(使い方がwからない。。。)

 

所感

Q. で、結局のところ使えるの?

所定のルールでpythonスクリプト書き、登録するとこんな感じで表示されるようです。(for文でクルクル回している処理が、小ジョブとしてそれぞれ表示されていたりするのはおもしろいですね)

Airflow_DAGs

ワークフロー全体で1つのコードのようなので、動的にジョブを組み合わせるとかは難しいのかもしれません。

IMには、用意されたジョブを動的に連結させて動かす仕組みが既にあるので、同様のことをする場合はジョブを選択していくとAirflow登録用のpythonコードが生成出来る仕組みが別途必要そうです。

ある程度固まっているワークフローをガンガン回すのには向いている感じがします。

 

Q. アーキテクチャー的には?

キューの管理やデータストアやワーカーは独立させる事ができるみたいなので、比較的障害等には強い気がします。

 

Q. オートスケールとかAWSとの相性は?

まだわかりません。ワーカーとしてスポットインスタンスを使えると最高なのですが。。

キュー管理に使われているceleryはバックエンドにSQSを使えたりするみたいです。

 

 

似たような仕組みを既に社内に持っているので実際に使うかは微妙ですが、引き続き動向は追っていこうかと思います。(試すとか言って起動しかしていないのはご愛嬌)

 

おわり

Aerospikeの勉強会に登壇してきました

こにちは、matsです。

 

昨日、行われていた「Aerospike Deep Dive」に登壇してきました。

aerospike_deep_dive

 

Deepと付いているのですが、どちらかと言うと導入事例やTips的なものがメインだったので全くDeepではありませんでした。。

内容的には

  • IMでの使われ方(導入事例) ← メイン
  • 導入時に検討した他のKVS
  • 導入して気づいたこと

こんな感じで、後半2つは参考程度のお話になります。

海外で大規模に運用しているところでは、BlueKaiやAppNexusなどのDMPで弊社と同様の使い方をしているようなので、Aerospikeの用途的には比較的王道をいっているのかと思います。なので、事例としては結構いいんじゃないかなと思い、お話させて頂いた感じです。

最後に質問で、SSD領域を使ってやっている属性データの加工の際のレスポンスについて聞かれましたが、Aerospike的にはほぼ全て1ms以下で応答していて、それ以上の精度で計測するのは正直辛いですね。。ほんと早すぎて限界が全くわからないです。

 

※追記

Youtubeに動画が上がりましたので追加しておきます。(他の登壇者の動画はこちら

 

 

絶賛エンジニアを募集中ですので、ElasticsearchやAerospikeなどを用いた大規模なデータ処理に興味のある方いらっしゃいましたらご連絡頂ければと思います〜。

採用ページはこちら