2014年3月31日月曜日

TCPコネクション数を監視するNagiosプラグイン

Matt Buck

TCPコネクション数を監視するNagiosプラグインを書きました。
こちらに置いておきます。
check_tcp_count.pl
https://github.com/takeshiyako2/nagios-plugins/tree/master/check_tcp_count

OSは、CentOS 6.5で動作確認しています。

関連記事
Linux kernelのTCP_TIMEWAIT_LEN を修正して、TIME_WAITを減らす

2014年3月27日木曜日

2014年4月以降のAWS料金値下げまとめ


AWS Summit 2014 | San FranciscoにてAmazonがAWSの値下げを発表しました。
公式サイトに新価格の詳細が記載されています。

Amazon EC2
https://aws.amazon.com/ec2/pricing/effective-april-2014/

Amazon S3
https://aws.amazon.com/s3/pricing/effective-april-2014/

Amazon RDS
https://aws.amazon.com/rds/pricing/effective-april-2014/

Amazon ElastiCache
https://aws.amazon.com/elasticache/pricing/effective-april-2014/

Amazon EMR
https://aws.amazon.com/elasticmapreduce/pricing/effective-april-2014/


Twitterでの反応です。










........

2014年3月24日月曜日

Redis Sentinelをセットアップして、お手軽にRedisのフェイルオーバーを実現する方法


言わずと知れた、Redisのフェイルオーバーツール、Redis Sentinel(http://redis.io/topics/sentinel)をお手軽に使う方法を紹介します。


フェイルオーバー時に、アプリサーバからRedisへの接続先を変更する方法として、”アプリサーバへ /etc/hosts を rsync で配布する” といった方法をとります。
いままでは、RedisサーバのIPアドレスの付け替えや、HAProxyの設定変更を自動で行う、などといった方法がありましたが、これは、敷居低めで実装できるのが嬉しいです。

動作イメージは下のようになります。
redis1が壊れたとき、redis2が自動でマスタに昇格してサービスを継続します。


詳しく説明します。
app1、app2の /etc/hosts には、Redisマスタのホスト名 redis-master.myservice.com と redis1 のIPアドレスを紐づける記述しておきます。
app1、app2のアプリケーションは、このホスト名 redis-master.myservice.com 宛にRedis接続をします。
フェイルオーバー時には、redis-master.myservice.com の IPアドレスを redis2 のものに変更した /etc/hosts を rsync で差し替えます。

サーバIDとIPアドレスはこのようになっているとします。

app1 (100.100.100.1): アプリサーバ1 + Redis Sentinel
app2 (100.100.100.2): アプリサーバ2
redis1 (200.200.200.1): Redisマスタ
redis2 (200.200.200.2): Redisスレーブ

試験環境は、CentOS 6.5、Redis 2.8.7です。
Redisは、既にインストールされている状態ではじめます。
Redis Sentinelは、app1サーバにセットアップします。
iptablesなどのアクセスコントロールは便宜設定してください。

◆ 事前準備

1)app1からapp2サーバへrootユーザでログインできるようにしておく。

フェイルオーバーするときに、hostsファイルを転送できるようにしておきます。

2)Redisマスタ -> スレーブのレプリケーションを構築しておく。

redis2サーバで設定します。

Redisスレーブの設定ファイルに、マスタの情報を記述
# vim /etc/redis/redis.conf
---
slaveof 200.200.200.1 6379
---

Redisリスタート
# /etc/init.d/redis stop
# /etc/init.d/redis start
Starting Redis server...

infoを確認
# redis-cli -p 6379 info | grep role -3
latest_fork_usec:0

# Replication
role:slave
master_host:200.200.200.1
master_port:6379
master_link_status:up
-> リンクステータスがupなのでおkです。

ログを確認
# tail -f /var/log/redis.log
[3888] 24 Mar 13:05:36.291 # Server started, Redis version 2.8.7
[3888] 24 Mar 13:05:36.291 * DB loaded from disk: 0.000 seconds
[3888] 24 Mar 13:05:36.291 * The server is now ready to accept connections on port 6379
[3888] 24 Mar 13:05:36.293 * Connecting to MASTER 200.200.200.1:6379
[3888] 24 Mar 13:05:36.293 * MASTER <-> SLAVE sync started
[3888] 24 Mar 13:05:36.329 * Non blocking connect for SYNC fired the event.
[3888] 24 Mar 13:05:36.351 * Master replied to PING, replication can continue...
[3888] 24 Mar 13:05:36.375 * Partial resynchronization not possible (no cached master)
[3888] 24 Mar 13:05:36.376 * Full resync from master: 895edcc4655424517d5a9ddc25fc86a4aadb7f91:1
[3888] 24 Mar 13:05:36.465 * MASTER <-> SLAVE sync: receiving 18 bytes from master
[3888] 24 Mar 13:05:36.465 * MASTER <-> SLAVE sync: Flushing old data
[3888] 24 Mar 13:05:36.465 * MASTER <-> SLAVE sync: Loading DB in memory
[3888] 24 Mar 13:05:36.465 * MASTER <-> SLAVE sync: Finished with success

-> success と出ていますね。

マスタに何かsetして、スレーブでgetしてみましょう。
ちゃんと、レプリケーションできているでしょうか?

3) Redisマスタのホスト名を /etc/hosts に記述する。(app1, app2)

# vim /etc/hosts
---
200.200.200.1 redis-master.myservice.com
---

アプリケーションからは、redis-master.myservice.com 宛に接続するようにしておきましょう。

◆ Redis Sentinelのセットアップ

app1サーバでRedis Sentinelを設定します。

sentinel.confファイルを編集。
# vim /etc/redis/sentinel.conf

マスタのIPアドレスを設定、quorumは1とします。
---
sentinel monitor mymaster 127.0.0.1 6379 2
->
sentinel monitor mymaster 200.200.200.1 6379 1
---

以下を追記
---
daemonize yes
pidfile /var/run/redis_sentinel.pid
loglevel notice
logfile /var/log/redis_sentinel.log
sentinel client-reconfig-script mymaster /usr/share/redis_sentinel/master_ip_failover.sh
---

◆ フェイルオーバー時に実行するスクリプトを用意

app1サーバで用意します。
※ rootユーザによるapp2サーバへのssh疎通を要チェックしておきましょう。

rsyncで /etc/hosts を配布するスクリプトを設置します。
このスクリプトが、フェイルオーバー時に実行されます。
# mkdir -p /usr/share/redis_sentinel/
# vim /usr/share/redis_sentinel/master_ip_failover.sh
---
#!/bin/bash
NEW_HOSTS=/usr/share/redis_sentinel/hosts

# app1
cp ${NEW_HOSTS} /etc/hosts

# app2
rsync -avz ${NEW_HOSTS} 100.100.100.2:/etc/hosts
---

パーミッションを変更。
# chmod 755 /usr/share/redis_sentinel/master_ip_failover.sh

フェイルオーバー時に app1,app2 サーバへ配布する /etc/hosts ファイルを設置します。
mysql-master.myservice.com のIPアドレスを redis2 スレーブのモノにします。
# vim /usr/share/redis_sentinel/hosts
---
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
200.200.200.2 redis-master.myservice.com
---

◆ Redis Sentinelをスタート

app1サーバでRedis Sentinelを実行します。
# /usr/bin/redis-server /etc/redis/sentinel.conf --sentinel

プロセスを確認
# pgrep -fl 26379
3921 /usr/bin/redis-server *:26379

ログを確認
# cat /var/log/redis_sentinel.log
[3921] 24 Mar 13:47:15.111 * Max number of open files set to 10032
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 2.8.7 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 3921
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

[3921] 24 Mar 13:47:15.112 # Sentinel runid is 4b6ddc264813bafaf9142dcb1f53a7b446e47d75
[3921] 24 Mar 13:47:15.112 # +monitor master mymaster 200.200.200.1 6379 quorum 1
[3921] 24 Mar 13:47:15.114 * +slave slave 200.200.200.2:6379 200.200.200.2 6379 @ mymaster 200.200.200.1 6379

Redis Sentinel起動完了です。

◆ Redisフェイルオーバー実験

redis1サーバを落として、ちゃんとフェイルオーバーするか見てみましょう。
iptablesなどを使って接続できないようにするといいかもしれません。

1)redis1でiptablesを使ってポートを閉じる。

# /etc/init.d/iptables start
iptables: ファイアウォールルールを適用中:                  [  OK  ]

2)app1でRedis Sentinelのログを確認。

15秒くらい待つと、フェイルオーバーが走る。
# tail -f /var/log/redis_sentinel.log
[4015] 24 Mar 14:30:19.127 # +sdown master mymaster 200.200.200.1 6379
[4015] 24 Mar 14:30:19.127 # +odown master mymaster 200.200.200.1 6379 #quorum 1/1
[4015] 24 Mar 14:30:19.127 # +new-epoch 3
[4015] 24 Mar 14:30:19.127 # +try-failover master mymaster 200.200.200.1 6379
[4015] 24 Mar 14:30:19.127 # +vote-for-leader 1aaecabcb27ff0f1491c64d98d4201162cb7746b 3
[4015] 24 Mar 14:30:19.128 # +elected-leader master mymaster 200.200.200.1 6379
[4015] 24 Mar 14:30:19.128 # +failover-state-select-slave master mymaster 200.200.200.1 6379
[4015] 24 Mar 14:30:19.194 # +selected-slave slave 200.200.200.2:6379 200.200.200.2 6379 @ mymaster 200.200.200.1 6379
[4015] 24 Mar 14:30:19.194 * +failover-state-send-slaveof-noone slave 200.200.200.2:6379 200.200.200.2 6379 @ mymaster 200.200.200.1 6379
[4015] 24 Mar 14:30:19.270 * +failover-state-wait-promotion slave 200.200.200.2:6379 200.200.200.2 6379 @ mymaster 200.200.200.1 6379
[4015] 24 Mar 14:30:20.187 # +promoted-slave slave 200.200.200.2:6379 200.200.200.2 6379 @ mymaster 200.200.200.1 6379
[4015] 24 Mar 14:30:20.187 # +failover-state-reconf-slaves master mymaster 200.200.200.1 6379
[4015] 24 Mar 14:30:20.264 # +failover-end master mymaster 200.200.200.1 6379
[4015] 24 Mar 14:30:20.264 # +switch-master mymaster 200.200.200.1 6379 200.200.200.2 6379
[4015] 24 Mar 14:30:20.264 * +slave slave 200.200.200.1:6379 200.200.200.1 6379 @ mymaster 200.200.200.2 6379
[4015] 24 Mar 14:30:50.354 # +sdown slave 200.200.200.1:6379 200.200.200.1 6379 @ mymaster 200.200.200.2 6379

3)redis2がマスタに昇格した事を確認

# redis-cli -p 6379 info | grep role -3
latest_fork_usec:0

# Replication
role:master
connected_slaves:0
master_repl_offset:1852
repl_backlog_active:0

4)app1のhostsが書き変わったことを確認

# cat /etc/hosts
200.200.200.2 redis-master.myservice.com

5)app2のhostsが書き変わったことを確認

# cat /etc/hosts
200.200.200.2 redis-master.myservice.com

フェイルオーバー完了です。
お疲れさまでした!


※ 注意
フェイルオーバーが実行されたあとに、redis1を復活させると、redis1の設定ファイルが書き変わり、スレーブとして起動するようになっています。

redis1
# cat /etc/redis/redis.conf
# Generated by CONFIG REWRITE
slaveof 200.200.200.2 6379
-> redis2がマスター、redis1がスレーブになっている。

redis2
# cat /etc/redis/redis.conf
-> slaveofの記述が削除されている

また、app1のRedis Sentinelの設定ファイルも書き変わっています。
案外、ハマりどころかもしれません。注意しましょう。

◆まとめ

Redis Sentinelをセットアップして、/etc/hostsや、rsyncなどの枯れたモノを使ってRedisをフェイルオーバできるようにしました。
インフラ構成が比較的ちいさなサービスなどで、”RedisのHA構成が欲しい”という要望があったときに、使えたりしそうです。
試してみてください。

参考


2014年3月19日水曜日

Python3をyumでインストールして、pipを使えるようにします。 CentOS6


Python3.3.0をyumでインストールして、pipを使えるようにします。
また、python3で動くアプリケーションとしてNetstat-monitorを動かしてみます。
環境は、CentOS release 6.4です。

Python3のインストール

yumレポジトリの準備
# cd /etc/pki/rpm-gpg/
# wget -q http://springdale.math.ias.edu/data/puias/6/x86_64/os/RPM-GPG-KEY-puias
# rpm --import RPM-GPG-KEY-puias
# vim /etc/yum.repos.d/puias-computational.repo
[PUIAS_6_computational]
name=PUIAS computational Base $releasever - $basearch
mirrorlist=http://puias.math.ias.edu/data/puias/computational/$releasever/$basearch/mirrorlist
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-puias

yumでpython3をインストール
# yum install python3.x86_64 python3-tools.x86_64

python3がインストールされた事を確認
# python3 --version
Python 3.3.0

python3のパスを確認
# which python3
/usr/bin/python3

pipのインストール

# wget https://pypi.python.org/packages/source/d/distribute/distribute-0.6.49.tar.gz --no-check-certificate
# tar xzvf  distribute-0.6.49.tar.gz
# cd distribute-0.6.49
# python3 setup.py install
# cd /usr/lib/python3.3/site-packages/distribute-0.6.49-py3.3.egg
# python3 ./easy_install.py pip

pipがインストールされた事を確認
# pip -V
pip 1.5.4 from /usr/lib/python3.3/site-packages/pip-1.5.4-py3.3.egg (python 3.3)

ここまでの手順をFabricにまとめました。こちらです。
https://github.com/takeshiyako2/fabric-scripts#install-python3

Netstat-monitorのインストール

python3で何かアプリケーションを動かしてみましょう。
Netstat-monitor(https://github.com/stalexan/netstat-monitor)を使用してみます。
このアプリケーションは、netstat --inet -alp を tail 表示してくれます。フィルターも設定できるみたいなので、色々とデバッグに使えそうです。

netaddrモジュールをインストール
# pip install netaddr

モジュール確認
# python3 -c "help('modules')"

# wget -O /tmp/netstat-monitor-last.tgz https://github.com/stalexan/netstat-monitor/tarball/master --no-check-certificate
# cd /tmp
# tar zxvf netstat-monitor-last.tgz
# cd stalexan-netstat-monitor-*

Netstat-monitorを実行
# python3 ./netstat-monitor

以下のようなログがずらずらっと表示されてきます。
Mar 19 18:43:46 tcp   12  td-agent 100.100.100.100:51011 s3-ap-northeast-1.amazonaws.com:443 ESTABLISHED 951   /usr/bin/ruby        /usr/bin/ruby /usr/sbin/td-agent --group td-agent --log /var/log/td-agent/td-agent.log --daemon /var/run/td-agent/td-agent.pid
Mar 19 18:43:46 tcp   13  td-agent 100.100.100.100:32999 s3-ap-northeast-1.amazonaws.com:443 CLOSE_WAIT  951   /usr/bin/ruby        /usr/bin/ruby /usr/sbin/td-agent --group td-agent --log /var/log/td-agent/td-agent.log --daemon /var/run/td-agent/td-agent.pid
Mar 19 18:43:46 udp   14  root     100.100.100.100:123   0.0.0.0:0                        3078  /usr/sbin/ntpd       ntpd -u ntp:ntp -p /var/run/ntpd.pid -g
Mar 19 18:43:46 udp   15  root     127.0.0.1:123        0.0.0.0:0                        3078  /usr/sbin/ntpd       ntpd -u ntp:ntp -p /var/run/ntpd.pid -g
Mar 19 18:43:46 udp   16  root     0.0.0.0:123          0.0.0.0:0                        3078  /usr/sbin/ntpd

かんたんですね!

2014年3月14日金曜日

Redisにパスワードを設定したときの起動スクリプトのサンプル


child is a rebel.

Redisにパスワードを設定したときは、デフォルトの起動スクリプトではシャットダウンができません。

Redisのパスワードを設定します。
# vim /etc/redis/6379.conf
requirepass password

Redisをリスタート。
# /etc/init.d/redis_6379 stop
# /etc/init.d/redis_6379 start

パスワードが設定された状態で、Redisをストップ。
# /etc/init.d/redis_6379 stop
Stopping ...
(error) ERR operation not permitted
Waiting for Redis to shutdown ...
Waiting for Redis to shutdown ...
Waiting for Redis to shutdown ...
Waiting for Redis to shutdown ...
Waiting for Redis to shutdown ...
Waiting for Redis to shutdown ...
Waiting for Redis to shutdown ...

シャットダウンできない。。。
これは、シャットダウンするときにパスワードが必要な為ですね。
起動スクリプトを下記のように編集すると良いでしょう。
PASS="password"でパスワードを設定。
シャットダウン時に-a $PASSオプションを追加します。

# vim /etc/init.d/redis_6379

#/bin/sh
# chkconfig: 345 44 56
# description: redis_6379
#Configurations injected by install_server below....

EXEC=/usr/local/bin/redis-server
CLIEXEC=/usr/local/bin/redis-cli
PIDFILE=/var/run/redis_6379.pid
CONF="/etc/redis/6379.conf"
REDISPORT="6379"
PASS="password"
###############

case "$1" in
    start)
        if [ -f $PIDFILE ]
        then
                echo "$PIDFILE exists, process is already running or crashed"
        else
                echo "Starting Redis server..."
                $EXEC $CONF
        fi
        ;;
    stop)
        if [ ! -f $PIDFILE ]
        then
                echo "$PIDFILE does not exist, process is not running"
        else
                PID=$(cat $PIDFILE)
                echo "Stopping ..."
                $CLIEXEC -p $REDISPORT -a $PASS shutdown
                while [ -x /proc/${PID} ]
                do
                    echo "Waiting for Redis to shutdown ..."
                    sleep 1
                done
                echo "Redis stopped"
        fi
        ;;
    *)
        echo "Please use start or stop as first argument"
        ;;
esac



以上、簡単なメモでした。