• DEVLABをリニューアルしました

    2014年 明けましておめでとうございます。

    年末年始の休暇を利用してDEVLABのサイトリニューアルを行いました。

    何気に3回目のリニューアルなのですが、今回はWordPressのテーマ自体を新しく作り直したので結構大規模リニューアルになりました。正月の後半は半ば家族サービス放棄で連日徹夜気味に作業してました・・・(笑)

    また、今回のリニューアルタイミングにてWordPressも3.7.1へアップグレードしました。実は年末にバージョン3.8も出ていたのですが、まだ日本語ローカライズ版は提供されていないので、最新安定版の3.7.1までとしてあります。

    昨年は多忙にかまけて投稿機会を逸してなかなか投稿数が伸びなかった私maenoですが、今年は心機一転して色々と投稿して行きたいと思いますので、本年もDEVLABともども弊社デベロッパーメンバーをよろしくお願いいたします。

    ...
  • MySQLでALTER TABLEでINDEXを作成するときの注意事項

    こんにちは。Ops側の小宮です。
    ある日朝来たら突然開発の方から相談いただいたので、後のために記録しておこうと思います。

    相談内容:
    jenkinsで本番デプロイを行ったが、処理を途中停止した。
    (CakeのDBマイグレーションスクリプトでデプロイした)
    KEYカラムにINDEXをはろうとしたがDBの応答がなくなり接続できなくなった。
    結果としてテーブルが破損したためRDSの時刻指定してロールバックする機能を用いた。
    (ALTERが終わってたかどうかとかはロールバックしたので不明)
    同じレコード数の試験環境で同じ操作をしたら特に異常なくすんなり終わった。
    もう一回同じことを本番でやりたいけどどうしましょう。
    MySQLのバージョンは5.5.27。

    私の個人的認識:
    普通、ALTERする時はロックがかかるから、
    事前に同じ構成と件数の試験環境でかかる時間を見積もってから
    その時間サービス止めてメンテ入れるべきです。
    (※5.5まで。5.6から一部のALTERはオンラインで大丈夫になったようです。)
    sorry表示に切り替えて更新のない環境でやってみましょう。
    (既存のELBの下のwebを全部はずして、別のサブドメインのwebにvhost切ってsorryコンテンツおいてELBに入れるとか)
    途中で強制終了とかするとMyISAMだとテーブル壊れやすそう。
    show full processlist;で現在のクエリとかかってる時間は見ることができる
    けどkillするのは最終手段かと。

    alter table mysqlとか、それプラス5.6とかでググると色々わかります。

    sh2さんのブログを見ると、以下のように書かれています。
    MySQLでALTER TABLE文の進捗状況を確認する - SH2の日記
    -————— MySQLでは
    変更後の定義にもとづく作業用テーブルを作成し、
    変更前のテーブルから作業用テーブルへデータをコピーして、
    最後に二つのテーブルを入れ替えるという仕組みになっています。
    テーブルへのインデックス追加についても、現在のところ大半の
    ケースで内部的にALTER TABLE文が実行されています。

    どこまですすんでるのか確認する方法:
    SHOW GLOBAL STATUS LIKE ‘Handler_write’;
    作業開始前にHandler_writeの値と対象テーブルのレコード件数を控えておけば、
    どこまで処理が進んだのかを確認することができるのです。

    InnoDBならinnotopをつかうと、row operationsのビューにズバリIns/Secがあるので、
    同様にしてALTER TABLEの完了予想が立てられますね。
    差を自分で計算しなくてもいいし、標準的なツールなので便利
    -—————

    ...
  • Mondo Rescue使ってみました(その1)

    おはようございます。インフラの宮下です。

    最近クラウド環境でイメージ作成ばかりしていたので、たまにはオンプレミス環境で
    フルバックアップも取得してみます。


    目次

    1. はじめに
    2. 環境
    3. mondorescueのインストール
    4. サーバのフルバックアップ
    5. 参考サイト

    1.はじめに

    定常的にOSバックアップをとるという案件で無く更新作業の前にバックアップを取得する必要があり色々とバックアップツールを検討していました。商用の検証もいくつか実施したのですが、今回はオープンソースの「Mondo Rescue」というバックアップツールを使ってみたいと思います。
    オープンソースを使う最大の理由は、コストと納期になりますね。計画的な案件であれば商用のバックアップツールの検討が最初になるかと思います。
    「Mondo Rescue」を選択した点としましては、NFSマウント先にファイルが保管できさらにそこからレストアも可能という情報が最大の「それ魅力」です。また、メディアからレストアするのも簡単そう(実際に簡単)なのも良さげでした。

    2.環境

    ロケーション:物理サーバ(富士通製) OS:Red Hat Enterprise Linux Server release 6.4

    3.mondorescueのインストール

    最初にmondorescueのリポジトリを追加します。

    [shell] vi /etc/yum.repos.d/mondorescue.repo [mondorescue] name=rhel 6 x86_64 - mondorescue Vanilla Packages baseurl=ftp://ftp.mondorescue.org//rhel/6/x86_64 #baseurl=ftp://213.30.161.23//rhel/6/x86_64 enabled=0 gpgcheck=1 gpgkey=ftp://ftp.mondorescue.org//rhel/6/x86_64/mondorescue.pubkey #gpgkey=ftp://213.30.161.23//rhel/6/x86_64/mondorescue.pubkey [/shell]

    準備完了と言う事でmondorescueリポジトリを使ってmondo resucue本体をインストールします。
    [shell] # yum install mondo –enablerepo=mondorescue =================================================================================================================================== Package Arch Version Repository Size =================================================================================================================================== Installing: mondo x86_64 3.0.4-1.rhel6 mondorescue 1.3 M Installing for dependencies: afio x86_64 2.5-1.rhel6 mondorescue 81 k buffer x86_64 1.19-4.rhel6 mondorescue 24 k mindi x86_64 2.1.7-1.rhel6 mondorescue 331 k mindi-busybox x86_64 1.18.5-3.rhel6 mondorescue 306 k syslinux x86_64 4.02-4.el6 mondorescue 855 k

    ...
  • natインスタンスの冗長化

    こんにちは。プラットフォームの小宮です。

    他を冗長化してもnatインスタンスを冗長化してないと、
    プライベートセグメントでHAしてるサーバ達がAWSのAPIサーバと通信できなくなって詰むなあと思いまして、
    先人の皆さまの記事を参考にして以下のとおりにしました。

    **・なんとなくどうするか検討
    **

    AmazonLinuxで作っちゃったので、たぶんHeartbeatとか入れづらいし、そもそもheartbaet使う必要ない気がする。
    待機系から監視してaws的にルーティングテーブル挿げ替えるだけでよさそう。

    待機系natインスタンスについて、
     作成しておかないと作成と起動とルーティングテーブル作るところもやらないといけないので切替時間が長くなる。
     インスタンス代がかかるけど起動もしたままがいいと思われ。

    **・とりあえず既存のAmazonLinuxのNATインスタンスの設定をいじるところから
    **
    sudoできるようにしてみる

    # usermod -G wheel user-op
    # id user-op
    uid=500(user-op) gid=501(user-op) groups=501(user-op),10(wheel)
    # visudo
    %wheel  ALL=(ALL)       ALL
    

    コメントはずす。
    他のインスタンスから渡ってsudoできるか確認する

    あとnatインスタンスにpythonのツール入れておく

    メール送信も設定
    AmazonLinuxではsendmailが動いてる模様だった。

    vi /etc/mail/submit.cf
    D{MTAHost}[172.18.10.22]
    Djnat01.hoge.com    ※nat02はそう変える
    service sendmail stop
    chkconfig sendmail off
    yum install mailx
    echo hoge |mail -s testkomi komiyay@xxxxx
    

    ロケールを合わせる

    ...
  • Android : WebView と HttpClient 間で セッションを同期する

    WebViewでログインした後、HttpClientを呼び出すと・・・あれログインしていないジャン! 逆もまたしかり。

    Androidの中ではWebViewとHttpClientは、例えれば別のブラウザとして扱われるようです。

    この件についてはあちらこちらで説明されています。

    [Android]WebView、HTTPClientでSessionを共有する

    HttpClientとWebViewの連携

    が、更になんも考えないで済むように同期だけを行うクラスを作成してみました。よかったらどうぞ。

     

     

     

    [code lang=“java” light=“true”] package your.package;

    import java.util.List;

    import org.apache.http.client.CookieStore; import org.apache.http.cookie.Cookie; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.cookie.BasicClientCookie;

    import android.webkit.CookieManager; import android.webkit.CookieSyncManager;

    /** * HttpClient, WebView間でセッションを同期するためのクラス */ public class SessionSync {

    // COOKIEの送出するドメインを指定します
    private static final String YOUR_DOMAIN = "your.domain";
    
    // COOKIE取得用のドメイン(.をつけてサブドメインもカバーします)
    private static final String COOKIE_DOMAIN = "." + YOUR_DOMAIN;
    // COOKIEを送出するURL
    private static final String COOKIE_URL = "http://" + YOUR_DOMAIN;
    
    // セッションIDを格納するパラメータ名を指定します
    // これはPHPの例
    private static final String SESSID = "PHPSESSID";
    
    /**
     * HttpClient側のセッションIDをWebViewに同期します
     * 
     * @param httpClient セッションを同期するHttpClient
     */
    public static void httpClient2WebView(DefaultHttpClient httpClient) {
        CookieStore store = httpClient.getCookieStore();
        List<Cookie> cookies = store.getCookies();
        CookieManager cookieManager = CookieManager.getInstance();
        for (Cookie cookie : cookies) {
            if (cookie.getDomain().indexOf(COOKIE_DOMAIN) < 0) {
                continue;
            }
            if (!SESSID.equals(cookie.getName())) {
                continue;
            }
            // ここで削除するとsyncしたタイミングでsetしたcookieも
            // 消える場合があるので削除は見合わせ
            // cookieManager.removeSessionCookie();
            String cookieStr = cookie.getName() + "=" + cookie.getValue();
            cookieManager.setCookie(COOKIE_DOMAIN, cookieStr);
            CookieSyncManager.getInstance().sync();
        }
    }
    
    /**
     * WebView側のセッションIDをHttpClientに同期します
     * 
     * @param httpClient セッションを同期するHttpClient
     */
    public static void webView2HttpClient(DefaultHttpClient httpClient) {
    
        String cookie = CookieManager.getInstance().getCookie(COOKIE_URL);
        String[] cookies = cookie.split(";");
        for (String keyValue : cookies) {
            keyValue = keyValue.trim();
            String[] cookieSet = keyValue.split("=");
            String key = cookieSet[0];
            String value = cookieSet[1];
            if (!SESSID.equals(key)) {
                continue;
            }
            BasicClientCookie bCookie = new BasicClientCookie(key, value);
            bCookie.setDomain(COOKIE_DOMAIN);
            bCookie.setPath("/");
            CookieStore store = httpClient.getCookieStore();
            store.addCookie(bCookie);
        }
    }
    

    } [/code]

    ...
  • AWS(VPC)上でheartbeat3でlvsを構成する話

    ※1年以上前の旧い記事なのでご注意ください。※

    こんにちは。プラットフォームの小宮です。

    今回は、ELBは高いのでスモールスタートだからLVSを構築しましょうという趣旨ですすめた記録です。 最初に書くのもなんですが、LVSでWEBもDBも負荷分散しちゃおうぜということだったんですが、結果的にはWEB側はやっぱELBにという話になりました。 (公私混同フラットNWであることを顧客に説明するのが大変だという話とSSLとかスケールとか運用の利便性等で。)

    普段よりは気をつける点: ・環境がAWS(インスタンスを気軽に作り直してChange Source/Dest CheckをDisableにし忘れる等に要注意) ・クライアントがグローバル越しだとDSRできない(エッジルータでENIとIPが合わないパケットが破棄される) ・フラットなNW構成でないとDSRできない(これは普段通りだけど気をつけるポイント) ・複数NWでNATインスタンスが必要になる等の特殊事情(だからNWは1つだけにしました) ・DBはDSR、WEBはNATで分散する ・VIPは使えるけどAWS的な管理上APIサーバと通信して切り替える必要がある ・AWS的な管理上splitbrainは実質起こらないがどっちについてるか確認必要 ・AWS的な制約でマルチキャストは使えないのでHA通信はunicastを用いる ・証明書は負荷分散ライセンスとかでWEBサーバ側で管理する

    目次: ・基本構成 ・分散対象側の基本的な設定 ・ipvsadmで負荷分散の単体テスト ・heartbeatの導入設定 ・ldirectordの導入設定 ・EIP・PrivateIP移動シェル作成 ・リソース設定 ・インスタンスコピーの際の作業 ・切替テスト ・ハマったところ

    ・基本構成

    LVS01(主系) LVS02(待機系) web2台、配信サーバ2台、db2台に対しそれぞれ80と443、3306readを分散

    lvs01:172.18.1.23 lvs02:172.18.1.25 db-r-vip:172.18.1.200 web-vip:172.18.1.199 db-client:web(local) web-client:any(global) real-db:172.18.1.220,221 real-web:172.18.1.33,34 webの分散方式:NAT dbの分散方式:DSR

    設計書ではフロントセグメントとバックセグメントに分かれていたのですが、AWS的な仕様上LVSと組み合わせる為にはフラットにせざるをえませんでした。 ⇒クライアントがグローバル越しのWEBサーバはエッジルータでENIとIPが一致しないパケットが破棄される為分散方式はDSRは無理でNATしか利用できない ※こちらのスライドの17枚目が論拠です。 ⇒分散方式がNATだとリアルサーバは負荷分散サーバをデフォルトGWとして指定する必要がある ⇒NATインスタンスはNICを一つしか持つことができない仕様だがデフォルトGWは同一セグメントでないと指定できない ⇒少なくともWEBはセグメント1つにしないとLVS+VPCでは負荷分散できないがDBとWEBの分散は同じLVSで一緒にやりたいしもうNWセグメントは1つでいいや ⇒バックセグメントが無くてもVPCだしSecurityGroupの設定さえまともなら大丈夫 というような事情によりまして設計書の仕様変更をしないとどうにもなりませんでした。 なんでHAproxyじゃないのかというと、運用上不慣れだからとLVSのがパフォーマンスがいいらしいから。DBだけでもDSRできるのは嬉しいです。

    ...
  • facebookのIPがmod_geoipで拒否される対応

    こんにちは。プラットフォームの小宮です。

    apacheのmod_geoipモジュールで海外を拒否してみたところ、
    Facebookの画像が表示されないということで対応しました。

    ・whoisが必要だが入ってなかったので他の入ってるサーバでパッケージ名を調べて導入

    [shell]$ which whois /usr/bin/whois # rpm -qf /usr/bin/whois jwhois-3.2.2-1

    # yum install jwhois Installed: jwhois.x86_64 0:4.0-19.el6 # which whois /usr/bin/whois[/shell]

    ・fb公式で許可リスト取得方法を確認
    以下のコマンドで定期的に更新リストを取得せよと公式に書いてある。
    App Security - Facebook開発者

    [shell]# whois -h whois.radb.net – ‘-i origin AS32934’ | grep ^route:|awk ‘{print $2}’ 204.15.20.0/22 69.63.176.0/20 ~略~ 69.63.184.0/21 66.220.144.0/20 69.63.176.0/20[/shell] ※65ブロックくらいだった。手作業はあり得ないので何とか自動化を試みる。

    ・設定追加方法の検討
    この辺に追記できるか考えてみる。
    [shell]# cat /etc/cron.monthly/geoip #!/bin/bash wget -q http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz gunzip GeoIP.dat.gz mv -f GeoIP.dat /usr/share/GeoIP/GeoIP.dat[/shell]
    datはバイナリなので自分で追記は困難。軽くググってもそんなことしてる人いない。
    [shell]# file /usr/share/GeoIP/GeoIP.dat /usr/share/GeoIP/GeoIP.dat: data[/shell]

    ...
  • MySQLのMyISAMが混在する環境のバックアップについて注意事項

    ※古い記事ですのでご注意ください※
    こんにちは。小宮です。

    社内のMyISAMテーブルが混在しているサービスにて、
    mysqldumpによるバックアップに失敗しコールドバックアップを取ったが不整合出たという事件について相談うけまして、
    その顛末を記録しがてら注意事項をまとめておきたいと思います。
     (昔軽く伝えた記憶があり皆知ってると思ってたんですが、わかりやすさや伝える力と、
     私と他の人のmysqlに対する愛のレベルが少し異なるという認識が足らなかったようです。
     トラブルは起きるもんだし失敗は挑戦の証で成功の元ですが同じことは繰り返さないようにしないと。)

    何が大切かって、マスタとスレーブのデータの整合性です。
     つまり、
     ⇒バックアップ対象が絶対に更新されてないこと
     ⇒バックアップ取得時点のポジションとバイナリログファイル名が明確であること
     が超重要です。
     MyISAM混在環境では気をつけないと不整合でます。
     不整合でると購入したはずのコンテンツが買われてないように見えるなど割と大変なことになりますね。
     InnoDBだけなら–single-transactionつけとけば不整合は気にしなくて大丈夫です。

    ・mysqldumpに失敗した原因

    mysqldump: Error 1317: Query execution was interrupted when dumping table
    

    このエラーは、
    mysqldumpでデータを読んでる間にクエリーが中断されると出るやつです。Ctrl + Cとかkillでスレッドが殺されたとか。。
    (とTwitterで教えていただきました。ありがとうございます。

    それから、整合性のためにマスタからmysqldumpでデータをとることになったのですが、
    その際にslaveでreplicationを止めて更新がない状態でとっている方法をそのまま用いたのも不整合が起きる原因になりました。
    (MyISAMが混在する環境なのにFLUSH TABLES WITH READ LOCK;をしてなかった)

    MyISAMが混在する環境の場合、トランザクションは使えないので、
    replicaion停止または共有ロックで更新停止が必要になります。

    ex)
    FLUSH TABLES WITH READ LOCK;
    sleepやsyncでロックが終わる(確実に更新停止される)のを待つ
    ポジションとファイル名をとりログに記録する
    mysqldumpする
    UNLOCK TABLES;
    

    特にクエリを中断したりしてない(中断と整合性がごっちゃ)という指摘があったりしてそれは私もよくわからないところですが、
    更新されないようにしてれば中断も起きるはずがないので、対処方法は更新を確実に止める一択かと思います。

    ...
  • AWSメンテナンスでstoppingのまま停止しない障害の対応

    こんにちは。小宮です。

    タイトルどおり障害がありまして、今後の為に記録しておこうかと思います。

    AWSメンテ通知の来たインスタンスをStopしたところ、最終的には6時間強ほどstoppingのままでした。
    今回のインスタンスは、自分で構築したわけでなく、構築メモは残っているもののメンテナンスされていない、
    という状況把握が難しいパターンでした。
    一応上がってるプロセスとポートくらいは控えてから止めましたが、snapshotは撮ってなくAMIも作っていませんでした。

    日本語フォーラムに投稿したところ特に反応がありませんでした。
    聞いた話によると英語フォーラムを使えば15分くらいで対応してもらえることもあるようです。

    その間、stoppingのインスタンスのsnapshotを撮ってAMI作成してそこから新インスタンスを起動してみましたが、
    NICの設定の問題かなにかで接続できませんでした。
    microインスタンスを起動しapacheだけ入れて簡単なsorryページを設置しました。

    stoppingのまま6時間ほど待ったのですが一向に進捗せず、
    しかもサポートにも未加入だったので、サポートに申し込んで以下のように問い合わせをしました。
    (申し込んだら10分くらいで反映されました)。
    -——————————– 1回目:
    EC2 Management ConsoleからサーバをStopしましたが、Stoppingから進みません。
    http://aws.amazon.com/jp/instance-help/
    に従い、何度かForce Stopを試みましたが同様のため、強制停止をお願いしたいです。

    Zone: ap-northeast-1a
    Instance: i-4a42a348

    インスタンスID: i-4a42a348
    -——————————– 2回目:

    先ほどstopしました。何か対応されましたでしょうか。
    同じインスタンスをstartしたいのですが、2回ほどstartしてもstopされてしまいます。
    可能なら起動をお願いできますでしょうか。
    -——————————– 私が時短なので帰宅後、stopedになってから選べたCreateImageでAMIを作って新インスタンスを起動したら接続できたようです。

    翌朝みたらサポートから返事が来ていました。
    -——————————– サポートの方から:
    お問い合わせ誠にありがとうございます。

    i-4a42a348についてお調べしたところ、仮想サーバホストに問題が発生していたためインスタンスの停止にお時間を要しておりました。
    EC2では、長時間StoppingやShuttingdownの状態が続いているインスタンスを自動でクリーンアップする仕組みがございます。
    今回はこちらの仕組みによってインスタンスのStopが行われておりました。
    このたびはご迷惑をおかけし、申し訳ございませんでした。

    インスタンスが起動できない件については、インスタンスとEBSボリュームの関連付けに問題が発生しており、その影響でインスタンスが起動しない状態となっているようです。
    お手数をおかけしますが、インスタンスにアタッチされているボリュームをデタッチ/アタッチして再度インスタンスの起動をお試しいただけるでしょうか。
    通常のデタッチが効かない場合、Force Detachをお試しください。

    ボリュームのデタッチ/アタッチを行ってもインスタンスが起動しない場合、恐れ入りますが、再度ご連絡いただけるでしょうか。

    ご不明な点がありましたらお知らせください。
    よろしくお願いいたします。
    -——————————–

    ...
  • VPC上でPrivateIPアドレスを付け替える

    こんにちは。小宮です。
    ちょっと前にAWSのVPC上でVIP(VirtualIPアドレス)を移動させる需要があって検証したのですが、
    個人的にメモってただけだったのと、質問される機会が数回ありましたので簡単にですが投稿しておきます。

    なんらかのクラスタ構成をVPC上で扱う際、VPC上でPrivateIPアドレスを付け替える必要が生じた場合、
    awsなので切替スクリプトをAPI使うように修正しないと内部はともかく外部から打ったPINGへの応答が帰ってこない。
    つまりVIPが移動したことになりません。

    つまり、以下のような感じになります
    落とすときは、IF落としてかつCLIも実行する
    [shell]ifconfig eth0:1 down ec2-unassign-private-addresses –network-interface eni-4b649*** –secondary-private-ip-address 10.0.0.96[/shell] ※ec2-unassign-private-addressesの短縮バージョンはec2upip
    起動するときも、IF起動かつCLI実行する
    [shell]ifconfig eth0:1 up ec2-assign-private-ip-addresses –network-interface eni-70609*** –secondary-private-ip-address 10.0.0.96[/shell] ※ec2-assign-private-ip-addressesの短縮バージョンはec2apip

    切替元のENI:eni-4b649***
    切替先のENI:eni-70609***

    参考:
    VPC 内の EC2 インスタンス に複数EIPを付与する
    ec2-assign-private-ip-addresses - Amazon Elastic Compute Cloud
    ec2-unassign-private-ip-addresses - Amazon Elastic Compute Cloud

    もし、EIPが紐づいてるENIをデタッチ、アタッチしたい場合、以下のような感じ。(たぶん(自分で試してないです))
    [shell]ec2-detach-network-interface ${eni_attach_id} ec2-attach-network-interface ${ENI_ID} –instance ${target_instance_id} –device-index ${TARGET_DEVICE_INDEX}[/shell]
    加えて、ifupしてip route処理をするといいらしい。
    [shell]ifconfig eth${TARGET_DEVICE_INDEX} up

    ...
  • MySQLのslaveでDuplicate entryエラーが出た時の対処

    こんにちは。小宮です。
    このまえ出たエラーの記録です。

    ・エラーログ

    >show slave status\G
    
                       Last_Error: Error 'Duplicate entry '1133523-2013-08-18 05:03:01' for key 'PRIMARY'' on query. Default database: '*****'. Query: 'INSERT INTO `event_****_logs` ...
    

    時刻がプライマリキーになってるから重複してる感じのエラーなような。
    ログとかセッションとか重複しやすい感じがします。

    念のためmysqldumpのオプションをみたものの、
    --skip-optは入ってないのでoptが勝手について–add-drop-tableは有効なはず。

    MYDUMP_PAR='--single-transaction --dump-slave=2 --routines --include-master-host-port --all-databases'
    

    http://dev.mysql.com/doc/refman/5.5/en/mysqldump.html

    データ投入後にreset slaveしてログファイルとポジション合わせてstart slaveするなど手順には問題がないように見えました。

    お客さまに重複エントリは全部skipしていいか確認いただいたところ
    Insertでプライマリキーが被ってるのは大丈夫なのかは別途開発側で確認でとりあえずskipという話に。
    (対象がサービスで使用していないいので復旧優先ということだったと思います。不整合が気になるならマスタからdump撮り直すのが良いです。)

    ・エラーのクエリをskipする方法
    1つだけなら、

     SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
    

    ですがいっぱいでてくる場合は
    Last_SQL_Errno: 1062
    こちらのエラー番号を指定してスキップ。重複エントリを全部スキップするということです。

    ...
  • Chefで書いたレシピをテストする(serverspec)

    こんにちは。小宮です。

    今回で最終回です。
    前回までにご紹介したレシピのテストするところをご紹介します。Serverspecを用います。

    なぜServerspecがいいかというのは以下リンクにも書いてますが、以下の点がよいと思います。
    ・Chefのテストツールでなく外部のツールなので依存関係がない(puppetでも使える)
    ・設計思想がシンプル簡単に使えるものということで、手間があんまりなくて簡単につかえた

    参考:
    Serverspec at hbstudy #45
    入門Chef Solo落ち穂拾い
    kayac/newbie-training
    「入門Puppet」
    resource_typeのマニュアル
    advanced_tips
    ncstudy#05 ハンズオン資料
    parallel_tests

    ・セットアップ
    バージョン0.3と0.6だとテストの書き方が若干違う感じだったので、マニュアルに沿ってる新しいほうを推奨します。
    [shell]# yum install rubygems

    gem install serverspec rake

    serverspec-init

    Select a backend type:
    
      1) SSH
      2) Exec (local)
    
    Select number: 1
    
    Vagrant instance y/n: y
    Input vagrant instance name: 10.0.0.241
     + spec/10.0.0.241/
     + spec/10.0.0.241/httpd_spec.rb[/shell]
    <br>
    コマンドの実行が終わると、上記のようにいくつかのファイルが作成されます。<br>
    

    [shell]# serverspec-init ~略~ Input target host name: 10.0.0.240 + spec/10.0.0.240/ + spec/10.0.0.240/httpd_spec.rb[/shell]
    SSHを指定し、ターゲットホストを入力すると、ホスト毎のディレクトリが作成されました。

    ...
  • Chefで既存手順のレシピを書く5(munin、zabbix)

    おつかれさまです。小宮です。

    前回に引き続き、munin,zabbixの手順のレシピをご紹介します。レシピはこの記事でおしまいです。
    記事の最後にはレシピの適用方法を記載します。

    ・muninのレシピ

    # cd /opt/src/rpms
    # mkdir -p /root/chef-repo/site-cookbooks/munin/files/default/rpms
    # mkdir -p /root/chef-repo/site-cookbooks/munin/files/default/var/www/html/munin
    # mkdir /root/chef-repo/site-cookbooks/munin/files/default/etc/munin/plugin-conf.d
    # cp -p /etc/munin/munin.conf /root/chef-repo/site-cookbooks/munin/files/default/etc/munin/
    # scp -Cp xxx-web01:/etc/munin/munin-node.conf /root/chef-repo/site-cookbooks/munin/files/default/etc/munin/
    # cp -p /var/www/html/munin/.htaccess /root/chef-repo/site-cookbooks/munin/files/default/var/www/html/munin/
    # cp -p /etc/munin/plugin-conf.d/munin-node /root/chef-repo/site-cookbooks/munin/files/default/etc/munin/plugin-conf.d/
    # tar cf /root/chef-repo/site-cookbooks/munin/files/default/rpms/munin-node-rpm.tar ./munin-node-rpm/
    # tar tf /root/chef-repo/site-cookbooks/munin/files/default/rpms/munin-node-rpm.tar ./munin-node-rpm/
    # tar cf /root/chef-repo/site-cookbooks/munin/files/default/rpms/munin-serv-rpm.tar ./munin-serv-rpm/
    # tar tf /root/chef-repo/site-cookbooks/munin/files/default/rpms/munin-serv-rpm.tar ./munin-serv-rpm/
    
    # cd /root/chef-repo/site-cookbooks/munin/recipes
    # touch munin-node.rb munin-server.rb munin-node-db.rb munin-node-web.rb
    # vi munin-node.rb
        filename = "munin-node-rpm.tar"
        cookbook_file "/tmp/#{filename}" do
          source "rpms/#{filename}"
          mode 0644
        end
    
        package "perl-DBI" do
          not_if "rpm -qa|grep perl-DBI"
          action :install
        end
    
        script "install_munin-node" do
          not_if 'ls /etc/munin/munin-node.conf'
          interpreter "bash"
          user        "root"
          code <<-EOL
            cd /tmp
            tar xf /tmp/#{filename}
            rpm -i /tmp/munin-node-rpm/perl-Dig*
            rpm -i /tmp/munin-node-rpm/perl-{C*,H*,I*,L*,N*,X*,li*}
            rpm -i /tmp/munin-node-rpm/perl-DBD-Pg*
            rpm -i /tmp/munin-node-rpm/munin-*
            cp -p /etc/munin/munin-node.conf{,.org}
          EOL
        end
    
        cookbook_file "/etc/munin/munin-node.conf" do
          source "etc/munin/munin-node.conf"
          mode 0644
        end
    
        script "link_plugins" do
          not_if 'ls /etc/munin/plugins/tcp'
          interpreter "bash"
          user        "root"
          code <<-EOL
            rm -f /etc/munin/plugins/*
            ln -s /usr/share/munin/plugins/cpu /etc/munin/plugins/cpu
            ln -s /usr/share/munin/plugins/if_err_ /etc/munin/plugins/if_err_eth0
            ln -s /usr/share/munin/plugins/if_ /etc/munin/plugins/if_eth0
            ln -s /usr/share/munin/plugins/iostat /etc/munin/plugins/iostat
            ln -s /usr/share/munin/plugins/load /etc/munin/plugins/load
            ln -s /usr/share/munin/plugins/memory /etc/munin/plugins/memory
            ln -s /usr/share/munin/plugins/tcp /etc/munin/plugins/tcp
            ln -s /usr/share/munin/plugins/df /etc/munin/plugins/df
          EOL
        end
    
        service "munin-node" do
          supports :status => true, :restart => true
          action [ :enable, :start ]
        end
    
    
    # vi munin-server.rb
        filename = "munin-serv-rpm.tar"
        cookbook_file "/tmp/#{filename}" do
          source "rpms/#{filename}"
          mode 0644
        end
    
        script "install_munin-serv" do
          not_if 'ls /etc/munin/munin.conf'
          interpreter "bash"
          user        "root"
          code <<-EOL
            tar xf /tmp/#{filename}
            rpm -i /tmp/munin-serv-rpm/*
            cp -p /etc/munin/munin.conf{,.org}
          EOL
        end
    
        cookbook_file "/etc/munin/munin.conf" do
          source "etc/munin/munin.conf"
          mode 0644
        end
    
        service "munin-node" do
          supports :status => true, :restart => true
          action [ :enable, :start ]
        end
    
        cookbook_file "/var/www/html/munin/.htaccess" do
          source "var/www/html/munin/.htaccess"
          mode 0644
        end
    
    # vi munin-node-web.rb
        script "link_plugins_web" do
          not_if 'ls /etc/munin/plugins/apache_accesses'
          interpreter "bash"
          user        "root"
          code <<-EOL
            ln -s /usr/share/munin/plugins/apache_accesses /etc/munin/plugins/apache_accesses
            ln -s /usr/share/munin/plugins/apache_processes /etc/munin/plugins/apache_processes
          EOL
        end
    
        service "munin-node" do
          supports :status => true, :restart => true
          action [ :enable, :restart ]
        end
    
    # vi munin-node-db.rb
        script "link_plugins_db" do
          not_if 'ls /etc/munin/plugins/mysql_threads'
          interpreter "bash"
          user        "root"
          code <<-EOL
            ln -s /usr/share/munin/plugins/mysql_queries /etc/munin/plugins/mysql_queries
            ln -s /usr/share/munin/plugins/mysql_slowqueries /etc/munin/plugins/mysql_slowqueries
            ln -s /usr/share/munin/plugins/mysql_threads /etc/munin/plugins/mysql_threads
          EOL
        end
    
        cookbook_file "/etc/munin/plugin-conf.d/munin-node" do
          source "etc/munin/plugin-conf.d/munin-node"
          mode 0644
        end
    
        service "munin-node" do
          supports :status => true, :restart => true
          action [ :enable, :restart ]
        end
    

    role毎にちがうコマンド実行するとかひとつのレシピ内でやる方法ってあるのかが気になります。ifとかでできるんでしょうか。
    今回はそんな方法はわからなかったので、webとdbそれぞれ用のレシピを分けて作りました。
    roleに適用する順序は、munin-node.rbを最初にしないとプラグインが最初全部消される仕様です。(レシピは上から順に実行されます)

    ...
  • Chefで既存手順のレシピを書く4(DBサーバ)

    おつかれさまです。小宮です。

    前回に引き続きdbserverのレシピについて書いていきます。
    のこってるのはmunin、zabbxとserverspecでのテストだけです。もうすこしの辛抱です。

    webと同じくバージョン固定インストールなので、外部レシピは基本的に使わない方向とする

    ・mysqlのインストールと起動と自動起動の有効化

    [shell]# cd /root/chef-repo/site-cookbooks/mysqld/recipes

    mkdir -p /root/chef-repo/site-cookbooks/mysqld/files/default/usr/local/src/rpms

    mkdir -p ../templates/default/etc/init.d

    mkdir -p ../files/default/etc/init.d

    mkdir -p ../files/default/root

    mkdir -p /root/chef-repo/site-cookbooks/mysqld/files/default/etc/logrotate.d

    mkdir -p /root/chef-repo/site-cookbooks/mysqld/files/default/opt/{backup,bin}

    scp -Cp xxx-db02:/opt/bin/mysql-back.sh /root/chef-repo/site-cookbooks/mysqld/files/default/opt/bin/

    cp -p /etc/logrotate.d/mysqld /root/chef-repo/site-cookbooks/mysqld/files/default/etc/logrotate.d/

    scp -Cp xxx-db01:/etc/init.d/mysqld ../files/default/etc/init.d/

    scp -Cp xxx-db02:/etc/my.cnf ../templates/default/etc/

    cp -p /root/.path_to_file ../files/default/root/

    cd /opt/src/rpms/

    tar czf /root/chef-repo/site-cookbooks/mysqld/files/default/usr/local/src/rpms/db-rpm.tar.gz ./db-rpm/

    tar czf /root/chef-repo/site-cookbooks/mysqld/files/default/usr/local/src/rpms/db-tools-rpm.tar.gz ./db-tools-rpm/

    tar tzf /root/chef-repo/site-cookbooks/mysqld/files/default/usr/local/src/rpms/db-rpm.tar.gz

    vi ../templates/default/etc/my.cnf

    diff /etc/my.cnf ../templates/default/etc/my.cnf

    53c53

    ...