MHAを使ってZabbixをカジュアルに冗長化してみる
Onpremiseな環境でHAなDBクラスタを組んだり監視サーバを構築したりなんて作業は、ちょっと前であればごくごく当たり前のものだったけど、最近はクラウドやSaas/Paasをどれだけ活用して、よりビジネスの本流に集中しようというご時世。 でも、やっぱりOnpremise、どうしても必要な時はある。今のレールに頼り切るのもいいけど、やっぱり勘所はおさえておきたいので、カジュアルにZabbixをHAした時のことを備忘録しておきます。
やりたいこと
Zabbix serverを冗長構成にしたい。 Zabbix serverの稼働に必要なものはざっくり以下。
Zabbix serverをActive-Activeで稼働させてしまうと、データベースに二重で書き込みが行われてしまうので、Active-Standbyにしておく必要がある。障害時に手動切替なんて面倒、かつ二次障害起こしかねないので避けたい。MySQLもReplication組むだけでは弱いので自動フェイルオーバーくらいさせておきたい。そもそも監視サーバなので手間隙かけたくないし、むしろちょっとしたノード障害くらい放置しておきたい。
MySQLには5.6以降、GTID + failoverが標準搭載されているが、5.6出たばかりの時にGTIDのバグを幾つか踏んで痛い目にあったのと、上述の通りZabbix serverもまとめてHA化したいが幾つものクラスタウェア使って運用するのは腰が重い。カジュアルに一括りにしてよろしくやってほしい。
ということで、MHA。MySQLのReplicationのラグをよしなに埋めてくれる素敵なものにもかかわらず、挙動や構成が大変シンプル、拡張ポイントも多く、カジュアルにZabbixまで含めたクラスタウェアとして使えそうだったので採択決めました。
MHAいろは
MHAのアーキテクチャや仕組みは、詳しくは 公式ドキュメント を参照。要点をまとめるとMHA自体の責務は大きく以下。
- MySQLの監視
- Master/Slave ノードの監視
- Replicationステータス/各ノードのPOSチェック/遅延状況
- Binlog出力有無
- Read Only有無
- など
- Failover
- 故MasterからのBinlog救出
- 昇格候補の選出
- 新Masterへの差分データ適用
- 新MasterへのRead only無効化
- 他Slaveへの差分データ適用
- 他SlaveのMaster host切替 (
CHANGE MASTER
)
実システムでDBのSlaveを昇格させるには、これ以外に業務や環境に依存する様々な処理が必要になるが、MHAでは様々なフックポイントが用意されているので、適切な場所に拡張スクリプトを仕込めば、実システムにあわせたFailover作業を全自動で行うことができる。 拡張スクリプトはPerlスクリプトで実装する。MHAがPerlで実装されており、これが内部でcallされるため。詳しくはソースコード参照。
構成は、以下の図のとおり、MySQL監視プロセスとしてのMasterHA-Manager (masterha_managerプロセス) と、MySQL各サーバ上で動作するMasterHA-Nodeが必要となる。Managerは監視プロセスとなるため常駐させる必要がある。Nodeは、Failover時にManagerから適宜SSH経由で発行される幾つかのコマンドを処理するだけとなるので、MasterHA-Nodeの動作に必要なものをインストールしておくだけで良い。 いずれも軽量なプロセスなので、好きなように構成組めば良い。例えばこんなところか。
松: 昇格用slaveと参照用DBを分ける
MHA manager [192.168.10.1] Master [192.168.10.11, VIP: 192.168.10.10] ├── Slave (cadidate_master) [192.168.10.12] ├── Slave (no_master, Read only) [192.168.10.13] └── Slave (no_master, Read only) [192.168.10.14]
竹: Slave 1機, Manager用のノードは別筐体
MHA manager [192.168.10.1] Master [192.168.10.11, VIP: 192.168.10.10] └── Slave [192.168.10.12]
梅: 最小構成
Master [192.168.10.11, VIP: 192.168.10.10] └── Slave (w/ MHA manager) [192.168.10.12]
MHA自体は単体で動作し、あくまでクラスタの監視と、Failover時のリカバリとフックポイントを提供するのみなので、既に稼働中の環境でもねじ込める点も良い。非常に軽量な作りなので、新設/既設いずれも親和性が高いだろう。
MHAはRPMが公開されておりインストールは瞬殺で終わるので割愛。 Managerの他、MySQLが稼働している全サーバにMHA Nodeを入れる必要がある点に注意。 詳細は、Installation を参照。
MHAの拡張ポイント
MHAの設定ファイルで、以下のParameterを定義できる。Perlスクリプトのpathを記載することで、これらが呼び出されるようになる。 https://code.google.com/p/mysql-master-ha/wiki/Architecture#Custom_Extensions
代表的なものを紹介すると、
master_ip_failover_script
※詳しくは 公式ドキュメント を参照
Failover時の挙動を指定できる。代表的なものは、仮想IPの付け替え、クラスタウェアの再起動、アプリケーションの参照先DBの切替など。
以下の3地点で、これらの拡張Perlスクリプトがcallされる。 Failoverの瞬間だけ実行されるわけではない点に注意して実装すること。
MHA Manager calls master_ip_failover_script three times. First time is before entering master monitor (for script validity checking), second time is just before calling shutdown_script, and third time is after applying all relay logs to the new master. MHA Manager passes below arguments (you don't need to set these arguments in the config file).
要するに以下のタイミングで発火されるので、"command" パラメータで条件分岐するようなPerlスクリプトを仕込めば良い。その他、スクリプトに渡される引数もあわせて、以下に記載しておく。
- Checking phase : MHA-Manager起動時(--command=status)
- Current master shutdown phase : Masterサーバシャットダウン時(--command=stop or stopssh)
- New master activation phase : フェイルオーバー完了時(--command=start)
- --command=start
- --ssh_user=(new master's ssh username)
- --orig_master_host=(dead master's hostname)
- --orig_master_ip=(dead master's ip address)
- --orig_master_port=(dead master's port number)
- --new_master_host=(new master's hostname)
- --new_master_ip=(new master's ip address)
- --new_master_port(new master's port number)
- --new_master_user=(new master's user)
- --new_master_password(new master's password)
サンプルコードは以下 https://github.com/yoshinorim/mha4mysql-manager/blob/master/samples/scripts/master_ip_failover
shutdown_script
※詳しくは 公式ドキュメント を参照
オプションで指定するPerlスクリプトで、Failover後のshutdown処理を指定できる。Split brain防止のために使用する。例えば、IPMIやiDRAC, ilo経由, ESXi cli, その他Hypervisor経由の強制シャットダウン、電源OFFなど。 発火タイミングは、 master_ip_failover_script --command=stopssh|stop の直後。SSH reachableな場合とそうでない場合で挙動を変えられる。
サンプルコードは以下 https://github.com/yoshinorim/mha4mysql-manager/blob/master/samples/scripts/power_manager
例えば、ESXiの場合、vim-cmd で以下のようなコマンドを実行するイメージ。statusチェック, 電源OFF, 電源ONできるので、これを含むPerlスクリプトを仕込めば実現できる。
# VMID=`vim-cmd vmsvc/getallvms|grep zabbix-test01|awk '{print $1}'` && if [ -n "$VMID" ]; then vim-cmd vmsvc/power.getstate $VMID; fi Retrieved runtime info Powered on # VMID=`vim-cmd vmsvc/getallvms|grep zabbix-test01|awk '{print $1}'` && if [ -n "$VMID" ]; then vim-cmd vmsvc/power.off $VMID; fi Powering off VM: # VMID=`vim-cmd vmsvc/getallvms|grep zabbix-test01|awk '{print $1}'` && if [ -n "$VMID" ]; then vim-cmd vmsvc/power.on $VMID; fi Powering on VM:
MHA managerプロセスのバックグラウンド起動
普通に起動するとフォアグラウンド。公式ドキュメント はDaemonTools使っているが、Upstart等Linuxのサービス管理ツールでもシンプルに実現できるので、この辺りでデーモン化してあげると手軽で良いだろう。 MHA MnanagerプロセスはFailoverすると終了するライフサイクルになっているので、自動起動やrespawn処理はあまり入れないほうが良さそうな気がする。以下サンプル。
description "MasterHA manager services" chdir /var/log/masterha exec /usr/bin/masterha_manager --conf=/etc/mha.cnf >> /var/log/masterha/masterha_manager.log 2>&1 pre-start exec /usr/bin/masterha_check_repl --conf=/etc/mha.cnf post-stop exec /usr/bin/masterha_stop --conf=/etc/mha.cnf
起動/終了/ステータスチェックはこんな感じ。
- start masterha-manager
- status masterha-manager
- stop masterha-manager
MySQL インストール
詳細は割愛。 MySQL 5.6でも5.7でも動くぽいので、好きなモノを選べば良いと思う。 注意点は以下。
- MySQL
- MySQL 5.7の罠があなたを狙っている - Slideshare
- Semi Replicationは有効化
- Master - Slave間の欠損が限りなく0に近くなるので、Failoverが早くなる。
- ただし、レイテンシとのトレードオフで判断すること
- relay_log_info_repository=TABLE はやめておけ
- MHA利用時、これを入れていると以下のようなエラーが出た。relay_log情報はMHAがよろしく見てくれるので、my.cnfではあえて有効化しておく必要はなし。
Getting relay log directory or current relay logfile from replication table failed on
- relay_log_purge = 0
- read_only は set文で。my.cnfには書くな。
- 元のSlaveがMasterに昇格した時に、my.cnfに read_only = 1 がセットされていると再起動のタイミングで戻り障害を引き起こす可能性があるため危険。
Zabbix インストール
ようやくZabbix。インストールの詳細は例によって割愛。
ポイントは、冒頭で触れたとおりMHAでZabbixまで含めてクラスタ化するため、MySQLのMasterと同一サーバ上でZabbix serverを稼働させるようにすること。 Zabbix serverプロセスをPacemaker等、別の機構でクラスタ化しても良いのだが、実績上Zabbix serverプロセスが落ちる可能性よりもホストがポシャることの方が多かったので。監視サーバなので、という割り切りです。なので、設定は以下のような感じ。
- zabbix_server.conf
Zabbix web (Apache + PHP) は、複数Activeで動作可能ので上述のクラスタとはわけて考えて良い。 何人ものエンジニアが大量のグラフが貼られたスクリーンを定期リロードすることを考えると、むしろ別サーバにApache + PHP専用機並べてバランシングさせておきたいくらい。 なので、PHPからDBの接続はVIP経由でアクセスさせる。以下、Webの初期設定のポイントを列挙しておく。それぞれのWebサーバに対して設定行うこと。
- http://$HOSTNAME/zabbix/ にアクセス
- インストール画面が出てくるので進めていく
- DB接続情報は以下で入力
- Database Host: VIP
- Database User: zabbix
- Database Password: 設定したパスワード
- Test Connectionして接続確認
- Zabbix server Detailは以下で入力
- Host: VIP
- Name: 任意の名前 (環境が分かると良い)
- 確認ダイアログが出るので、間違いないか確認。
- これを全てのApache/PHPに対して行う (↑で生成された設定ファイル撒くでも構わない)
master_ip_failoverスクリプト for zabbix
最後の仕上げ。MHAで障害検知時は、MySQLの他、VIPとZabbix serverもセットでFailoverさせるようなスクリプトを用意しておく。あとは、/etc/mha.cnf の master_ip_failover に指定しておけば良い。 VIPの付け替えを行うのでARPキャッシュの更新を忘れないように。さもないと、フェイルオーバーしたのにつながらないなんてことのないように。 以下、サンプルです。
#!/usr/bin/env perl # # If you wanna know about the paramaster, "master_ip_failover_script", # read the below document. # # https://code.google.com/p/mysql-master-ha/wiki/Parameters#master_ip_failover_script # # [Usage] # master_ip_failover_zabbix \ # --virtual_ip=192.168.10.10/16 \ # --orig_master_vip_eth=eth0 \ # --new_master_vip_eth=eth0 # # [Description] # --virtual_ip => Virtual IP / mask # --orig_master_vip_eth => Device name that is attached virtual ip on origin master host. # --new_master_vip_eth => Device name that is attached virtual ip on new master host. # use strict; use warnings FATAL => 'all'; use Getopt::Long; use MHA::DBHelper; my ( $command, $ssh_user, $orig_master_host, $orig_master_ip, $orig_master_port, $new_master_host, $new_master_ip, $new_master_port, $new_master_user, $new_master_password, $virtual_ip, $orig_master_vip_eth, $new_master_vip_eth ); GetOptions( 'command=s' => \$command, 'ssh_user=s' => \$ssh_user, 'orig_master_host=s' => \$orig_master_host, 'orig_master_ip=s' => \$orig_master_ip, 'orig_master_port=i' => \$orig_master_port, 'new_master_host=s' => \$new_master_host, 'new_master_ip=s' => \$new_master_ip, 'new_master_port=i' => \$new_master_port, 'new_master_user=s' => \$new_master_user, 'new_master_password=s' => \$new_master_password, 'virtual_ip=s' => \$virtual_ip, 'orig_master_vip_eth=s' => \$orig_master_vip_eth, 'new_master_vip_eth=s' => \$new_master_vip_eth, ); exit &main(); sub main { # for debug print("---------- start master_ip_failover script ----------"); if ( defined $command ) { print(" command => $command\n") }; if ( defined $ssh_user ) { print(" ssh_user=s => $ssh_user\n") }; if ( defined $orig_master_host ) { print(" orig_master_host => $orig_master_host\n") }; if ( defined $orig_master_ip ) { print(" orig_master_ip => $orig_master_ip\n") }; if ( defined $orig_master_port ) { print(" orig_master_port => $orig_master_port\n") }; if ( defined $new_master_host ) { print(" new_master_host => $new_master_host\n") }; if ( defined $new_master_ip ) { print(" new_master_ip => $new_master_ip\n") }; if ( defined $new_master_port ) { print(" new_master_port => $new_master_port\n") }; if ( defined $virtual_ip ) { print(" virtual_ip => $virtual_ip\n") }; if ( defined $orig_master_vip_eth ) { print(" orig_master_vip_eth => $orig_master_vip_eth\n") }; if ( defined $new_master_vip_eth ) { print(" new_master_vip_eth => $new_master_vip_eth\n") }; # For current mastre shutdown phase # execute the below flow. # 1. unbind virtual ip from the origin master host. # 2. stop zabbix server process. if ( $command eq "stop" || $command eq "stopssh" ) { my $exit_code = 1; eval { `ssh $orig_master_host -o 'ConnectTimeout=5' '/etc/init.d/zabbix-server stop; /sbin/ip addr del $virtual_ip dev $orig_master_vip_eth'`; $exit_code = 0; }; if ($@) { warn "Got Error while shutdown phase: $@\n"; exit $exit_code; } exit $exit_code; } # For new master activation phase # execute the below flow. # 1. start zabbix server process. # 2. bind virtual ip on the new master host. # # Notice: # * You don't need to unable the paramster "read_only = 1" and enable binary log, # because they are already defined MHA common module. # elsif ( $command eq "start" ) { my $exit_code = 10; eval { my $ping_interface = join(".", $virtual_ip =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/ ); `ssh $new_master_host -o 'ConnectTimeout=15' '/sbin/ip addr add $virtual_ip dev $new_master_vip_eth && /sbin/arping -U $ping_interface -c 3 && /etc/init.d/zabbix-server start'`; $exit_code = 0; }; if ($@) { warn "Got Error while activation phase: $@\n"; # If you want to continue failover, exit 10. exit $exit_code; } exit $exit_code; } elsif ( $command eq "status" ) { # do nothing exit 0; } else { &usage(); exit 1; } } sub usage { print "Usage: master_ip_failover --command=start|stop|stopssh|status --orig_master_host=host --orig_master_ip=ip --orig_master_port=port --new_master_host=host --new_master_ip=ip --new_master_port=port --virtual_ip=ip --orig_master_vip_eth=eth --new_master_vip_eth=eth\n"; }
以上で、カジュアルにZabbix serverが冗長化出来ます。 Zabbix serverプロセスが落ちたりVIP剥がれてもFailoverしないので、そのあたりは割りきって参考にして下さい。
まとめ
MHAはソースもPerlでそこまでボリューム多くないので気軽に読めちゃいます。 日本語の情報も多い(なにせ作者が日本人: 元DeNA, 現Facebookの松信さん)ので、他メンバーへの技術トランスファーも楽ちん、運用容易性が非常に高いのでおすすめです。
結局、MHAの宣伝みたいになってしまいました。。
iPhone 6Sが出たのでiPhone6 + MVNO に乗り換えてみた
iPhone 6S / 6S plus が2015年9月25日に発売されました。 2年前にSoftbankで購入したiPhone 5Sの2年分割払 + 月月割 が10月で切れるので、次をどうするか悩んだのですが、タイトルのとおり、このタイミングでiPhone 6 + MVNO への切替を試してみました。 試算上、端末代含めた今後2年間の出費を半額程度に減らすことができました。
- 以下、10月時点の情報です。
- 当ブログの情報は個人的に調べて試算したものなので間違いがあるかもしれません。これによる一斉の責任は負いかねます。
- もし数値や認識に間違いなど見つかったらご指摘頂けますと幸いです。
iPhone 6 + MVNOにした背景
今までSoftbankの機種変のレールにそのまま乗っかり、2年分割払いで購入して月々割引 & 旧端末下取のパターンでiPhone 4S, 5Sと使ってきました。 Facetime オーディオやLINE電話などを使うことが多いので通話料はあまり取られないのですが、機種の分割払いも含めて月々7,000円前後かかっていました。年間 84,000円。 こうしてみると、結構かかってる。 今年は子どもも生まれ、色々と支出も増える年になったので、出来るだけ余計な出費は抑えたい。 仮にこの固定費を半額程度に抑えられたら、ルンバでも買って時間捻出できるなと思ったのがきっかけでした。
iPhone 6Sのアップデート内容を見ると、1200万/500万画素のカメラ、4Kビデオ、3D touchなどそこそこアップデートはありましたが、会社で検証端末は手に入るので、私物として確保したいと強く思えるような、ビビッと来るものがなかったので、現状キープか型落ちのiPhone 6を調達するで良いかと思い始めました。
また、ここ1〜2年で急激に盛り上がりを魅せているMVNOも試してみたい思いがあったので、まずはフラットに検討してみようと思ったのが背景です。
料金比較
ということで、支出がどの程度になるか、幾つかのパターンでシミュレーションしてみました。
前提
自分の生活と用途を考えて、以下の制約をおきました。
月々の通信量3GB以内
自宅や職場にいる時はWifiにつないでいるので、月々の通信量は2GB程度に収まっています。 なので、3GB程度のプランで十分そうでした。
音声通話
Facetime オーディオやLINE電話などを使うことが多いですが、緊急時などいざというときに音声電話はほしいです。また、電話番号変わると各調整が非常に手間なので、キャリア変えるにしてもMNPして電話番号はキープしておきたいです。
iPhoneを購入する場合ストレージは16GB
今までは "大は小を兼ねる" という言葉に従い、面倒な容量切り詰め作にかかる時間を買う目的で64GBを使ってきました。ただ、この4年間の運用で不要なアプリやデータが貯まり散らかる一方だし、写真などのデータは端末に入れておく理由は全くなく、共有フォトストリームやGoogleフォトなどクラウドサービスに放り込んでおいたほうが利便性は高いので、仮に機種を返るなら不要物を根こそぎ消す前提で16GBを候補にしました。 あと、自分は手が大きい方ではなく画面が大きいと辛いので、Plusではなく小さい方を候補に選びました。
SIMフリー版でもいいんですが、値段が大きく変わってくるので。10月時点で値段に3〜4万程度の開きがありました。 MVNOの多くはdocomo SIMなので、選択肢の多いほうが望ましいと考えました。
Apple iPhone 6 16GB シルバー 【docomo 白ロム】MG482J
- 出版社/メーカー: アップル
- メディア: エレクトロニクス
- この商品を含むブログ (2件) を見る
Apple iPhone 6 16GB スペースグレイ 【国内版SIMフリー】MG472J
- 出版社/メーカー: Apple Computer
- メディア: エレクトロニクス
- この商品を含むブログを見る
候補
ということで、上がった候補が以下。
利用中のキャリアが、"実質0円で機種変できるキャンペーン" をやっていたので、比較のため候補にあげてみました。 docomo乗換に関しては、代理店がキャッシュバックキャンペーンをやっていたりするので、もう少し調べれば大手キャリアに分のある選択肢も出てくるのかもしれません。10月時点では、iPhone6も台数限定で一括0円キャンペーン + キャッシュバックなどやっていたようです。 ただ、複雑怪奇な契約体型から脱したい思いもあったし、キャッシュバックやっている店舗を調べるのも足を運ぶのも時間がかかり過ぎる印象があり、"台数限定" に焦るのもバカバカしかったので、そういったものは対象外としました。
MVNO業者は、どこもプランが横並びなので、メジャーなIIJmio (みおふぉん) をサンプルにおきました。
- 現状維持: iPhone 5S (64GB) + Softbank (ホワイトプラン + パケットし放題フラット for 4G LTE)
- 機種/プラン変更: iPhone 6S (16GB) + Softbank (スマ放題ライト + データ定額パック5GB)
- docomoにMNP: iPhone 6S (16GB) + docomo (カケホーダイライトプラン + データMパック5GB)
- MVNOにMNP: iPhone 6S (16GB) + MVNO (3GB程度通信 + 音声通話)
- MVNOにMNP: iPhone 6 (16GB) + MVNO (3GB程度通信 + 音声通話)
見積もってみると
あくまで試算ですが、こうしてみると結構な開きが出ました。
型落ちのiPhone6で、MVNOで運用するとさすがに安いです。新しい機種を買うにも関わらず、現状stayと比べると先2年の総出費が倍以上変わります。
面白いのが、Softbankで機種変をしてもしなくてもTotalの出費はほとんど変わらないという点です。
1.現状維持 | 2.機種変更 | 3. docomoにMNP | 4. MVNOにMNP | 5. MVNOにMNP | |
---|---|---|---|---|---|
音声通話基本料 | ¥1,008 | ¥1,836 | ¥1,836 | ¥756 | ¥756 |
データ通信基本料 | ¥6,156 | ¥5,400 | ¥5,400 | ¥972 | ¥972 |
インターネット接続サービス | ¥324 | ¥324 | ¥324 | ¥0 | ¥0 |
端末代 24ヶ月分割 | ¥0 | ¥3,900 | ¥3,888 | (※1) ¥3,906 | (※1) ¥2,354 |
機種変サポート(24ヶ月間) | ¥0 | -¥2,835 | -¥3,456 | ¥0 | ¥0 |
MNP特典 | (※2) -¥450 | ¥0 | ¥0 | ||
特典 (12ヶ月間) | ¥0 | ¥0 | -¥1,350 | ¥0 | ¥0 |
下取り | ¥0 -¥1,065 | (※3) -¥625 | (※3) -¥625 | (※3) -¥625 | (※3) -¥625 |
1年目 月々支払額 | ¥7,488 | ¥7,560 | ¥5,567 | ¥5,009 | ¥3,329 |
2年目 月々支払額 | ¥7,488 | ¥7,560 | ¥6,917 | ¥5,009 | ¥3,329 |
2年間 総支払額 | ¥179,712 | ¥181,440 | ¥149,808 | ¥120,216 | ¥79,900 |
- ※全て税込み
- ※1:
- ※2:
- MNP特典で ¥10,800 (税込) 割引されるとのことなので24分割した数値を利用
※3:
- 主要なオンライン中古買取店で最高買取価格が ¥25,000 程度でした
- ただ、今使ってるiPhone5Sは多少傷もあるので、¥15,000 程度で仮置きしました。
参考
ということで、10月中旬〜11月中旬の2年契約更新期間 (違約金が発生しない1ヶ月) のタイミングで、プラン5の 型落ちiPhone6 + MVNO に切り替えることにしました。
iPhone調達とMVNO切替
iPhoneはAmazonで購入しました。 今はさらに値下がりしているようですが、私が購入した時は上記見積もりの¥56,500で購入することが出来ました。 赤シム引いてしまうと後で悲しい思いをするので白ロム保証を明記しているところを選ぶと良いと思います。 iPhoneは注文して2日後に届きました。
MVNOはいくつか比較検討した結果、IIJmioのみおふぉんを選びました。理由は通信実績です。 MVNOは競争が激しく、特に新興はキャンペーンを打ち出して料金も割引されることがあります。 ユーザが少ないうちは通信も快適でメリットが多いのですが、ユーザが増えた途端速度が落ちたなんてこともあるようです。 あくまで10月までの実績ベースですが、IIJmioは比較的通信が安定しており、ユーザ増加にあわせて増強対応も進められているようでした。
参考にしたのはこちらのサイトです。
格安SIM(MVNO)の速度比較 - androidlover.net
ちなみに、解約違反金は音声通話を入れている場合は¥0ではないですが、月々その額は減っていき、1年経つとそれ以降は違約金はかからなくなるそうです。
IIJmioもAmazonで購入しました。こちらは注文して翌日にMNP用の書類が届きました。
IIJ IIJmio SIM 音声通話 パック みおふぉん IM-B043
- 出版社/メーカー: IIJ
- 発売日: 2014/03/29
- メディア: エレクトロニクス
- この商品を含むブログ (7件) を見る
MNPの場合は書類のみ届きます。キャンペーンコードが入ってるので、IIJmioのWebサイトで申請を進めると、数日後にSIMカードが届きます。
なお、手続き前にキャリアからMNP予約番号を取得しておくこと。softbankはMNP予約番号はMySoftbankから申請できず、店頭か電話での申し込みになります。
SIMカードが届いたら開通手続きを行えば、1時間程度で新しいSIMが使えるようになります。 全て自宅で行えるのでありがたいですね。
揃ったものがこちら。 SIMは当然docomo SIMでした。
64GB→16GBへの移行とiPhone5S売却
データの整理は思った以上に大変でした。
4SでiPhoneを使い出して以来、ずっと64GBで運用してきたので不要なアプリや写真、聞かない音楽が貯まり散らかりまくっていたので。 16GBといえども、iOSやメタデータが乗ってくるので、実際に使える領域は10GB程度と予め割りきっておくと良いです。 私は音楽の取捨選択に最も苦労しました。
移行が無事完了したら、あとは旧端末iPhone5Sの売却です。 私は周囲の買取評判が比較的良かったゲオのSmarketを利用しました。
スマートフォンの買取ならゲオのSmarket | iPhone・Androidなど高価買取
申し込みをすると、数日後段ボール箱が届くので、手順通り初期化とアクティベートを行ってから箱に収納し送り返します。 数日後査定結果がメールで送られてくるので、同意すればその額が銀行口座に振り込まれます。 この時のために2年前iPhoneの箱は捨てずにとっておいたので、傷はありながらも条件は少しは良くなるのではと期待。結果、私は¥17,500程度で買い取ってもらえました。 iPhone6の購入価格が ¥56,500 だったので、実質手に入れたので、実質 ¥39,000 程度で手に入れたことになります。
移行してみて
もうすぐ一ヶ月程度経ちますが、不自由なく快適に過ごしています。
通信状況はちゃんと計測していないですが、私の生活範囲では体感むしろ向上した気がします。 ランニングコストも大幅に削減できたし、複雑怪奇な料金プラン/契約から脱することもできました。
節約バンザイ。自由バンザイ。
AWS CLI のprofileを簡単に切り替える
意外と知らない人がちらほらいたので、書き留めておく。
AWSとAPIとIAMについて
基本的にAWSの全てのサービス / リソースの操作はAPIによって行われます。 (Management Consoleの操作も内部的には全て同じAPIアクセス) S3への画像のuploadから、EC2 Instanceの増設/設定変更から、CloudWatchの参照、Support Caseの起票まで、あらゆる操作をAPIで行うことができるので、 単純なWeb Applicationだけでなく、オペレーション自動化など多種多様な用途で活用することになり、IAM User/Access Keyもあわせて複数用意することが多いと思います。
環境やサービスによってAWSのアカウント自体を分ける運用も多いと思いますが、そうなると扱うKeyの数は益々増えていきます。
AWS CLI
何かAWSのリソースを使ってものづくりをする際に、デバッグなどで AWS CLI を使うことは多いと思います。 なんたってワンライナーで手軽にAPI叩けますからね。 蛇足ですが、S3 のオブジェクト一覧見る時なんか、Management Console見るよりも、AWS CLI叩くことのほうが私は多いです。そのほうが速い。
本題
だいぶ引き伸ばしましたが、本題です。 幾つものUser, Keyを併用して使っている時に、ユーザを切り替えて権限確認、動作確認したい場合の方法です。 至ってシンプル。 --profile オプションを使いましょう。 以下、Helpより引用。
$ aws help ( ...omitted ...) --profile (string) Use a specific profile from your credential file. ... $ aws configure help ( ...omitted ...) SYNOPSIS aws configure [--profile profile-name] ...
aws configure
コマンドで --profile *profile-name*
を付与して設定を進めると、指定した名前で別の設定を加えることができます。
default (無名) は消えず別の内容で登録され、他サブコマンド実行時に同様に --profile *profile-name*
オプションを付与するだけでアカウントを切り替えできます。
以下設定例。
$ aws configure --profile bob AWS Access Key ID [AKIA************hoge]: AWS Secret Access Key [****************hOgE]: Default region name [ap-northeast-1]: Default output format [None]:
設定内容は $HOME/.aws/config, credentials ファイルに INI形式で保存されます。 中身を見ると以下のように、default (無名) はそのままに、上のprofile-name で指定した情報が追記されています。
$ cat .aws/config [profile default] region = ap-northeast-1 [profile bob] region = ap-northeast-1 $ cat .aws/credentials [default] aws_access_key_id = AKIA************DMKA aws_secret_access_key = ************************************hoge [bob] aws_access_key_id = AKIA************hoge aws_secret_access_key = ************************************hOgE
切替を試してみましょう。 defaultはrootアカウントのKey, S3の任意のbucketのみ権限があるようなIAM Userをbobとしてprofile登録しています。
# root権限でbucket一覧確認 $ aws s3 ls 2015-10-15 19:28:40 fuga 2015-10-15 19:29:17 hogehoge # bobユーザでfuga bucketの中身をls $ aws s3 ls s3://fuga/ --profile bob 2015-10-15 19:44:10 14152 test.png # hogehoge bucketにアクセス (権限なし) $ aws s3 ls s3://hogehoge --profile bob A client error (AccessDenied) occurred when calling the ListObjects operation: Access Denied
終わりに
jq コマンド、補完入力設定と同じくらい必須のTIPsだと思います。 環境変数にcredential書く手もありますが、その場合profileオプションで切り替えられず少々不便になるので、こちらのほうがオススメです。
AWS CLIは鬼のようにできることが多いのと、たまにManagement Consoleではできない操作なんかもあったりするので、 移動中などでちまちま暇つぶしがてらリファレンス呼んでみると面白いです。 aws — AWS CLI 1.8.12 documentation
Ansible入門&ハンズオン資料を公開しました
少し時間が経ってしまいましたが、 先日Ansible入門というイベント でAnsibleの説明とハンズオンをする機会を頂きました。 資料は SlideShare に公開しているので、これからAnsible始めたいという方はご参考にしていただければ幸いです。 資料の後半にハンズオン用の題材があり、Playbookの例はGithubに公開しています。
概要
Ansibleに興味がある未経験者〜使い始めた or 別の構成管理は使ったことがあるくらいのAnsible初心者をターゲットとし、受講後自走できるようにという思いで作りました 資料自体は、「構成管理とは」「なぜやるのか」という導入から始まり、Ansibleの世界観や登場人物をざっくりと説明しています。 読めばキーワードがざっと入って脳内インデックスができ、一時間半程度のハンズオンを経ればある程度勘所はつかめるようになるので、あとは公式ドキュメントなど見ながら自主学習してね、というスタンスの資料です。 ハンズオンは計3つです。
- 基礎編
- adhoc編
- ansibleコマンドでadhocにshellモジュールを実行する
- 応用編
※ "冪等性ちゃんと担保する": 要するに、dry-run モード ansible-playbook --check
で実行してchangedにならないようにする。
Playbookの基礎を抑えている内容となっていると思うので、大体の勘所がつかめ、すぐに業務自動化に励めると思います。 Ansibleが素晴らしいのは、エージェントレスでアーキテクチャも記法もシンプルなので、季節の環境を汚すことなくスモールスタートでねじ込める点です。 さくっと運用便利ツールや監視エージェントをばらまく、脆弱性対応するくらいのカジュアルな使い方から運転できるのは大きいですね。 私は去年まで1年ちょっとChefに使っていましたが、Ansibleのこのシンプルさはとても好きです。
SlideShare
ハンズオンの回答例
uorat/ansible-handson · GitHub
感想
当日は台風の影響もあり、申し込み数ほどに参加者は集まらなかったのですが、参加頂いた方は皆熱心に臨んでくださったので救われましたw "収穫が多かった、タメになった" という感想を幾つか頂きました。 小さいイベントですが、せっかく来て頂いた方には何かを持ち帰ってアクションに繋げられるようにしたいと思ったことと、この資料も今回に閉じず社内勉強会などで使いまわしたいという思いがあり、それなりに考えてコンテンツ作ったので、こういう声は純粋に嬉しいですし、今後の励みになります。 ご協力頂いた皆さま、ありがとうございました。
なお、ハンズオンのgit module使ってデプロイするというお題の中で、 @yteraoka さんの ansible-tutorial - Github を参照させていただきました。
以下のgithub.ioですね。ServerspecでCI回すところまで含まれていて素晴らしいTutorialです。 是非こちらも参考になさって下さい。
Ansible チュートリアル | Ansible Tutorial in Japanese
あと、この本もおすすめです。
- 作者: 若山史郎
- 発売日: 2014/07/30
- メディア: Kindle版
- この商品を含むブログ (2件) を見る
naoyaさんのChef入門と同じくらいのボリューム感ですね。
入門Chef Solo - Infrastructure as Code
- 作者: 伊藤直也
- 出版社/メーカー: 伊藤直也
- 発売日: 2013/03/11
- メディア: Kindle版
- 購入: 16人 クリック: 1,027回
- この商品を含むブログ (19件) を見る
Socket.io with Websocket の SSL/TLS 対応
※ (2016/9/19 追記) Nginx 使った対応方法も記載しているので、あわせて参考にして下さい。
昨今のサービスにおいて、暗号化はもはや必須の流れである。 GoogleやFacebookなど主要なサービスはずいぶん前からHTTPS通信を標準としているし、HTTPS化対応しているサイトはSEO的にも優遇されるようになる という方針が出ていたりする。
前記事でSocket.IO + Redis PubSubを用いたリアルタイムメッセージ配信の仕組みをまとめたが、このままWebSocketを利用すると当然インターネット上を平文のテキストが流れてしまう。 また、チャット機能を呼び出す親元のWebページがHTTPSで提供されているものであれば、Mixed Content でブラウザによっては暗号化されていないWebSocket通信をブロックされることもあるだろう。 後からSSL/TLS対応を入れると往々にしてハマるので、ハナから対応しておくに越したことはない。
ということで、Socket.IOを用いたWebSocket通信をSSL/TLS対応させる。 以下、プログラム側での対応方法を記したが、NginxをWebSocket Proxyとして利用 できるので、NginxでSSL Terminationさせる手もある。
ポイント
- ブラウザによってはWebSocket通信が利用できないことがあるため、Socket.IOでは、クライアントに適した通信プロトコルを自動選択する仕組みが実装されている。
- WebSocket と xhr-polling の2択。
- https://github.com/socketio/engine.io#transports
- セッションを張り続けて通信を行うWebSocketを使う以上、ボトルネックになりがちなロードバランサーを介することは推奨できない。
- ロードバランサは最初の接続確立のみ利用し、WebSocket通信はクライアントからサーバに対して直刺しさせる
例えばAWSで運用している場合、SSL TerminationをELBに任せることが多いと思うが、WebSocket通信をELBを介さず行うため、サーバサイド (Socket.js on Node.js) で暗号化させる必要がある。
実装
サーバサイド
サーバに事前に配置したサーバ証明書、中間CA証明書、秘密鍵のセットをロードさせて起動することで、SSL対応が可能。 この対応で、Listenしたポートでhttps, wss通信が可能となる。
var fs = reqquire('fs'); var io = require('socket.io').listen(3000, { key : fs.readFileSync('/etc/pki/tls/private/your.domain.com.key').toString(), cert: fs.readFileSync('/etc/pki/tls/certs/your.domain.com.crt').toString(), ca: fs.readFileSync('/etc/pki/tls/certs/your.domain.com.cer').toString(), 'log level':1 });
当然、証明書のドメインとWebSocket接続時にクライアントから指定するドメインは揃える必要がある。 ワイルドカードで証明書を作成していれば、例えば hostname.domain.com で接続させれば良い。
※DNSにホスト名で名前解決できるようにA recordを登録しておく必要あり
クライアントサイド
以下のとおり、https で指定する。 "wss"ではない。 前に述べたとおり、handshake時にどのプロトコル (WebSocket / xhr-polling) で対話するかを採択するが、その通信は httpないしはhttpsで行われる。 handshakeが成功すると、wss または xhr-poolling over TLS で接続確立される。
<script src="https://hostname.domain.com:3000/socket.io/socket.io.js"></script> <script> var socket = io.connect('https://hostname.domain.com:3000'); ... your logic ... </script>
ソース (※ 2016/5/15 追)
※ローカルのメモを転記しておく。
Socket.IOのdocumentaionにはSSL/TLS対応に関する記載が見当たらなかったが、ソース読んでみると明解。
Socket.IO
Socket.IO のコードを読んでみると、 `require('socket.io').listen した時に options.key があれば https#CreateServer 呼びだすロジックになっている。 ちょっと古いが、socket.io (v0.9.13) /lib/socket.io.js l63 - l66 抜粋
if (options && options.key) server = require('https').createServer(options); else server = require('http').createServer();
Node.js - https.createServer
Official Documentationにあるとおり、 https.createServer の options は tls.createServer と同様で、以下のフィールドでSSL/TLS通信に必要なフィールドを指定できる。
https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener https://nodejs.org/api/tls.html#tls_tls_createserver_options_secureconnectionlistener
終わりに
以上、Socket.IOでのWebSocket通信のSSL対応の一例としてプログラム側での対応方法を記したが、NginxをWebSocket Proxyとして利用 できるので、NginxでSSL Terminationさせるという方法もある。 手っ取り早く試すなら上記でも良いが、既にNginxを投入済みのサイトであればNginx WebSocket Proxyを用いても良いかも。
※ (2016/9/19 追記) Nginx 使った対応方法も記載しているので、あわせて参考にして下さい。
はじめてのNode.js -サーバーサイドJavaScriptでWebアプリを開発する-
- 作者: 松島浩道
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2013/03/15
- メディア: 大型本
- クリック: 15回
- この商品を含むブログ (5件) を見る
実践Node.js プログラミング (Programmer's SELECTION)
- 作者: Mike Cantelon,Marc Harter,T.J. Holowaychuk,Nathan Rajlich,生越昌己,吉川邦夫
- 出版社/メーカー: 翔泳社
- 発売日: 2014/06/10
- メディア: 大型本
- この商品を含むブログ (1件) を見る
Socket.io + Redis PubSubでリアルタイムメッセージ配信
とあるサービスに「チャット機能」を追加しようという話になり、急ピッチで仕組みを用意することになった。 仕様/要件はふわっとしているものの、 2週間後にはリリースというケツは決まっている。 はてさてどうしたものかとその瞬間は思ったものだが、無事仕組みとして載せられたので、備忘記しておく。
リアルタイムチャット機能
要件は以下。
例えば、動画を視聴しているとして、その動画の横に、自分含む視聴者のコメントが流れてくる、 ようなものを想像してもらえれば良い。
Socket.IO
「クライアント - サーバ間のリアルタイムなメッセージのやり取り」ということで、
という方針は早々に決まった。自動的にサーバは Node.js に決定。 ブラウザからのアクセスがあるため、xhr-polling / WebSocket をSocket.IO が両方サポートしていることは有難かったし、WebSocket通信を数行で始められる手軽さも魅力的だった。 ケツが2週間後なので実装コストがなるべく少なく済み、ビジネスロジックに集中できる方法を採択する必要があったため。
Socket.IOのポイントをまとめると、
- WebSocket, xhr-polling をサポート、クライアントの動作環境に応じていずれかを自動採択する
- "1 : 1" や "1 : N" のようなBasicな特定双方向通信、一斉配信 (broadcast)、接続単位を論理的に分離する 名前空間/namespace や 部屋/room 機能 など様々な配信方法をサポート
インストールは npm で一発 。 実装イメージは以下。
server side
var io = require('socket.io').listen(3000); io.sockets.on('connection', function (socket) { ... your logic ... });
client side
<script src="http://your.domain.com:3000/socket.io/socket.io.js"></script> <script> var socket = io('http://your.domain.com:3000'); socket.on('connect', function() { ... your logic ... }); ... and so on... </script>
ネイティブアプリ用のクライアントライブラリもある。 Socket.IOのGithub を見たところ、 C++ の実装もあるようだ。
Redis PubSub
Socket.IO on Node.js なWeb/Appサーバに対して、各クライアントはWebSocket通信で接続する。 接続数増と耐障害性を担保するためWeb/Appサーバの冗長化を考えた時に、一斉配信するメッセージを複数台のサーバにどのように伝達させるかで一瞬悩んだ。 所謂Publish / Subscribe ... ということで思い出したのがRedis。 "危険なほどのスピード" で有名なオンメモリKey-Value データストアで、扱えるデータ構造がMemcached と比べて豊富、ディスクへの永続化もあり人気のKVSだが、このRedis、PubSub も提供している。
1. 購読者 (subscriber) 、任意のkeyをsubscribeする
$ redis-cli 127.0.0.1:6379> SUBSCRIBE hoge Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "hoge" 3) (integer) 1
2. (別のターミナルで) 出版者 (publisher) 、1で指定したkeyでメッセージをpublishする
$ redis-cli 127.0.0.1:6379> PUBLISH hoge "hello pubsub" (integer) 1
3. 購読者 (subscriber) の端末に、2で配信されたメッセージが表示される
$ redis-cli 127.0.0.1:6379> SUBSCRIBE hoge Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "hoge" 3) (integer) 1 1) "message" ←追加 2) "hoge" ←追加 3) "hello pubsub" ←追加
Socket.IO - Redis の連携は容易。Socket.IOのバージョンによりインストール方法が若干変わる点に注意。
- Socket.IO v0.9 系まで
- Socket.IO 内に同梱されているため、特に追加インストールは必要なし。
- 呼出は require('redis')
- Socket.IO v1.0 以降
- 外部ライブラリとして切り離された socket.io-redis をインストール
- 呼出は require('socket.io-redis')
ちなみに、AWSのElasticCacheはRedisをサポートしており、Read Replica & Multi-AZも対応している。
PubSubはReplica Nodeに対しても有効で、PubSub sessionに関しても負荷対策が可能。
- Node.jsからReplica Nodeに対してSubscribe sessionを張っておく
- コメント投稿はMaster Nodeに対してPublish
- Read Replicaに対してSubscribeしている全購読者に配信される
WebSocketとELB
Socket.IO on Node.js サーバを冗長化させた場合の振り分け方も一工夫必要だった。 通常のHTTP通信と異なるため。注意点は以下の2点。
- Cient - Server間の通信は通常のHTTP通信と異なりWebSocketで接続持続される
- Socket.ioによるhandshake処理は必ず同一サーバに接続させなければならない
例えば、ロードバランサーを上段に挟む場合、全てのセッションがロードバランサーに対して張られることとなる。 通常のHTTPと異なりWebSocketのセッションを張り続けるという特性上、接続を集約させるロードバランサーがボトルネックになる危険がある。 また、ロードバランサーによっては、Socket.IO/WebSocketの間に立てない場合がある。例えば、AWSのELB。
- ProtocolはHTTPかTCPか → "あちらを立てればこちらが立たず"
- HTTPを選ぶと、ELBによりHTTP Headerが書き換えられWebSocketのhandshake時に利用するHTTP Upgrade headerが削られWebSocket接続できない (XHR-Pollingが強制される)
- TCPを選ぶと、Sticky Sessionが利用できず接続するたびに別のサーバが応答するためhandshakeに失敗することがある
- 参考: Express / Socket.IO をスケールアウトしてみよう
- どちらのProtocolを選んでも、ELBによりTimeout扱いとされ通信が切断される可能性がある。
AWSのSolution Architectも、ELBは最初のセッション確立時にのみ利用してdispatchしてWebSocketさせるのが良いと言及している。
教えに従い、接続情報を返すAPIをクライアント側で呼出してから、サーバに対して直接WebSocket通信させる方式とした。
システム構成
行き着いたシステム構成は以下。
- Web/Appサーバ: Node.js/Socket.IO, Apache/PHP on Amazon EC2
- Load Balancer: Amazon ELB
- DB: Amazon RDS for MySQL
- KVS: Amazon ElastiCache for Redis
主機能がApache / PHPで動くWebアプリケーションのため、APIは既存資産を流用して実装。 Apahce/PHP を Node.js/Socket.IOと同梱させAPIを提供するようにした。 同梱させた理由は、接続情報管理の実装を省き自分のホスト名を返すようにしたかったため。 本来は、APIサーバは切り離して、ステータス含めて接続情報を管理するようにしたほうが望ましいと思う。
次回は、WebSocket接続のSSL/TLS対応をまとめようと思う。
はじめてのNode.js -サーバーサイドJavaScriptでWebアプリを開発する-
- 作者: 松島浩道
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2013/03/15
- メディア: 大型本
- クリック: 15回
- この商品を含むブログ (5件) を見る
- 作者: Josiah L. Carlson,長尾高弘
- 出版社/メーカー: KADOKAWA/アスキー・メディアワークス
- 発売日: 2013/12/27
- メディア: 大型本
- この商品を含むブログ (4件) を見る
Amazon Web Services クラウドデザインパターン設計ガイド 改訂版
- 作者: 玉川憲,片山暁雄,鈴木宏康,野上忍,瀬戸島敏宏,坂西隆之,日経SYSTEMS
- 出版社/メーカー: 日経BP社
- 発売日: 2015/05/28
- メディア: 単行本
- この商品を含むブログ (3件) を見る
Amazon Web Services パターン別構築・運用ガイド
- 作者: NRIネットコム株式会社,佐々木拓郎,林晋一郎,小西秀和,佐藤瞬
- 出版社/メーカー: SBクリエイティブ
- 発売日: 2015/03/25
- メディア: 大型本
- この商品を含むブログ (2件) を見る