タイトル

Need for Answer

2014年12月19日金曜日

gateがvHost対応したのでテンプレ的なコンフィグ作ってみた

gate使ってますか!
自サイトにお手軽にgoogle認証を組み込めるという、夢のプロダクトです!

Ver0.4でついにvhost対応されました。これで『トップディレクトリからのパスを変更すると動かなくなるプロダクト』でも問題なく動かせるようになりました!ヤッタネ!

…ということで、コンフィグのテンプレ的なものを作ってみました。

#==========================================
# Config for gate
#==========================================
# Gate の待ち受けポート
# Forwardポートは最下部で設定
address: :8888

#==========================================
# ssl keys (optional)
#==========================================
# ssl:
#   cert: ./ssl/ssl.cer
#   key: ./ssl/ssl.key

#==========================================
# 認証
#------------------------------------------
# Github または google認証
#==========================================
auth:
  session:
    # authentication key for cookie store
    key: secret456
    cookie_domain: hoge.com

  info:
    # oauth2 provider name (`google` or `github`)
    # google または github
    service: google

    # your app keys for the service
    client_id: [googleAPI_ID]
    client_secret: [googleAPI_secret] 
    # your app redirect_url for the service:
    # if the service is Google, path is always "/oauth2callback"
    redirect_url: http://hogehoge.hoge.com/oauth2callback

   #--------------------------------------
   # 制限ユーザー
   #--------------------------------------
   # restrict user request. (optional)
   # restrictions:
   #  - hoge.com    # domain of your Google App (Google)
   #  - @gmail.com # specific email address (same as above)
   #  - your_company_org  # organization name (GitHub)

#==========================================
# document root for static files
#==========================================
htdocs: ./htdocs

#==========================================
# proxy 設定
#==========================================
proxy:
  - path: /
    host: hogehoge.hoge.com
    dest: http://127.0.0.1:8080

2014年12月4日木曜日

ELB配下にあるDjangoにリクエストプロトコルを判断させたい

ELB配下にあるEC2にプロトコルを渡したい、そんなこと有りますよね!
何が困ってそんなことをって話なのですが、下記2点に該当する人だと思います。

  1. ELBにSSLアクセラレーションさせてる(HTTPS→HTTP変換)
  2. EC2にApache→Djangoを使ってる
で詳細な問題って何?な話なのですが、「ELBが渡してくるリクエストヘッダと、Djangoが解釈するリクエストヘッダが微妙に違う」ってことです。ちなみにこんなかんじです。

  • ELBが送るリクエストヘッダ → X-Forwarded-Proto:https
  • Djangoが解釈したいリクエストヘッダ → X-Forwarded-Protocol:https

なので、「リクエストヘッダの内容を判断して、Djangoに送るヘッダを書き換えよう」ってのが具体的なアクションになります。

という事で、Apacheのconfigを作ってみました。


#
# for Django
#
LoadModule headers_module modules/mod_headers.so
LoadModule setenvif_module modules/mod_setenvif.so
SetEnvIf X-Forwarded-Proto https PROTO_HTTPS
RequestHeader set X-Forwarded-Protocol "https" env=PROTO_HTTPS

2014年11月28日金曜日

AWS-VPCでNATインスタンスを切り替えるのまき

AWS-VPCでNATインスタンス…作ってますか!

NATインスタンスが単一障害点だから…って無言のプレッシャーかけられてるエンジニア、多いと思います!

ということでNATサーバーを切り替えるスクリプト作りました。
NATインスタンスにIAM_Roleを適用してから使うといいと思います!

#!/bin/sh
#======================================================
# NATインスタンスを自分に切り替えるスクリプト
#======================================================
#======================================================
# 概要
#------------------------------------------------------
# 特定のルーティングテーブルのアウトバウンド(0.0.0.0/0)
# を、「シェルを実行しているインスタンス」へ切り替える
# スクリプトです
#======================================================
# つかいかた
#------------------------------------------------------
# 1 - 待機側のインスタンスが、稼働側のインスタンスを死活
#     監視する(実装して下さい)
# 2 - 死亡が確認されたらこのシェルを実行してください
#======================================================
# 前準備
#------------------------------------------------------
# VPC => RouteTable で、「NATサーバーを通過するRouteTableID」
# を調べる。NATインスタンスのいるRouteTableIDではないので
# 注意。下のCHANGE_RTBに記載する
#------------------------------------------------------
CHANGE_RTB="[ここを書き換える]"
#======================================================

# リージョンを宣言 ------------------------------------
export AWS_DEFAULT_REGION=`curl --connect-timeout 3 -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed 's/.$//g'`
MY_ID=`curl -s http://169.254.169.254/latest/meta-data/instance-id`

echo "================================="
echo " CHANGE RouteTable..."
echo "================================="
echo " Current Setting => " `ec2-describe-route-tables ${CHANGE_RTB} --region ${AWS_DEFAULT_REGION} | grep 0.0.0.0`
echo "---------------------------------"
echo " CHANGE RouteTable => ${CHANGE_RTB} / MyInstance-ID => ${MY_ID}"
echo "---------------------------------"

ec2-replace-route ${CHANGE_RTB} --region ${AWS_DEFAULT_REGION} -i ${MY_ID} -r 0.0.0.0/0

echo " Done!!"
echo " Current Setting => " `ec2-describe-route-tables ${CHANGE_RTB} --region ${AWS_DEFAULT_REGION} | grep 0.0.0.0`
echo "================================="

2014年11月25日火曜日

複数台のサーバーでconfigを同期するだけのスクリプト

複数台のサーバーでconfigを同期する必要…有りますよね!
copyしてからサービスの再起動とかよくやると思うんですよ!

いっつも適当に書くので、メモすることにしました。
とりあえずnginxでやってますが、td-agentとかでもやり方は一緒です。

#!/bin/sh
#==========================================
# Enviroment
#==========================================
# 設定ファイルを送信する先
DEPLOY_SERVER="10.10.xxx.xxx"

# 設定ファイルの入っているディレクトリ
SYNC_DIR="/etc/nginx"

# 設定ファイル編集後に実行するコマンド
RELOAD_CMD="/etc/init.d/nginx reload"

#==========================================
# Config Deploy
#==========================================
# 実行時間計測用
START=`date +%s`

echo "-------------------------------------"
echo " Erase Remote Config Files..."
echo "-------------------------------------"
ssh ${DEPLOY_SERVER} rm -fr ${SYNC_DIR}
ssh ${DEPLOY_SERVER} mkdir ${SYNC_DIR}

echo "-------------------------------------"
echo " Deploy Config Files..."
echo "-------------------------------------"
scp -p -r ${SYNC_DIR}/* root@${DEPLOY_SERVER}:${SYNC_DIR}

echo "-------------------------------------"
echo " Service Reload (Remote)..."
echo "-------------------------------------"
ssh ${DEPLOY_SERVER} ${RELOAD_CMD}

echo "-------------------------------------"
echo " Service Reload (Local)..."
echo "-------------------------------------"
${RELOAD_CMD}

# 実行時間計測用
END=`date +%s`
SS=`expr ${END} - ${START}`
HH=`expr ${SS} / 3600`
SS=`expr ${SS} % 3600`
MM=`expr ${SS} / 60`
SS=`expr ${SS} % 60`

echo "-------------------------------------"
echo " F I N I S H ! !"
echo "-------------------------------------"
echo " Exec Time => ${HH}:${MM}:${SS}"
echo "-------------------------------------"

2014年11月24日月曜日

ELBからのヘルスチェックは適当に200を返そう

Elastic Load Balancing(ELB)便利ですね!ELBの後ろにnginxを置いてる人、多いと思います!

…なのですが、ELBのHTTPヘルスチェックのためにファイルを置くのめんどくさい!ELBにはHTTPで応答できるかだけ監視して欲しいってこと…あると思います!

ということでこんな設定でどうでしょうか!

map $http_user_agent $bot {
  default                  0;
  ~*(ELB-HealthChecker)    1;
}

server {
    if ($bot = 1) {
      return 200;
    }
}

2014年10月1日水曜日

AWSのELBのエフェメラルポートは1024-65535

タイトルに書いてあることが全てなのですが、Amazon Web ServicesのElastic Load Balancingのエフェメラルポートは1024-65535です。ここに書いてあります。
Network ACLs - Amazon Virtual Private Cloud

これが何か?という話なのですが、「Amazon Virtual Private CloudのNetworkACLを使うと、エフェメラルポートを指定する必要がある」ということなんですね。ここでポイントになるのが、「クライアント→ELB→EC2」という通信路の「ELB→EC2」部分のエフェメラルポートになります。

ちなみにLinuxの使うエフェメラルポートは32768-61000です。念のため確認するにはこんな感じのコマンドです。

cat /proc/sys/net/ipv4/ip_local_port_range

どーでもいいんだけど、NetworkACLってTCPフラグで書けるようにならないのかな…

2014年9月16日火曜日

lsyncdでユーザーを指定してsyncしたい

lsyncd便利ですよね!rsyncサービス使わなくてもファイル同期できるので、不要なサービスを起動させなくていいのが利点だと思います!

とはいえrootで実行すると、配布先のファイルパーミッションがrootになってしまう
…そんな悩みを持ってる人もいるかもしれません!

…ということでサクッと解決。

sync {
  default.rsyncssh,
  source = "配布するローカルディレクトリ",
  host= "配布先のホスト名",
  targetdir = "配布先のどのディレクトリに配置するか",

  rsync = {
    archive = true,
    compress = false,
    whole_file = false,
    sh = "/usr/bin/ssh -l [ユーザー名] -i [接続ユーザーが使う鍵ファイル]"
  },

  ssh = {
    port = 22
  }
}

Nginxのステータスをjsonで取得する

Nginx使ってますか!

 …で使ってるとステータスをjsonで取得したくなリますよね!作りました!
Githubへのリンク

作りましたは嘘です!先人の素晴らしいソースをちょっと改良しただけです!
 td-agentでステータスを収集したりとかするときに便利だと思います。

2014年7月2日水曜日

fluentdで統計情報を取るぞの巻

fluentdネタが好評だったので。
vmstat・メモリ使用率・ディスク使用量をfluentdで定期的に収集します。

シェルスクリプトにするのも面倒だったので、ワンライナー処理。
ポイントはawkでOFSを指定すると、タブ区切りに出来るところでしょうか。

# Performance Check ---------------------------
<source>
  type exec
  command vmstat | awk 'BEGIN{OFS="\t"} NR==3 {print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17}'
  keys procs-r,procs-w,mem-swpd,mem-free,mem-buff,mem-cache,swap-in,swap-out,io-blockin,io-blockout,system-in,system-cs,cpu-usr,cpu-sys,cpu-idle,cpu-wait,cpu-steal
  format tsv
  tag vmstat
  run_interval 60s
</source>

<source>
  type exec
  command free -m | awk 'BEGIN{OFS="\t"} NR==2 {print $2,$4,$6,$7,(1-($4+$6+$7)/$2)*100}'
  keys mem-total,mem-free,mem-buffer,mem-cached,mem-used-per
  format tsv
  tag mem_use
  run_interval 60s
</source>

<source>
  type exec
  command df | awk 'BEGIN{OFS="\t"} NR==2 {print $2,$3,$3/$2*100}'
  keys disk-total,disk-used,disk-used-per
  format tsv
  tag disk_use
  run_interval 60s
</source>

2014年6月18日水曜日

AWSコンソールに複数アカウントでログインしたい!

AWS案件を複数抱えていると、AWSコンソールを複数アカウントで比較したいこと…有りますよね!
ということでやり方です!

GoogleChromeでシークレットモードを使いましょう!WindowsならCTRL+SHIFT+Nです!これで通常とシークレットモードの2つ、アカウントを同時にオープンできます!

…これでは足りない人は、GoogleChrome拡張機能のMultiLoginを使いましょう!開いているタブごとにアカウントを変更することが出来ます!万事解決。

2014年4月16日水曜日

ZFS理解図

ZFSの簡単な理解図を作りました。
poolとかvolumeとかdataとかって何?って時に見ると良いと思います!

2014年3月27日木曜日

AWSと消費税

AWSを利用している皆さん、『東京リージョンにおけるAWSのサービス料金請求プロセスの明確化に関する御案内』というメール来てますよね!(2014年3月時事ネタ)

AWSの請求って『税金』の部分が見えないから意識しないですよね。意識しても取られてますが!ということで調べてみました。

…実は『AWS の請求に関するよくある質問』を読むとあっさり解決してしまうのですが、簡単に言うと『「既定のお支払い方法」に関連づけられた住所』に基づいた税金がかかります。

つまり東京リージョン以外のEC2とかを使っていても、税率が変わるとかは無いということですね。といっても日本では『売上税』は取られないのですが!

あと消費税について記載のある部分は『Amazon EC2 よくある質問』ですね。表示価格は消費税込みです。

2014年3月20日木曜日

MySQL冗長化モデル

以前作成したMySQLの冗長化モデルをご紹介。
  • MySQL
  • LVS
  • iptables

を利用しています。

Master及びSlaveそれぞれの冗長化及びスケールについて、参考になる部分もあるかと。運用実績も1年以上経過し、稼働中の障害復旧もできているので大丈夫なんじゃないかな-と思います。


2014年3月19日水曜日

『大事なことはタグに書く』的なお話

AWS EC2運用をしていると、『AWS運用に関する変数』をどうやって収納するか悩みますよね!OSのユーザー権限とも違うし、テキストで置いたらセキュリティ的にも…とか思うと夜も寝られません。

ということで、『EC2のタグに書いてしまえばいいじゃない!』という発想もあるよ!というお話です。

色々利点は有るのですが、一番の利点は『AWS Management Console上で確認・変更できる』ということじゃないでしょうか。

awscli+jqのサンプルコードを書いてみました。


# タグをつける
# 同一Keyに実行すると、上書きされる
aws ec2 create-tags --resources `curl -s http://169.254.169.254/latest/meta-data/instance-id` --tags "Key=TEST,Value=TESTValue"

# タグの値を取得
aws ec2 describe-tags --filters "Name=resource-id,Values=`curl -s http://169.254.169.254/latest/meta-data/instance-id`"|jq -r ‘.Tags[] | select(.Key=="TEST")|.Value’ ⇒ TESTValue  or null

# タグを削除
# keyが存在しなくてもreturnはtrue
aws ec2 delete-tags --resources `curl -s http://169.254.169.254/latest/meta-data/instance-id` --tags "Key=TEST"

2014年3月18日火曜日

Amazonの買い物をGoogleCalendarへ登録するChrome拡張機能

Amazon.co.jpの買い物って、いつ届くか忘れますよね!
過去からのテロ攻撃って怖いですね。

…ということで、amazonの商品お届け予定日をGoogleCalendarに登録するChrome拡張機能を作りました!

Amazon2GoogleCalendar

Google Chrome拡張機能をインストールすると、Amazon.co.jpの『注文履歴を見る』ページにGoogleCalendarへ登録するボタンが追加されます。使い方簡単。



Amazonが公式にwebcal対応してくれればいいのにな…。

2014年3月17日月曜日

AWSのアクセスキーとシークレットキーを運用する

AWSより「AWS アカウントアクセスキーの管理方法に関する重要な変更」というメールを貰った皆さん!IAMできちんと運用してないですよ、と注意されたようなものですね!

…ということでAWSのアクセスキーとシークレットキーってどうやって運用するのが良いの?というお話。結論を先に言うと、『権限が限定されたAWSアクセスキーを作る』ということです。

以下本題。

セキュリティの根本的な考え方として、『WEBに公開しているシステムは、実行ユーザーで出来る全てのことをやられる可能性が有る』というのが有ります。

仮にApacheをApacheユーザーで実行していたとしたら、コンソールでApacheユーザーにスイッチした時に出来る事は全て出来る、と考えます。『ブラウザからアクセスしているから大丈夫』とか『ベーシック認証かけてるから大丈夫』なんて何の防御力も無いです。

つまり、『実行ユーザーには最低限の権限だけを与えて、ハックされても問題ないようにする』ということです。『入られない』ではなく、『入られても問題ない』を中心に考えよう、ということです。

この考えはAWSのユーザー管理も一緒です。つまり『AWSアクセスキーとシークレットキーが漏れても、権限を絞っておけば被害が抑えられる』と考えます。


これを実運用に落とし込みます。AWSは権限を、『IAMで作成するユーザー単位』で定義します。つまり、『このユーザーはAWSのどの機能まで使えるのか?』ということです。

新規作成されたAWSアカウントは『ルートアカウント』と呼ばれ、AWSへのアクセス権限がフルにあるということです。(Administrator・rootをイメージして頂ければよいかと)

その上でIAMでユーザーを新規作成し、画面に出てきたAWSアクセスキーとシークレットキーを控えておきます。

そのアカウントに最低限の権限を付与します。(S3にだけアクセスできる、とか)

あとはそのキーを利用すれば、最低限のセキュリティは守られるという事になります!

『入られる事を前提』と考えますと、『入り口を限定すること』『定期的にキーを変更すること』といった運用が必要、という事にもなりますね。

2014年3月16日日曜日

Gmailで繰り返し来るメールを自動削除する

定期配信されるメールって有りますよね。
そういうメールって、最新のもの以外はいらなかったりしませんか?

ということで、『決まった題名のメールを1通だけ残して、あとはアーカイブ』をGmailで自動化しよう!というお話です。

とりあえず使うものはGmailとGoogle Apps Scriptになります。簡単に説明すると『GmailをメンテナンスするJavaScript』をGoogleのサービスで定期実行させる、ということです。こんなことも無料で出来るんですよ。

以下ソース。

var TITLE="メールのタイトル"

// メイン処理
function Main(){
  var TMPOBJ = STRinMailTitle(TITLE);
  ArcOldMail(TMPOBJ);
}

// 文字列が含まれたスレッドオブジェクト配列を返却
function STRinMailTitle(STR){
  var RETOBJ = [];
  
  var thds = GmailApp.getInboxThreads();
  for(var n in thds){
    var thd = thds[n];
    var subject = thd.getMessages()[0].getSubject();
    if (subject.indexOf(STR,0) != -1){
      RETOBJ.push(thd);
    }
  }
  return RETOBJ;
}

// スレッド配列を処理する
function ArcOldMail(OBJ){
  
  var TMPOBJ=OBJ;
  
  // 配列先頭を削除
  TMPOBJ.shift();
  // 先頭以外は既読・アーカイブする
  GmailApp.markThreadsRead(TMPOBJ);
  // アーカイブ
  GmailApp.moveThreadsToArchive(TMPOBJ);
}

上記ソースをGoogleドライブのスクリプトを新規作成して、仕込んで下さい。

次に1行目の「メールのタイトル」部分を、『定期メンテナンスしたいメールのタイトル』に書き換えてください。部分一致でも大丈夫です。

あとは、Main()を時間トリガーに仕込みます。

可読性を上げるために処理を削りましたが、『1通目だけラベルをつける』『メール本文で判定』とか色々なことが出来ますので、改造してみてはいかがでしょうか?

2014年3月14日金曜日

なぜELB経由のEC2にGlobal IPを割り当てられないのか?

ELBでアクセスしているEC2。AWSインフラ構築者が一度は聞く相談として、『ELBで公開しているWEBに、固定Global IPも割り当てたいんだけど?』が有ります…よね。

なんでみんな気軽に『Elastic IPをEC2に割り振ればいいんじゃないの?』って言うんでしょう!

『出来ない』と答えるにしても、説明面倒ですよね!
そんな悲しい歴史を断ち切るために、わかりやすく解説しました!

ELB経由でアクセスする、通常パターンを図解してみました。


ここでは簡単に『EC2は、外部(0.0.0.0/0)から来た通信を、ELBにのみ打ち返している』と思ってくれればいいです。

さて、このEC2にElastic IPを割り当てましょう。そして外部からアクセスするとどうなるでしょうか?(NGパターンですね。)


これが『通信できない』状態です。つまり『EC2はElastic IPから来た通信を、ELBに打ち返している』のです。外部からの入り口が2つになっても、EC2がどの入口にレスポンスを返却すれば良いのかは判ってないのです。

そしてデフォルトの通信経路、ELBに向かって通信を返します。受け取ったELBは返却先が判らないので、通信が迷子になるのです。説明おしまい。

※解決方法は色々あるので説明省略!

2014年3月13日木曜日

AWS EC2バックアップを定期的に取得する方法(awscli+jq版)

AWS EC2のストレージ信頼度は高いです。が、人為ミスによるコンテンツ紛失はどうにもなりません。…EC2をバックアップしたいという需要はクラウドでも一緒ですね。

先人の作り上げたShellScriptをawscli+jqで移植しよう!というお話です。STOP!車輪の再発明!

長いので使い方を先に説明しますと、『all_createsnapshot.sh』をどこかのEC2で実行すると、タグ付けられたEC2-Instanceを全部バックアップします!cronに登録しておくと良いと思います!

前置き終了以下解説。

awscli』と『jq』のインストールが必須です。
jqはパスの通った所に置いて下さい。

まずはShellScriptから説明します。

2つのShellScriptは同一ディレクトリに設置して下さい。awscliの設定ファイル設置場所をハードコードしておりますので、各自ご修正ください。

2つのShellScriptの役割はこんな感じです。
  • all_createsnapshot.sh ⇒ バックアップ対象のEC2のInstance-IDをリスト化
  • createsnapshot.sh ⇒ Instanse-IDを渡すとSnapshotを取得。過去分は削除。
ログは『標準出力』『/var/log/message』の2つに出力されます。

ShellScriptはパラメータを渡して実行する事ができます。
通常は自動取得されますので、設定の必要は無いです。

all_createsnapshot.sh
パラメータ 内容 未指定時
-h ヘルプを表示 表示しない
-c AWS_CONFIG_FILEの場所を指定
(外部から引き渡すときに使用)
Shell内設定を使用

createsnapshot.sh
パラメータ 内容 未指定時
-h ヘルプを表示 表示しない
-c AWS_CONFIG_FILEの場所を指定
(外部から引き渡すときに使用)
Shell内設定を使用
-i SnapShotを取得したいInstanceID 実行中のインスタンス
-g SnapShotを保存する世代数 5

#!/bin/bash
#
# All Instances CreateSnapshot script

CONFIG_FILE=/root/aws/account.txt

opterror(){
    echo "Usage: $prog -c [config]" 1>&2
    echo "             -h HELP"
    exit 1
}

while getopts c:h OPT
do
  case $OPT in
    "h" ) HELP=1 ;;
    "c" ) CONFIG="$OPTARG" ;;
      * ) opterror
  esac
done

# TimeWatch Start ----------------------------
START_TIME=`date +%s`
TMPTXT="$0 Start EC2 SnapShot JOB..."
echo "${TMPTXT}" && logger -t $0 -i "${TMPTXT}"

# Exec ---------------------------------------
test ! -z $HELP   && opterror
test ! -z $CONFIG && CONFIG_FILE=${CONFIG}

export AWS_CONFIG_FILE=${CONFIG_FILE}
script_dir=$(cd $(dirname $BASH_SOURCE); pwd)

# Exec Failed Check --------------------------
test -z ${AWS_CONFIG_FILE} && echo "Not Set AWS_CONFIG_FILE ..." && exit 1
test ! -f ${script_dir}/createsnapshot.sh && echo "Not Find createsnapshot.sh ..." && exit 1

# Loop Tagged Instances
aws ec2 describe-instances --filters "Name=tag-key,Values=backup" "Name=tag-value,Values=ON"|jq -r ".Reservations[].Instances[].InstanceId"| while read INSTANCE_ID
do
    GENERATION=`aws ec2 describe-instances --instance-id=${INSTANCE_ID} |jq -r '.Reservations[].Instances[].Tags[]|select(.Key== "generation").Value'`
    test -z ${GENERATION} && GENERATION=5

    TMPTXT="Backup INSTANCE is ${INSTANCE_ID} and Generation is ${GENERATION}"
    echo "${TMPTXT}" && logger -t $0 -i "${TMPTXT}"

    if [ ! -z $CONFIG ];then
        ${script_dir}/createsnapshot.sh -i ${INSTANCE_ID} -g ${GENERATION} -c $CONFIG
    else
        ${script_dir}/createsnapshot.sh -i ${INSTANCE_ID} -g ${GENERATION}
    fi
done

# TimeWatch STOP -----------------------------
END_TIME=`date +%s`

SS=`expr ${END_TIME} - ${START_TIME}`

HH=`expr ${SS} / 3600`
SS=`expr ${SS} % 3600`
MM=`expr ${SS} / 60`
SS=`expr ${SS} % 60`

TMPTXT="$0 exec Total Time => ${HH}:${MM}:${SS}"
echo "${TMPTXT}" && logger -t $0 -i "${TMPTXT}"

#!/bin/bash
#
# CreateSnapshot script
# using awswcli + jq

CONFIG_FILE=/root/aws/account.txt
export LANG=C

#=====================================================
opterror(){
    echo "Usage: $0 -i [instance_id] -g [backup generation] -c [config]" 1>&2
    echo "          -h HELP"
    echo "          if Not Defined instance_id, take Backup Myself."
    exit 1
}

while getopts i:g:c:h OPT
do
  case $OPT in
    "h" ) HELP=1 ;;
    "i" ) EC2_INSTANCE_ID="$OPTARG" ;;
    "g" ) EBS_GENERATION_COUNT="$OPTARG" ;;
    "c" ) CONFIG_FILE="$OPTARG" ;;
      * ) opterror
  esac
done

#------------------------------------------------------
test ! -z $HELP && opterror
test ! -z $CONFIG && CONFIG_FILE=${CONFIG}

export AWS_CONFIG_FILE=${CONFIG_FILE}

test -z $EC2_INSTANCE_ID && EC2_INSTANCE_ID=`curl -s http://169.254.169.254/latest/meta-data/instance-id`
test -z $EBS_GENERATION_COUNT && EBS_GENERATION_COUNT=5
#======================================================

EBS_VOLUME_ID=`aws ec2 describe-volumes|jq --arg hoge ${EC2_INSTANCE_ID} -r '.Volumes[]|select(.Attachments[].InstanceId ==$hoge)|.VolumeId'`

# Create SnapShot --------------------
NOW=`date +"%Y/%m/%d %k:%M:%S"`
DESCRIPT_TXT="AutoBackup ${EC2_INSTANCE_ID} created at ${NOW}"
aws ec2 create-snapshot --volume-id ${EBS_VOLUME_ID} --description "${DESCRIPT_TXT}" >/dev/null 2>&1

# Error Catch ------------------------
RESULT=$?
TMPTXT="${EC2_INSTANCE_ID} create snapshot ${EBS_VOLUME_ID} "

if [ ${RESULT} -ne 0 ];then
  TMPTXT="${TMPTXT} => failed..."
else
  TMPTXT="${TMPTXT} => Success!!"
fi

echo "${TMPTXT}" && logger -t $0 -i "${TMPTXT}"

# List & Sort Delete SnapShots -------
SNAPSHOTS=(`aws ec2 describe-snapshots |jq --arg hoge ${EBS_VOLUME_ID} -c '.Snapshots[] | select(.VolumeId==$hoge) | [ .StartTime, .SnapshotId, .Description ]'| grep "AutoBackup" |sort -t "," -k 1,1| awk -F'[,"]' '{print $5}'`)
SNAPSHOTS_LINE=${#SNAPSHOTS[*]}

CNT=`expr ${SNAPSHOTS_LINE} - ${EBS_GENERATION_COUNT}`

# Exit -------------------------------
if [ ${CNT} -lt 0 ];then
  exit 0
fi

# Delete OLD SnapShot ----------------
for ((i = 0; i < ${CNT}; i++)){
  aws ec2 delete-snapshot --snapshot-id ${SNAPSHOTS[i]} >/dev/null 2>&1

  RESULT=$?
  TMPTXT="${SNAPSHOTS[i]} delete"

  if [ ${RESULT} -ne 0 ];then
    TMPTXT="${TMPTXT} => failed..."
  else
    TMPTXT="${TMPTXT} => Success!!"
  fi

  echo "${TMPTXT}" && logger -t $0 -i "${TMPTXT}"
}

次に、実際の使用方法を説明します。

バックアップ取得対象のEC2にTagを付けます。「Key:backup Value:ON」のものをバックアップ対象とします。「Key:generation Value:[任意の数値]」をつけると、その世代分以降のバックアップは削除されます。未指定時は5世代です。


あとはどこかのEC2で『all_createsnapshot.sh』を実行すれば、タグ付けされたEC2のSnapShotが取得されます。

なおバックアップ削除は『Descriptionに「AutoBackup」という文字列が含まれている物のみ』対象にします。手動取得したSnapshotsが勝手に消去されることは無いのでご安心下さい。

参照元:
【AWS】クラウド時代のバックアップ管理術  ~tagを活用したsnapshotの世代管理~
Amazon EBSのスナップショット(バックアップ)を取得しつつ世代管理も行うスクリプト



2014年3月11日火曜日

AWSアカウントを跨いでAMIをコピーしたい!

AWSでアカウントを跨いでAMIをコピーしたい…ありますよね!

『アカウント間でのAMI共有』は機能提供されているので問題無いのですが、共有されたAMIはコピー出来ません。グレーアウトしてますね。

実はOwnerが自分のAMIの物しかコピー出来ないのです。



AWS Management Consoleで出来ないなら、awscliだ!…とコマンドを発行してみましょう。
# aws ec2 copy-image --source-region ap-northeast-1 --source-image-id ami-******** --name AMI_Copy_Test
{
    "ImageId": "ami-********"
}
コマンドプロンプトでは成功したかのようなステータスが返ってきますが、確認してみるとこんなステータスになってます。


ということで解決方法。
  1. 共有されたAMIを元に、新規インスタンス起動
  2. 起動インスタンスから、Create Image
あんまりスマートじゃない気がしますね…

2014年3月10日月曜日

New RelicのApdexって何?

New Relicをお使いの皆さん、Apdexって何?という疑問…あると思います!
Wikipediaにも説明がありますが、2行で要約。

何割の人がレスポンススピードに満足しているか?』です。
0~1の範囲になり、1がみんな満足です。

以下New Relicのロジックを翻訳してみます。
『サーバー応答』と『ブラウザ』でのApdexがありますが、違いは後述。

まず『レスポンスに満足する秒(T)』を自己定義します。NewRelicのデフォルトは0.5秒です。
Applications>Settings>Application>App server>Apdex Tで設定可能です。

次にレスポンス速度毎に3分類し、アクセス回数を集計します。
『不満』はTの4倍超の時間です。(4倍はApdexの決まり)

満足(Satisfied)⇒0.5秒以下
容認(Tolerated)⇒0.5~2秒の間
不満(Frustrated)⇒2秒超

3つの数字が出ますので、これを計算式に代入するとApdexスコアが出ます。
Apdexスコア = (満足数 + 容認数 / 2) / アクセス合計数



上記計算式のNewRelicリンクも貼っておきます。

この値が0.7を下回るとエラーとなります。
アラート閾値を変更したい時は、Tools>Alert policiesで設定できます。

次に『サーバー応答』と『ブラウザ』の違いを説明します。
要約すると『レスポンスを計測する範囲の違い』です。

『サーバー応答』のレスポンスは、『ユーザーリクエストがサーバーに到着~サーバーがコンテンツを応答まで』になります。
サーバー⇒エンドユーザー間のネットワーク到達時間は考慮されていません

それに対して『ブラウザ』はユーザーがリクエストを発行してから、ドキュメントがロードされるまでの時間になります。
つまりネットワーク到達時間も考慮に入れている事になります。

これはNewRelicエージェントがJavaScriptを自動的に埋め込んで計測しています。
httpドキュメントの最下部にJavaScriptが自動添付されているのが確認できますね。

2014年3月7日金曜日

monitの罠

monit使ってますか!

プロセス監視やhtmlファイル改ざんチェック、ftpでディレクトリアップロードにアップロードされた時アクションするとか、アイデア次第で色々使えますね。非常に便利。

…実は設定ファイルを書くときに、注意しなければならない罠があるのです。
check process ntpd with pidfile /var/run/ntpd.pid
    start program = "/etc/init.d/ntpd start"
    stop program = "/etc/init.d/ntpd stop"
    if 5 restarts within 5 cycles then timeout

上記設定ファイルは問題が有ります。何が問題か?といいますと、『設定ファイルの末尾が空白改行』なのです。監視プロセスが落ちても再起動しません。『~timeout』の後に有る改行を削除すれば大丈夫です。

とりあえずmonit5.5だとなってたので、皆さん注意しましょうね、というお話でした。

2014年3月6日木曜日

素晴らしきヒィッツカラルド

横長のjpgやpngファイルを半分分割して、連番名にしてくれるツールを作りました。
本とかパンフレットを見開きスキャンした時に使うことを想定しています。
要.Net frameworks 4.5。

素晴らしきヒィッツカラルド

  1. エクスプローラーから対象ファイルをドラッグして下さい。(フォルダは対応しません)
  2. 横長のファイルのみ自動判別し、編集対象にします。それ以外は無視します。
  3. 『右開き』『左開き』を指定することが出来ます。
  4. jpgは圧縮率を指定することが出来ます。
  5. ファイル名接頭詞を指定することが出来ます。
  6. 連番は『1』から始まります。
  7. 処理中に1・2を変更する事が出来ます。各人の使用モラルに任せます。
  8. 作業ディレクトリ配下に『Edit』というフォルダを作ります。作業時には、その中にあるファイルを一旦全消去します。

【2014/03/25:追記】 拡張子の大文字・小文字判定が甘かったので修正

AWS CloudWatchの値をfluentdに流す方法

AWSのcloudwatchは2週間以上前のデータを見ることが出来ません。要件次第では自力ハウジングする必要があります。先人に感謝しつつ実現しましょう、というお話。

概要は、『fluentdでShellScriptを定期的にkickし、返り値をtsv形式で受け取る』という感じ。fluentdで受け取ったあとは、outputプラグインにお任せしましょう。

まずはShellScript。『aws cloudwatch get-metric-statistics』で取得した値を、tsv形式で吐き出すスクリプトです。今回はSNS通信の送信・失敗数をカウントすることにしました。

get-metric-statisticsは該当する値が無いとnullを返すので、『0』を代入する必要が有ります。これくらいしか悩む所ありません。
#!/bin/bash
export AWS_CONFIG_FILE=[適当なパス]

if [ $# -ne 1 ]; then
  LASTSEC=300
else
  LASTSEC=$1
fi

LASTSEC_CMD="$LASTSEC seconds ago"

NOW=`date +"%Y/%m/%dT%I:%M:%SJST"`
LASTDAY=`date -d "$LASTSEC_CMD" +" %Y/%m/%dT%I:%M:%SJST"`

# DEBUG -----------------------------------
#LASTDAY=`date -d '5 days ago' +"%Y/%m/%dT%I:%M:%SJST"`

# Get CloudWatch DATA ---------------------
SEND=`/usr/bin/aws cloudwatch get-metric-statistics --namespace "AWS/SNS" --metric-name "NumberOfMessagesPublished" --start-time $LASTDAY --end-time $NOW --period $LASTSEC --statistics "Sum" --dimensions Name=Application,Value=********** --output text | awk 'NR==2 {print $2}'| sed -e "s/.0//g"`

FAILED=`/usr/bin/aws cloudwatch get-metric-statistics --namespace "AWS/SNS" --metric-name "NumberOfNotificationsFailed" --start-time $LASTDAY --end-time $NOW --period $LASTSEC --statistics "Sum" --dimensions Name=Application,Value=********** --output text| awk 'NR==2 {print $2}'| sed -e "s/.0//g"`
# null check ------------------------------
if [ -z $SEND ]; then
  SEND="0"
fi
if [ -z $FAILED ]; then
  FAILED="0"
fi

# echo TSV Format -------------------------
echo -e "$SEND\t$FAILED"

このShellScriptをfluentdからkickしてもらいます。ShellScriptから吐き出されたtsvにはkey、tagがないので、ここで定義します。起動間隔もここで定義できます。
<source>
  type exec
  command [shellのパス]
  keys [key名1],[key名2]
  tag [タグ名]
  run_interval 300s
</source>
fluentdに投げ込んだ後は、S3に送るなりmongoDBに喰わせるなりご自由に!