このエントリーをはてなブックマークに追加

Homebrew Cask をまとめてアップグレードするシェルスクリプトを作った

2017年初めてのブログになります。
今年は小さい内容でも、できる限りアウトプットしていきたいと思います。

さて、日頃使っている Homebrew Cask ですが、まとめたアップグレードするとき、このエントリにあるようなスクリプトを使っていました。

ただ、最近のアップグレードでこの方法が利用できなくなってしまいました。
そこで、とりあえず自前でシェルスクリプトを書いてみました。

検索したところ、homebrew-cask-upgradeのようなものがあったのですが、動作しませんでした。

ポイントとしては、`brew update` で Homebrew Cask ファイルはアップグレードされる前提で、`brew cask info` したときの結果を解析して、バージョンが違っていた場合は、`brew cask reinstall` を実行しているだけです。

手元の macOS では動いているので、しばらくこのシェルスクリプトを使ってみようかと思います。

また、`brew cask update` を実行すると、次のようなメッセージが表示されるので、もう利用しない方が良いかもしれませんね。


Warning: Calling `brew cask update` is deprecated and will be disabled on 2017-07-01!

このエントリーをはてなブックマークに追加

2016年の自分と Datadog

このエントリは、Datadog Advent Calendar 2016 の 10 日目のエントリです。

2016年を振り返ってみると、Datadog をフル AWS の本番システムに導入して本格稼働している年でした。
実はまだまだすべての設定は完了していないのですが、2016年の自分と Datadog について、どのような関わりがあったのか、このエントリで振り返ってみたいと思います。

2016年2月
フル AWS のシステム向けのモニタリングツールで Datadog を導入することが正式に決まりました。
そこで、チーム向けに Datadog について簡単に紹介してしほしいと相談されたので、まずは Datadog 入門編のスライドで紹介しました。

このスライドでは、Datadog の一通りの機能を紹介しています。

2016年8月
こうして、Datadog Agent を導入していたのですが、いくつか使いにくい部分があったのでDatadog Agent にいくつかプルリクエストを送ってみました。Python は、あまり本格的には書いたことがなかったのですが、やりたいことベースだったので、とても楽しく変更することができました。

今日時点で3件ほど、DataDog Agent に無事マージされました。なかなか時間がかかったものがありましたが、OSS へ貢献するという貴重な体験ができました。

それでは、プルリクエストの内容を振り返ってみたいと思います。

バージョン 5.9.0 では、HTTP/HTTPS URL を監視するための http_check である URL がリダイレクトコードを返すかどうか確認したいことがあったので、”allow_redirects” パラメータを追加しました。このパラメータを false に設定すると、実際にリダイレクトはしないため、その時点の HTTP ステータスコードを監視することができます。これで、302 などを監視することができるようになりました。

バージョン 5.10 では、SSH 接続を監視するための ssh_check に SSH キータイプ ECDSA を追加しました。最近では、Ed25519 というキータイプが主流になっているので、このキータイプも対応したいことですが、内部で使っている paramiko がどうも対応していないらしく、Issue にあげて

もう一つ、プロセスを監視する process に PID ファイルを指定することができるようになりました。今までの process はプロセス名の文字列のみでしか指定できなかったので、PID ファイルを指定することで、さらに便利にプロセスの監視ができるようになりました。

あと一点 MySQL の監視でクエリー数が 20 に制限されている理由を聞いてみたのですが、無視されているため、とりあえずこの制限を外したもので本番システムは監視していますね。

まだまだ、微妙に改善したいところがあるので、来年以降も順次プルリクエストを投げていきたいと思います。

もう一つ Ruby のクライアントのdogapi-rb ですが、なんとなく CI が警告をはかないように修正のプルリクエストを投げました。最初はまったく返信がなかったのですが、プルリクエストを修正して再度提出したところすぐにマージしてくれました。

2016年11月
#dd_sushi 〜 Datadog and Sushi の秋が開催されたので参加してきました。Sushi はわずか 5 分ほど?で完売してしまったらしいのですが、勝手に飛び込み LT をしようと思って資料を準備したのですが、けっこうお堅い雰囲気で LT をすることができませんでした。

いちお、スライドを公開しておきます。

こんな感じで、2016年の自分と Datadog との関わりを振り返ってみました。
早く、Datadog APM も試してみたいですし、その他の新機能も続々とリリースされる様子なので、もっと手軽に楽に夜も安眠できるように Datadog を使って効率的にシステムのモニタリングを行っていきたいと思います。

このエントリーをはてなブックマークに追加

Codenize Meetup で LT してきました

Codenize Meetup で LT 枠が急遽空いたので LT をしてきました。

少し前に作って、今でも業務でバリバリ使っている Kumogata のラッパーツール kumogata-template について紹介しました。

個人的には、業務で AWS だけを使うなら、Terraform よりも CloudFormation だなと思います。少し前までは、最新のリソースに追いついていないことがあったのですが、今ではあまりそんなことはない印象です。

Kumogata は、CloudFormation の JSON 変換ツールなので、実際には CloudFormation で簡潔しているので、最悪の場合 JSON を直接変更できるし、change set という機能で dry-run 的なこともできます。

今回の Meetup でも、Terraform で消耗しているお話がありましたが、CloudFormation ではあまり消耗することもないです。商用サポートもあるところも、業務で使うには、重要なところだと思います。

とても素晴らしい実りのある Meetup でしたので、第2回に期待です。

あと、個人的にもできる限り Codenize には貢献していきたいです。

久しぶりに LT というアウトプットをしましたが、やっぱりアウトプットすることで学びがあるので、今後も定期的にアウトプットをしていきたいと思います。

このエントリーをはてなブックマークに追加

CentOS 7 で手軽に Ruby 2.3 を使う方法

CentOS 7 の System Ruby は、2.0 系です。System Ruby はそのままに、2.3 系を手軽に使う方法を紹介したいと思います。

まず、EPEL が入っている環境で CentOS SCLo Software Collections をインストールします


# yum -y install centos-release-scl-rh centos-release-scl

Ruby 2.3 をインストールします。


$ yum -y install rh-ruby23

あとは、/etc/profile.d/ruby23.sh を、次のように作成します。


# /etc/profile.d/ruby23.sh - ruby 2.3

source /opt/rh/rh-ruby23/enable
export X_SCLS="`scl enable rh-ruby23 'echo $X_SCLS'`"

これで、ログインし直させば、自動的に Ruby 2.3 に PATH が通っていますので、Ruby 2.3 を手軽に使うことが出来ます。

このエントリーをはてなブックマークに追加

xargs のちょっとした Tips

xargs を使うと手軽にコマンドを並列実行できて便利ですが、xargs を使ったいくつかのちょっとした Tips を紹介したいと思います。

基本は、次のようなになります。


$ echo a"\n"b | xargs -t -P 2 -n 1 echo "command"
echo command a
command a
echo command b
command b

この例だと、”command (a|b)” を表示するコマンドになりますが、echo をとることで任意のコマンドの末尾に自由にパラメータを渡すことができます。

末尾ではなく、コマンドの途中のパラメータを渡したいときは、次のようにするとできます。


$ echo -e a"\n"b | xargs -t -P 2 -n1 -I '{}' echo "command {} param2"
echo command a param2
command a param2
echo command b param2
command b param2

-I オプションを使うと、任意のパラメータに置換することができます。上の例だと、{} になります。xargs に渡すパラメータが改行区切りでないといけないので注意してくさい。
そのままやってしまうと、次のようになります。


$ echo a"\n"b | xargs -t -n1 -P 2 -I '{}' echo "{} command"
echo a b command
a b command

ちゃんとコマンドを並列実行する場合は、GNU Paralell を使うのが定番ですが、インストールする必要があるので、お手軽にやりたいときには xargs を使うと便利です。

# 10/19 追記
コメントにあった指摘で、-P オプションを付与するように修正しました。

このエントリーをはてなブックマークに追加

CentOS 7.x で最新の Node.js をインストールする方法

CentOS 7.x 公式で提供している Node.js のバージョンは、現時点で 0.10.42 とかなり古いバージョンになります。
現在の Node.js の最新の安定版は 6.x ですから、こちらをインストールしてみたいところです。

もちろん、普通にコンパイルしてインストールする方法があるのですが、コンパイルはせずにパッケージなどでさくっと導入したいと思って、その方法を調べてみました。すると、2つの方法がありそうです。

1. n package を使ってインストールする方法
この方法では、既存の node.js npm から n というパッケージを導入して、n パッケージ経由で node.js を複数バージョンできるものです。今回は、複数バージョンではなく、単に安定版だけをインストールしたかったので、この方法は見送りました。

2. NodeSource が提供しているパッケージを使う
NodeSource から、deb、yum、向けに各バージョンの node.js パッケージが提供されています。
CentOS 7 もサポートされているため、今回はこちらの方法で Node.js を差し替えてみました。

方法は、次のとおりです。

1. 既存の node.js を削除します

$ sudo yum remove -y nodejs npm

2. NodeSource の yum リポジトリを追加します

# curl -sL https://rpm.nodesource.com/setup_6.x | bash -
あるいは直接パッケージをインストールします
# rpm -i https://rpm.nodesource.com/pub_6.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm

3. node.js をインストールします

$ sudo yum install -y nodejs
※自動的に、対応している npm などもインストールされます
$ node -v
v6.4.0

ということで、手軽に CentOS 7.x に最新安定版の Node.js をインストールすることができました。
Node.js のバージョンアップ追従もパッケージ側の方もちゃんと行っているため、とても便利でした。

このエントリーをはてなブックマークに追加

[macOS] git-secret が動かなかった

ご存じ git-secret とても便利ですが、ふとちゃんと使っていたところ、git commit 時に、次のように失敗していました。


$ git commit -m "foo" foo.txt
[ERROR] Matched one or more prohibited patterns

Possible mitigations:
– Mark false positives as allowed using: git config –add secrets.allowed …
– Mark false positives as allowed by adding regular expressions to .gitallowed at repository’s root directory
– List your configured patterns: git config –get-all secrets.patterns
– List your configured allowed patterns: git config –get-all secrets.allowed
– List your configured allowed patterns in .gitallowed at repository’s root directory
– Use –no-verify if this is a one-time false positive

よくよく原因を調べてみると、git-secret の commit_msg_hook フックの grep コマンドに失敗しているのが分かりました。
macOS の grep は、BSD 由来の grep だったことが原因でした。


/usr/bin/grep --version
grep (BSD grep) 2.5.1-FreeBSD
83242 (prj/github/github-practic

GNU grep で切り替えて、無事対処しました。いちお、issue をこっそり本家に投稿しておきました。
alias grep=ggrep だとうまくいなかったので、思い切って gnu grep に入れ替えてみました。


$ brew tap homebrew/dupes
$ brew install grep --with-default-names

これで無事 git-secret が動作しているので、クラウド破産の危機が減ったかと思います。

あと、この情報を参考に、ついでにいくつか GNU のものにまとめて差し替えてみました。BSD 系のものを使うときには /usr/bin/ を指定すればよいので忘れないでおきます。

このエントリーをはてなブックマークに追加

EMR 上の Hadoop / Spark の Web UI にアクセスする方法

プライベートサブネット上に EMR 上の Hadoop / Spark の Web UI をインターネット経由でアクセスしたくなりました。

ちゃんとした方法ですと、EMR上でSparkのWeb UIにアクセスする方法 | Developers.IOにあるとおり、次の2つ選択肢があるようです。

  1. SSH トンネリング
  2. SSH トンネリング + SOCK プロキシ

どちらも SSH を利用するため、外部からは接続はできません。

あとは、AWS VPC VPN 接続を使ってプライベートサブネットに接続する選択肢が考えられますが、この場合拠点に VPN が必要です。

そのような環境はなかったので、同一プライベートサブネット上の Nginx からプロキシする方法で設定してみました。

まず試してみると、ほとんどプライベート DNS になっているため、Nginx プロキシでレスポンスボディを変更する必要がありました。

レスポンスボディを書き換えることができるモジュールを探してみたところ、openresty/replace-filter-nginx-moduleyaoweibin/ngx_http_substituions_filter_module がありました。

どちらのモジュールも試したところ、前者の replace-filter-nginx-module は複数箇所の書き換えがなぜかうまくできず、結果的には後者の  ngx_http_substitutions_filter_module を使うことになりました。

Hadoop UI を /cluster、Spark UI を /spark、としていますが、ちょっと長くなりますが、次のようにかなり無理矢理ですが、設定することで無事うまくいきました。
なお、proxy まわりの設定は必要最低限の設定にしてあります。

    # Ganglia
    location /ganglia {
        proxy_pass http://EMR Master Public DNS:80/ganglia;
        proxy_redirect off;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # Hadoop UI
    location /cluster {
        resolver [Private DNS ※Ansible でいうと ansible_dns.nameservers[0] とかになりますね] valid=60s;
        set $backend "";
        set $my_host "";
        set $my_port "";

        if ($request_uri ~ /cluster/_/(.+)$) {
            set $backend $1;
        }

        if ($request_uri ~* ^/cluster/_/(.+?):(\d+)\/.+$) {
            set $my_host $1;
            set $my_port $2;
        }

        if ($backend != "") {
            proxy_pass http://$backend;
            break;
        }

        if ($request_uri ~* /cluster/static/(.+)$) {
            proxy_pass http://EMR Master Public DNS:8088/static/$1;
            break;
        }

        # この設定が、レスポンスボディを変更する設定です
        # Then の書き換えは必要ないですが、見栄え的に修正しました
        subs_filter "Then, " ". Then, " r;
        subs_filter "href=\"/static" "href=\"/cluster/static" r;
        subs_filter "src=\"/static" "src=\"/cluster/static" r;
        subs_filter "<a href=\"http://(.+):8088\"" "<a href=\"/cluster\"" r;
        subs_filter "<a href='http://(.+):8088/(.+)'" "<a href='/$2'" r;
        subs_filter "<a href=\"http://(.+):8088/cluster/(.+)\"" "<a href=\"/cluster/_/$1:8088/cluster/$2\"" r;

        subs_filter "<a href=\"//(.+):8042\"" "<a href=\"/cluster/_/$1:8042/node\"" r;
        subs_filter ",\"<a href='http://(.+):8042'" ",\"<a href='/cluster/_/$1:8042/node'" r;
        subs_filter ",\"<a href='http://(.+):8042/(.+)'" ",\"<a href='/cluster/_/$1:8042/$2'" r;
        subs_filter "http-equiv=\"refresh\" content=\"1; url=http://(.*)\"" "http-equiv=\"refresh\" content=\"1; url=https://$host/cluster/_/$1\"" r;

        subs_filter "<a href='http://.+:20888/(.+)'" "<a href='/spark'" r;
        subs_filter "<a href=\"http://.+:20888/(.+)\"" "<a href=\"/spark\"" r;

        subs_filter "href=\"/node\/node" "href=\"$request_uri" r;
        subs_filter "href=\"/node\/allApplications" "href=\"$request_uri/allApplications" r;
        subs_filter "href=\"/node\/allContainers" "href=\"$request_uri/allContainers" r;

        subs_filter "href=\"/jobhistory/(.+)" "href=\"/cluster/_/$my_host:$my_port/jobhistory/$1" r;
        subs_filter "href=\"/(conf)" "href=\"/cluster/_/$my_host:$my_port/$1" r;
        subs_filter "href=\"/(logs)" "href=\"/cluster/_/$my_host:$my_port/$1" r;
        subs_filter "href=\"/(stacks)" "href=\"/cluster/_/$my_host:$my_port/$1" r;
        subs_filter "href=\"/(jmx)(.+)" "href=\"/cluster/_/$my_host:$my_port/$1$2" r;

        proxy_pass http://EMR Master Public DNS:8088/cluster;
        proxy_redirect off;
     }

    location /spark {
        resolver [Private DNS ※Ansible でいうと ansible_dns.nameservers[0] とかになりますね] valid=60s;
        set $backend "";
        set $my_host "";
        set $my_port "";

        if ($request_uri ~ /spark/_/(.+)$) {
            set $backend $1;
         }

        if ($request_uri ~* ^/spark/_/(.+?):(\d+)\/.+$) {
            set $my_host $1;
            set $my_port $2;
        }

        if ($backend != "") {
            proxy_pass http://$backend;
            break;
        }

        if ($request_uri ~* /spark/static/(.+)$) {
            proxy_pass http://EMR Master Public DNS:18080/static/$1;
            break;
        }

        if ($request_uri ~* /spark/history/(.+)$) {
            proxy_pass http://EMR Master Public DNS:18080/history/$1;
            break;
        }

        # この設定が、レスポンスボディを変更する設定です
        subs_filter "href=\"/\"" "href=\"/spark\"" r;
        subs_filter "href=\"/static" "href=\"/spark/static" r;
        subs_filter "src=\"/static" "src=\"/spark/static" r;
        subs_filter "href=\"/history/application_(\w+)/(\d+)\"" "href=\"/spark/history/application_$1/$2/jobs/\"" r;
        subs_filter "?id=" "/?id=";
        subs_filter "href=\"/\?page(.+?)\"" "href=\"/spark/?page$1\"" r;

        subs_filter "<a href=\"http://(.+):8042/(.+)\"" "<a href=\"/cluster/_/$1:8042/$2\"" r;

        proxy_set_header Accept-Encoding "";

       proxy_pass http://EMR Master Public DNS:18080/spark;
       proxy_redirect off;
}

このようにして頑張って書き換えてプロキシさせてあげると、Hadoop/Spark UI をウェブ経由で手軽に見ることができます。

もちろん、上記にあげたポートは Security Group で許可してする必要があります。node も含めると、具体的には 80, 8041, 8042, 8088, 18080, 19888, 20888, ポートの接続許可が必要です。
は、EMR のクラスターごとの固有設定になりますので、僕はプライベート DNS を Route 53 に登録して、その内部ドメインを参照しています。

なお、この方法ですと、EMR がバージョンアップしたときにはその都度 UI に変更があれば subs_filter の変更が必要になります。

上の設定は EMR Release 4.6.0 Hadoop 2.72. + Spark 1.6.1 の環境で動作確認しています。

# 6/16 追記

一部 /spark の書き換えルールを修正しました。

この設定で問題がないと思ったんですが、Spark History Server どうも同じ URL なのにも関わらず初回は 302 を返すため、http 経由でもアクセス可能として、次のような設定を入れる必要がありました。
具体的には、 “https:// server_name/spark/history/application_1464686385340_0492/1/jobs/” にアクセスすると、”http://server_name/history/application_1464686385340_0492/1/jobs/” に 302 リダイレクトされます。。。

location /history {
    rewrite ^/(.*) https://server_name/spark/$1 redirect;
}
このエントリーをはてなブックマークに追加

td-agent のカスタムパッケージを作った

td-agent とても便利ですよね、fluentd をインストールするのに、もっとも手軽な方法だと思って、いつも愛用しています。

さて、fluentd のプラグインが増えていくると、特に複数台のサーバに導入するとき、けっこうな時間がかかって来ました。
せっかく、omnibus-td-agent が公開されているので、これをカスタマイズしてみました。

このカスタマイズでの、公式 omnibus-td-agent からの差分はこちらになりますが、おもに次のようなカスタマイズを行っています。

  • specific_install のインストール(たまに検証用に使ったり、rubygem にないものをどうしても使いたいとき)
  • fleuntd バージョンの固定(現行バージョンは 0.12.22  なので少し古いので、あとで更新しておきたいと思います)
  • 次のプラグインたちの同梱
    • dstat
    • datadog_event
    • dogstatsd
    • elasticsearch
    • file-alternative
    • filter_typecast
    • flowcounter
    • forest
    • grep
    • multiprocess
    • record-modifier
    • record-reformer
    • sampling-filter
    • typecast
    • map(公式では label 対応していないため、独自に拡張したものを利用)
    • dogapi gem

この変更で独自に拡張したい場合は、plugin_gems.rb に追加したいプラグインを設定することで、それらのプラグインを含めたパッケージを作ることができます。

あとは、Vagrant 上でビルドして、自身の Yum リポジトリに追加して、インストールするだけです。

この変更で、自分が使っているプラグインを含めた td-agent の配布がとても簡単になりました。

このエントリーをはてなブックマークに追加

GPG キーの移動方法

少し前に GitHub で GPG 署名がサポートされたため、さっそく使っているのですが、他のマシンに GPG キーを移動する方法を調べてみました。

OS X の場合は、brew install gpp2 して、gpg2 コマンドを使ったほうがよいわけですが、次のようになります。

移行元のマシンで実行

$ email=< メールアドレス >
$ name=< ファイル名 >
$ gpg2 -a --export $email > $name-public-gpg.key
$ gpg2 -a --export-secret-keys $email > $name-secret-gpg.key
$ gpg2 --export-ownertrust > $name-ownertrust-gpg.txt

移行先のマシンで実行

$ email=< メールアドレス >
$ name=< ファイル名 >
$ gpg2 --import $name-secret-gpg.key
$ gpg2 --import-ownertrust $name-ownertrust-gpg.txt
$ gpg2 --list-keys
...

こんな感じであっさりとできました。

あと、都度リポジトリで GPG の設定をするのはめんどくさいので、次のようなシェルスクリプトを書いて使っています。


#!/bin/sh

email=$1
if [ -z "$email" ]; then
email=$(git config user.email)
fi

gpg=gpg
if [ $(which gpg2) ]; then
gpg=gpg2
fi

gpg_pub_key=$($gpg --list-keys | grep -1 "< $email>"| grep -e "^pub")
gpg_pub_key_id=$(echo $gpg_pub_key | cut -d ' ' -f 2 | cut -d '/' -f 2)
if [ -z "$gpg_pub_key_id" ]; then
echo "Could not get gpg pub key - $gpg_pub_key_id"
exit 1
fi

git config --local gpg.program $gpg
git config --local user.signingkey $ggp_pub_key_id
git config --local commit.gpgsign true

このスクリプトでメールアドレスを省略された場合は、リポジトリ設定のメールアドレスを利用しているのでけっこう便利です。

コミット履歴に「Verified」と標示されるのは、少しかっこいいですよね!