2016年10月28日金曜日

AWS SDK for PHP

PHPから手軽にAWSの情報にアクセスして操作できるのは非常に楽です。
よくあるタグでEC2インスタンスを検索する方法を紹介。
検索で出てくる情報が古い(非推奨)だったりなので、書き止めます。

公式リファレンス
https://aws.amazon.com/jp/sdk-for-php/

composerを使わない手軽な方法は、pharファイルを使う事です。
pharは、PHPのクラスファイル群を1ファイルにまとめたライブラリです。
右のインストールボタン[AWS SDK for PHP]を押すと、説明ページが出てきて、そこにダウンロードリンクがあります。

require 'aws.phar';

$config = array(
   'region' => 'ap-northeast-1', //東京リージョン指定
   'version' => 'latest', //Service APIsにあるAPI Version。latestだとアップデートで動かなくなるから注意
);
$client = new Aws\Ec2\Ec2Client($config); //EC2操作なので、EC2のクライアントをインスタンス化
$result = $client->describeInstances(array(//インスタンスの詳細情報を取得
   'Filters' => array( //検索条件を指定
      array(
         'Name' => 'instance-state-name',
         'Values' => array('running'), //起動中インスタンス指定
      ),array(
         'Name' => 'tag:Name', // タグキー名が Name
         'Values' => array('hoge'), /./ 値が hoge
      ),
   ),
));
$reservations = $result['Reservations'];
foreach ($reservations as $reservation) {
   $instances = $reservation['Instances'];
   foreach ($instances as $instance) {
      // ここでインスタンスごとの情報を使った処理ができます 
   }
}
ロードバランサを使っていても、各インスタンスのローカルIPを引っ張ってきてrestによる操作なんてことも手軽で良いですね。
詳しくは APIリファレンス に全て書かれていますが、全て英語です。

2016年10月25日火曜日

さくらのクラウドで古いサーバーのHDD容量アップ手順

最近のイメージファイルなら起動時に自動的に容量を認識して再設定してくれますが、何年も前の古いイメージファイルから作ったサーバーは、手動で容量を設定しなくてはなりません。

設定はOS(パーテーション方式)によっても異なります。
あとはイメージの作られた時期によっても、パーテーションの分け方が違っていますね。

今回作業したのは、CentOSで、1つのHDDが3つのパーテーションに分かれてたサーバーでした。

まず、サーバーをシャットダウン。
そして、移行先のブランクディスクを追加。
この状態で、サーバーを起動。

コピー中に重要なファイルに書き込みが発生して破損しないように気を付けないといけません。
MySQLなどDBサービスは停止しておきましょう。

シェルに入り、HDDを丸ごとコピー。
コピー元がvda、コピー先がvdbとすると
# dd if=/dev/vda of=/dev/vdb bs=512M
この丸ごとコピーではパーテーション情報もコピーされるため、容量確保がコピー元と同じになります。
なので修正してあげる必要があります。

こっから先は、パーテーション方式で違います。
2Tに対応していない古い方式のMBR、2T以上扱える新しい方式のGPT。
64bitOSなら後者になっていると思います。


GPTなら parted コマンドで設定。 MBRなら fdisk です。


partedでの流れ

# parted /dev/vdb
unit s
print

printで出てきたパーテーション一番下の領域を容量最大まで増やします。
Start 部分の番号が開始シリンダであり重要なので、見える状態にしておきましょう。

容量を増やすには、いったんパーテーションを削除して、再度確保するだけです。
フォーマットはしないので、データはそのまま復活します。 
rm 3
mkpart primary xxxxxs -1s
xの部分は、必ず元の Start の番号を入れます。でないとエラーになります。
同じ開始位置から、最後まで(-1s)を指定です。

もう一度 print を実行して状態を確認すると、容量が増えているはずです。
quit で終了します。
※fdiskでの流れも基本的には一緒です。

ファイルシステムが破損していないかチェック
# e2fsck -f /dev/vdb3
もう一つ容量変更を再設定してあげないといけないのがあります。
# resize2fs /dev/vdb3
※容量を小さくする場合は手順が逆で、 resize2fsで小さくしてpartedで再設定です。

以上で設定が完了します。
サーバーをシャットダウンし、古いHDDを外して再起動してください。

2016年10月15日土曜日

MySQL テーブル設計

MySQLというか、RDSでのDB設計・・・カラム(フィールド)の設計について

まず初心者が行ってしまうのは、1レコード(行)に全ての情報をつめこんでしまう設計。
後で一切いじることのない完結した物なら問題ありませんが、大抵は追加追加でどんどん膨れ上がってしまいます。

また、一行に詰め込むにはあまりにも無駄に膨大なカラム数になる場合もあります。
あまり増えると、1行のデータ上限にひっかかり、エラー発生という落とし穴もあります。
TEXT等の長いカラムは、1レコードあたり10カラムもあるといつエラーになってもおかしくありません。

一番やってほしくないカラム構成は

id, data1, data2, data3......

同じ意味のカラムがぽんぽんぽんと、何も考えないで作った感丸出しですね。
こういう場合は、重複しているカラムごとに1レコードにします。

id, key, data

1行ですんでいたのが複数行になり、行が大量になってしまうではないかと思うかもしれませんが、いいんです。
スピードもデータ容量も誤差の範囲です。 扱い方が変わるだけです。

キーバリュー(key-value)方式みたいな単純な構造にすることで、拡張性が飛躍的にあがります。
今までカラムを増やすたびにDB操作だったのが、その必要がなくなるり、動的にカラムを扱えるようになります。
扱い方次第では、行ロックである InnoDB の恩恵も強くうけられるようになります。


次に、どうしても1レコードに収めたい。しかしカラムは今後増えて行く可能性がるから柔軟にしたい。
これを解決できるのは、増えて行くカラムは検索対象にならないというのが大前提です。
id,data
dataの値は配列をシリアライズして圧縮をかけた物にします。
配列なので、自由自在にデータ項目を増やせます。
検索できないので出番は少ないですが、大きなシステムでは使うことがあります。


以上の3パーンが基本となり、それぞれのデータをどの方式で格納するかを決めます。
迷ったら2番目が後々楽ですが、最初のコーディングが少し多くて面倒かな。
実際は、マスターテーブルと関連付けて少し複雑になる場合が多いです。

具体例で言いますと、会員情報のテーブル構成では

member_id, pw
member_id, key, value
このように2つのテーブルにわけます。1つ目はマスターテーブルと呼ばれる物ですね。
マスターテーブルでは、ログイン時に必要な会員IDとパスワードのみを保存します。
会員情報本体のカラム構成が変化しないとわかっていれば、1行にまとめても良いです。

もちろんこれは絶対的な設計ではなく、要件によって使い分けてください。


2016年10月13日木曜日

CentOS + JIRA + HTTPS

JIRA(Tomcat)を強制HTTPS化する手順です。
JIRAに限らずTomcat共通なのですが、JIRAで行ったのでJIRAとします。

自己署名証明書での手順です。

1.Keystoreの作成(一般的なpemではない方です)

JIRAをインストールしたディレクトリを確認します。
CentOSなら、 /opt/atlassian/jira/ だと思います。

作成コマンド
/opt/atlassian/jira/jre/bin/keytool -genkey -alias jira -keyalg RSA -keystore /home/jira/.keystore

/home/jira は、JIRAの実行ユーザーのホームです。 必ずJIRAの実行ユーザーのホームを指定してください。
ホームに置けない理由がある場合は、置いたディレクトリをJIRAの実行ユーザーのみが読み書きできる設定にしてください。
ファイルではなくディレクトリというのがポイントです。

自己署名なので、設定内容は適当で問題ありません。
最初に設定するパスワードだけはメモってください。後で使います。

2.サーバー設定
/opt/atlassian/jira/conf/server.xml

HTTPSの設定(ポート8443の設定)がコメントアウトされているので、外してください。
設定を追加します。

keystoreFile="/home/jira/.keystore"
keystorePass="作成時に指定したパスワード"
keyAlias="jira"
3.強制HTTPS化
/opt/atlassian/jira/conf/web..xml

httpでアクセスしてきたら、httpsへいダイレクトするように設定します。
web-app要素の最後に追加してください。

  <security-constraint>
    <web-resource-collection>
      <web-resource-name>hogehogeeee</web-resource-name>
      <url-pattern>/*</url-pattern>
      <http-method>GET</http-method>
      <http-method>POST</http-method>
    </web-resource-collection>
    <user-data-constraint>
      <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
 </security-constraint>
4.再起動
service jira stop
service jira start

以上で終わりです。

2016年10月9日日曜日

古いpiwikとMySQL5.6

わけありでアップデートができないpiwik2.1のDBを、MySQL5.6に引き上げました。

しかし、エラー発生。

「MySQL gone away」
mysqlがどっかいっちゃったよ~というエラーです。
コネクションが意図しないタイミングで閉じられた場合に発生するエラーです。

エラータイミングは、piwikのアーカイブ生成時でした。

設定が悪いのか、ログファイルに詳細なエラー内容は無しの状態。

ぐぐると、タイムアウトとか、バッファが足りないからというのしかなく、解決になりませんでした。

そこで!
sqlを実行させるさせる所でバックトレース内容を出力させて調査。
gone awayエラーが発生したクエリ実行時のバックトレースを追っていきました。

gone awayが発生したクエリでは、その時点ではすでに接続がきれているので、もっと手前で本当のエラーが発生しているだろうと当たりをつけます。
エラーで完了できず、次のクエリで gone awayかなと。

手前のクエリのバックトレースと比較して、最後の共通メソッド・・・すなわちメインロジックを探します。
そこの例外内容を確認すると・・・あった!
csvファイルでテーブルに書き込んでいるところで、値がutf8じゃないよエラーをPDOがスローしていました。


クエリ実行メソッドを見ると、クエリを実行するたびに接続のチェックをしているみたいだけど、これがどうもすり抜けている状態です。
csvでの取り込みにしっぱいしたら、エラーをもみ消して通常のクエリで挿入というロジックもどうなのかと。


まとめると
csv取り込みエラーで接続消滅。 utf8でデータ挿入するも、blobカラムの値がバイナリデータとなっていた。
ここのエラーで接続が切れる。
しかし、シングルトンの変数の中身が null とならないため、接続中と判定される。
そのまま接続オブジェクトを使いまわそうとして、gone away。 もう接続切れてるからね!

今までは、接続中と判定されず、再接続ができていたのでしょうか。
それとも文字判定が無かったのでしょうか。

解決編

解決すには、バイナリデータを16進数にするか、挿入時の文字コードをlatin1にするか、csvによる挿入をコメントアウトするか。

csv挿入は、1つのクエリで一気に挿入できるのでパフォーマンがいい。このままにしたい。
16進数にするには、文字列として扱われないように改造が必要になりそう。嫌だ。
残る強制latin1、テーブルを見るとマルチバイトが入るカラム無し。 これに決めた!

core/Db/BatchInsert.php::tableInsertBatch()
csv定義配列に、'charset' => 'latin1' を追加するのみ。


2016年10月6日木曜日

nginx fastcgi_params を include する箇所

「ffastcgi_param  SCRIPT_FILENAME    ********;」
「include fastcgi_params」
の順序について、includeを後に書く人が多く、それだとincludeの中身で上書きされて意味が無いという記事を見かけました。


しかし、includeを後に書く人が多いということは、それで正しく設定できている事を意味します。

何故なのか!

ここで動作検証に重要な要素が1つあります。
「対象のバージョン」です。

nginxもバージョンアップでどんどん変わっていっています。 毎回必ず書いていた設定が不要になったりします。
そしてfastcgi_paramsファイルの中身も、かわっていっているのです。

最新版のfastcgi_paramsの中にあるSCRIPT_FILENAMEの設定欄を見てみると・・・・


設定無し!


fastcgi_paramsの中にSCRIPT_FILENAMEの設定が存在しないため、どうでもいいということですね。

まぁ、色々あさるばあい、設定の優先度については注意したほうが良いです。
日頃からincludeを先に書くようにしていたほうが、いつか良い事があるかもしれません。