2011年11月24日木曜日

HAProxy(1.4)でMemcachedの負荷分散(障害時の切り離しも)

スズキです。

こちらのMySQLに引き続き、
HAProxy(1.4)でMySQLの自動フェイルオーバーにあわせて接続先を変更
Memcachedも試してみました。

HAProxyの設定ファイル(/etc/haproxy/haproxy.cfg)は下記のようにしています。

global
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
    stats socket /var/lib/haproxy/stats

defaults
    mode                    tcp
    log                     global
    retries                 3
    timeout connect         10s
    timeout client          1m
    timeout server          1m

listen memcache
    bind 0.0.0.0:11212
    mode tcp
    balance roundrobin
    server memcache1 suz-lab-ha1:11211 check port 11211
    server memcache2 suz-lab-ha2:11211 check port 11211

上記で、Memcachedの負荷分散や障害時の切り離しが確認できました。
Repcachedを利用すれば、障害時キャッシュのロストも防げると思います。

全部、ローカルHAProxy経由にすればいいのか!?
--------
http://www.suz-lab.com

HAProxy(1.4)でMySQLの自動フェイルオーバーにあわせて接続先を変更

スズキです。

下記で自動フェイルオーバーするMySQLができたので、
VPC上のEC2(CentOS 6.0)でDRBD(8.3)とHeartbeat(3.0)とMySQL(5.5)
次は、それに合わせて接続先を変更する仕組みを考えます。

EC2はVPCでも仮想IPアドレスが利用できないので、
まず、hostsファイルを変更したり、内部DNSをたて、DNSレコードを変更したりして、
自動フェイルオーバーに合わせた接続変更(接続ホスト名のIPアドレスを変更)を
行う方法を考えると思います。

ただ、上記の方法は、ミドルウェアのインストール&設定のみで完結せず、
多少の仕組みの作り込みが必要になってしまうはずです。

今回はMySQLに接続するサーバには必ずHAProxyをインストールし、
アプリケーションはlocalhostのMySQL(HAProxy)に接続し、
フェイルオーバーに伴う接続先変更はHAProxyに任せる方法を試してみました。

まずは、HAProxyのインストールです。
# yum -y install haproxy

"haproxy.cfg"は下記のようにしました。
# cat /etc/haproxy/haproxy.cfg 
global
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
    stats socket /var/lib/haproxy/stats
defaults
    mode                    tcp
    log                     global
    retries                 3
    timeout connect         10s
    timeout client          1m
    timeout server          1m
listen mysql
    bind 0.0.0.0:3306
    mode tcp
    option mysql-check
    balance roundrobin
    server mysql1 suz-lab-ha1:3306 check port 3306
    server mysql2 suz-lab-ha2:3306 check port 3306

ただし、このままだと、HAProxyからMySQLへのヘルスチェックで、
MySQLがHAProxyからの接続をブロックしてしまうので、
MySQLの設定を下記のようにしておきます。

# cat /etc/my.cnf
[mysqld]
...
max_connect_errors=999999999
...

上記のHAProxy経由でMySQLに接続すると、MySQL側をフェイルオーバーさせても、
数秒でHAProxyが接続先をフェイルオーバー後のMySQLに変更してくれ、
アプリケーションは問題なくMySQLに接続し続けることができるようになります。

そして、この方法なら、ミドルウェア(HAProxy)のインストール&設定で、
自動フェイルオーバーにあわせた接続先変更が可能です。

この方法が一番いいような...
--------
http://www.suz-lab.com

2011年11月23日水曜日

VPC上のEC2(CentOS 6.0)でDRBD(8.3)とHeartbeat(3.0)とMySQL(5.5)

スズキです。

下記に続いてMySQL連携も試してみます。
VPC上のEC2(CentOS 6.0)でDRBD(8.3)とHeartbeat(3.0)
DRBD/Heartbeat/MySQLの連携に関しては、下記ですでに紹介もしています。
そろそろDRBDに挑戦 (MySQL連携編)

【suz-lab-ha1/suz-lab-ha2で実行】

▼mysqlサーバのインストール
# yum -y install mysql-server

▼/var/lib/mysqlをdrbdのファイルシステムにシンボリックリンク
# chown mysql.mysql /mnt/drbd/mysql
# rmdir /var/lib/mysql
# ln -s /mnt/drbd/mysql /var/lib/mysql

【suz-lab-ha1で実行】

▼データベースの作成
# /etc/init.d/mysqld start
MySQL データベースを初期化中:  Installing MySQL system tables...
OK
Filling help tables...
OK
...
※suz-lab-ha1のDRBDがプライマリとします。

▼haresourcesファイルの修正(mysqld追加)
# cat /etc/ha.d/haresources
suz-lab-ha1 drbddisk::mysql Filesystem::/dev/drbd0::/mnt/drbd/mysql mysqld

【suz-lab-ha2で実行】

▼haresourcesファイルの修正(mysqld追加)
# cat /etc/ha.d/haresources
suz-lab-ha2 drbddisk::mysql Filesystem::/dev/drbd0::/mnt/drbd/mysql mysqld

【suz-lab-ha1/suz-lab-ha2で実行】
# /etc/init.d/heartbeat restart

この状態だと、suz-lab-ha1のDRBDがプライマリで、MySQLが起動しています。
(suz-lab-ha2のMySQLは起動していません)

suz-lab-ha1のHeartbeatを停止すると、suz-lab-ha2のDRBDがプライマリになり、
その後、MySQLも起動します。(自動フェイルオーバーします)

次はHAProxyでMySQLの接続先が切り替わることの確認です。
--------
http://www.suz-lab.com

VPC上のEC2(CentOS 6.0)でDRBD(8.3)とHeartbeat(3.0)

スズキです。

下記に続いてHeartbeat連携も試してみます。
VPC上のEC2(CentOS 6.0)でDRBD(8.3)
Heatbeatに関しては、すでに下記で紹介もしています。

【suz-lab-ha1/suz-lab-ha2で実行】

▼heartbeatのインストール
# yum -y install heartbeat

▼heartbeatの設定ファイル作成
# cd /etc/ha.d
# cp /usr/share/doc/heartbeat-3.0.4/ha.cf ./
# cp /usr/share/doc/heartbeat-3.0.4/authkeys ./
# cp /usr/share/doc/heartbeat-3.0.4/haresources ./

▼authkeysファイルの編集
# cat authkeys
auth 1
1 crc
#2 sha1 HI!
#3 md5 Hello!

▼authkeysファイルのパーミッション変更
# chmod 600 authkeys

【suz-lab-ha1で実行】

▼ha.cfファイルの編集
# cat ha.cf
debugfile /var/log/ha-debug
logfile /var/log/ha-log
logfacility     local0
keepalive 2
deadtime 30
warntime 10
initdead 120
udpport 694
ucast eth0 10.0.1.87
auto_failback off
node    suz-lab-ha1
node    suz-lab-ha2

▼haresourcesファイルの編集
# cat haresources
suz-lab-ha1 drbddisk::mysql Filesystem::/dev/drbd0::/mnt/drbd/mysql


【suz-lab-ha2で実行】

▼ha.cfファイルの編集
# cat ha.cf
debugfile /var/log/ha-debug
logfile /var/log/ha-log
logfacility     local0
keepalive 2
deadtime 30
warntime 10
initdead 120
udpport 694
ucast eth0 10.0.0.228
auto_failback off
node    suz-lab-ha1
node    suz-lab-ha2

▼haresourcesファイルの編集
# cat haresources
suz-lab-ha2 drbddisk::mysql Filesystem::/dev/drbd0::/mnt/drbd/mysql

【suz-lab-ha1/suz-lab-ha2で実行】

▼heartbeatの起動
# /etc/init.d/heartbeat start

上記で、DRBDがプライマリーのHeartbeat(suz-lab-ha1)をストップすると、
自動的にsuz-lab-ha2のDRBDがプライマリーになり、マウントされることが確認できます。

次はMySQLをこの上にのせないと...
--------
http://www.suz-lab.com

VPC上のEC2(CentOS 6.0)でDRBD(8.3)

スズキです。

以前、下記のように物理サーバで試していたのですが、
そろそろDRBDに挑戦(設定&稼働編)
それをVPC上のEC2でも試して見ました。

環境は下記のとおりです。
▼suz-lab-ha1
IP: 10.0.0.54(subnet: 10.0.0.0/24: a zone)
EBS: /dev/xvdf1

▼suz-lab-ha2
IP: 10.0.1.36(subnet: 10.0.1.0/24: b zone)
EBS: /dev/xvdf1

AMIは当然、
SUZ-LAB謹製 CentOS AMI (6.0.4 32bit ap-northeast-1)
です!

▼hostnameの設定

【suz-lab-ha1で実行】
# cat /etc/sysconfig/network
NETWORKING=yes
NETWORKING_IPV6=no
HOSTNAME=suz-lab-ha1

【suz-lab-ha2で実行】
# cat /etc/sysconfig/network
NETWORKING=yes
NETWORKING_IPV6=no
HOSTNAME=suz-lab-ha2

【suz-lab-ha1/suz-lab-ha2で実行】

▼DRBD8.3のインストール
# yum -y install drbd83-utils kmod-drbd83
※8.4は、なんかうまくいかなかったので...

▼hostsファイルの設定
# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain
10.0.0.54   suz-lab-ha1
10.0.1.36   suz-lab-ha2

▼drbdファイルの設定
# cat /etc/drbd.d/mysql.res
resource mysql {
    on suz-lab-ha1 {
        device /dev/drbd0;
        disk /dev/xvdf1;
        address 10.0.0.228:7789;
        meta-disk internal;
    }
    on suz-lab-ha2 {
        device /dev/drbd0;
        disk /dev/xvdf1;
        address 10.0.1.87:7789;
        meta-disk internal;
    }
}

▼drbdの構築
# drbdadm create-md mysql
Writing meta data...
initializing activity log
NOT initializing bitmap
New drbd meta data block successfully created.
success

▼drbdの起動

【suz-lab-ha1で実行】
# /etc/init.d/drbd start
Starting DRBD resources: [ d(mysql) ]........

【suz-lab-ha2で実行】
# /etc/init.d/drbd start
Starting DRBD resources: [ d(mysql) n(mysql) ].

※両方ほぼ同時に起動する必要があります。

【suz-lab-ha1で実行】

▼ファイルシステムの作成
# drbdsetup /dev/drbd0 primary -o
# mkfs.ext4 /dev/drbd0 
mke2fs 1.41.12 (17-May-2010)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=0 blocks, Stripe width=0 blocks
65536 inodes, 262127 blocks
13106 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=268435456
8 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks: 
 32768, 98304, 163840, 229376

Writing inode tables: done                            
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 28 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.

▼ファイルシステムのマウント
# mkdir -p /mnt/drbd/mysql
# cat /etc/fstab
/dev/xvda1      /               ext4   defaults       1 1
none            /proc           proc   defaults       0 0
none            /sys            sysfs  defaults       0 0
none            /dev/pts        devpts gid=5,mode=620 0 0
none            /dev/shm        tmpfs  defaults       0 0
/mnt/swap/0.img swap            swap   defaults       0 0
/dev/drbd0      /mnt/drbd/mysql ext4   defaults       0 0
# mount /mnt/drbd/mysql

これで設定完了です。

下記の最後の方に記述しているテストも試して見ましたが、
そろそろDRBDに挑戦(設定&稼働編)
問題ありませんでした。

次は、Heartbeat連携!
--------
http://www.suz-lab.com

2011年11月22日火曜日

SUZ-LAB謹製 CentOS AMI (6.0.4 32bit ap-northeast-1)

スズキです。

下記をアップデートしました。
SUZ-LAB謹製 CentOS AMI (6.0.3 32bit ap-northeast-1)
AMIを「suz」で検索してもらえれば、
811118151095/suz-lab_ebs_centos-core-i386-6.0.4
として見つかるはずです。

アップデート内容は下記となります。

パッケージのアップデート
# cat /etc/yum.conf 
[main]
...
exclude=kernel*
...
# yum -y update
※カーネルアップデートすると起動しなくなったので、カーネルは除外しています。

ローケール関係を日本語に
CentOS(6.0)でロケール関係の設定

ELRepoをyumリポジトリ追加
CentOS6.0にDRBDをインストール

Enjoy!
--------
http://www.suz-lab.com

CentOS6.0にDRBDをインストール

スズキです。

EC2上でDRBDの動作確認をすることになったので、
まずはCentOS6.0にDRBDをインストールしてみました。

ちなみにCentOS5.xな場合は、以前、下記のように本ブログで紹介しています。

CentOS6.0の場合は、下記のように"yum"リポジトリの追加から必要となります。

# rpm -Uvh http://elrepo.org/elrepo-release-6-4.el6.elrepo.noarch.rpm
# cat /etc/yum.repos.d/elrepo.repo
...
[elrepo]
...
enabled=1
...
[elrepo-extras]
...
enabled=1
...
※"elrepo-extras"も"enabled=1"にしています。

すると、下記のようにリポジトリが追加されていることが確認できます。

# yum repolist
...
repo id         repo name                                                status
base            CentOS-6 - Base                                          4558
cr              CentOS-6 - CR                                            1705
elrepo          ELRepo.org Community Enterprise Linux Repository - el6    127
elrepo-extras   ELRepo.org Community Enterprise Linux Repository - el6      6
epel            Extra Packages for Enterprise Linux 6 - i386             5391
extras          CentOS-6 - Extras                                           1
remi            Les RPM de remi pour Enterprise Linux 6 - i386            403
rpmforge        RHEL 6 - RPMforge.net - dag                              4142
updates         CentOS-6 - Updates                                        783
...

ここまで準備できたら、下記のように、いつもの"yum"コマンドでインストールできます。

# yum -y install drbd84-utils kmod-drbd84

次はVPC上のEC2でDRBDの実験です。
--------
http://www.suz-lab.com

2011年11月17日木曜日

#サンタクラウドの集計(その2)

スズキです。

下記に引き続き、少しづつ進めています。
#サンタクラウドの集計(その1)

該当Tweetの取得は検索APIを利用しているのですが、時間が経つと
昔のTweetが検索できなくなってしまう可能性があります。

なので前回(#AWS77)は、Tweetデータを"togetter"から取得(スクレイピング)を
していたのですが、スクレイピングは好きじゃないので、今回は前回のTweetデータに
新規Tweetを追加する形にしました。

具体的には検索からのTweetの集合から前回のTweet集合の差分をとり、
その差分を前回のTweet集合に追加したものを、最新のTweet集合としています。
そして、その処理を一時間に一回実行しています。

最終的なスクリプトは下記のような感じになっています。

// 初期設定
require_once("/opt/aws/php/default/sdk.class.php");
date_default_timezone_set("Asia/Tokyo");
define("AWS_KEY"       , "AAAAAAAAAAAAAAAAAAAA");
define("AWS_SECRET_KEY", "ssssssssssssssssssssssssssssssssssssssss");
$s3 = new AmazonS3();
$s3->set_region(AmazonS3::REGION_APAC_NE1);

// 前回作成したランキング情報の取得
$response = $s3->get_object(
    "www.suz-lab.com",
    "santacloud/tweet.json",
    array("curlopts" => array(CURLOPT_SSL_VERIFYPEER => false))
);
$ranking_old = json_decode($response->body, true);

// 最新のランキング情報の取得
$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
$keyword = "%23jawsug%20%23%E3%82%B5%E3%83%B3%E3%82%BF%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89"; 
$page    = 1;
$ranking_current = array();
do {
    curl_setopt($curl, CURLOPT_URL, "http://search.twitter.com/search.json?result_type=recent&rpp=100&page=$page&q=$keyword");
    $tweet_json   = curl_exec($curl);
    $tweet_object = json_decode($tweet_json, true);
    foreach($tweet_object["results"] as $tweet) {
        if(strpos($tweet["text"], "RT ") === false) {
            array_push($ranking_current, array(
                "tweet_id"         => $tweet["id_str"],
                "tweet_text"       => $tweet["text"],
                "tweet_user_name"  => $tweet["from_user"],
                "tweet_user_image" => $tweet["profile_image_url"],
            ));
        }
    }
    $page++;
} while(count($tweet_object["results"]));

// 前回のランキング情報と最新のランキング情報の差を取得し、その差を前回のランキングに追加
$ranking_diff = array_udiff($ranking_current, $ranking_old, function($a, $b) {
    if($a["tweet_id"] === $b["tweet_id"]) {
        return 0;
    } else {
        return ($a["tweet_id"] > $b["tweet_id"]) ? 1 : -1;
    }
});
$ranking_tmp = array_merge($ranking_diff, $ranking_old);

// Retweet情報を取得
$ranking = array();
foreach($ranking_tmp as $tweet) {
    curl_setopt($curl, CURLOPT_URL, "http://api.twitter.com/1/statuses/" . $tweet["tweet_id"] . "/retweeted_by.json");
    $retweet_json   = curl_exec($curl);
    $retweet_object = json_decode($retweet_json, true);
    if(!isset($retweet_object["error"])) {
        $tweet["retweet_users"] = array();
        foreach($retweet_object as $retweet) {
            array_push($tweet["retweet_users"], array(
                "retweet_user_name"  => $retweet["screen_name"],
                "retweet_user_image" => $retweet["profile_image_url"]
            ));
        }
        array_push($ranking, $tweet);
    }
}

// Retweet数順にソート
usort($ranking, function($a, $b) {
    if(count($a["retweet_users"]) == count($b["retweet_users"])) {
        return 0;
    } else {
        return (count($a["retweet_users"]) > count($b["retweet_users"])) ? -1 : 1;
    }
});

// 最新のランキング情報をS3にアップロード
$response = $s3->create_object("www.suz-lab.com", "santacloud/tweet.json", array(
    "body"        => json_encode($ranking),
    "acl"         => AmazonS3::ACL_PUBLIC,
    "contentType" => "text/javascript",
    "curlopts"    => array(CURLOPT_SSL_VERIFYPEER => false)
));

// 最新のランキング情報をアーカイブとしてS3にアップロード
$date = date("YmdHis");
$response = $s3->create_object("www.suz-lab.com", "santacloud/tweet/$date.json", array(
    "body"        => json_encode($ranking),
    "acl"         => AmazonS3::ACL_PUBLIC,
    "contentType" => "text/javascript",
    "curlopts"    => array(CURLOPT_SSL_VERIFYPEER => false)
));

次は下記を改善する予定です。
  • 同じようなTweetをマージ
  • TwitterAPIの100回/時の実行制限対策

今のTweetは80弱なので、そとそろ100回/時の対策をしないと...
--------
http://www.suz-lab.com

2011年11月15日火曜日

#サンタクラウドの集計(その1)

スズキです。

#サンタクラウド の集計ページはS3上で公開しています。
つまり、S3のWebサイトホスティング機能を使っています。

そして、一時間に一回更新されるランキングの部分は、下記のようなスクリプトで
適当なEC2でランキングデータのJSONファイルを毎時作成し、
JavaScriptで読み込んでいます。

// 初期設定
$curl = curl_init();
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
$keyword = "%23jawsug%20%23%E3%82%B5%E3%83%B3%E3%82%BF%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89"; 
$page    = 1;
$ranking = array();

do {

    // 該当するTweetを取得
    curl_setopt($curl, CURLOPT_URL, "http://search.twitter.com/search.json?result_type=recent&rpp=100&page=$page&q=$keyword");
    $tweet_json   = curl_exec($curl);
    $tweet_object = json_decode($tweet_json, true);

    foreach($tweet_object["results"] as $tweet) {

        // RT以外のTweetのRetweetを取得
        if(strpos($tweet["text"], "RT ") === false) {
            curl_setopt($curl, CURLOPT_URL, "http://api.twitter.com/1/statuses/" . $tweet["id_str"] . "/retweeted_by.json");
            $retweet_json   = curl_exec($curl);
            $retweet_object = json_decode($retweet_json, true);

            // Tweetがまだ存在してたら
            if(!isset($retweet_object["error"])) {
                $retweet_users = array();

                // Retweet情報の追加
                foreach($retweet_object as $retweet) {
                    array_push($retweet_users, array(
                        "retweet_user_name"  => $retweet["screen_name"],
                        "retweet_user_image" => $retweet["profile_image_url"]
                    ));
                }

                // Tweet情報の追加
                array_push($ranking, array(
                    "tweet_id"         => $tweet["id_str"],
                    "tweet_text"       => $tweet["text"],
                    "tweet_user_name"  => $tweet["from_user"],
                    "tweet_user_image" => $tweet["profile_image_url"],
                    "retweet_users"    => $retweet_users
                ));
            }
        }
    }

    $page++;
} while(count($tweet_object["results"]));

// Retweet数順にソート
usort($ranking, function($a, $b) {
    if(count($a["retweet_users"]) == count($b["retweet_users"])) {
        return 0;
    } else {
        return (count($a["retweet_users"]) > count($b["retweet_users"])) ? -1 : 1;
    }
});

// JSONファイルにしてS3にアップロード
require_once("/opt/aws/php/default/sdk.class.php");
define("AWS_KEY"       , "AAAAAAAAAAAAAAAAAAAA");
define("AWS_SECRET_KEY", "ssssssssssssssssssssssssssssssssssssssss");
$s3 = new AmazonS3();
$s3->set_region(AmazonS3::REGION_APAC_NE1);

$response = $s3->create_object("www.suz-lab.com", "santacloud/tweet.json", array(
    "body"        => json_encode($ranking),
    "acl"         => AmazonS3::ACL_PUBLIC,
    "contentType" => "text/javascript",
    "curlopts"    => array(CURLOPT_SSL_VERIFYPEER => false)
));

今回は、Tweet情報は"togetter"からでなく、直接Twitterから取得しています。
なので、ほっとくと昔のTweetが取得できなくなってしまうので、早いうちに(今日中に)、
前回のTweet情報に新規分を追加する形にします。

また、TwitterへのAPI接続は一時間に100回しかできないので、Tweetが100以上になると、
対策をしなければいけません...

とりあえず、昔のTweetが消える前に、新規追加形式にしないと...
--------
http://www.suz-lab.com

2011年11月14日月曜日

"AWS SDK for PHP"でS3にファイルアップロードしようとしたら証明書関係のエラー

スズキです。

#サンタクラウド の準備してるときに起きたエラーです。

いつものように下記のコードでS3にファイルをアップロードしようとしたら、

$response = $s3->create_object("www.suz-lab.com", "santacloud/tweet.json", array(
    "body"        => json_encode($ranking),
    "acl"         => AmazonS3::ACL_PUBLIC,
    "contentType" => "text/javascript"
));

次のようなエラーが発生してしまいました。

PHP Fatal error:  Uncaught exception 'RequestCore_Exception' with message 'cURL resource: Resource id #10; cURL error: SSL: certificate subject name '*.s3-ap-northeast-1.amazonaws.com' does not match target host name 'www.suz-lab.com.s3-ap-northeast-1.amazonaws.com' (51)' in /opt/aws/php/1.4.2.1/lib/requestcore/requestcore.class.php:824
Stack trace:
#0 /opt/aws/php/1.4.2.1/services/s3.class.php(723): RequestCore->send_request()
#1 /opt/aws/php/1.4.2.1/services/s3.class.php(1230): AmazonS3->authenticate('www.suz-lab.com', Array)
#2 /opt/suzuki/bin/twitter(38): AmazonS3->create_object('www.suz-lab.com', 'santacloud/twee...', Array)
#3 {main}
  thrown in /opt/aws/php/1.4.2.1/lib/requestcore/requestcore.class.php on line 824

"*.s3-ap-northeast-1.amazonaws.com"の証明書だと、
"www.suz-lab.com.s3-ap-northeast-1.amazonaws.com"にはマッチしない、
というエラーです。
"suz-lab.s3-ap-northeast-1.amazonaws.com"なら問題ないようですが、
バケット名に"."がある場合は、上記のエラーが発生してしまうようです。

回避方法は下記のように、証明書の検証をしないように
"cURL"のオプション(CURLOPT_SSL_VERIFYPEER => false)をつける方法となります。

$response = $s3->create_object("www.suz-lab.com", "santacloud/tweet.json", array(
    "body"        => json_encode($ranking),
    "acl"         => AmazonS3::ACL_PUBLIC,
    "contentType" => "text/javascript",
    "curlopts"    => array(CURLOPT_SSL_VERIFYPEER => false)
));

少し調べてみると、このオプションは
cURL 7.10 以降、デフォルト値は TRUE です。また、 cURL 7.10 以降、デフォルトでインストールされています。
とのことです。

実際にバージョンを調べてみると、下記のとおりで、

# curl --version
curl 7.19.7 (i686-pc-linux-gnu) libcurl/7.19.7 NSS/3.12.7.0 zlib/1.2.3 libidn/1.18 libssh2/1.2.2
Protocols: tftp ftp telnet dict ldap ldaps http file https ftps scp sftp 
Features: GSS-Negotiate IDN IPv6 Largefile NTLM SSL libz 

以前このオプション無しで問題なかったのは、
この"cURL"のバージョンが古かったからだと思います。

とりあえず、解決してよかった...
--------
http://www.suz-lab.com

2011年11月8日火曜日

Mailmanのダイジェストメールを一日一回から一時間に一回にする

スズキです。

"cloudpack"の監視サービスで、一時間に一回アラートメールの
ダイジェストメールを送る必要性が出てきました。

実現手段として、ML(Mailman)のダイジェストメール機能
(一日分のメールを一つのメールにまとめて一日一回送る機能)
を利用することにしたのですが、当然、一日一回を一時間に一回にする必要があります。

といっても、簡単で、ダイジェストメールは下記のcrontabで、
定期的にコマンドを実行することで実現しています。

# cat /etc/cron.d/mailman 
...
# Noon, mail digests for lists that do periodic as well as threshhold delivery.
0 * * * * mailman /usr/lib/mailman/cron/senddigests
...

デフォルトは一日一回になるように設定されているのですが、
上記のように一時間に一回実行されるように変更すれば、
ダイジェストメールも一時間に一回になります。

ちなみに、"/etc/cron.d/mailman"は"/etc/init.d/mailman start"で、
"/usr/lib/mailman/cron/crontab.in"が"/etc/cron.d/mailman"に
コピーされるようになっています。

ですので、恒久的に"cron"の設定を反映する場合は、
"/usr/lib/mailman/cron/crontab.in"も同様に修正する必要があります。

Mailmanはこれで終了。次はML運用方法の整理とSES化...
--------
http://www.suz-lab.com

Mailmanのメールの文章を変更

スズキです。

Mailmanは監視関係で送信しているアラートメールの、1時間ごとダイジェストを
送るために利用しています。
なので、ダイジェストメールの文面も、それように変更したいところです。

文面は下記にテンプレートがあるので、適当なものを修正すればOKです。

# pwd
/usr/lib/mailman/templates/ja
# ls *.txt
adminsubscribeack.txt    bounce.txt    cronpass.txt  invite.txt    nomoretoday.txt  postheld.txt  subauth.txt       unsubauth.txt
adminunsubscribeack.txt  checkdbs.txt  disabled.txt  masthead.txt  postack.txt      probe.txt     subscribeack.txt  userpass.txt
approve.txt              convert.txt   help.txt      newlist.txt   postauth.txt     refuse.txt    unsub.txt         verify.txt

メールのサブジェクトなどは、下記を修正する必要もあります。

# pwd
/usr/lib/mailman/messages/ja/LC_MESSAGES
# ls
mailman.mo  mailman.po

修正は次のように"po"ファイルを編集して、"gettext"パッケージの
msgfmtで"mo"ファイルを更新する形となります。

# yum -y install gettext
# msgfmt mailman.po -o mailman.mo

変更したい文面が、どのファイルにあるかの調査がめんどう...
--------
http://www.suz-lab.com

Mailmanのインストール

スズキです。

監視の仕組みでML的な機能が必要になってしまったので...

早速インストールして起動してみると、エラーです...

# yum -y install mailman
# /etc/init.d/mailman start
mailman を起動中: サイトリスト名がありません: mailman
                                                           [失敗]

"mailman"という名前のMLが無いとのことなので、下記のように作成します。

# /usr/lib/mailman/bin/newlist mailman
Enter the email of the person running the list: alert@cloudpack.jp
Initial mailman password: 
To finish creating your mailing list, you must edit your /etc/aliases (or
equivalent) file by adding the following lines, and possibly running the
`newaliases' program:

## mailman mailing list
mailman:              "|/usr/lib/mailman/mail/mailman post mailman"
mailman-admin:        "|/usr/lib/mailman/mail/mailman admin mailman"
mailman-bounces:      "|/usr/lib/mailman/mail/mailman bounces mailman"
mailman-confirm:      "|/usr/lib/mailman/mail/mailman confirm mailman"
mailman-join:         "|/usr/lib/mailman/mail/mailman join mailman"
mailman-leave:        "|/usr/lib/mailman/mail/mailman leave mailman"
mailman-owner:        "|/usr/lib/mailman/mail/mailman owner mailman"
mailman-request:      "|/usr/lib/mailman/mail/mailman request mailman"
mailman-subscribe:    "|/usr/lib/mailman/mail/mailman subscribe mailman"
mailman-unsubscribe:  "|/usr/lib/mailman/mail/mailman unsubscribe mailman"

Hit enter to notify mailman owner...

そして上記の指示通り、下記のように"aliases"に追記し、

# cat /etc/aliases
...
## mailman mailing list
mailman:              "|/usr/lib/mailman/mail/mailman post mailman"
mailman-admin:        "|/usr/lib/mailman/mail/mailman admin mailman"
mailman-bounces:      "|/usr/lib/mailman/mail/mailman bounces mailman"
mailman-confirm:      "|/usr/lib/mailman/mail/mailman confirm mailman"
mailman-join:         "|/usr/lib/mailman/mail/mailman join mailman"
mailman-leave:        "|/usr/lib/mailman/mail/mailman leave mailman"
mailman-owner:        "|/usr/lib/mailman/mail/mailman owner mailman"
mailman-request:      "|/usr/lib/mailman/mail/mailman request mailman"
mailman-subscribe:    "|/usr/lib/mailman/mail/mailman subscribe mailman"
mailman-unsubscribe:  "|/usr/lib/mailman/mail/mailman unsubscribe mailman"

"newaliases"で反映して、念のためPostfixも再起動して、
Mailmanを起動すると、今度は下記のように無事、成功しました。

# newaliases
# /etc/init.d/postfix restart
Shutting down postfix:                                     [  OK  ]
Starting postfix:                                        
# /etc/init.d/mailman start
Starting mailman:                                          [  OK  ]

これで、アラートメールのダイジェストができる...
--------
http://www.suz-lab.com

2011年11月7日月曜日

iPhone4Sでプレゼンテーション

スズキです。

下記、LTしてきました。
JAWS-UG大阪第4回勉強会LT資料(AWStatsでS3&CloudFrontのアクセス解析)

今回のLTは、iPhone4Sのミラーリング機能を使って、
iPhone4Sを直接プロジェクターにつないで行いました。

プロジェクターにつなぐには、下記のVGAアダプターが必要となります。


実際にプロジェクターに移した資料は、パワーポイントで作成し、
PDFに変換して、Dropboxに入れて、GoodReaderでiPhone側で表示してました。

注意点は2つほどあります。

  • プレゼン中に画面がロックされないように、画面ロックを無効にする。
  • プレゼン中にメールなどの通知がこないようにフライトモードにしておく。

パワーポイントで資料作ってる所がまだダサい感じですが、
これでプレゼンだけならiPhoneのみ持っていけばよくなりました。

Japan AWS User Group (JAWS-UG) - Kyoto勉強会 第2回
もiPhoneでLT予定です。
--------
http://www.suz-lab.com

CentOS(6.0)でロケール関係の設定

スズキです。

CentOS(5.x)では下記のように設定して問題なかったのですが、
CentOSで初期起動時にLANGを設定
下記のCentOS(6.0)ではうまくいきませんでした…
SUZ-LAB謹製 CentOS AMI (6.0.3 32bit ap-northeast-1)

まず、利用できるロケールを確認します。

# locale -a | grep ja_JP
ja_JP
ja_JP.eucjp
ja_JP.ujis
ja_JP.utf8

次に、下記のように、LANGが"ja_JP.utf8"になるように設定します。

# cat /etc/sysconfig/i18n
LANG="ja_JP.utf8"

そして再起動後、下記のようにロケールの状態を確認すると、
警告メッセージが出てしまいました…

# locale
locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: LC_ALL?????????????????????: ??????????????????????
LANG=ja_JP.utf8
LC_CTYPE=UTF-8
LC_NUMERIC="ja_JP.utf8"
LC_TIME="ja_JP.utf8"
LC_COLLATE="ja_JP.utf8"
LC_MONETARY="ja_JP.utf8"
LC_MESSAGES="ja_JP.utf8"
LC_PAPER="ja_JP.utf8"
LC_NAME="ja_JP.utf8"
LC_ADDRESS="ja_JP.utf8"
LC_TELEPHONE="ja_JP.utf8"
LC_MEASUREMENT="ja_JP.utf8"
LC_IDENTIFICATION="ja_JP.utf8"
LC_ALL=

解決策としては、LC_CTYPEも"ja_JP.utf8"になるように設定すると、

# cat /etc/sysconfig/i18n
LANG="ja_JP.utf8"
LC_CTYPE="ja_JP.utf8"

再起動後、下記のように警告メッセージが出なくなります。

# locale
LANG=ja_JP.utf8
LC_CTYPE=ja_JP.utf8
LC_NUMERIC="ja_JP.utf8"
LC_TIME="ja_JP.utf8"
LC_COLLATE="ja_JP.utf8"
LC_MONETARY="ja_JP.utf8"
LC_MESSAGES="ja_JP.utf8"
LC_PAPER="ja_JP.utf8"
LC_NAME="ja_JP.utf8"
LC_ADDRESS="ja_JP.utf8"
LC_TELEPHONE="ja_JP.utf8"
LC_MEASUREMENT="ja_JP.utf8"
LC_IDENTIFICATION="ja_JP.utf8"
LC_ALL=

"SUZ-LAB謹製 CentOS AMI"にも反映しなければ…
--------
http://www.suz-lab.com

2011年11月4日金曜日

JAWS-UG大阪第4回勉強会LT資料(AWStatsでS3&CloudFrontのアクセス解析)

スズキです。

簡単なものですが...


以下は本ブログの関連記事です。

それでは、大阪の皆さん、よろしくお願いします。
--------
http://www.suz-lab.com

JAWS-UG大阪&京都でLTします

スズキです。

下記のJAWS-UG(大阪&京都)でLTします。

Japan AWS User Group (JAWS-UG) - Osaka勉強会 第4回
日時 :2011/11/05 14:00 to 18:00
会場 :テレビ大阪 西館1F (大阪市中央区大手前1-2-15)
AWStatsでS3&CloudFrontのアクセス解析

Japan AWS User Group (JAWS-UG) - Kyoto勉強会 第2回
日時 :2011/11/10 19:30 to 21:30
会場 :株式会社はてな 8F セミナールーム (京都府京都市中京区高宮町206 御池ビル9F)
S3とVarnishを組み合わせた事例的なもの

近頃携わっていた、「cloudpack Tools」の経験をアウトプットする感じでしょうか?

セキュリティグループの状態をテキストに出力してバージョン管理するやつも、
どこかで話したいなー...
--------
http://www.suz-lab.com

2011年11月2日水曜日

Monitでファイルの存在チェック

スズキです。

下記のような設定でファイルの存在確認をし、
存在しない場合は、適当なスクリプトを実行できるようになります。

check file test with path /tmp/test.txt
   start program = "/tmp/start.sh"
   stop program = "/tmp/stop.sh"
   if does not exist then restart
   if 5 restarts within 5 cycles then timeout

上記はファイルが存在しなかったら、
リスタート(start.sh & stop.sh)するようになっています。
そして、5回リスタートしても復旧しなかった場合は、
それ以上リスタートしなくなるようになります。

これを"s3fs"の監視&自動復旧に使おう。
--------
http://www.suz-lab.com

RDS(MySQL)をNagiosで監視

スズキです。

RDSは下記のような感じでNagiosで監視しています。

define host {
    use                    cloudpack-dummy-host
    host_name              suz-lab-rds
    address                suzlab.xxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com
}
define service {
    use                    cloudpack-service
    host_name              suz-lab-rds
    service_description    dns
    check_command          check-dns-ip-cloudpack!xxx.xxx.xxx.xxx
}
define service {
    use                    cloudpack-service
    host_name              suz-lab-rds
    service_description    mysql
    check_command          check-mysql-cloudpack!user!pass
}

define host {
    name                     cloudpack-dummy-host
    use                      generic-host
    register                 0
    check_command            check-dummy-cloudpack
    max_check_attempts       1
    normal_check_interval    5
    retry_check_interval     1
}
define service {
    name                     cloudpack-service
    use                      generic-service
    register                 0
    max_check_attempts       3
    normal_check_interval    5
    retry_check_interval     1
}
define command {
    command_name    check-dummy-cloudpack
    command_line    $USER1$/check_dummy 0
}
define command {
    command_name    check-mysql-cloudpack
    command_line    $USER1$/check_mysql -H $HOSTADDRESS$ -u $ARG1$ -p $ARG2$
}
define command {
    command_name    check-dns-ip-cloudpack
    command_line    $USER1$/check_dns -H $HOSTADDRESS$ -a $ARG1$
}
(ブログ用に調整しているので、このままでは動作しないかもしれません...)

まず、RDSのHOSTとしてのチェックですが、RDS自体はPINGが通らないので、
下記のように"check_dummy"コマンドを利用するようにしています。
Nagiosで"ping"できないHostを監視

次に、下記で紹介したMulti-AZのフェイルオーバー検知として、DNSのチェックも行なっています。
RDSのフェイルオーバーに関する注意点

最後は、通常のMySQLの監視です。

ブログ、全然書いてない...
--------
http://www.suz-lab.com