Twilio で電話通知

Twilio で電話通知

概要

障害検知をメールや Slack に流しても休日に業務系連絡を見ることは少ない。

その為、より検知報告に気付きやすくする様、

電話通知にするべく Twilio を導入する運びとなりました。

まずは利用するまでの簡単な手順をまとめました。

※コードのサンプルが Twilio のサイト内にあるので導入しやすかったです。

手順

1. Twilio にアクセス

以下リンクから Twilio にアクセスします。

http://twilio.kddi-web.com

2. 新規登録

名前、E-mail、パスワード(大小半角英数字)と

何にどの言語で利用するかを選択して

「始めましょう」をクリック。

「始めましょう」という日本語はユーザ目線でなく違和感ありますね。

3. アカウント認証

以下2つの認証方法があります。

  • 電話番号に SMS に確認コードを送信させる
  • 電話番号に Twilio から着信があり確認コードのダイヤルキーを入力する。

後者は Twilio の音声読み上げロボットから電話がかかって来るので

どんな感じで通知されるか試してみたい方は是非後者を選択してみてください。

スムーズなイントネーションではないですが、伝えたい気持ちは誰よりもあります。

4. Twilio から電話をかけてみる

アカウント認証確認後、Twilio 製品の「プログラマブル Voice」ページ Top に遷移しました。
メニューから ツール をクリックしツールページに遷移してください。

To 指定

音声通話>通話>電話をかける の API Explorer にて
必須To に 電話番号認証した番号を入力してください。

但し、日本番号(+81)の場合、
090******** の番号は

はじめの 0 を削除し、 +81 を prefix として追加し、

+8190******** となりますので注意してください。

URL 指定

条件Url に Twilio からの電話を受け取った際、

電話のキーダイヤルを押下した際の挙動を url 形式で指定可能です。

適当に準備できる Url がない場合は、

以下のような適当な Url で良いです。

http:/hogehoge.hogehoge.co.jp

通知実行

ページ下部の リクエストを発行する ボタンをクリックします。

※料金が発生します とありますが、Trial は料金を請求されるということはありません。

同アカウントでアップグレードする際は、発信した電話料金も合わせて請求されることになるので、テスト完了後は別途アカウントを取得することを推奨します。

電話を受け取る

Twilio から電話がかかってきたかと思います。

キーダイヤルを入力すると、 Url で指定したプログラムが動作しますが、

適当に入力したので

アプリケーションエラーが発生しました。電話を終了します。
と通知されるはずです。

実際にプログラムから使用する際は、

指定した Url でキー入力を受け取ってその後の挙動を制御する、

という流れになります。

実際に利用した例

担当した業務では、Zabbix からの障害検知を Twilio で担当者に電話報告(エスカレーション)するという仕組みを構築しました。

例)以下のような挙動が実現できます。

Zabbix で障害検知



Twilio

↓ 電話

対応者

↓ 対応者が「1」をクリック

指定した Url のプログラム実行

↓「1」を受け取り、障害対応可能な旨を Zabbix へ通知

Zabbix (障害対応中)

Zabbix & Twilio 参考

zabbix-twillio

上記サイトでの zabbix-twilio 連携の手順で進めた場合、

twilio でキーダイヤル入力後、 以下のようなエラーが発生し、イベント登録ができません。

API error -32602: The "user.login" method must be called without the "auth" parameter

zabbix-twilio.php 内の Zabbix_APIクラスが古い為です。

zabbix-twilio.php

PhpZabbixApi

上記をダウンロードし、 php build.php で 以下 2 ファイルを生成し、

こちらを呼び出し Zabbix_ApiZabbixApi とを変更してください。

  • ZabbixApi.class.php

  • ZabbixApiAbstract.class.php

  • /var/www/html/zabbix-twilio/zabbix-twilio.php

1
2
3
4
5
+ require_once 'ZabbixApi.class.php';
+ use ZabbixApi\ZabbixApi;

- $api = new Zabbix_API ( $ZABBIX_API, $ZABBIX_USER, $ZABBIX_PASS );
+ $api = new ZabbixApi ( $ZABBIX_API, $ZABBIX_USER, $ZABBIX_PASS);

ZabbixApi は Basic 認証を設定している場合にも対処しています。

1
2
// 例)
$api = new ZabbixApi ( $ZABBIX_API, $ZABBIX_USER, $ZABBIX_PASS, $BASIC_AUTH_USER, $BASIC_AUTH_PASS);

検証環境

  • Amazon Linux AMI release 2015.09
  • Zabbix 2.5 (3.0α)
  • PHP 5.6.14
  • MySQL 5.5.46

以上

意外と容量食ってた yum cache

yum cache 容量

1
2
# du -sh /var/cache/yum
155M /var/cache/yum

155MByteある汗

yum cache 削除

1
2
3
4
5
# yum clean all
読み込んだプラグイン:fastestmirror
リポジトリーを清掃しています: base epel extras mysql-connectors-community mysql-tools-community mysql56-community nginx treasuredata updates
Cleaning up everything
Cleaning up list of fastest mirrors

yum cache容量確認

1
2
# du -sh /var/cache/yum
8.0K /var/cache/yum

スッキリ!

サーバから容量不足のアラートで少しでも容量減らしたいときに
役立ちました。

潤沢にサーバスペックを用意できるクライアントでない場合もあるので
地道に必要な知識だと感じました。

Kibana4 検索窓での検索 正規表現パターンマッチ等

Kibana4 検索窓での検索 正規表現パターンマッチ等

概要

アクセスログを fluentd で集積(aggregate)して
ElasticSearch へ保存、そのデータを kibana で表示しています。

ちょっとしたアクセスログ解析したい場合、
かつては、SSH でサーバにログインして
コマンド実行し検索するという工程を踏んでいました。

ですが、Kibana で検索することにより
サーバログインすることなく、検索がスムーズになりました。

リモートログインして誤った操作等もなくなる、
また本番環境アカウントの公開範囲を絞ることができ
良いことが増えました。

実際構築しても使う側がどう検索したら良いかわからないということが
ちょいちょいあったので
Kibana4 検索窓での検索方法を簡単にまとめました。

前提

  • Kibana4
  • ドメイン名を以下とする

http(s)://hogehoge.jp

範囲指定

  • http ステータスコード 200 から 400 検索

status: [200 TO 400]

否定

  • 例) 指定ドメイン以外のリファラ検索
  • referer という項目について 正規表現での否定(NOT)のパターンマッチで検索します。
1
NOT referer:/http(s?)\:\/\/hogehoge\.jp\/(.*)/

複合検索

  • 例) 指定ドメイン以外、且つ、200 ステータス
1
NOT referer:/http(s?)\:\/\/hogehoge\.jp\/(.*)/ AND status:200

随時、事例があれば追記していきます。

運用中のNginxをノーメンテでバージョンアップ&HTTP2.0モジュールを導入

運用中のNginxをノーメンテでバージョンアップ&HTTP2.0モジュールを導入

概要

運用中の Nginx に HTTP2.0 モジュール http_v2_module を導入し
サイトのパフォーマンス向上を図ります。

※ Nginx 1.9.5 から http_spdy_modulehttp_v2_module に変更しています。

環境

  • CentOS Linux release 7.1.1503 (Core)
  • Nginx 1.9.3 インストール済み/稼働中

したいこと

  • Nginx のバージョンアップ (1.9.5 以上)
  • http_v2_module インストール

現状確認

1
2
3
4
5
6
7
# nginx -V

nginx version: nginx/1.9.3
built by gcc 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC)
built with OpenSSL 1.0.1e-fips 11 Feb 2013
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-threads --with-stream --with-stream_ssl_module --with-mail --with-mail_ssl_module --with-file-aio --with-ipv6 --with-http_spdy_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic'

※module や log, pid のパスは各環境に毎に異なります。

まずは 1.9.5 以上にバージョンアップして http_v2_module を導入したいと思います。

Nginx 1.9.6 インストール

今回は 2015.11.17 時点で最新の 1.9.6 をインストールします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# cd /usr/local/src
# wget http://nginx.org/download/nginx-1.9.6.tar.gz
# tar xvf load/nginx-1.9.6.tar.gz
# cd nginx-1.9.6
# ./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-threads --with-stream --with-stream_ssl_module --with-mail --with-mail_ssl_module --with-file-aio --with-ipv6 --with-http_v2_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic'

# make
# make install

~~~ インストール完了 ~~~

# nginx -V
nginx version: nginx/1.9.6
built by gcc 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC)
built with OpenSSL 1.0.1e-fips 11 Feb 2013
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-mail --with-mail_ssl_module --with-file-aio --with-ipv6 --with-http_v2_module --with-http_geoip_module --with-cc-opt='-O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic'

version が 1.9.6 となり
configure arguments に --with-http_v2_module が追加されていることがわかります。

要点は元々導入済み http_spdy_modulehttp_v2_module に変更しビルドです。
--with-http_spdy_module がなければ --with-http_v2_module 追加です。

nginx server ディレクティブ修正

ssl http2.0 対応する様、修正します

1
2
3
server {
- listen 443;
+ listen 443 ssl http2;

Nginx configure test & reload

  • configure test 実施します。
  • 以下のように syntax is ok が出ない場合は設定に誤りがあるので修正してください。
1
2
3
4
# nginx -t

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
  • 設定を再読み込みします。
1
# nginx -s reload

上記で設定完了です。
これまでノーメンテでバージョンアップし、http_v2_module インストールができました。

早速 https スキーマとなるページにアクセスしてみましょう。

http2.0 設定確認

  • Chrome ブラウザの Extension SPDY インディケータで確認
  • FireFox 開発ツール> ネットワーク > ヘッダから確認

SPDY インディケータで確認

HTTP/2 and SPDY indicator

拡張モジュールをインストールして確認してみると
SPDY インディケータが青くなっていることが確認できます。

FireFox 開発ツール> ネットワーク > ヘッダから確認

参考サイト

Elasticsearch curatorで不要Indexをまとめて削除

概要

fluentd + ElasticSearch + kibana を運用していますが
ある日ElasticSearchが動作しなくなる事象が発生しました。

過去indexが溜まりに溜まってメモリ不足というエラー。

logはS3にアップロードしているし、
不要なIndexは適宜削除して対策しました。

環境

  • CentOS Linux release 7.0.1406 (Core)
  • ElasticSearch 1.7.1
  • Python 2.7.5
  • pip 7.1.0

curator インストール

  • ElasticSearchをインストールしているサーバにて以下実施
1
# pip install curator

curator コマンド実行

  • ElasticSearchをインストールしているサーバにて以下実施
1
2
3
4
5
6
7
8
# 14日(2週間)経過でclose
curator --host localhost close indices --prefix logstash --older-than 14 --time-unit days --timestring %Y.%m.%d

# 35日(4週間)経過でdelete
curator --host localhost delete indices --prefix logstash --older-than 35 --time-unit days --timestring %Y.%m.%d

# 2日経過でbloom filter無効化
curator --host localhost bloom indices --prefix logstash --older-than 2 --time-unit days --timestring %Y.%m.%d

上記をjenkinsで SSH plugin
リモートサーバにログインして実行するよう、
設定して定期ポーリングで1日1回実行させてます。

以上

コンテンツがgzip圧縮されているかチェック

Use Redis via Python

Memorandum

The below codes is how to use redis via Python.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/usr/bin/python
# coding: UTF-8

import redis

r = redis.StrictRedis(host='localhost', port=6379)

# set/get string.
r.set('test1', 'aiueo')
r.expire('test1', 1000)
print r.get('test1') # aiueo

# set/get integer.
r.set('test2', 2)
print r.get('test2') # 2

# Check key exit.
print r.exists('test1') # True
print r.exists('test0') # False

# pattern match
keys = r.keys('test*')
if len(keys) > 0 :
for key in keys:
print '--------------------------------------------'
print key # test1, test2
print r.get(key) # aiueo, 2
print r.type(key) # Type : string, string
print r.ttl(key) # Expire : if not set, set "-1"

r.append('test1', '_kkkkkkk')
print r.get('test1') # aiueo_kkkkkkk

# delete cache.
r.delete('test1')
print r.exists('test1') # False

Thanks.

By grunt, uglify js & minify css on MacOSX.

By grunt, uglify js & minify css on MacOSX.

environment

  • MacOSX 10.11
  • grunt-cli v0.1.13
  • grunt v0.4.5

Install npm, Initilize npm

1
2
3
cd ~              # depending on your preference.
brew install npm
npm init
  • Result
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
About to write to /Users/kenzo/go/src/github.com/flag/public/package.json:

{
"name": "public",
"version": "1.0.0",
"description": "gruntfile",
"main": "Gruntfile.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "xxxxxxxx@gmail.com",
"license": "ISC",
"devDependencies": {
},
"dependencies": {
}
}

Install grunt-cli

1
npm install -g grunt-cli

With --save-dev option, add install module infomation to package.json.

Install grunt modules

1
2
3
4
5
6
7
8
9
10
11
12
npm install -g grunt --save-dev
npm install grunt-contrib-watch --save-dev
npm install grunt-contrib-copy --save-dev
npm install grunt-contrib-clean --save-dev
npm install grunt-contrib-cssmin --save-dev
npm install grunt-contrib-uglify --save-dev
npm install grunt-image --save-dev
npm install grunt-contrib-htmlmin --save-dev
npm install load-grunt-tasks --save-dev
npm install grunt-jsbeautifier --save-dev
npm install grunt-cssbeautifier --save-dev

Module map.

Module Detail
grunt-contrib-watch Monitoring update files.
grunt-contrib-copy Copy file or directory.
grunt-contrib-clean Clean file or directory.
grunt-contrib-cssmin Minify CSS files.
grunt-contrib-uglify Uglify & Compress Javascript files.
grunt-contrib-image Optimize image files (jpeg, jpg, gif, png, swf, etc…).
grunt-contrib-htmlmin Minify HTML files.
grunt-jsbeautifier beautify Javascript files.
grunt-cssbeautifier beautify Javascript files.

Confirm package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
cat package.json

{
"name": "public",
"version": "1.0.0",
"description": "grunt",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "*********@gmail.com",
"license": "ISC",
"devDependencies": {
"grunt": "^0.4.5",
"grunt-contrib-clean": "^0.6.0",
"grunt-contrib-copy": "^0.8.2",
"grunt-contrib-cssmin": "^0.14.0",
"grunt-contrib-htmlmin": "^0.6.0",
"grunt-contrib-uglify": "^0.10.0",
"grunt-contrib-watch": "^0.6.1",
"grunt-cssbeautifier": "^0.1.2",
"grunt-image": "^1.1.1",
"grunt-jsbeautifier": "^0.2.10",
"load-grunt-tasks": "^3.3.0"
}
}
  • Add dependencies of grunt modules to package.json !

move to parent directory of css, js folder

1
cd /path/to/project/public/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
tree

/public/

├─Gruntfile.coffee # make `Gruntfile.coffee` at next step.

├── css
│ ├── bootstrap.css
│ ├── img.css
│ ├── style.css
│ └── reset.css

└── js
├── jquery-1.9.1.js
├── img.js
├── login.js
└── signup.js

Create Gruntfile.coffee or Gruntfile.json

  • Today, I create a Gruntfile.coffee.
  • For example, Only Uglify js, Minify css, Beautify js, css.
1
vim Gruntfile.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
module.exports = (grunt) ->

# current path.
path = require('path')
current = path.resolve('.')

# load npm task.
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-jsbeautifier');
grunt.loadNpmTasks('grunt-cssbeautifier');

grunt.initConfig

# define directory.
dir:
js: 'js'
css: 'css'
img: 'img'

# minify CSS.
cssmin:
all:
expand: true
cwd: current + '/<%= dir.css %>/'
src: '*.css'
dest: current + '/<%= dir.css %>/'

# uglify js.
uglify:
options:
mangle: true
compress: true
all:
expand: true
cwd: current + '/<%= dir.js %>/'
src: '*.js'
dest: current + '/<%= dir.js %>/'

# beautify js.
jsbeautifier:
files: '**/*.js'
options: []

# beautify css.
cssbeautifier:
files: '**/*.css'
options: []

grunt.registerTask 'default', ['cssmin', 'uglify']

Make symbolilc Link of ‘node_modules’

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
cd <path where Gruntfile.coffee exist>
ln -s ~/node_modules .
tree

/public/
├─Gruntfile.coffee
├─node_modules -> /Users/kenzo/node_modules

├── css
│ ├── bootstrap.css
│ ├── img.css
│ ├── style.css
│ └── reset.css

└── js
├── jquery-1.9.1.js
├── img.js
├── login.js
└── signup.js

Execute grunt command.

1
2
cd <path where Gruntfile.coffee exist>
grunt # By no parameter, execute default task.
  • If You want to execute only cssmin, excute command grunt cssmin

Thakns.

Ruby & gem インストール

備忘録です。

環境

  • CentOS 5.8 (Final)

ruby 2.1.2 インストール

1
2
3
4
5
6
7
# cd /usr/local/src
# wget http://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.2.tar.gz
# tar xvfz ruby-2.1.2.tar.gz
# rm ruby-2.1.2.tar.gz
# cd ruby-2.1.2
# ./configure
# make; make install

gem インストール

1
2
3
4
# wget http://production.cf.rubygems.org/rubygems/rubygems-2.2.2.zip
# unzip rubygems-2.2.2.zip
# cd rubygems-2.2.2
# ruby setup.rb

以上

Nginx Basic認証設定、社内IPなど特定ipのみ許可

概要

サービス公開前にNginxで
Basic認証を掛ける必要がありました

ちょうど社内公開したときでもあり
Basic認証のポップアップが出るのが鬱陶しいのもあって
社内だけオフりたい、というときに以下のような設定をしました。

Basic認証設定

1
# yum install -y httpd-tools
1
2
3
4
# cd /etc/nginx
# htpasswd -c .htpasswd <Basic認証ユーザ>
New password: <Basic認証ユーザのパスワード入力>
Re-type new password: <もう一度、Basic認証ユーザのパスワード入力>

Nginx configureファイル編集

1
# vim /etc/nginx/conf.d/default.conf
1
2
3
4
5
6
7
8
9
location / {
....

# Basic認証設定
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;

....
}

特定IPのみ許可したい場合

1
# vim /etc/nginx/conf.d/default.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
location / {
....

# add start -----
satisfy any;
allow <許可IP>;
allow <許可IP>;
deny all;
# add end -----

# Basic認証設定
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;

....
}

あとは 許可IPを随時増やせば良いです。

Webアプリケーション開発におけるNginxあるあるかなと思います♪

以上です。