AWS CLI で Athena のクエリ実行を同期的に行う

Athena に対するクエリを AWS CLI で実行する場合、一度のコマンドでクエリ結果を取得することは出来ません。

いくつかのコマンドを実行して結果を取得するような流れになってます。

クエリ結果取得までのコマンド実行の流れ

1. クエリ実行開始 ( start-query-execution )

start-query-execution \
  --query-string <value> \
  --result-configuration <value>
  • クエリは非同期的に処理されるため時間の掛かるクエリであってもコマンドの結果はすぐに返ってくる。
  • 結果は QueryExecutionId (クエリ実行 ID) のみ。

2. クエリ実行状況の問い合わせ ( get-query-execution )

get-query-execution --query-execution-id <value>
  • start-query-execution で得られたクエリ実行 ID を渡してクエリの実行状況を問い合わせる。
  • クエリの実行ステータスを取得できる。
    • SUBMITTED: 実行キューに追加された
    • RUNNING: 実行中
    • SUCCEEDED: 実行完了した
    • CANCELLED: キャンセルされた
    • FAILED: 失敗した
  • SUCCEEDED の場合は一緒に実行結果の出力先の S3 Path (.csv) が返ってくる。

3. クエリ結果取得 ( get-query-results )

get-query-results --query-execution-id <value>
  • start-query-execution で得られたクエリ実行 ID を引数に渡してクエリの実行結果を JSON format として取得する。
  • ページング取得に対応。
  • S3 へ出力された get-query-execution の実行結果 CSV を JSON 形式で取得するだけのコマンドのため、生の CSV 形式でもよければ S3 から直接取得すればよい。

つまりスクリプトでクエリを実行して結果を取得するには…

  1. start-query-execution でクエリ実行を開始
  2. 定期的に get-query-execution を実行してクエリ実行完了を待つ
  3. 完了したら aws s3 cp もしくは get-query-results で実行結果を取得する

クエリ実行完了を待つコードを毎回書くのが地味に面倒なので関数化した

#!/bin/bash
set -eu
set -o pipefail

# 取得対象のテーブル名
readonly TABLE_NAME="sample_table_name"
# Athena のクエリ結果出力先
readonly QUERY_OUTPUT_LOCATION="s3://aws-athena-query-results/"

# 同期的に Athena Query を実行します。
#
# params:
#   $1 string クエリ出力先パス
#   $2 string 実行するSQL
# result:
#   string `aws athena query_execution_result` の結果 (json)
function athena_query_execution_sync() {
  # クエリ実行開始
  query_id=$(aws athena start-query-execution \
    --result-configuration OutputLocation="$1" \
    --query-string "${2}" | jq -r '.QueryExecutionId')

  # クエリ結果問い合わせの最大リトライ回数
  MAX_RETRY=5
  # クエリ結果問い合わせ間隔 (秒)
  FETCH_INTERVAL_SECONDS=10

  try_cnt=1
  while true ; do
    if [ ${try_cnt} -ge ${MAX_RETRY} ] ; then
      echo "Error: timeout" >&2
      exit 1
    fi

    # クエリ実行完了を待つため一定時間待機
    sleep ${FETCH_INTERVAL_SECONDS}

    # クエリの状態取得
    query_execution_result=$(aws athena get-query-execution --query-execution-id ${query_id})
    query_state=$(echo ${query_execution_result} | jq -r '.QueryExecution.Status.State')

    # クエリ実行が完了していたら正常終了させる
    if [ ${query_state} = 'SUCCEEDED' ] ; then
      echo "${query_execution_result}"
      return
    fi

    try_cnt=$(( try_cnt + 1 ))
  done
}

# 事前にパーティションをロード
sql="MSCK REPAIR TABLE ${TABLE_NAME}"
athena_query_execution_sync "${QUERY_OUTPUT_LOCATION}" "${sql}"

# クエリ実行 (SQLは適当)
sql="SELECT * FROM ${TABLE_NAME} WHERE date='2017-10-21' LIMIT 20"
query_result=$(athena_query_execution_sync "${QUERY_OUTPUT_LOCATION}" "${sql}")
result_s3_path=$(echo "${query_result}" | jq -r '.QueryExecution.ResultConfiguration.OutputLocation')

# クエリ実行結果 (CSV) を stdout へ出力
aws s3 cp "${result_s3_path}" -

続きを読む

Proxyが厳しい企業内からも利用できるJupyter NotebookをAWS上に用意する

やりたいこと

  • Deep Learning向けのAIMを、Amazon AWSのEC2で動かす
  • Proxy内からもアクセスできるように、Jupyter NotebookをPort443で動かす
  • 通常は安く動かし、必要なときだけパワフルなGPUで動かす
    • インスタンスタイプを変更したらJupyter Notebookが自動で起動
    • インスタンスタイプを変更してもIPアドレスが変わない

Machine Learning や Deep Leaning を学習していると、自分のPCではパワーが足りなかったり、複数の環境を整えるために容量が足りなくなってきたりします。また、時間がかかる処理をさせている時には、コーヒーを飲みながらサクサクとWebサーフィンして待ちたいです。

そこでAmazonのAWS上にEC2インスタンスとして環境を作ります。Lazy Girlの記事を見ると、まさにDeep Learning向けのAMIが用意されている。GPUも使えます。

A Lazy Girl’s Guide to Setting Up Jupyter on EC2 for Deep Learning

Deep Learning AMIを起動

Lazy Girlの記事に従ってセットアップし、デフォルトのPort 8888 できちんとJupyter Notebookにアクセスできることを確認する。

なお、

source src/anaconda3/bin/activate root

をするだけで、

> which jupyter
~/src/anaconda3/bin/jupyter

となったので、.bash_profile にPATHを追加するくだりは必要なかった。

Port 443 で Jupyter Notebookを起動

Portを8888から、Proxyを通過できる443へ変更します。

nano ~/.jupyter/jupyter_notebook_config.py

c.NotebookApp.port = 443

そのままubuntuユーザでjupyter notebookを起動させようとすると、443のような低い番号のポートはダメだと怒られるので、rootで起動します。

sudo jupyter notebook --allow-root

これで厚いProxyの壁に阻まれた会社内からでもJupyter Notebookへアクセスして学習を続けられます!

自動起動の設定

インスタンスタイプを変更するには、一度EC2インスタンスをStopする必要があります。
自動的にJuypter Notebookが立ち上がるようにserviceとして登録しておくと便利です。
(会社のProxyがPort 22を通してくれないので、SSHして手動で起動させられない問題も解決)

sudo nano /etc/systemd/system/jupyter.service

[Unit]
After=network.target

[Service]
ExecStart=/home/ubuntu/start_jupyter.sh

[Install]
WantedBy=default.target

sudo chmod 664 /etc/systemd/system/jupyter.service

nano /home/ubuntu/start_jupyter.sh

#!/bin/bash

source /home/ubuntu/src/anaconda3/bin/activate root
cd /home/ubuntu/notebook
jupyter notebook

chmod 744 /home/ubuntu/start_jupyter.sh

サービスはrootユーザで起動するので、ubuntuユーザからsudoで起動する場合とは挙動が違うようです。rootユーザとして起動したときに読み込まれるjupyter_notebok_config.pyファイルを用意してあげます。

sudo su
>/home/ubuntu# cd
>~# mkdir .jupyter
>~# cp /home/ubuntu/.jupyter/jupyter_notebook_config.py /root/.jupyter/
>~# exit 

サービスを登録してスタート。きちんと動いていることを確認。

~$ sudo systemctl enable jupyter.service
~$ sudo systemctl start jupyter.service
~$ sudo systemctl status jupyter.service

Elastic IP でIPを固定

EC2インスタンスを再起動すると、IPアドレスが変わってしまいます。
Elastic IPサービスを使用すると、同じIPアドレスでアクセスできるようになります。

EC2 Management Console -> Elastic IPs -> Allocate new address

なお、EC2インスタンスをSTOPしている時にはElastic IPサービスの利用料が掛かります。(EC2インスタンスにattachされている時にはElastic IPサービスの部分は無料)

N.Virginiaでの料金だと、倹約のためにEC2インスタンスをSTOPしていても月に$3.6掛かります。t2.nanoをずっと動かし続けた$4.18とほとんど変わらない。

Instance Type Monthly $
stopped 3.60
t2.nano 4.18
t2.micro 8.35

おまけ (System Shell Command)

会社のProxyは非常に厳しく、Port 22を通してくれません。SSHでサーバにアクセスしてGitHubからexampleをダウンロードしたり、必要なモジュールをインストールしたりしたい時に困ります。

でもJupyter NotebookにさえWebブラウザからアクセスできればなんとかなります。

Jupyter NotebookのPython promptでは、!ping www.bbc.co.ukのように「!」で行をスタートすればシステムシェルコマンドが打てます。

Screen Shot 2017-10-21 at 10.40.29.png

続きを読む

aws ecr get-loginでunknown shorthand flag : ‘e’

aws ecr get-loginでエラーが返ってくる

$ aws ecr get-login | bash
unknown shorthand flag: 'e' in -e
See 'docker login --help'.

dockerのバージョンによっては aws ecr get-login | bash でエラーが発生するようです。

$ docker -v
Docker version 17.09.0-ce, build afdb6d4

解決法

--no-include-email を使う。

$ aws ecr get-login --no-include-email | bash

参考

続きを読む

logmonとALBのdrainingでリロード攻撃(F5アタック)へのパッシブ対策

以下の記事で紹介した小ネタの、具体的な利用例です。

1. 対策の内容

リロード攻撃(F5アタック)への対策としては、前段のApacheにmod_dosdetectorやmod_evasiveを入れる、WAFを導入する等があります。
このように、前段ですべて対応できれば良いのですが、

  • リロード攻撃を行っているのが正規ユーザである
  • リクエストによって(また、ユーザ毎に処理に必要なデータ量の多寡によって)レスポンスタイムにばらつきがある

というような場合、なかなか前段だけでの対処は難しいのではないかと思います。
そこで、Webアプリケーションサーバ(Tomcatなど)の処理が詰まってしまったときに、サービスの完全停止を避けるためにWebアプリケーションサーバの再起動を行うことがあると思いますが、

  • 「処理が詰まった」といっても、詰まり始めのうちは「特定の遅い処理」だけが「詰まる」のであり、それ以外のリクエストに対する処理は正常にレスポンスを返すことができている
  • 正常なレスポンスを返すことができるリクエストまで、再起動で中断するのは(なるべく)避けたい

ということで、Apacheのgraceful restartのような処理をしよう…というのが今回の内容です。

※きちんとgracefulな処理をするためには、Webアプリケーションサーバは複数台必要です。

2. ポリシー・IAM Roleの準備

まずは、先ほどの記事にある通り、以下の作業を行います。

  • ポリシーを設定する
  • 設定したポリシーをEC2用IAM Roleにアタッチする
  • そのIAM RoleをEC2(Webアプリケーションサーバ)にアタッチする

なお、今回のケースでは、「ec2:DescribeInstances」に対する権限は不要ですので、この部分はカットしても良いでしょう。

3. EC2上の設定

以下の記事を参考に、EC2(Webアプリケーションサーバ)にlogmonを導入します。

logmon.confには、以下の内容を設定します。

  • 1行目 : 監視対象のログファイル(Apacheのエラーログなら「:/var/log/httpd/error_log」など)
  • 2行目 : 監視対象のキーワード(正規表現/Tomcatのレスポンスが返らない場合を拾うのなら「[error] (70007)The timeout specified has expired」にマッチする内容)
  • 3行目 : 先の記事に示されているとおり

続いて、最初の記事で紹介したスクリプト「aws_utils.sh」を配置し(私の例では「/usr/local/sbin/」内)、「get_instance_id()」の部分だけ以下の内容に置き換えます。

aws_utils.sh(変更部分のみ)
#######################################
# 自身のインスタンス ID を取得する
# Returns:
#   INSTANCE ID
#######################################
get_my_instance_id() {
  instance_id=`/usr/bin/curl http://169.254.169.254/latest/meta-data/instance-id`
  if [ -z "$instance_id" ]; then
    echo 'host not found'
    exit 2
  fi
  echo ${instance_id}
}

※draining(登録解除の遅延)時間の長さに合わせて「SLEEP」の秒数も調整します。

それから、crontabから一定間隔で呼び出すスクリプト(私の例では「/usr/local/sbin/check_count.sh」)を配置します。

check_count.sh
#! /bin/sh

# スクリプトをインポートする
. /usr/local/sbin/aws_utils.sh

# トリガ判定
if [ `cat /tmp/logmon_count` -ge 20 ]; then

  # 閾値越え -> logmonサービス停止
  /sbin/service logmon stop

  # 二重トリガ起動防止(countを0に)
  echo 0 > /tmp/logmon_count

  # ALBでターゲットグループから外す
  ALB_TARGET_GROUP_ARN=('arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:targetgroup/YYYY/zzzzzzzzzzzzzzzz' 'arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:targetgroup/YYYY/zzzzzzzzzzzzzzzz')
  INSTANCE_ID=$(get_my_instance_id)

  for arn in ${ALB_TARGET_GROUP_ARN[@]}
  do
    alb_deregister ${arn} ${INSTANCE_ID}
  done

  # ALBでdraining完了待ち
  for arn in ${ALB_TARGET_GROUP_ARN[@]}
  do
    alb_waiter ${arn} ${INSTANCE_ID} 'unused' > /dev/null
  done

  # Webサービス停止
  /sbin/service tomcat8 stop

  /bin/sleep 10

  # サービス起動
  /sbin/service tomcat8 start

  /bin/sleep 10

  /sbin/service logmon start

  # ALBでターゲットグループに戻す
  for arn in ${ALB_TARGET_GROUP_ARN[@]}
  do
    alb_register ${arn} ${INSTANCE_ID}
  done

  # ターゲットグループに戻ったことを確認する
  for arn in ${ALB_TARGET_GROUP_ARN[@]}
  do
    alb_waiter ${arn} ${INSTANCE_ID} 'healthy' > /dev/null
  done

fi

# countを0に
echo 0 > /tmp/logmon_count

if文の「20」は閾値です。適切な値に調整してください。
この例ではWebアプリケーションサーバとしてTomcat8を使っていますが、適切なものに置き換えてください。Tomcatの場合は、draining前後でPrintClassHistogramの出力などもしておくと良いです。

また、この例ではEC2(Webアプリケーションサーバ)を複数のターゲットグループ(配列「ALB_TARGET_GROUP_ARN」)に登録しています。
それぞれのターゲットグループでdraining時間が違う場合は、時間が短いものを先に記述すると良いです(後述の通りログを記録する場合は特に)。
1つの場合は配列にせず、for文で回す必要もありません。

なお、この例ではログを /dev/null に捨てていますが、実際に使うときにはきちんとログファイルに記録しておいたほうが良いです(時刻などとあわせて)。

最後に、このスクリプトを、実行ユーザ(rootなど)のcrontabに登録します(私の例では1分間隔で実行⇒閾値は1分当たりのカウントに対して設定)。このとき、1行目に「SHELL=/bin/bash」を挿入しておきます。

crontab登録例
SHELL=/bin/bash

*/1 * * * * /bin/sh /usr/local/sbin/check_count.sh

設定できたら、カウントファイル(私の例では「/tmp/logmon_count」)に閾値以上の値を書き出して、正しくdraining→ターゲットから削除→Webアプリケーションサーバ再起動→ターゲットに登録が行われるか、確認します。

テスト
echo 20 > /tmp/logmon_count

4. 注意点

drainingすると再起動には時間が掛かるので、Webアプリケーションサーバは最低でも4台程度は必要です。

続きを読む

CloudFrontキャッシュを削除するシェルスクリプトを書いてみた。

AWS CLI を使えば、 AWS Console へアクセスすることなく
CloudFrontキャッシュの削除も行えます。

削除対象が多い場合はその対象を記したjsonファイルを用意して、
AWS CLI からそのjsonファイルを利用して CloudFrontキャッシュ の削除を行うのですが、
毎回書き換えが必要な項目がjsonファイル内にあります。

手作業で毎回書き換えてましたがさすがに面倒になってきたので
シェルスクリプトを書きました。

Macユーザーなので Macでの作業想定で書きます。

概要

AWS Consoleアクセスすれば、
Cloud Frontのキャッシュ手動削除はできるのですが、
面倒なので AWS CLI を使ってシェルスクリプトから
削除できるようにしたものです。

必要な準備

AWS CLI のローカルインストール

詳しいインストール手順はこちら

macOSの場合は Python 2.6.3 以降が必要なので

$ curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
$ sudo python get-pip.py

で pip をインストールしてから

$ sudo pip install awscli

して

$ aws help

でヘルプが出ればOKです。

AWS CLI の設定

CLI利用するのに専用の configure 設定を一度行う必要があります。
これも上記URLに設定方法があるのですが、

  • AWS Access Key ID(以下 AKID)
  • AWS Secret Access Key(以下 SAK)
  • region name
  • output format

の4つが必要です。
この設定プロファイルは

~/.aws/credentials # AKID と SAK

~/.aws/config # region name と output format

に入ります。

プロファイル名を付ければ複数のプロファイルを格納できます。
この2ファイルは1回設定しちゃえばあとはいじらなくてOKです!

↓こんな感じ

~/.aws/credentials
[profile hogehoge]
aws_access_key_id=****************      # AKID
aws_secret_access_key=****************  # SAK
~/.aws/config
[profile hogehoge]
region=ap-northeast-1                   # region name
output=json                             # output format

invalidation-batch の準備

削除対象を指定するバッチファイル(json)を作成します。
↓こんな感じです。

invbatch.json
{
    "Paths"  : {
        "Quantity": 5,
        "Items"  : [
            "/",
            "/sp/",
            "/css/main.css",
            "/js/libs.js",
            "/js/main.js"
        ]
    },
    "CallerReference": "YYYYMMDD-HHNNSS"
}

Itemsに削除対象を DocumentRoot からのパスで指定します。
ワイルドカード()も使えます。
この指定方法は **AWS Console
* での指定方法と一緒です。

注意点

CallerReference は毎回ユニークな値を入れておかなければいけません。
これが意外と面倒なのでこの部分の書き換え込みでシェルスクリプト化しました。

Note:
削除対象が変われば ItemsQuantity も変えなきゃです、、

このファイルは削除対象の変更がなければ、1回設定しちゃえばあとはいじらなくてOKです!

キャッシュ削除用シェルスクリプト設定

シェルスクリプトに実行権限$ chmod a+x ***を与えておいて、実行します。
中身は↓こんな感じです。

clear_cache.sh
#!/bin/bash

# 設定用変数
dist_id="*******************"   # AWS CloudFrontのDistribution ID
batch_json="invbatch.json"      # nvalidation-batchファイル名
profile="hogehoge"              # プロファイル名
url="http://hogehoge.jp"        # サイトURL

# 実行部分
echo "Move directory ..."
cd `dirname $0`
echo "Invbalidation-batch json update"
echo `less $batch_json_base | jq '.CallerReference |= "'$profile'_'$time_stamp'"'` > $batch_json
echo "CloudFront cache clear ..."
echo `aws cloudfront create-invalidation --distribution-id $dist_id --invalidation-batch "file://$batch_json" --profile $profile`

※ jq使ってjsonの書き換えを行なっているのでjqのインストールが必要です。

jqのインストール方法
https://stedolan.github.io/jq/download/

コード内のコメントにありますが、

  • AWSのCloudFrontDistribution ID
  • nvalidation-batch ファイル名
  • プロファイル名
  • サイトURL

が必要です。

このファイルは1回設定しちゃえばあとはいじらなくてOKです!

キャッシュ削除シェルスクリプト実行

$ ./clear_cache_shupure.sh
Move directory ...
Invbalidation-batch json update
CloudFront cache clear ...
{ "Invalidation": { "Status": "InProgress", "InvalidationBatch": { "Paths": { "Items": [ "/images/girls/*.png", "/", "/images/sakabar/*.png", "/images/events/*.jpg", "/sp/gekijo/", "/sp/sakabar/", "/gekijo/", "/sp/", "/images/girls/0924.png", "/css/main.css", "/sakabar/" ], "Quantity": 11 }, "CallerReference": "shupure_1506515279" }, "Id": "I2N11BY0PH6UI9", "CreateTime": "2017-09-27T12:28:03.125Z" }, "Location": "https://cloudfront.amazonaws.com/2017-03-25/distribution/E1JZGHRP8PFLBD/invalidation/I2N11BY0PH6UI9" }
CURL check ...
 % Total  % Received % Xferd Average Speed  Time  Time   Time Current
                 Dload Upload  Total  Spent  Left Speed
 0 50672  0   0  0   0   0   0 --:--:-- --:--:-- --:--:--   0
 X-Amz-Cf-Id: eHRIZxCp2k5-aecSw1ABCI-OB7aPtK_EEs4y0elK8bucqB6e1B-zrA==

CloudFront キャッシュ削除のレスポンスjsonが改行されてないのが気持ち悪いですが、
InProgressが表示されていればキャッシュ削除スタートしてます。

キャッシュ削除されてるかはcurlなどでレスポンスヘッダを確認してください。

$ curl -I http://hogehoge.jp

続きを読む

ec2(amazon linux)にnode.jsを導入

前提
 ・EC2のインスタンスを作成済み(yumのupdateも完了)
 ・インスタンスのセキュリティーグループでsshを許可している
 ・インスタンスにSSHに繋げる
 ・Macでターミナルを使用

手順
 1. 依存パッケージのインストール
 2. node.js v6 をインストール(当時の安定版の最新版)
 3. node.jsのインストール

1. 依存パッケージのインストール

sudo yum install -y gcc-c++ make

2. node.js v6 をインストール(当時の安定版の最新版)

curl --silent --location https://rpm.nodesource.com/setup_6.x | sudo bash -

3. node.jsのインストール

sudo yum install -y nodejs

以上〜♪

続きを読む

AWSでインスタンス起動直後にシェルスクリプトを実行

シェルスクリプトを用意

実行したいシェルスクリプト/path/to/target_shell_script.sh

#!/bin/bash
# chkconfig: 2345 98 20
# description: service_name
# processname: service_name

date >> /home/rev84/date.log

んで service に登録

#コピーする場合
sudo cp /path/to/target_shell_script.sh /etc/init.d/service_name
# 直接書く場合
#sudo vim /etc/init.d/service_name

sudo chmod 0755 /etc/init.d/service_name
sudo chkconfig --add service_name
sudo chkconfig service_name on

停止し、起動すると実行される。

続きを読む

EC2 へ fish-shell インストール

» 良くわからないけどできた感じなので、他にもっといい方法有ると思う。

LinuxBrew インストール

homebrewのlinux版みたいなものらしい。これを叩く。

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install)"
ログ
==> Installation successful!
# ...
Warning: /home/linuxbrew/.linuxbrew/bin is not in your PATH.

(パス通すか)これでコマンドが使えます。

/home/linuxbrew/.linuxbrew/bin/brew 

Fish インストール

homebrewと一緒ですね。

/home/linuxbrew/.linuxbrew/bin/brew install fish
ログ
==> Caveats
You will need to add:
  /home/linuxbrew/.linuxbrew/bin/fish
to /etc/shells.

Then run:
  chsh -s /home/linuxbrew/.linuxbrew/bin/fish
to make fish your default shell.

==> Summary
🍺  /home/linuxbrew/.linuxbrew/Cellar/fish/2.6.0: 896 files, 48.3MB

/etc/shells へ追記

sudo vim /etc/shells

で、/home/linuxbrew/.linuxbrew/bin/fishを一番最後の行に追加します。

こんな感じになる

/etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash
/home/linuxbrew/.linuxbrew/bin/fish

デフォルトシェル変更

ユーザー名は好きな名前で、chshします。

sudo chsh -s /home/linuxbrew/.linuxbrew/bin/fish ec2-user

確認

一旦sshを入り直して、$SHELLがちゃんと変ったらOK。

ec2-user@ip-x-x-x-x ~> echo $SHELL
/home/linuxbrew/.linuxbrew/bin/fish

ただやっぱり、linuxbrewでインストールしたコマンドを使いやすくするためにconfig.fishではパスを追加した方がいいかも。

vim ~/.config/fish/config.fish
~/.config/fish/config.fish
set -gx PATH /home/linuxbrew/.linuxbrew/bin $PATH

続きを読む

unisonでローカルとサーバをお手軽に同期する

はじめに

ローカルとサーバのディレクトリを同期する必要があったので、今回unisonを使ってみました。
予想以上にunisonのバージョンを揃えたりと面倒だったのでインストール手順を残しておきます。
基本的に上からコピペすれば動くと思います。

ローカル

unisonのインストール
$ brew install unison
# プロジェクトを作成
/Users/user.name/.unison/project.prf

下記参考に諸々書き換える(IPはhostでいける)
これがどこのサーバと同期するか、何を同期するかの設定ファイルとなります。

# リモートのディレクトリ
root = ssh://project.com//var/www/project
# ローカルのディレクトリ
root = /Users/user.name/Desktop/project


ignore = Path vendor
ignore = Name {tmp,log}
auto = true
times = true
prefer = newer

サーバ

結構長い
コケるけど無視

curl -kL https://raw.github.com/hcarty/ocamlbrew/master/ocamlbrew-install | bash

インストールが終わるとocamlbrewというディレクトリが出来ます。

.bashrcに下記をコピペ(ocamlbrewのバージョンは合わせてください)

.bashrc
__ocaml_path__="$HOME/ocamlbrew/ocaml-4.03.0" # ~/ocamlbrewをlsしてみて適切なバージョン番号に置き換えてください
PATH="$__ocaml_path__/bin:$PATH"
export OPAMROOT="$__ocaml_path__/.opam"
source "$OPAMROOT/opam-init/init.bash" > /dev/null 2> /dev/null || true

パスを通す

source ~/.bashrc

インストール

ここも少し長い

opam switch 4.03.0

インストール

opam install oasis utop Batteries ocamlscript
sudo yum install ocaml ocaml-camlp4-devel ctags ctags-etags

ファイルをダウンロード&移す

サーバにインストールするために、パッケージをダウンロードします。
ローカルとサーバのunisonのバージョンを合わせる必要があるので、ローカルにインストールしたバージョンをダウンロード
してください。

サイト http://www.seas.upenn.edu/~bcpierce/unison//download/releases/

macで解答

解凍したファイルをサーバにアップロード

scp -r /Users/shoichi/Downloads/src project.com:/home/webmaster

アップロードしたファイルに移動してビルド

make
# ビルドが終わったらこのコマンドをインストールしたら叩く
sudo cp -v unison /usr/bin/

これでセットアップが完了しました。
あとはローカルに戻って下記を実行して、同期していきましょう。

実行

unison project -repeat watch

以上です。

参考

http://qiita.com/yuya_presto/items/f35f556770196f964810
https://plus.google.com/103080563170453474101/posts/ZMBytWVkhTn
https://www.digitalocean.com/community/questions/install-unison-in-centos-7

続きを読む

[AWS]EC2シャットダウン時にログをS3に逃がす

AWS上でAutoScaleを利用していると、ヘルスチェックでミスったりの予期せぬEC2停止でEC2ごと削除されることがままあります。
いざ原因をログから解析しようと思っても、EC2ごとログが消えているため、どうにもならないことがありました。

そんなときのためにEC2停止時に指定したログをS3上に逃がすスクリプトを作成しました。
注:この方法は、EC2がshutdownコマンドなどで正常停止する場合に取得可能です。(AutoScaleなどから切り離された時など)
EC2自体がカーネルパニックやハードウェア障害で正常に停止していない場合はこの方法では救えません(経験上ほぼないですが)

[必要なもの(※Amazon Linuxに設定する前提)]

-EC2停止時にS3にログを退避するスクリプト
-退避する対象のログリスト
-ログ退避スクリプトをEC2停止時に実行するサービス起動・停止(init.d)スクリプト

[EC2停止時にS3にログを退避するスクリプト]

日付とインスタンスIDをログに付与してS3にアップロード
※1 以下はawsの情報取得にcredentialsにアクセスキーを記載して利用しているが、IamRoleを利用できるならばそのほうがよい
※2 パスも/usr/local/bin/と/usr/local/etc/を利用しているが任意

/usr/local/bin/logmvs3_shutdown.sh
#!/bin/sh

DATESTR=`date +%Y%m%d_%H%M%S`

# コンフィグ情報読み込み
INSTANCEID=`wget -q -O - http://169.254.169.254/latest/meta-data/instance-id`
AWSSETTING=/root/.aws/credentials
SRCFILELIST=/usr/local/etc/shutdown_targetfile.txt
TMPCPPATH=/tmp/logtmp
BUCKET=hogehoge-log
FOLDER=hoge/shutdown

export AWS_CONFIG_FILE=$AWSSETTING

# ログ取得の対象を作業フォルダにコピー
mkdir -p $TMPCPPATH 2>/dev/null

cat ${SRCFILELIST} | while read FILEPATH
do
cp -f ${FILEPATH} $TMPCPPATH/
done

# 指定パス対象にgzip化
for i in `find $TMPCPPATH -maxdepth 1 -type f | egrep -v gz`
do
        gzip -c $i > $i"_shutdown_"$INSTANCEID"_"${DATESTR}.gz
        rm -f $i
done

# S3のフォルダへ.gzファイルをアップロード 合わせて、取得したログ一覧も
aws s3 cp $TMPCPPATH s3://$BUCKET/$FOLDER/$DATESTR/ --exclude "*" --include "*.gz" --recursive
aws s3 cp $SRCFILELIST s3://$BUCKET/$FOLDER/$DATESTR/

# 作業フォルダを削除する
rm -rf $TMPCPPATH
[EC2停止時にS3にログを退避するスクリプト]

ファイル単位で指定
ここではシステム関連の/var/log/のみ退避させている。tomcatやnginxなどのアプリケーションログも指定可能
各システムに必要なものを指定する

/usr/local/etc/shutdown_targetfile.txt
/var/log/messages
/var/log/cron
/var/log/secure
[ログ退避スクリプトをEC2停止時に実行するサービス起動・停止(init.d)スクリプト]

サービス起動時に2重起動防止をしておき、サービス停止時(マシン停止時)にスクリプトを実行
chkconfig: runlevel 起動順番 終了順番 のため、起動を一番遅く、停止時は一番早く実行する

/etc/rc.d/init.d/logmvs3_shutdown
#!/bin/bash
#
# Version: 0.1
#
# chkconfig: 345 99 01
# description: logmvs3_shutdown shell
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin

# Source function library.
. /etc/init.d/functions

start() {
        touch /var/lock/subsys/logmvs3_shutdown
}

stop() {
        rm -f /var/lock/subsys/logmvs3_shutdown
        /usr/local/bin/logmvs3_shutdown.sh

restart() {
        stop
        start
}


case "$1" in
        start)
                start
                ;;
        stop)
                stop
                ;;
        restart)
                restart
                ;;
        *)
                echo "Usage: $0 {start|stop|restart}"
                exit 1
esac
exit 0
[サービス登録と確認]

あとは以下のコマンドを実行し、サービスに登録および開始しておく
chkconfig --add logmvs3_shutdown
service logmvs3_shutdown start

再起動してみて、指定のS3バケットのフォルダにログがアップロードされていればOK

続きを読む