読者です 読者をやめる 読者になる 読者になる

tkuchikiの日記

Linux やプログラミングについて書きます。

RDS for MySQL と Amazon Aurora でクエリによる取得行数を取得するなら SHOW GLOBAL STATUS WHERE variable_name = 'Innodb_rows_read' を使うのが良い

AWS RDS MySQL Aurora

WEB+DB PRESS vol.94 特集1第5章P32 で、MySQL のクエリによる取得行数を取得するには、

mysql -u root -e "SHOW ENGINE INNODB STATUS\G" | grep "Number of rows"

を実行すると記載しましたが、Amazon Aurora の Reader(Read Replica) は SHOW ENGINE INNODB STATUS を実行しても何も結果を返さないためこの方法が使えません。
しかし、 SHOW GLOBAL STATUS WHERE variable_name = 'Innodb_rows_read' であれば Aurora の Writer, Reader に関係なく取得できます(もちろん RDS for MySQL でも OK です)。

mysql -u root -NBe "SHOW GLOBAL STATUS WHERE variable_name = 'Innodb_rows_read'" | awk '{print $2}'

ということで、 SHOW GLOBAL STATUS WHERE variable_name = 'Innodb_rows_read' を使うのがおすすめです!

【CentOS 6, Amazon Linux 対応】 unbound と ldns の RPM 作成方法

ldns unbound CentOS AmazonLinux RPM

epel repo から unbound が削除されました。

追記: CentOS6 の extras に unbound が入っているという情報をいただきました。@hfm さんありがとうございます!

無いなら作りましょう、ということで RPM 作成方法です。

検証環境

手順

CentOS 6 は unbound の tarball を取得して、同梱されている spec ファイルを少し書き換えて build すれば良いのですが、Amazon Linux には unbound が依存している ldns-devel がありません。
そのため、まず ldns の RPM を作ります。

yum-builddep と spectool を使うので、以下の package をインストールします。

yum install -y yum-utils rpmdevtools

ldns

まず、ldns の tarball に spec ファイルが同梱されているので取り出します。

curl -sO https://www.nlnetlabs.nl/downloads/ldns/ldns-1.6.17.tar.gz
tar zxf ldns-1.6.17.tar.gz ldns-1.6.17/packaging/fedora/ldns.spec

ldns.spec の改行コードに CR がついているため rpmbuild に失敗するので削除します。

cat ldns-1.6.17/packaging/fedora/ldns.spec | tr -d \\r > ~/rpmbuild/SPECS/ldns.spec
## nkf でも OK
# nkf -Lu --overwrite ldns-1.6.17/packaging/fedora/ldns.spec
# mv ldns-1.6.17/packaging/fedora/ldns.spec ~/rpmbuild/SPECS/ldns.spec

そのまま spec ファイルを使うと Amazon Linux だとエラーがでます。
具体的には、

  • %{__python}python
    • /usr/bin/python が python2.7 になっていても %{__python} が python2.6 となるため、dist-package の path が 2.6 になるので no such file or directory でエラー
  • Source: の URL の typo でエラー

diff は以下のとおりです。

4,5c4,5
< %{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
< %{!?python_sitearch: %global python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
---
> %global python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")
> %global python_sitearch %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")
10c10
< Version: 1.6.13
---
> Version: 1.6.17
14c14
< Source: http://www.nlnetlabs.nl/downloads/%{%name}/%{name}-%{version}.tar.gz
---
> Source: http://www.nlnetlabs.nl/downloads/%{name}/%{name}-%{version}.tar.gz

diff には含めていないですが、%changelog も更新しましょう。

次に、依存パッケージをインストールします。

yum-builddep -y ~/rpmbuild/SPECS/ldns.spec

tarball を ~/rpmbuild/SOURCES 以下に配置します。

spectool -R -g ~/rpmbuild/SPECS/ldns.spec
## mv でも OK
# mv ldns-1.6.17.tar.gz ~/rpmbuild/SOURCES/

準備が整ったので build します。

rpmbuild -ba ~/rpmbuild/SPECS/ldns.spec

これで ldns の RPM ができました。

unbound

まず、unbound の tarball に spec ファイルが同梱されているので取り出します。

curl -sO http://unbound.net/downloads/unbound-1.5.10.tar.gz
tar zxf unbound-1.5.10.tar.gz unbound-1.5.10/contrib/unbound.spec
mv unbound-1.5.10/contrib/unbound.spec ~/rpmbuild/SPECS/

unbound はバージョン以外は修正しなくても build できるので、 Version を書き換えます。 diff は以下のとおりです。

3c3
< Version: 1.4.18
---
> Version: 1.5.10

こちらも diff には含めていないですが、%changelog も更新しましょう。

次に、依存パッケージをインストールします。 自前の yum repo に ldns を追加していない場合は、build した RPM を予めインストールする必要があります。

rpm -ivh ~/rpmbuild/RPMS/x86_64/ldns-1.6.17-1.amzn1.x86_64.rpm ~/rpmbuild/RPMS/x86_64/ldns-devel-1.6.17-1.amzn1.x86_64.rpm
yum-builddep -y ~/rpmbuild/SPECS/unbound.spec

tarball を ~/rpmbuild/SOURCES 以下に配置します。

spectool -R -g ~/rpmbuild/SPECS/unbound.spec
## mv でも OK
# mv unbound-1.5.10.tar.gz ~/rpmbuild/SOURCES/

Docker Container 上で RPM を build する場合に root で作業を行った際、spec ファイルの permission を変更しないと error: Bad owner/group /path/to/unbound.spec というエラーがでました。
その場合は以下のコマンドを実行します。

chown root: ~/rpmbuild/SPECS/unbound.spec

準備が整ったので build します。

rpmbuild -ba ~/rpmbuild/SPECS/unbound.spec

これで unbound の RPM ができました。

まとめ

ldns と unbound は spec ファイルが用意されているので少し書き換えるだけで RPM を作ることができました。
改行コードでエラーになるという問題は初めて遭遇したので勉強になりました。

mackerel-agent-plugin の diff の出力結果を加工してデータを per sec にする

mackerel-plugin-mysql を例にすると、

$ ./mackerel-plugin-mysql | grep Com_
mysql.cmd.Com_insert    0.000000        1475200487
mysql.cmd.Com_select    6.000000        1475200487
mysql.cmd.Com_update    0.000000        1475200487
mysql.cmd.Com_update_multi      0.000000        1475200487
mysql.cmd.Com_delete    0.000000        1475200487
mysql.cmd.Com_delete_multi      0.000000        1475200487
mysql.cmd.Com_replace   0.000000        1475200487
mysql.cmd.Com_set_option        0.000000        1475200487

は、1 分間に各 SQL をどれくらい実行したかという結果だと思いますが、
秒間どれくらい実行しているかというデータを見たいことがあると思います(少なくとも私は見たい)。

mackere-agent-plugin-helper の Metrics 構造体に Scale というフィールドがあり、データに指定の値を乗算する機能があります(キロバイトバイトに変換したいときに 1024 をかけるみたいな感じ)。
これに 1 / 60 を渡せるようにすればよいかと思いましたが、 Metrics 構造体の Type が unit32uint64 の場合、 Metrics.Scaleuint32 または uint64 でキャストするので 0 になるためこの方法は使えませんでした。
プラグインを変更するにしても、Type を全部 float64 にしてしまうのは乱暴ですし、特定の値だけ 60 で除算する、というのをどうやって指定するのかという問題があります。

そこで、mackerel-agent-plugin の出力結果を加工してしまうという方法があります。
mackerel-plugin-mysql を例にすると、mysql.cmd.Com_* だけ 60 で除算したい場合、

$ ./mackerel-plugin-mysql | awk '{val=$2; if ($1 ~ /mysql\.cmd\.Com_/){ val = val / 60.0 } printf("%s\t%.6f\t%d\n", $1, val, $3) }'

のようにすれば OK です。
awk はちょっと... という場合は perlruby でも良いと思います。

※ go-mackerel-plugin-helper は、commit 04727eebfbb32b6ba54880d497fcaf94f18be810 時点のもので確認しています。

ISUCON6 予選2日目2位通過しました

ISUCON ISUCON6 予選

@hilotter さん、@Konboi と流れ弾として ISUCON6 予選2日目に参加して2位通過しました。
使用言語は Go で、私は足回りを整えて少しコードを書きました。

謝辞

運営の皆様ありがとうございました。
とても充実した時間を過ごすことができました。

やったこと

前日まで

  • メンバー各自で pixiv 社内 ISUCON 2016 を解く
  • 環境セットアップスクリプトを用意する
    • ユーザ作成、nginx、MySQL、Redis を簡単にいれられるようにしておく
  • デプロイスクリプトを用意する
    • 1台だけなので rsync & sshmake allsystemctl restart する
  • alp の修正・PR merge
    • PR をくださった @vzvu3k6k さん、issue 報告してくださった @hilotter さんありがとうございました
  • nginx、MySQL、Redis の設定ファイルを作っておく

当日

起床成功

10:00 ~

  • Azure の VM 起動
  • アプリのコードを Bitbucket に push
  • isuter.go に patch をあてる
  • デプロイスクリプト微調整
  • nginx のログ集計
  • mysqldump をとる
  • pt-query-digest する
  • slowlog-sorter で遅いクエリを眺める

11:00 ~

  • go 以外の systemd の設定を消す
  • 他の二人がコードを読んでいる間にミドルウェアとアプリの再起動確認をする
    • reboot が 1, 2分くらいで終わるので楽だった
  • とにかく htmlify の正規表現が重いので初期データだけでも Redis にのせる準備を始める(@Konboi)
  • index をはる
  • url_for を消す

12:00 ~

  • ベンチ回す前に毎回ログを truncate するのが面倒になったのでデプロイ時にやるようにする
  • entry のクエリを修正(自己結合)
  • コードを読んだり、PRをレビューしたり

13:00 ~

  • SELECT COUNT を変数に持って実行しないようにする
  • isuda から直接 star テーブル読むようにする(@hilotter)

14:00 ~

  • login 時に session にユーザ名をいれて DB を参照しないようにする PR を作る(結局 merge していない)
  • アプリを Go で動かすようにしてから一度もスコアがでなくて絶望感漂う
    • perl のアプリでベンチを回したときに 2000 くらい出た以外はずっと 0
  • Go で書いたキャッシュ作成スクリプトが遅すぎて Perl で書き直す(@Konboi)
  • キャッシュを作っている間にキーワードの追加・削除時にキャッシュをどうしようか考え始める(@hilotter, @tkuchiki)

15:00 ~

  • キャッシュができたのでベンチを回す

f:id:tkuchiki:20160920150231p:plain

  • スコア 0 からいきなり 118245 になって全員のテンション爆上げ
    • ダッシュボードの Messages に色々出ているからだめかもという話しをしていたら idobata で PASS になっていれば大丈夫という発言を見て安心する
  • キャッシュの整合性を直すことは諦めてスコアの再現性を高めることに注力しようということになる
    • この判断を即決できたのが良かった

16:00 ~

  • ベンチを回すたびにキャッシュを作り直すスクリプトを作る(@Konboi)
  • 再起動確認を始める
    • Redis より isuda が先に起動しようとして起動に失敗することがあったので依存関係を設定
  • unix domain socket を使うようにする(問題が出たので元に戻した)
  • 以降、ひたすらベンチを回して再起動確認する、の繰り返し

感想

キャッシュの整合性は全く取れていないので Messages が一つでも出ていたら Fail または大幅に減点されていたら予選通過は無理でした(石とかまさかり投げないで...)。
我々の戦略で唯一良かったのは(というと二人に失礼ですが...)、アプリとしての正しさは無視して、すぐにスコアを安定させる方向に振り切ったことだと思っています。
スコアは一番良いときで 19万くらい低いときで 8万という感じだったので、多分大丈夫だろうという感じではありましたが、稀に Fail することがあったのと低いときのスコアが出たら予選通過できなさそうな雰囲気だったので、結果が出るまではだめかもと思っていました。
最終的に運良く予選通過できましたが力不足を感じたので、日々精進しなくてはならないなと改めて思いました。
本選は実力で結果を出したい...

あわせて読みたい

WEB+DB PRESS Vol.94 で特集「実践スケーラブルAWS」を執筆しました & 恵贈御礼

AWS WEB+DB PRESS

本日 8/24 発売の WEB+DB PRESS Vol.94 で、 特集1「[鍵は監視にあり!]実践スケーラブルAWS 規模に適した設計,負荷に応じた増減,障害への自動対応」
の第3章から5章を執筆しました。

gihyo.jp

謝辞

株式会社技術評論社 WEB+DB PRESS編集部様からご恵贈いただきました。ありがとうございます。
また、この度は執筆の機会をいただきましたこと重ねて御礼申し上げます。

もともと、fujiwara さん宛てに執筆依頼があったのですが、
無理を言って共著で書かせていただくことになりました。機会をいただきありがとうございました。

f:id:tkuchiki:20160819201510j:plain

特集「実践スケーラブル AWS」について

この特集では、AWS で1〜100台規模のサーバを運用する際、どのようなことを考えて設計するとスケールしやすくなるのか解説しています。
今まで WEB+DB PRESS またはその他の雑誌で、数多くの AWS の特集が組まれてきたと思いますが、
本特集ではタイトルにもあるように「監視」に重点を置いた内容となっております。
第2章では運用における監視についてやどのような監視が必要かを Zabbix と Mackerel を例に紹介しています。第3章ではWeb・アプリケーションサーバ、第4章ではキャッシュサーバ(memcached と Redis)、第5章ではデータベースサーバ(MySQL) の監視について記しております。第6章では、オートスケールの監視について触れています。特に3〜5章では、各章2ページほど監視について紙面を割いています。
全体を通して、まだAWSでの監視やオートスケールに取り組んでいない方もすでにがっつり運用されている方にも参考になる内容になっているのではないかと思います(そうであれば幸いです)。

特集は32ページありますので、読み応えがあると思います。
是非、お手にとっていただけますと幸いです!

HAProxy の external-check で Read Replica から Master に昇格した Amazon Aurora に接続できないようにする

haproxy

追記 2016/07/22 19:06

error: 'Lost connection to MySQL server at 'reading initial communication packet', system error: 0' というエラーがでて接続できなくなる現象が発生するようなので、改良が必要なようです。
エラーの検証をしようとしたら再現できなかったので、とりあえず気にしなくても良さそうです。

追記 2016/07/19 18:48

ブックマークにもコメントいただきましたが、
SHOW GLOBAL VARIABLES LIKE 'innodb_read_only'; を実行して、
OFF なら master、ON なら Read Replica という判断方法もあります。
Amazon Aurora を使用する際のベストプラクティス に書いてあります。
なぜ、これを使わなかったかというと、検証したときは知らなかったからです...

検証した環境は以下の通りです。

$ haproxy -v
HA-Proxy version 1.6.6 2016/06/26
Copyright 2000-2016 Willy Tarreau <willy@haproxy.org>

$  cat /etc/system-release
Amazon Linux AMI release 2016.03

RDS for MySQL は Multi-AZ 構成にした場合、スタンバイ用のインスタンスにアクセスできません。
Amazon Aurora(以降、Aurora) はスタンバイインスタンスが Read Replica となっているため参照することができます。
Aurora を HAProxy で参照分散するとき、Read Replica のいずれかが Master に昇格するため、
Read Replica のつもりで参照していたインスタンスが Master になっている可能性があります。
Slave 参照しない Read Replica を用意し、Master に昇格させるインスタンスの優先順位を調整することで、 HAProxy からは Master に参照することがないように調整することも可能ですが、
一台は余剰なインスタンスとなってしまいますし、3台構成の場合に Master と Read Replica 1台が同時にダウンした場合どうするかなど、 考慮しなくてはならないことがたくさんあります。
もちろん、Master を参照しても負荷的に問題なければ良いですが、Slave 参照する場合は Master への負荷を軽減したい場合でしょうから問題になるケースが多いのではないでしょうか。
以上のことから、HAProxy の mysql-check では意図しない挙動をしてしまいます。 そこで、HAProxy の external-check という、任意のコマンドでヘルスチェックを行う機能を利用できないか検証しました。

haproxy.conf

使用した設定ファイルです。

global
   external-check

resolvers mydns
   nameserver dns1 10.2.0.2:53
   nameserver dns2 8.8.8.8:53
   resolve_retries 3
   timeout retry   1s
   hold valid      60s

defaults
    log             127.0.0.1 local1 debug
    retries 2
    timeout connect 3000
    timeout server 5000
    timeout client 5000

frontend f_mysql_slave
    bind            127.0.0.1:3307
    default_backend b_mysql_slave

backend b_mysql_slave
    log             127.0.0.1 local1 debug
    mode tcp
    option external-check
    external-check path "usr/bin:/bin:/usr/local/bin"
    external-check command /usr/local/bin/check_mysql_slave.sh
    balance         roundrobin
    server          slave test-db01.xxxxxx.ap-northeast-1.rds.amazonaws.com:3306 check resolvers mydns
    server          master test-db.cluster-xxxxxx.ap-northeast-1.rds.amazonaws.com:3306 check resolvers mydns backup

external-check を使うためには、

global
   external-check

backend b_mysql_slave
        option external-check
        external-check path "usr/bin:/bin:/usr/local/bin"
        external-check command /usr/local/bin/check_mysql_slave.sh

が必要です。

server master ... backup は Read Replica が全部ダウンしたときのみ Master を参照するための設定です。

external-check command

HAProxy がコマンドを実行する際に環境変数を設定するようになっています。
環境変数は以下のとおりです。

  • HAPROXY_PROXY_ADDR
    • backend の bind IP
    • backend に定義した bind は無視されるので実質使用しない(はず)
  • HAPROXY_PROXY_ID
    • backend ID.
  • HAPROXY_PROXY_NAME
    • backend 名
  • HAPROXY_PROXY_PORT
    • backend の bind port
    • backend に定義した bind は無視されるので実質使用しない(はず)
  • HAPROXY_SERVER_ADDR
    • server の IP
  • HAPROXY_SERVER_CURCONN
    • server のカレントコネクション数
  • HAPROXY_SERVER_ID
    • server の ID
  • HAPROXY_SERVER_MAXCONN
    • server の 最大コネクション数
  • HAPROXY_SERVER_NAME
    • server の設定名
  • HAPROXY_SERVER_PORT
    • server で設定したホストの port
  • PATH
    • external-check path で設定した PATH

詳細は external-check command を参照してください。 環境変数を上から順に出力した例は以下のとおりです。

 
2
b_mysql_slave

10.206.1.20
0
2
0
slave
3306
usr/bin:/bin:/usr/local/bin

check_mysql_slave.sh

ヘルスチェックを行うスクリプトです。

#!/bin/bash

BACKUP="master"
MASTER_IP=$(dig +short test-db.cluster-cnttkfxtxwao.ap-northeast-1.rds.amazonaws.com | tail -n 1)
[ "${MASTER_IP}" = "" ] && exit 1
[ "${HAPROXY_SERVER_NAME}" = "${BACKUP}" ] && exit 0
[ "${HAPROXY_SERVER_ADDR}" != "${MASTER_IP}" ]
  • ${MASTER_IP} が取得できなければ fail
  • ${HAPROXY_SERVER_NAME} = ${BACKUP} の場合、backup 以外のインスタンスはダウンしているので Master を参照するようにする
  • ${HAPROXY_SERVER_ADDR} != ${MASTER_IP} の場合、Read Replica を参照しているのでヘルスチェックを success にする
追記: 2016-07-25 16:05

SHOW GLOBAL VARIABLES LIKE 'innodb_read_only'; を使う場合は以下のようになります。

#!/bin/bash

BACKUP="master"
READ_ONLY=$(mysql -u haproxy -h ${HAPROXY_SERVER_ADDR} -P ${HAPROXY_SERVER_PORT} -BN -e "SHOW GLOBAL VARIABLES LIKE 'innodb_read_only';" --connect-timeout=5 | awk '{print $2}')

[ "${HAPROXY_SERVER_NAME}" = "${BACKUP}" ] && exit 0
[ "${READ_ONLY}" = "ON" ]

DNSを引く場合と違って、BACKUP 以外は環境ごとに変わる要素がなくなったので使いやすくなっています。

検証結果

Master と Read Replica それぞれ 1 台ずつで 2 種類の検証を行いました。

Read Replica が Master に昇格した場合

backup の設定は削除した状態です。
server slave = Master なのでヘルスチェックに失敗しています。
Read Replica が 1 台なので no server available になっていますが、Read Replica が 2台以上ある場合は、
Read Replica には接続できて、Master には接続できない状態になります。

Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1032ms, status: 2/3 UP.
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1032ms, status: 2/3 UP.
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1007ms, status: 1/3 UP.
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1007ms, status: 1/3 UP.
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1016ms, status: 0/2 DOWN.
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1016ms, status: 0/2 DOWN.
Server b_mysql_slave/slave is DOWN. 0 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue.
Server b_mysql_slave/slave is DOWN. 0 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue.
backend b_mysql_slave has no server available!
backend b_mysql_slave has no server available!

backup を設定して、Read Replica が Master に昇格した場合

backup 以外の server のヘルスチェックに失敗して、backup のみヘルスチェックに成功した場合のログです。
Master 以外ダウンしているときは Master に接続できるようになっていることがわかります。

Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1014ms, status: 2/3 UP.
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1014ms, status: 2/3 UP.
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1007ms, status: 1/3 UP.
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1007ms, status: 1/3 UP.
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1014ms, status: 0/2 DOWN.
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1014ms, status: 0/2 DOWN.
Server b_mysql_slave/slave is DOWN. 0 active and 1 backup servers left. Running on backup. 0 sessions active, 0 requeued, 0 remaining in queue.
Server b_mysql_slave/slave is DOWN. 0 active and 1 backup servers left. Running on backup. 0 sessions active, 0 requeued, 0 remaining in queue.
b_mysql_slave/master changed its IP from 10.2.0.10 to 10.2.1.20 by mydns/dns1.
b_mysql_slave/master changed its IP from 10.2.0.10 to 10.2.1.20 by mydns/dns1.
Health check for server b_mysql_slave/slave succeeded, reason: External check passed, code: 0, check duration: 1015ms, status: 1/2 DOWN.
Health check for server b_mysql_slave/slave succeeded, reason: External check passed, code: 0, check duration: 1015ms, status: 1/2 DOWN.
Health check for server b_mysql_slave/slave succeeded, reason: External check passed, code: 0, check duration: 1007ms, status: 3/3 UP.
Health check for server b_mysql_slave/slave succeeded, reason: External check passed, code: 0, check duration: 1007ms, status: 3/3 UP.
Server b_mysql_slave/slave is UP. 1 active and 1 backup servers online. 0 sessions requeued, 0 total in queue.
Server b_mysql_slave/slave is UP. 1 active and 1 backup servers online. 0 sessions requeued, 0 total in queue.
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1014ms, status: 2/3 UP.
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1014ms, status: 2/3 UP.
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1007ms, status: 1/3 UP.
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1007ms, status: 1/3 UP.
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1016ms, status: 0/2 DOWN.
Health check for server b_mysql_slave/slave failed, reason: External check error, code: 1, check duration: 1016ms, status: 0/2 DOWN.
Server b_mysql_slave/slave is DOWN. 0 active and 1 backup servers left. Running on backup. 0 sessions active, 0 requeued, 0 remaining in queue.
Server b_mysql_slave/slave is DOWN. 0 active and 1 backup servers left. Running on backup. 0 sessions active, 0 requeued, 0 remaining in queue.

まとめ

HAProxy の external-check で、Aurora の Read Replica が Master に昇格したときに参照させないようにすることができました。
また、Read Replica が全台ダウンしたときだけ Master を参照できることも確認できました。
独自のヘルスチェックが行えるので、他にも応用ができそうですね。

Amazon Linux で certbot(letsencrypt) を使って SSL 証明書を取得する

SSL Nginx certbot letsencrypt

※2016年5月16日現在の情報です。
バージョンが変わると動作しなくなる可能性があります。

letsencrypt のクライアントが certbot に改名したようです
(See: https://github.com/certbot/certbot)。
Amazon Linux 上で certbot-auto(letsencrypt-auto) を使って SSL 証明書を取得する手順を検証しました。

検証した環境は以下のとおりです。

  • certbot-auto(letsencrypt-auto) 0.6.0
  • Amazon Linux 2016.03
    • amzn-ami-hvm-2016.03.1.x86_64-gp2 (ami-29160d47)
  • Nginx 1.8.1

コマンドはすべて ec2-user で実行しました。

試行錯誤した結果、

https://github.com/certbot/certbot/issues/2872#issuecomment-211959637

のように pip と virtualenv のバージョンを上げたらうまくいきました。

pip と virtualenv のバージョンを上げる

sudo easy_install pip
sudo pip install --upgrade pip

pip をアップグレードすると、/usr/local/bin/pip に最新版の pip がインストールされたので、
以降はこちらを使います。

sudo /usr/local/bin/pip install --upgrade virtualenv

letsencrypt 環境を作成

virtualenv で letsencrypt 環境を作成します。

mkdir -p ~/.local/share
virtualenv -p /usr/bin/python27 ~/.local/share/letsencrypt
. ~/.local/share/letsencrypt/bin/activate

certbot-auto を実行

例では Nginx を使っていますが、Apache や certbot の Standalone Web サーバを使いたい場合は適宜変更してください。
Nginx や Apache を使う場合は予め起動しておいてください。

curl -s -L -O https://dl.eff.org/certbot-auto
chmod +x ./certbot-auto
./certbot-auto certonly --webroot -w /usr/share/nginx/html -d your.domain --agree-tos -m your@email.address --debug

以下の様な出力になったら成功です。

yum install の出力
...

Checking for new version...
Creating virtual environment...
Installing Python packages...
Installation succeeded.
Requesting root privileges to run certbot...
   sudo CERTBOT_AUTO=./certbot-auto /home/ec2-user/.local/share/letsencrypt/bin/letsencrypt certonly --webroot -w /usr/share/nginx/html -d your.domain --agree-tos -m your@email.address --debug
Version: 1.1-20080819
Version: 1.1-20080819

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/your.domain/fullchain.pem. Your
   cert will expire on 2016-08-14. To obtain a new version of the
   certificate in the future, simply run Certbot again.
 - If you lose your account credentials, you can recover through
   e-mails sent to your@email.address.
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

証明書の更新

以下のコマンドでできるようなので定期的に実行して、Web サーバを reload するようにしておくと自動更新できると思います。

./certbot-auto renew --webroot -w /usr/share/nginx/html --force-renew --debug
Checking for new version...
Requesting root privileges to run certbot...
   sudo CERTBOT_AUTO=./certbot-auto /home/ec2-user/.local/share/letsencrypt/bin/letsencrypt renew --webroot -w /usr/share/nginx/html --force-renew --debug

-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/your.domain.conf
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/your.domain/fullchain.pem
-------------------------------------------------------------------------------

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/your.domain/fullchain.pem (success)