カテゴリー別アーカイブ: 運用

AWS RDSのログ監視をZabbixで。

| コメントをどうぞ

AWSのRDSはCLIツールでログの取得が出来きるのでZabbixサーバにRDSのログを取得して通常のログ監視設定と似たような感じで監視をします。ZabbixでRDSのログ監視をするには以下の条件が必要になります。

● RDSのログを取得できる権限(IAM)を持っていること。
● CLIツールを導入していること。

正確にはCLIツール無くてもプログラム書ける人ならとってこれるようですが、自分のような非プログラマでもAPIにアクセスしてデータを取得できるCLIツールをリリースしてくれているので使わない手は無いです。
CLIツールは複数の言語版がありますが、JAVA版とPython版を使います。

何故2種類使うのか?となりますが、前にJAVA版で色々とCLIツールで監視データ取得したりバックアップ運用していたのですがJAVA版は重いのです。t2.microでZabbixを動かしていたのですが、CLIを使ったスクリプトを複数個動かすとCPULoadがかなり高くなってました。t2.microでZabbixを動かす事自体問題あるのですが、ブラウザでのアクセスは反応遅いけどもその状態で1年くらいZabbixが落ちたりもせずAWSの障害通知メールも飛ばしてくれてたので放置してましたが、去年の4月にチーム編成が変わって同じチームになった人から「Python版使ってますが重いと感じたことないですけど?」と言われて試してみたら「本当だ軽い・・・」今まで使ってたスクリプトをPython版に書きなおして現在に至るまでZabbixサーバが重くなったことはありませんでした。

AmazonLinuxには最初からPython版CLIツールがセットアップされてるくらいだしPython版のみで行こう!

・・・と思ったらログをtail出来る機能がJAVA版にはあったけどpython版はやり方がわからない。もしくは無いかもしれない。。
(aws-cli/1.3.18 Python/2.6.6のバージョンではよくわからなかった。)

その為、いつかPython版でRDSのログtailの方法がわかったらいつでも全部Python版に変更出来る用に最初の部分はPythonコマンドで実行してtailの部分はJAVA版で実行しています。

● Python版CLIインストール
AmazonLinuxなら最初から入っていますが、CentOSではインストールします。yumで入るので楽です。

# yum install python -y
# yum install python-devel -y
# yum install python-setuptools -y
# easy_install pip
# pip install awscli

次に認証に使うファイルが必要なので作成します。AWSのアクセスキーとシークレットアクセスキーを中に記述します。リージョンはRDSが動いているところにします。ファイル名はアカウント/サービスごとに分けると後で楽です。

# vi 任意の名前

[default]
aws_access_key_id=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
aws_secret_access_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
region=ap-northeast-1

認証ファイルの場所を設定します。

# export AWS_CONFIG_FILE=任意の名前で作成したファイル

コマンドのタブ補完が効かないので効くようにします。毎回補完出来るように.bash_profileに書いておくのも良さそうです。

# complete -C aws_completer aws

セットアップがうまく行ったかか確認します。ログファイルがずらっと表示されればうまく行っています。

# aws rds describe-db-log-files --db-instance-identifier RDS名 --output text

            UNIXエポック  ファイル名     
DESCRIBEDBLOGFILES      1425877196000   error/postgresql.log.2015-03-09-04      4470072
DESCRIBEDBLOGFILES      1425880791000   error/postgresql.log.2015-03-09-05      5148177
DESCRIBEDBLOGFILES      1425884399000   error/postgresql.log.2015-03-09-06      581115
DESCRIBEDBLOGFILES      1425887996000   error/postgresql.log.2015-03-09-07      105250
DESCRIBEDBLOGFILES      1425888531000   error/postgresql.log.2015-03-09-08      36301

「–output」で指定した形式で表示してくれます。「table」と指定するとteble形式、「text」と指定するとテキスト形式で表示してくれます。何も指定しないと「json」形式で表示されて見にくいです。(jqとかかまさないと見づらい)

● JAVA版CLIセットアップ
JAVA版CLIのセットアップ方法はこのブログでも他の人が紹介されているので省略します。(手抜き)

RDSのログをtailするだけだとAWS側で定期的(1時間ごと?)にローテされて見失うので一定間隔で
ログが新しくなったかチェックして最新のログを吐き出すスクリプトを作成します。

●RDSログをtailするスクリプト

#!/bin/sh

# EC2-APITools settings
export JAVA_HOME=/usr

# keys
export AWS_CREDENTIAL_FILE=クレデンシャルファイルのPATH
export AWS_CONFIG_FILE=configファイルのPATH

# RDS CLI setting
export AWS_RDS_HOME=/usr/local/rds
export EC2_REGION="ap-northeast-1"
export PATH=$PATH:$JAVA_HOME/bin:$AWS_RDS_HOME/bin

COMMAND=スクリプトの絶対PATH
DBINSTANCEID=RDSの名前
LOGDIR=ログを保管するPATH

LOG=`aws rds describe-db-log-files --db-instance-identifier $DBINSTANCEID --output text| awk  '{ print $2"\t"$3"\t"$4 }' | awk '{print substr($0,1,length($1)-3)"\t"$2"\t"$3}' | awk '{ print strftime("%Y/%m/%d %H:%M:%S",$1)" "$2" "$3 }' | tail -1 | awk '{print $3}'`

LOGFILENAME=`echo $LOG | sed 's/[a-z]*\///g'`

rds-watch-db-logfile $DBINSTANCEID --log-file-name  $LOG > ${LOGDIR}/$LOGFILENAME 2>&1 &


C=0
while [ $C = 0 ]

do

LOG2=`aws rds describe-db-log-files --db-instance-identifier $DBINSTANCEID --output text| awk  '{ print $2"\t"$3"\t"$4 }' | awk '{print substr($0,1,length($1)-3)"\t"$2"\t"$3}' | awk '{ print strftime("%Y/%m/%d %H:%M:%S",$1)" "$2" "$3 }' | tail -1 | awk '{print $3}'`

if [ $LOG != $LOG2 ];then

pgrep -f $LOG | xargs kill -9

$CMDPATH

fi

sleep 300

done

AWS側のローテはおそらく一時間に一回くらいのようですが、スクリプト内では5分に一回チェックして
新しくなったら新たにログファイルを作り直してtailするようにしています。
このスクリプトをバックグラウンドで動かしっぱなしにして
あとはこのログをZabbixでログ監視すればRDSのログ監視が可能になります。

問題点として、古いファイルを消すようにしていないのでローテ後のログファイルが溜まっていく事と、
JAVAのCLIはやっぱり重い事です。

あと、身も蓋もないですが、RDSのログをリアルタイムで監視したいという要件自体がほぼほぼ無いです。

AWS ECSで insecureレジストリ(非SSL)を参照したい

| コメントをどうぞ

お盆も過ぎまして、ここ最近はなんだか涼しく感じるTokyoです。
そろそろ夏休みシーズンも終わりですね。
私はというもの8月は業務に明け暮れ、9月に夏休みがずれました。

がはは!俺が勝ち組だ!

どうも、DiceK Mikamiです。
 
 
今回は、AWS ECS(EC2 Container Service)にて、非SSLレジストリからイメージを取得するTipsをご紹介したいと思います。
続きを読む

Zabbixの監視通信をStunnelで暗号化する。

| コメントをどうぞ

Zabbixの監視通信は平文で行われます。なのでパケットを眺めると通信内容などが盗み見されます。監視システムははLAN内で完結する事が多いので盗み見出来ても問題無いですが、リモート監視などを行っていると問題になる場合があります。個人的には監視データが見られてもさして問題じゃないのでは?と思いますが、セキュリティの厳しい要件やお客さんに「暗号化してません。平文です。」というのは何かとまずい事があります。ですので暗号化します。

試しに暗号していない通信を他のサーバでキャプチャしてみると・・・
(Zabbixサーバ宛に流れている通信をキャプチャ)

        0x0000:  4500 007e 9026 4000 4006 c20e ac16 c80b  E..~.&@.@.......
        0x0010:  ac16 c80c dca5 2742 331a 8fce 55ce 00f2  ......'B3...U...
        0x0020:  8018 0073 5e76 0000 0101 080a 9206 1fe9  ...s^v..........
        0x0030:  00b0 34a8 6e65 742e 6966 2e69 6e5b 5741  ..4.net.if.in[WA
        0x0040:  4e20 4d69 6e69 706f 7274 2028 4950 7636  N.Miniport.(IPv6
        0x0050:  292d 5379 6d61 6e74 6563 2045 6e64 706f  )-Symantec.Endpo
        0x0060:  696e 7420 5072 6f74 6563 7469 6f6e 2046  int.Protection.F
        0x0070:  6972 6577 616c 6c2d 3030 3030 5d0a       irewall-0000].

“net.if.in[WAN.Miniport.(IPv6)-Symantec.Endpoint.Protection.Firewall-0000].” と、人間が理解できる文字列で通信内容が覗き見出来ます。

以下は暗号化を施した通信になります。

        0x0000:  4500 0067 534c 4000 4006 fe89 ac16 c80b  E..gSL@.@.......
        0x0010:  ac16 c882 eb0c 274a e2cf a450 dcb4 2c70  ......'J...P..,p
        0x0020:  8018 007a 55df 0000 0101 080a 921e cdd0  ...zU...........
        0x0030:  7cc0 41e5 1403 0300 0101 1603 0300 28ac  |.A...........(.
        0x0040:  3564 cb7b 0072 0ce9 286f ecc3 1ff9 0b83  5d.{.r..(o......
        0x0050:  af2a da85 2d00 19fe 36ed 5efd ca2a 3734  .*..-...6.^..*74
        0x0060:  47a6 d9ce 1731 2d                        G....1-

通信内容が覗き見してもわからなくなっています。Zabbixの監視通信を行うのに良さそうな方法は2通りあります。

暗号化したVPNを張ってその中で通信。
通信を暗号化したトンネルを通す。

● VPNで暗号化のメリット
暗号化されたVPNで通信する方法はハードウェアもしくはソフトウェアでVPNを張って通信をすると全ての通信が暗号化されますのでZabbixの監視通信以外も暗号化出来ます。監視対象が多い場合もVPNに参加させるかVPNルータを経由させる形にすれば良いので容易に暗号化する監視対象を追加出来ます。

● VPNで暗号化のデメリット
VPNを張るという行為自体がNGな場合もあります。

● 暗号化したトンネルを張って通信を通す。のメリット
SSHトンネル等が有名です。手軽に1対1の通信を暗号化出来ます。監視対象が1台しか無いときでわざわざVPNを張らなくても・・・という場合に使いやすいです。

● 暗号化したトンネルを張って通信を通す。のデメリット
暗号化するソフトのポートの他に暗号化したい通信のポートが別途必要になります。複数ホストがある場合はその分数を掛け算で必要になります。

今回はStunnelで暗号化します。

Stunnelはサーバ、クライアント方式でStunnelで接続したトンネルを張り、その中に指定のポートを転送して通信します。Stunnelを起動すると自ホスト内に指定したポートが開きます。そこへのアクセスするとトンネルを張った相手ホストに転送します。

● Stunnelの概要図
stunnel

Stunnelは一つのデーモンでサーバとして動くポートとクライアントとして動くポートを指定して動かせますの
で一つのサーバ内でこのポートはクライアントとして外部のStunnelとトンネル張るがこのポートはサーバとして外部から受け付ける。というような事が可能です。

これを利用してZabbixサーバ側では、

● ログ等のアクティブチェックはStunnelのサーバモードで各エージェントからトンネル経由で受け取る。
● パッシブチェックは各エージェントに対してStunnelのクライアントモードでトンネル経由で問い合わせる。

と言った構成にしていきます。

Zabbixサーバ側の設定

  1. Stunnelのインストール


  2. CentOSならyum一発で導入出来ます。

    # yum install stunnel -y
    
  3. SSL証明書の作成
  4. OpenSSLを使って自前証明書を作成します。ブラウザでアクセスすることも無いので自前で何ら問題無いです。
    ここでよくある自前証明書作成コマンドで作成したものだと何故か私の環境では、

    Linux⇔Linux間は問題なくトンネル張れるが、Linux⇔WindowsとLinux⇔Linuxが混在する環境で全部にトンネル張ろうとすると失敗しました。失敗というか、Windows側で起動時に鍵のエラーが出ました。

    証明書作成コマンド

    # openssl genrsa 2048 > stunnel.key
    # openssl req -new -key stunnel.key > stunnel.csr
    # openssl x509 -days 3650 -req -signkey stunnel.key < stunnel.csr > stunnel.crt
    

    Stunnelのドキュメントに証明書/鍵の作成方法が書いてありますのでそちらで試すとWindowsとLinuxが混在した環境でも全部起動出来て繋がりました。

    To generate a key and self signed certificate, execute the following commands:
    
    cd /etc/pki/tls/certs
    make stunnel.pem
    
    Note that by default, the file containing the key and certificate has its
    permissions set to 0600, which means that any service using it needs to be
    started as root in order to read it.  Such a service should be configured
    to switch UIDs using stunnel's "-s" flag.
    

    証明書と鍵を一つのファイルにしないと駄目なのかもしれません。わかりませんが。。

    ※追記:書き忘れましたが、上のまんまで実行すると有効期限が365日で出来てしまいます。期限が切れるとStunnelが繋がらなくなります。深く考えずにやったので一度期限切れでStunnel経由の監視が全部出来なくなってしまった事があります。なので「make stunnel.pem」の前に「/etc/pki/tls/certs/Makefile」内の記述、「-days 365」を書き変えて長くしてから「make stunnel.pem」を実行します。今は「-days 9999」で作成して有効期限自体もZabbixで監視するようにして対策してあります。

  5. Zabbixサーバ側のStunnelの設定ファイルを書きます。
  6. ● /etc/stunnel/stunnel.conf

    cert = /etc/stunnel/stunnel.pem
    key = /etc/stunnel/stunnel.pem
    sslVersion = all
    options = NO_SSLv2
    options = NO_SSLv3
    setuid = nobody
    setgid = nobody
    pid = /etc/stunnel/stunnel.pid
    socket = l:TCP_NODELAY=1
    socket = r:TCP_NODELAY=1
    verify = 3
    CAfile = /etc/stunnel/stunnel.pem
    debug = 4
    output = stunnel.log
    [Zabbix passive HOST1]
    client = yes
    accept = 127.0.0.1:10060
    connect = XX.XX.XX.XX:10052
    [Zabbix passive HOST2]
    client = yes
    accept = 127.0.0.1:10062
    connect = XX.XX.XX.XX:10052
    
    [Zabbix Active]
    accept = 10061
    connect = 10051
    

    client=yes とするとクライアントモードでStunnelをサーバモードとして待ち受けているホストに繋ぎます。
    最初に自身の設定したポート、例えば10060に繋ぐと繋ぎたいホストの10052へ接続します。
    何もつけないとサーバモードで待ち受けます。ここをアクティブチェックの受け取り口にします。
    verify=3で証明書が一致しないと接続を蹴るようにします。そうしないとどこからでも接続されてしまいます。
    (単に暗号化したいならばverify指定しないと接続出来ます。)

Zabbixエージェント側の設定

インストール迄は同じです。証明書/鍵はサーバ側で作成したものをコピーして使います。

  1. Stunnelのインストール
  2. # yum install stunnel -y
    
  3. Zabbixエージェント側のStunnelの設定ファイルを書きます。
  4. ● /etc/stunnel/stunnel.conf(HOST1)

    cert = /etc/stunnel/stunnel.pem
    key = /etc/stunnel/stunnel.pem
    sslVersion = all
    options = NO_SSLv2
    options = NO_SSLv3
    setuid = nobody
    setgid = nobody
    pid = /etc/stunnel/stunnel.pid
    socket = l:TCP_NODELAY=1
    socket = r:TCP_NODELAY=1
    verify = 3
    CAfile = /etc/stunnel/stunnel.pem
    debug = 4
    output = stunnel.log
    [Zabbix passive]
    accept = 10060
    connect =10050
    [Zabbix Active]
    client = yes
    accept = 127.0.0.1:10051
    connect = XX.XX.XX.XX:10061
    

    ZabbixサーバからのパッシブチェックをStunnelが動いている10060で受け取り自身の10050へ渡します。アクティブチェックは自身から送信するのでZabbixサーバのStunnel待ち受けポートの10061へ飛ばします。
    こちらもサーバとして待ち受けるポートがあるのでverify=3として証明書が一致しない場合は接続しないようにします。

以上で設定そのものは完成です。Stunnelを起動すれば繋がるようになります。但しWIndows版は公式サイトのインストーラーで入れれば自動起動が出来ますがLinux版はinitスクリプトが存在しない為作成します。

● Linux版でStunnelのinitscript作成(サーバ、クライアント共通)
(/etc/init.d/stunnel)

#!/bin/sh
# chkconfig: 345 70 40
# description: stunnel

# Source function library.

. /etc/init.d/functions


STUNNEL=/usr/bin/stunnel
CONF=/etc/stunnel/stunnel.conf
prog=stunnel

start() {
                echo -n $"Start $prog: "
                daemon $STUNNEL $CONF
                echo
        }

stop() {
                echo -n $"Stop $prog: "
                killproc $STUNNEL
                echo
        }

case "$1" in
        start)
                start
                ;;
        stop)
                stop
                ;;
        restart)
                stop
                start
                ;;
        status)
                status $STUNNEL
                ;;
        *)
                echo "Usage:$0 {start|stop|restart|status}"
                ;;
esac

作成したら自動起動も設定しておきます。

# chkconfig --add stunnel
# chkconfig stunnel on

起動します。(サーバ、クライアント両方)

# /etc/init.d/stunnel start

Zabbixサーバからzabbix_getを使って動作確認します。

# zabbix_get -s 127.0.0.1 -p 10060 -k agent.hostname
HOST1

自身のローカルIPの10060ポートに対して実行したzabbix_getでエージェント側のホスト名が返ってきているのでトンネルがうまく張れているのが確認できます。

アクティブチェックがうまくとれているかはzabbix_senderでも出来ますが実際にZabbixでログ監視を作ったほうがわかりやすいです。

Amazon EC2 Container Service( AWS ECS )を触ってみた

| コメントをどうぞ

もう2月ですよ。
2月と言えば、イベントが色々ありますね。
節分だったり、バレンタインだったり。
えーと、甘いものは結構好きです。
甘いものは結構好きです!
大事なことなので2回書きました。
どうも、DiceK Mikamiです。

さて、今回は昨年の AWS re:Invent2014 にて発表されたAmazon EC2 Container Service(以下、ECS)をようやく触ってみましたので、その所感など。

ECSは、AWSから提供されるコンテナ管理サービスで、端的にいえば 「EC2上でDocker動かそうぜ!」 なサービスです。
と言っても、今までだってEC2にDockerをセットアップすれば、同じようなことができていたわけですが、ECSによってより簡単にかつコンテナに最適化されたサービスを受けることができるようになりました。
まぁ、ものは試しと言うことで触ってみましょう。
続きを読む

リアルタイム・バックエンドサービス「Firebase」を使ったWebアプリ作成

| 2件の返信

Firebaseは、チャットのようなリアルタイム性の高いアプリを作る際に、端末とサーバー間、端末同士でのデータ同期などのバックエンドで行う処理をAPI提供してくれる便利なバックエンドサービスです。用途としては、複数人でのリアルタイムコミュニケーションアプリやモバイルアプリのオフライン対応などが多いそうです。

まずは試しにということで、Firebaseを使ってグループテキストチャットのサンプルを作成してみましたので、Firebaseの使い方についてご紹介したいと思います。

続きを読む

Tomcat の PUTメソッドが息をしていない問題

| コメントをどうぞ

あけましておめでとうございます。
本年も有為無為に関わらず書き散らかしていく所存にございます。
生暖かい眼差しでお付き合いいただければと思います。
どうぞよろしくお願いいたします。
DiceK Mikamiです。

さて突然なのですが、アプリケーションサーバにTomcatを利用していると、たまにとんでもない大穴にはまったりします。
今回はそんなお話です。
続きを読む

New RelicのJavaエージェントのインストールでエラー

| コメントをどうぞ

今回はNew RelicのJavaエージェントをインストールしてみました。

環境

  • OS: Amazon Linux
  • Tomcat7: yumでインストール

公式ドキュメント

以下のドキュメントを参考にインストールを行いました。
https://docs.newrelic.com/docs/agents/java-agent/installation/java-agent-manual-installation

実行した手順

インストールモジュールをダウンロード

New Relicにログインしてダウンロードします。

モジュールを解凍してtomcatのHOMEに置きます。

# unzip newrelic-java-3.12.0.zip -d /usr/share/tomcat7

インストールを実行

# cd /usr/share/tomcat7/newrelic
# java -jar newrelic.jar install

エラー

Dec 5, 2014 13:14:07 +0900 [28863 1] com.newrelic INFO: Agent is using Logback
***** ( ( o))  New Relic Java Agent Installer
***** Installing version 3.12.0 ...
File /usr/share/tomcat7/bin/catalina.sh does not exist, so it can't become an EditableFile.
No need to create New Relic configuration file because:
 .:. A config file already exists: /usr/share/tomcat7/newrelic/newrelic.yml
***** Install incomplete
***** Next steps:
For help completing the install, see https://newrelic.com/docs/java/new-relic-for-java

/usr/share/tomcat7/bin/catalina.shがないためにエラーが出ました。
tomcatをyumでインストールした場合、自動でサービスが/etc/init.d/tomcat7として保存されるため、catalina.shは存在しません。

catalina.shの作成

今回はパッケージされたTomcatのcatalina.shからコピーして、
/usr/share/tomcat7/bin/catalina.sh を作成しました。

再度実行

# java -jar newrelic.jar install

インストールが完了しました。

NR_JARとCATALINA_OPTSの転記

/usr/share/tomcat7/bin/catalina.shを見てみると、以下の行が追記されていました。

# ---- New Relic switch automatically added to start command on 2014 Dec 05, 13:51:37
NR_JAR=/usr/share/tomcat7/newrelic/newrelic.jar; export NR_JAR
CATALINA_OPTS="$CATALINA_OPTS -javaagent:$NR_JAR"; export CATALINA_OPTS

上記をTomcatの起動時に読み込まれる任意のファイルに記述します。
その後Tomcatを起動すると、New RelicのJava監視が開始されました。

AWS上のZabbixをPacemakerで冗長化 その3(MySQLReplicate編)

| コメントをどうぞ

前回はAWS上のZabbixをPacemaker + DRBDで冗長化しましたので今回は、

● Pacemaker + MySQLレプリケーション(SemiSync)

をやります。MySQLは整合性の高いSemiSyncを採用します。SemiSyncはMySQL5.5以降で使えます。5.5以降はデフォルトのリポジトリには無いのでMySQL5.5以降があるリポジトリを追加するかソースからインストールします。


前提条件としてMySQLは既にインストール/Replication設定済みとします。(導入部分も書くと長くなる為。機会があれば別途導入方法も書きます。)

  • Pacemaker(HeartbeatV2) + MySQLレプリケーション(Semisync)

  • cluster3

    DRBDの時と同じように前回のheartbeatの設定ファイル、cib.xml等が/var/lib/heartbeat/crmに残っている為、一旦削除します。
    (稼働/待機両方で消します。残っていると同期されて元に戻ってしまう為)

    ● 稼働/待機系で前回の設定ファイル削除(/var/lib/heartbeat/crmの下を全消しでOK)

    # rm /var/lib/heartbeat/crm/* -fr
    

    ● 一旦heartbeatを起動

    # /etc/init.d/heartbeat start
    

    MySQL用のxmlファイルを置いて起動しても何故かうまく行かず初期のcibに上書きされてしまう場合は一旦起動後に置き換える事で上手く行きます。

    ● cib.xml無しで起動すると以下のようになります。(クラスタホストが認識されているだけの状態)

    ============
    Last updated: Fri Dec  5 12:46:25 2014
    Stack: Heartbeat
    Current DC: zabbixcluster-2 (e1c9433f-8e5b-8681-2867-5a4dd5880dfe) - partition w
    ith quorum
    Version: 1.0.13-30bb726
    2 Nodes configured, unknown expected votes
    0 Resources configured.
    ============
    
    Online: [ zabbixcluster-1 zabbixcluster-2 ]
    

    ● ここでZabbix+MySQLレプリケーション用のファイルを以下のようにどこかのディレクトリ(/tmpなどどこでもOK)用意します。

    ※nodeidなどは環境に合わせて適宜置き換えます。

    <cib epoch="19" num_updates="0" admin_epoch="0" validate-with="pacemaker-1.0" crm_feature_set="3.0.1" have-quorum="1" dc-uuid="f76af805-bfff-66bd-3d83-95a20a3807ef" cib-last-written="Mon Dec  8 16:12:17 2014">
      <configuration>
        <crm_config>
          <cluster_property_set id="cib-bootstrap-options">
            <nvpair id="cib-bootstrap-options-default-resource-stickiness" name="default-resource-stickiness" value="INFINITY"/>
            <nvpair id="cib-bootstrap-options-no-quorum-policy" name="no-quorum-policy" value="ignore"/>
            <nvpair id="cib-bootstrap-options-stonith-enabled" name="stonith-enabled" value="false"/>
            <nvpair id="cib-bootstrap-options-dc-version" name="dc-version" value="1.0.13-30bb726"/>
            <nvpair id="cib-bootstrap-options-cluster-infrastructure" name="cluster-infrastructure" value="Heartbeat"/>
          </cluster_property_set>
          <cluster_property_set id="mysql_replication">
            <nvpair id="mysql_replication-prm_mysqld_REPL_INFO" name="prm_mysqld_REPL_INFO" value="zabbixcluster-1|mysql-bin.000103|2698"/>
          </cluster_property_set>
        </crm_config>
        <nodes>
          <node id="f76af805-bfff-66bd-3d83-95a20a3807ef" type="normal" uname="zabbixcluster-1"/>
          <node id="e1c9433f-8e5b-8681-2867-5a4dd5880dfe" type="normal" uname="zabbixcluster-2"/>
        </nodes>
        <resources>
          <master id="ms_mysqld">
            <meta_attributes id="ms_mysqld-meta_attributes">
              <nvpair id="ms_mysqld-meta_attributes-master-max" name="master-max" value="1"/>
              <nvpair id="ms_mysqld-meta_attributes-master-node-max" name="master-node-max" value="1"/>
              <nvpair id="ms_mysqld-meta_attributes-clone-max" name="clone-max" value="2"/>
              <nvpair id="ms_mysqld-meta_attributes-clone-node-max" name="clone-node-max" value="1"/>
              <nvpair id="ms_mysqld-meta_attributes-notify" name="notify" value="true"/>
            </meta_attributes>
            <primitive class="ocf" id="prm_mysqld" provider="heartbeat" type="mysql">
              <instance_attributes id="prm_mysqld-instance_attributes">
                <nvpair id="prm_mysqld-instance_attributes-binary" name="binary" value="/usr/bin/mysqld_safe"/>
                <nvpair id="prm_mysqld-instance_attributes-replication_user" name="replication_user" value="replicate"/>
                <nvpair id="prm_mysqld-instance_attributes-replication_passwd" name="replication_passwd" value="bsp12345"/>
              </instance_attributes>
              <operations>
                <op id="prm_mysqld-start-0" interval="0" name="start" timeout="120s"/>
                <op id="prm_mysqld-stop-0" interval="0" name="stop" timeout="120s"/>
                <op id="prm_mysqld-monitor-20s" interval="20s" name="monitor" timeout="30s"/>
              </operations>
            </primitive>
          </master>
          <group id="group_zabbix">
            <primitive class="lsb" id="mysqld" type="mysqld">
              <operations>
                <op id="mysqld-start-0" interval="0" name="start" timeout="60">
                  <instance_attributes id="mysqld-start-0-instance_attributes">
                    <nvpair id="mysqld-start-0-instance_attributes-prereq" name="prereq" value="fencing"/>
                    <nvpair id="mysqld-start-0-instance_attributes-on_fail" name="on_fail" value="restart"/>
                  </instance_attributes>
                </op>
                <op id="mysqld-monitor-10" interval="10" name="monitor" timeout="60">
                  <instance_attributes id="mysqld-monitor-10-instance_attributes">
                    <nvpair id="mysqld-monitor-10-instance_attributes-on_fail" name="on_fail" value="restart"/>
                  </instance_attributes>
                </op>
                <op id="mysqld-stop-0" interval="0" name="stop" timeout="60">
                  <instance_attributes id="mysqld-stop-0-instance_attributes">
                    <nvpair id="mysqld-stop-0-instance_attributes-on_fail" name="on_fail" value="ignore"/>
                  </instance_attributes>
                </op>
              </operations>
            </primitive>
            <primitive class="lsb" id="httpd" type="httpd">
              <operations>
                <op id="httpd-start-0" interval="0" name="start" timeout="60">
                  <instance_attributes id="httpd-start-0-instance_attributes">
                    <nvpair id="httpd-start-0-instance_attributes-prereq" name="prereq" value="fencing"/>
                    <nvpair id="httpd-start-0-instance_attributes-on_fail" name="on_fail" value="restart"/>
                  </instance_attributes>
                </op>
                <op id="httpd-monitor-10" interval="10" name="monitor" timeout="60">
                  <instance_attributes id="httpd-monitor-10-instance_attributes">
                    <nvpair id="httpd-monitor-10-instance_attributes-on_fail" name="on_fail" value="restart"/>
                  </instance_attributes>
                </op>
                <op id="httpd-stop-0" interval="0" name="stop" timeout="60">
                  <instance_attributes id="httpd-stop-0-instance_attributes">
                    <nvpair id="httpd-stop-0-instance_attributes-on_fail" name="on_fail" value="ignore"/>
                  </instance_attributes>
                </op>
              </operations>
            </primitive>
            <primitive class="lsb" id="zabbix_server" type="zabbix_server">
              <operations>
                <op id="zabbix_server-start-0" interval="0" name="start" timeout="60">
                  <instance_attributes id="zabbix_server-start-0-instance_attributes">
                    <nvpair id="zabbix_server-start-0-instance_attributes-prereq" name="prereq" value="fencing"/>
                    <nvpair id="zabbix_server-start-0-instance_attributes-on_fail" name="on_fail" value="restart"/>
                  </instance_attributes>
                </op>
                <op id="zabbix_server-monitor-10" interval="10" name="monitor" timeout="60">
                  <instance_attributes id="zabbix_server-monitor-10-instance_attributes">
                    <nvpair id="zabbix_server-monitor-10-instance_attributes-on_fail" name="on_fail" value="restart"/>
                  </instance_attributes>
                </op>
                <op id="zabbix_server-stop-0" interval="0" name="stop" timeout="60">
                  <instance_attributes id="zabbix_server-stop-0-instance_attributes">
                    <nvpair id="zabbix_server-stop-0-instance_attributes-on_fail" name="on_fail" value="ignore"/>
                  </instance_attributes>
                </op>
              </operations>
            </primitive>
          </group>
        </resources>
        <constraints>
          <rsc_colocation id="zabbix_master" rsc="ms_mysqld" rsc-role="Master" score="INFINITY" with-rsc="group_zabbix"/>
          <rsc_order first="ms_mysqld" first-action="promote" id="mysql_master" score="INFINITY" then="group_zabbix" then-action="start"/>
        </constraints>
        <rsc_defaults>
          <meta_attributes id="rsc-options">
            <nvpair id="rsc-options-resource-stickiness" name="resource-stickiness" value="INFINITY"/>
            <nvpair id="rsc-options-migration-threshold" name="migration-threshold" value="1"/>
          </meta_attributes>
        </rsc_defaults>
      </configuration>
    </cib>
    

    ● 上記で作成したcib.xmlをheartbeatを起動したまま以下のコマンドで置き換えます。

    # cibadmin --replace --xml-file cib.xml.mysql_repl
    

    ● そうするとすぐにheartbeat側で反映されます。

    Online: [ zabbixcluster-1 zabbixcluster-2 ]
    
     Master/Slave Set: ms_mysqld
         Masters: [ zabbixcluster-1 ]
         Slaves: [ zabbixcluster-2 ]
     Resource Group: group_zabbix
         mysqld     (lsb:mysqld):   Started zabbixcluster-1
         httpd      (lsb:httpd):    Started zabbixcluster-1
         zabbix_server      (lsb:zabbix_server):    Started zabbixcluster-1
    

    heartbeatで用意されているOCFを使うとMySQLプロセスの他にMaster/Slaveの状態も監視して、フェイルオーバー時に自動で「CHANGE MASTER」迄実行してMasterとSlaveの切替をしてくれます。heartbeatのcolocationとorderで指定する事によって、MySQLがMasterで動いている方でZabbix、httpdを起動するクラスタが構成出来ます。(片系が壊れてもMasterで動いている方で稼働します。)

    ● MySQLレプリケーションで片系故障時

    Online: [ zabbixcluster-2 ]
    
     Master/Slave Set: ms_mysqld
         Masters: [ zabbixcluster-2 ]
         Stopped: [ prm_mysqld:0 ]
     Resource Group: group_zabbix
         mysqld     (lsb:mysqld):   Started zabbixcluster-2
         httpd      (lsb:httpd):    Started zabbixcluster-2
         zabbix_server      (lsb:zabbix_server):    Started zabbixcluster-2
    

    MySQLに障害が発生して長時間Slaveが止まっていたり、何等かの理由でMySQLが起動してもSlave側が同期してくれていない場合があります。この時pacemakerからはMaster/Slaveとして動作しているように見える為異常を検知しません。MySQLにログインしてSLAVEのステータス確認コマンドを実行しないとわかりません。

    ● スレーブの状態確認コマンド(スレーブ側で実行)

    mysql> show slave status\G
    

    ● コマンド結果

                   Slave_IO_State: Waiting for master to send event
                      Master_Host: zabbixcluster-2
                      Master_User: replicate
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: mysql-bin.000136
              Read_Master_Log_Pos: 455117
                   Relay_Log_File: mysqld-relay-bin.000002
                    Relay_Log_Pos: 455263
            Relay_Master_Log_File: mysql-bin.000136
                 Slave_IO_Running: Yes
                Slave_SQL_Running: Yes
                  Replicate_Do_DB:
              Replicate_Ignore_DB:
               Replicate_Do_Table:
           Replicate_Ignore_Table:
          Replicate_Wild_Do_Table:
      Replicate_Wild_Ignore_Table:
                       Last_Errno: 0
                       Last_Error:
                     Skip_Counter: 0
              Exec_Master_Log_Pos: 455117
                  Relay_Log_Space: 455420
                  Until_Condition: None
                   Until_Log_File:
                    Until_Log_Pos: 0
               Master_SSL_Allowed: No
               Master_SSL_CA_File:
               Master_SSL_CA_Path:
                  Master_SSL_Cert:
                Master_SSL_Cipher:
                   Master_SSL_Key:
            Seconds_Behind_Master: 0
    Master_SSL_Verify_Server_Cert: No
                    Last_IO_Errno: 0
                    Last_IO_Error:
                   Last_SQL_Errno: 0
                   Last_SQL_Error:
      Replicate_Ignore_Server_Ids:
                 Master_Server_Id: 2
    1 row in set (0.00 sec)
    

    重要なところは、

                 Slave_IO_Running: Yes
                Slave_SQL_Running: Yes
    

    の2つがYesとなっていないとMaster/Slave動作出来ていても実際はレプリケーションされていません。(他にもレプリの遅延時間とか見ないとなりませんが、とりあえずこの2つがYesでないとはじまりませんので。)Master側は動いているので監視は継続されますが、フェイルオーバーした際に不整合でZabbixがおかしくなります。

    この部分をZabbixで監視します。Slave側のMySQLへ接続して「show slave status\G」を実行するスクリプトを作成してZabbixの外部チェックで監視します。内容はSlave側のMySQLへ接続して「show slave status\G」を実行するものなら何でも良いです。本構成ではZabbixはMySQLがMasterで動作しているサーバで動くようになっていますのでフェイルオーバー後も問題無くSlaveの状態監視を継続出来ます。

    ※ 双方向で「show slave status\G」が実行出来るように権限設定しておく必要があります。

    スクリプトはこんな感じのものでも期待した動作してくれます。

    #!/bin/sh
    
    SLAVEHOST=`sudo /usr/sbin/crm_mon -1 | grep Slaves | sed 's/^  *//g' | awk '{print $3}'`
    STATUS="show slave status\\G"
    
    case "$1" in
    io)
    mysql -h $SLAVEHOST -e "$STATUS" | grep -w "Slave_IO_Running" | grep "Yes" | sed 's/^  *//g'
    ;;
    sql)
    mysql -h $SLAVEHOST -e "$STATUS" | grep -w "Slave_SQL_Running" | grep "Yes"| sed 's/^  *//g'
    ;;
    esac
    

    ● ZabbixでのSlave状態監視画面
    slavestatus

    これでSlave側の同期していない状態を検知出来ます。障害検知したら手動でMySQLレプリケーションの不整合を修正します。修正パターンが何パターンかありここの自動化は見合わせました。(無理に自動化するとトドメさしかねない。。)

    以上で3回に渡ってAWS上のZabbix冗長構成を、

    ● Pacemaker + RDS (1回目)
    ● Pacemaker + DRBD (2回目)
    ● Pacemaker + MySQLレプリケーション(3回目)

    のパターンで構築する方法のご紹介を終了します。

    [Docker] MySQLコンテナと連携したTomcatコンテナのデータソース設定を動的に行うメモ

    | コメントをどうぞ

    Dockerにはコンテナ同士をリンクする機能があり、IPアドレスやポート番号などの情報をリンク先コンテナに渡すことができます。

    この機能を使って、MySQLコンテナから渡される接続情報をTomcatコンテナのデータソース設定として動的に定義する方法を調査してみました。

    以下はTomcatコンテナ “tomcat_test” を作成し、MySQLコンテナ “some-mysql” をリンクするコマンドです。

    docker run --link some-mysql:mysql -it -p 8888:8080 --name tomcat_test tomcat:7.0 /bin/bash

    Dockerイメージはオフィシャルで提供されているものを利用しています。

    printenv で確認すると、以下のような環境変数が追加されていることが確認できます。

    MYSQL_ENV_MYSQL_MAJOR=5.6
    MYSQL_ENV_MYSQL_VERSION=5.6.22
    MYSQL_ENV_MYSQL_ROOT_PASSWORD=mysecretpassword
    MYSQL_PORT_3306_TCP=tcp://172.17.0.9:3306
    MYSQL_PORT_3306_TCP_ADDR=172.17.0.9
    MYSQL_PORT_3306_TCP_PORT=3306
    MYSQL_PORT_3306_TCP_PROTO=tcp
    MYSQL_PORT=tcp://172.17.0.9:3306
    MYSQL_NAME=/tomcat_test/mysql

    続きを読む

    Amazon Linux + Tomcat7のJDBC接続でBasicDataSourceFactoryがないというエラー

    | コメントをどうぞ

    Amazon LinuxにTomcat7をyumでインストールして、MySQLと接続するアプリケーションを起動したところ、以下のようなエラーが出ました。

    Caused by: java.lang.ClassNotFoundException: org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory
    

    参考URL

    解決策として、フォーラムの以下の投稿が参考になりました。
    https://forums.aws.amazon.com/thread.jspa?messageID=394470

    続きを読む