RedashをAMIから起動してみた

公式AMIからインスタンスの起動

https://redash.io/help-onpremise/setup/setting-up-redash-instance.html

から AMI を選択します。Region ap-northeast-1 の AMI リンクをクリックするとインスタンスタイプを選択する画面に遷移するので、適当なインスタンスタイプを選択します。

1年間の無料枠を使っているので無料で使える t2.micro にしました。

キーペアを設定して起動します。

アクセス設定

マネジメントコンソールからインスタンスのセキュリティーグループのインバウンドで HTTP アクセスを適切に許可します。

これでブラウザからインスタンスのIPにアクセスすればページが表示されます。

internal_server_error.png

Internal Server Error(500エラー)ですね。サービス側に問題がありそうなので確認します。

サーバ側設定

起動したインスタンスに SSH ログインします。

とりあえずサービスを再起動してみます。

$ sudo supervisorctl restart all
redash_server: stopped
redash_celery_scheduled: stopped
redash_celery: stopped
redash_celery: started
redash_server: started
redash_celery_scheduled: started

再度ブラウザをリロードしてみますが、Internal Server Error に変化はありません。

supervisord のログを確認します。

$ less /var/log/supervisor/supervisord.log

が、怪しそうなログは出ていません。Redash が使っているサービスの起動状態をひとつひとつ確認します。

PostgreSQL のプロセスを確認します。

$ ps aux | grep -i postgres
ubuntu   21547  0.0  0.0  12948   932 pts/0    S+   13:47   0:00 grep --color=auto -i postgres

見つからないので、PostgreSQL が起動していない事が原因のようです。ログを確認します。

$ less /var/log/postgresql/postgresql-9.5-main.log
2017-10-16 13:32:30 UTC [1352-1] LOG:  database system was shut down at 2017-08-13 12:39:56 UTC
2017-10-16 13:32:30 UTC [1352-2] LOG:  MultiXact member wraparound protections are now enabled
2017-10-16 13:32:30 UTC [1351-1] LOG:  database system is ready to accept connections
2017-10-16 13:32:30 UTC [1356-1] LOG:  autovacuum launcher started
2017-10-16 13:32:31 UTC [1361-1] [unknown]@[unknown] LOG:  incomplete startup packet
2017-10-16 13:34:33 UTC [1351-2] LOG:  received fast shutdown request
2017-10-16 13:34:33 UTC [1351-3] LOG:  aborting any active transactions
2017-10-16 13:34:33 UTC [1705-1] redash@redash FATAL:  terminating connection due to administrator command
2017-10-16 13:34:33 UTC [1704-1] redash@redash FATAL:  terminating connection due to administrator command
2017-10-16 13:34:33 UTC [1356-2] LOG:  autovacuum launcher shutting down
2017-10-16 13:34:34 UTC [1353-1] LOG:  shutting down
2017-10-16 13:34:34 UTC [1353-2] LOG:  database system is shut down
2017-10-16 13:34:53 UTC [19851-1] FATAL:  could not map anonymous shared memory: Cannot allocate memory
2017-10-16 13:34:53 UTC [19851-2] HINT:  This error usually means that PostgreSQL's request for a shared memory segment exceeded available memory, swap space, or huge pages. To reduce the request size (currently 148488192 bytes), reduce PostgreSQL's shared memory usage, perhaps by reducing shared_buffers or max_connections.

FATAL エラーが出てますね。その前にログの時刻が見づらいので、タイムゾーンを日本時間に変更します。

$ sudo timedatectl set-timezone Asia/Tokyo
$ date
Mon Oct 16 22:53:17 JST 2017

JST に変わりました。

先ほどの PostgreSQL のエラーは割り当てられたメモリサイズが大きいというもののようです。

$ sudo vi /etc/postgresql/9.5/main/postgresql.conf

#max_connections = 100
max_connections = 50

#shared_buffers = 128MB
shared_buffers = 32MB

少ないですね。再起動します。

$ sudo /etc/init.d/postgresql restart
Restarting postgresql (via systemctl): postgresql.service.

プロセスを確認します。

$ ps aux | grep -i postgres
postgres 21785  0.0  1.5 186840 15880 ?        S    23:02   0:00 /usr/lib/postgresql/9.5/bin/postgres -D /var/lib/postgresql/9.5/main -c config_file=/etc/postgresql/9.5/main/postgresql.conf
postgres 21787  0.0  0.3 186840  3832 ?        Ss   23:02   0:00 postgres: checkpointer process
postgres 21788  0.0  0.3 186840  3832 ?        Ss   23:02   0:00 postgres: writer process
postgres 21789  0.0  0.3 186840  3832 ?        Ss   23:02   0:00 postgres: wal writer process
postgres 21790  0.0  0.6 187244  6104 ?        Ss   23:02   0:00 postgres: autovacuum launcher process
postgres 21791  0.0  0.3 148544  3128 ?        Ss   23:02   0:00 postgres: stats collector process
ubuntu   21808  0.0  0.1  12948  1092 pts/0    S+   23:02   0:00 grep --color=auto -i postgres

起動した!

ブラウザからアクセスすると。

welcome_redash.png

表示された!

Admin ユーザを登録すればとりあえず使えるようになります。

このままだとメール設定などが出来ていなので、必要であればヘルプ

https://redash.io/help/

などを参考にします。

ちなみに

最初に試した時は、次のような en_US.UTF-8 ロケールが無いというエラーが出ていました。

2017-10-09 08:38:28 UTC [2801-1] redash@redash FATAL:  database locale is incompatible with operating system
2017-10-09 08:38:28 UTC [2801-2] redash@redash DETAIL:  The database was initialized with LC_COLLATE "en_US.UTF-8",  which is not recognized by setlocale().
2017-10-09 08:38:28 UTC [2801-3] redash@redash HINT:  Recreate the database with another locale or install the missing locale.

確認すると確かに無い。

$ locale -a
C
C.UTF-8  # en_US.utf8 がない
POSIX

そのため、次のようにして en_US.UTF-8 をインストールして起動しました。

$ sudo locale-gen en_US.UTF-8
$ locale -a
C
C.UTF-8
en_US.utf8
POSIX

この記事を書くために最初から通して試してみたら en_US.utf8 ローカルが入っていて、再現しませんでした。

Issue を立てたのですが、勘違いだった可能性が高いのでそっと閉じました。

続きを読む

Djangoの既存プロジェクトをec2にデプロイ

概要

詰まりまくったのでメモ。Dockerで開発していたのでそのままデプロイしたろ!と思っていたが意味わからなすぎて断念。(おそらく?)一般的な方法でデプロイした。もっと良い方法があれば教えて欲しい限りです。

環境

OS: Amazon Linux AMI release 2017.09
ローカル: Docker
Python: 3.6.2
Django: 1.11.5
Gunicorn: 19.7.1
Nginx: 1.12.1

AWSの設定

インスタンスの作成

AWSの設定はAmazon Web Services 基礎からのネットワーク&サーバー構築を参考にした。

AWSに登録してコンソール > EC2からインスタンスを作成する。全部デフォルト。t2microなら無料。
VPC、サブネット、ルートテーブル、ゲートウェイ、セキュリティグループやらが作成される(はず)。なかったら作ってVPCに紐付ける。sshキーをダウンロードまたは登録しておく。

ポートの開放

EC2 > セキュリティグループからポートが開放できる。セキュリティグループを選択 -> インバウンド -> 編集 -> ルールの追加で80番ポート、8000番ポート(確認用、あとで閉じる)を開く。タイプはカスタムTCP、ソースは0.0.0.0/0で良い。
ここで EC2 > インスタンス から作ったインスタンスの詳細が確認できる。右側のパブリックDNSでドメイン、IPv4パブリックIPでIPが確認できる。

nginxのインストール

AWSにsshでログイン。キーペアをダウンロードした場合は~/.sshに置いて別のキー名を指定する。

# ssh -i ~/.ssh/id_rsa ec2-user@(インスタンスのIP)

以下ではrootで作業する。

$ sudo su -

以下、EC2にNginx + Gunicorn + SupervisorでDjangoアプリケーションをデプロイするを参考にnginxをインストール。

nginx入れる。

$ yum install nginx

nginxを起動する。

$ nginx

nginxの自動起動設定

$ chkconfig --add nginx
$ chkconfig nginx on

自動起動設定できているか確認する。

$ chkconfig | grep nginx
nginx           0:off   1:off   2:on    3:on    4:on    5:on    6:off

また、http://(パブリックDNS)を確認してnginxが起動しているか確認する。

Djangoプロジェクトの起動

AWSにプロジェクトを送る。

scpでzipで固めたDjangoプロジェクトを送る。また送る前にrequirements.txtは用意しておく。

# pip freeze > requirements.txt
# scp -i ~/.ssh/id_rsa ~/path/to/project.zip ec2-user@yourIP:home/ec2-user/

送ったものがhome/ec2-userに落ちているはず。解凍する

$ unzip project.zip

ほんとはgitで落とせばいいんだろうけどプライベートリポジトリにしてるので新しいuser登録して新しくssh登録してってしないといけないのかな。誰か教えてください。

pythonとかを入れる

色々考えるのがめんどくさかったのでEC2サーバにPython3環境構築を参考にした。

gitとpyenv入れる。-yが全部yesって答えるオプションらしい。初めて知った。

$ yum install git -y
$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv

path通す。

$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile

コマンド通るか確認。

$ pyenv -V

依存関係を入れる。

$ sudo yum install gcc zlib-devel bzip2 bzip2-devel readline readline-devel sqlite sqlite-devel openssl openssl-devel -y

本体を入れる。

$ pyenv install 3.6.2

pythonを切り替える。これはrootのpythonなので、sudo su -後でないとデフォルトのpythonに戻ってしまうので注意。

$ pyenv global 3.6.2
$ pyenv rehash
$ python --version
Python 3.6.2

Django、その他諸々のプロジェクトに必要なライブラリをインストールする。

$ pip install --upgrade -r project/requirements.txt

requirements.txtにGunicornが入ってなければGunicornを入れる。
Gunicornとはwsgiサーバーのことで、nginxとDjangoを繋ぐものみたいなイメージ。

$ pip install gunicorn

manage.pyの上でDjangoを起動させる。

$ gunicorn your_project.wsgi --bind=0.0.0.0:8000

http://(パブリックDNS):8000を確認すると、ALLOWED_HOSTSに追加してね!と出るので追加する。

/your_project/settings.py
# 中略
ALLOWED_HOSTS = ['(パブリックDNS)']
# 以下略

もう一回確認してプロジェクトが見えれば成功。

Nginxの設定の変更

再びEC2にNginx + Gunicorn + SupervisorでDjangoアプリケーションをデプロイするを丸パクリ。本当にありがとうございました
/etc/nginx.confとあるが、Amazon Linuxでは/etc/nginx/nginx.confにあった。
以下引用

/etc/nginx.confを以下の通り編集する

/etc/nginx.conf
〜中略〜

http {
   〜中略〜

   upstream app_server {
       server 127.0.0.1:8000 fail_timeout=0;
    }

   server {
        #以下4行はコメントアウト
        #listen       80 default_server;
        #listen       [::]:80 default_server;
        #server_name  localhost;
        #root         /usr/share/nginx/html;

       # 以下3行を追加
        listen    80;
        server_name     IPアドレス or ドメイン;
        client_max_body_size    4G;

       # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

       location / {
            # 以下4行を追加
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            proxy_pass   http://app_server;
        }

   〜以下略〜

nginxの再起動

$ service nginx restart
Stopping nginx:                                            [  OK  ]
Starting nginx:                                            [  OK  ]

Djangoを再びGunicornで立ち上げる

$ gunicorn your_project.wsgi --bind=0.0.0.0:8000

http://(パブリックDNS)で確認できたら成功。

daemon化

今はコマンドからGunicornを起動しているだけなので、ログアウトしたら終了してしまう。そこでGunicornをデーモン化して常駐するようにしたい。
ただ色々な所を見ると、Surpervisorというツールでそれが可能なようだが、SurpervisorはPython3系に対応していないので2系の環境をもう一つ作れとのこと。んなアホな。
もうちょっと調べてみると、普通に-Dというオプションをつけるだけでデーモンとして起動できるらしい。

起動

$ gunicorn your_project.wsgi --bind=0.0.0.0:8000 -D

終了するときは

$ ps -ef | grep gunicorn
root     17419     1  0 Oct07 ?        00:00:08 /root/.pyenv/versions/3.6.2/bin/python3.6 /root/.pyenv/versions/3.6.2/bin/gunicorn your_project.wsgi --bind=0.0.0.0:8000 -D
root     17422 17419  0 Oct07 ?        00:00:01 /root/.pyenv/versions/3.6.2/bin/python3.6 /root/.pyenv/versions/3.6.2/bin/gunicorn your_project.wsgi --bind=0.0.0.0:8000 -D
root     21686 21594  0 08:05 pts/0    00:00:00 grep --color=auto gunicorn
$ kill 17419

スクリプトで起動

ただこのままだと毎回めんどくさいので、シェルスクリプトでサーバーを起動、停止するにあるスクリプトを使わせてもらう。

Flaskとかで作ったちょっとしたサーバーの起動/停止用のシェルスクリプト。
gunicornでデーモン状態にしている。
startで起動、stopで終了、restartでstop+start。

your_project.sh
#!/bin/sh
PROGNAME=`basename $0`
BASEDIR=`dirname $0`
PIDFILE=$BASEDIR/$PROGNAME.pid

start() {
  echo "Starting server..."
  cd $BASEDIR
  gunicorn flaskhello:app -p $PIDFILE -D
}

stop() {
  echo "Stopping server..."
  kill -TERM `cat $PIDFILE`
  rm -f $PIDFILE
}

usage() {
  echo "usage: $PROGNAME start|stop|restart"
}

if [ $# -lt 1 ];  then
  usage
  exit 255
fi

case $1 in
  start)
    start
    ;;
  stop)
    stop
    ;;
  restart)
    stop
    start
    ;;
esac

以下のgunicorn flaskhello:app -p $PIDFILE -D
gunicorn your_project.wsgi --bind=0.0.0.0:8000 -Dに書き換える。

$ sh your_project.sh start   #起動
$ sh your_project.sh stop    #終了
$ sh your_project.sh restart #再起動

sshを切ってもhttp://(パブリックDNS)が見えたら成功。ひとまず見えるようになった。

staticファイルが見つからない

ただここまで追ってもcss,jsなどstaticファイルは見つかってないはず。以下で見えるようにする。
setting.pyのSTATIC_URL、STATIC_PATHは設定済みでローカルでは見える状態とする。
詳しい解説 -> Django での static files の扱い方まとめ

staticファイルのコピー

manage.pyの上でstaticファイルを指定したディレクトリにコピー

$ python manage.py collectstatic

nginx.confをいじる

nginx.confにstaticファイルのディレクトリを登録する。

/etc/nginx/nginx.conf
server{
    # 〜中略〜
    location /static {
         alias /home/ec2-user/your_project/static;
         #settings.pyで設定したのと同じ場所を記述
    }
    # 〜以下略〜
}

パーミッション変更

ここでnginxとgunicornを再起動する。

$ sh your_project.sh stop
Stopping server...
$ service nginx restart
Stopping nginx:                                            [  OK  ]
Starting nginx:                                            [  OK  ]
$ sh your_project.sh start
Starting server...

するととpermission deniedが出た。これはec2-userにotherからの権限がないせいだった。
参考によると、このディレクトリに移動する権限が必要らしい。
/home/でec2-userに権限を与える。

$ ls -l
drwx------  5 ec2-user ec2-user 4096 Oct  6 04:19 ec2-user
$ chmod o+x ec2-user
$ ls -l
drwx-----x  5 ec2-user ec2-user 4096 Oct  6 04:19 ec2-user

gunicornを再起動すると無事にstaticファイルにアクセスできて終了。

参考

EC2にNginx + Gunicorn + SupervisorでDjangoアプリケーションをデプロイする
EC2サーバにPython3環境構築
シェルスクリプトでサーバーを起動、停止する
Django での static files の扱い方まとめ
Nginxでつくる、どシンプルな静的コンテンツサーバ

続きを読む

AWS Greengrassを利用する際の「センサー制御部」と「新しいLambda関数のデプロイ」について

9/26のJAWS-UG IoT専門支部主催「AWS Greengrass Handson」を受講し終わったばかりの松下です

受講目的

  1. AWS Greengrass Coreからセンサー制御ってどうするの?
  2. Lambda関数の更新時の手順は?

この2点が前から気になっていました。運用するのに必須だからさ。

結論

AWS Greengrass についてわかった事 (たぶん)

AWS Greengrass Core (エッジデバイス上で動くコンテナプロセス、以下ggc) は、AWS IoT に対するMQTT Proxyサーバ的役割と、Lambda実行環境を持っている。

そのため

  • ggcを起動すると 8883 ポートでMQTT接続を待ち受ける
  • オフラインとなったとしても、センサー制御部プログラム側から見ると、AWS IoTに直接接続しているかの如く動作し続けることができる

AWS Greengrass Coreとセンサー制御部の関係

ggcやその上で動くLambdaからOSが持っているローカルリソース、例えば /dev/ttyUSB0 をRead/Writeすることはできない。(と推測される)

  • そのため、「センサーからReadする→AWS Greengrass SDKを使って)ggcにデータを投げる」というプログラムが必要。また、このプログラムが動くようにする環境が必須
  • また、上記プログラムの活動制御はggcは行ってくれないので、systemdのUnitを作る※、そのプログラム自体の更新の仕組みを考える、等が必須
    • ※ggc上のLambdaを更新する際、ggcのMQTT接続が切れる模様。そうなると、センサー制御部のプログラムは再接続の仕組みを持たせるか、supervisor的なところから再起動してもらう必要がある

Lambda関数の更新時の手順

ggc上で動くLambdaのイメージ

ハンズオンでの構成を再現すると

ThingShadowSensor.py
  (publishするように書く)
     ↓
(8883:sensing/data/Sensor-01)
     ↑
  (subscribeするように設定)
Lambda:cpuUsageChecker-01:VERSION
  (publishするように書く)
     ↓
(8883:$aws/things/Alert-01/shadow/#)
     ↑
  (subscribeするように書く)
ThingAlertSensor.py

わかりづらくてゴメン。何が言いたいかというと、Lambda関数だ~とか言わず、結局のところMQTTのトピックを介してパイプ処理をしている。そして、ggc内はスクリプトじゃなくてLambda関数を実行できるよ、という解釈で大丈夫。(たぶん)

そのため、この行先(=サブスクリプション)に、たとえば Lambda:cpuUsageChecker-01:NEW-VERSION が含まれるエントリー(トピックの組み合わせ)を作ってあげれば NEW-VERSION な Lambda関数が起動する。

手順は以下の通り;

  1. AWS Lambda関数を更新、発行する (新しいバージョンができる)
  2. クラウド側AWS Greengrassの「Lambda」メニューで、新しいバージョンのLambda関数を「追加」する (複数のバージョンが存在することになる)
  3. クラウド側AWS Greengrassの「サブスクリプション」メニューで、新しいバージョンのLambda関数を「ソース」や「ターゲット」とするエントリーを作成し、古いバージョンのLambda関数を利用しているエントリーを消す
    • 消さなくても良い。その代わり、トピックを調整する必要がある
  4. クラウド側AWS Greengrassの「グループ」メニューから、デプロイする

まだわからないこと

  • ggcに対してすっぴんのMQTTクライアント接続が可能なのか? (AWS Greengrass SDKはデカすぎる。センサー制御プログラムは極力小さくしたいはずだ!)

あとがき

市川さんはじめ、全国のJAWS-UG IoT 専門支部の方々、お疲れ様でしたー!!!

続きを読む

Predicting Red Hat Business Value

I. Definition

Project Overview

The history of Open Source project is not so new, however, the faster new technologies are developing and the world is getting globalized, the more people engage in open source projects and the communities are growing. Thanks to the Internet, you are not necessary to be near around the communities to work with them. New innovative ideas are stimulated by people’s interaction across the world and developed as open source projects, e.g. OpenStack, Hadoop and TensorFlow.
But on the other hand, adapting open source products to business operation is not so easy. The development of open source products is very agile and engineers all over the world are always updating the source code. Because of the agility, open source products are always kind of beta version and have some bugs. As a result, there are many companies which offer professional services such as implementation, consulting and maintenance to help businesses utilize open source products.

Today, there are many companies packaging open source products as their service, e.g. Tera Data, HortonWorks, Mirantis and Red Hat. However, they are struggling to scale their business [1]. Even Red Hat, which has been one of the most successful Open Source Platform Business companies since they released their own Linux distribution called “Red Hat Linux” in 1994, the amount of earning is small comparing to other tech giants. For example, Amazon, which started a new cloud service “AWS” a decade ago, earned 12 billion dollars revenue only from AWS in 2016 [2], on the other hand, Red Hat earns just 2 billion dollars revenue from their total business in 2016 [3]. (But the amount is still much bigger than other open source business model based companies).

Problem Statement

Therefore, in order to find ways to maximize their business opportunities, a prediction model is to be created to “accurately identify which customers have the most potential business value for Red Hat” based on their characteristics and activities.”

In the data sets of this project, there are feature characteristics and a corresponding target variable “outcome” which is defined as yes/no binary flag. (It means, a customer’s activity has business value if the outcome of his/her activity is “yes”). Thus, it is necessary to create a binary prediction model which predicts what activities result in positive business outcome or not. As most of the features are categorical data, however, the data should be encoded into numerical values at first. Then, as supervisor data which has several features corresponding with the target “outcome” variable, the data set is passed to binary classification algorithm such as Decision Tree, Logistic Regression and Random Forest. Now, we have no idea which one should be used for this problem, as a result, these algorithms are going to be compared and the most appropriate one is chosen as a base model for the prediction model. When comparing the algorithms, the same metrics would be used to appropriately evaluate their result. After that, by using grid search method, the parameters for the algorithm will be optimized. Then, the prediction model is evaluated again and finally the optimized model is presented.

Metrics

To measure and evaluate the performance of the prediction results, Area under ROC Curve [4] is going to be used as this is a binary classification problem. In ROC curve, true positive rates are plotted against false positive rates. The closer AUC of a model is getting to 1, the better the model is. It means, a model with higher AUC is preferred over those with lower AUC.

II. Analysis

Data Exploration

Data set used in this project contains following data (You can find the data set at Kaggle project page [5]:

  • people.csv: This file contains people list. Each person in the list is unique identified by people_id and has his/her own corresponding characteristics.
  • act_train.csv: This activity file contains unique activities which are identified activity_id. Each activity is corresponding to its own activity characteristics. In the activity file, business value outcome is defined as yes/no for each activity.

Here, there are 8 types of activities. Type 1 activities are different from type 2-7 activities. Type 1 activities are associated with 9 characteristics, on the other hand, type 2-7 activities have only one associated characteristic. And also, in both csv files, except for “date” and “char_38” columns, all data type is categorical so it should be encoded before being processed by binary classification algorithms. Also, as the data sets are separated into 2 csv files, these files should be combined into a merged data set. After the merge, the shape of the training data set is (2197291, 55); 54 predictor features plus 1 target variable.  
Exploratory Visualization
The following chart shows how many activities are performed in each month. According to the chart, “2022/10” has the maximum over 350,000 activities, on the other hand, “2022/07” has the minimum around 50,000 activities. Even though there are some difference in the number of activities among months, it shows no sign of upward trend.

image

Fig. 1 Number of activities per month

The following chart shows how many people joined the community in each month. Even though there are some difference in the number of people join among months, it shows no sign of upward trend. However, as it shows the number of new people join at each month, it means, the number of community member is increasing month by month. According to the data set, the number of people in the data set is 189118 and the average number of people join per month is around 9000. Therefore, this community has more than 50% YoY growth in the number of community member. (It is amazing given the fact most of open source communities are struggling to gather people, however, it is also reasonable to think the similar number of people leave the community as well. But the data set includes no data to investigate it.)

image

Fig. 2 Number of people join per month

The following chart is a very simple overview of the outcome of activities. It shows how many activities result in positive business value (“outcome” = 1) or not. As a result, 44% of activities has positive business impact.

image

Fig. 3 Number of activities per outcome

The following chart is the histogram of community members based on the average outcome of their activities. Maximum is 1, minimum is 0 and the interval is 0.1. What is interesting here is the distribution is completely divided into 2 groups. Some people contribute to the community no matter what activities they do, but on the other hand, some people hardly contribute to the community. Therefore, finding people who has business value for the community is very critical for the prosperity of the community.

image

Fig. 4 Distribution of average outcome by people

In sum, there are 2 things I would like to mention here regarding to the charts. First, this community is a very active community in which constantly new members take part and many activities are performed, moreover, the numbers are really big. So it is reasonable to assume the samples in the dataset are not biased and represent the distribution of Red Hat’s community. Second, the above chart shows whether Red Hat community gains business value or not depends on who performs an activity. Therefore, the issue of this project stated in “Problem Statement” section is an appropriate target to be solved and creating a prediction model is a relevant approach.

Algorithms and Techniques

In order to predict which customers are more valuable for Red Hat business, a binary classification model should be created based on supervised algorithms such as decision tree, logistic regression and random forest tree by using training dataset which includes feature characteristics and a corresponding target variable “outcome” which is defined as yes/no binary flag.

In this project, 3 classification algorithms, Decision Tree [6], Logistic Regression [7] and Random Forest [8] are going to be compared at first. Each of them has its pros and cons, however, all of them can learn much faster than other supervise classification algorithms such as Support Vector Classifier [9]. The dataset of this project has more than 2 million samples with 50+ features, furthermore, 3 algorithms will be compared and grid search method will be used as well in the later phase of this project to optimize parameter. Therefore, choosing CPU and time efficient algorithms is reasonable choice.

These 3 algorithms are widely used for binary classification problem. Logistic Regression gives you a single linear decision boundary which divide your data samples. The pros of this algorithms are low variance and provides probabilities for outcomes, but as the con, it tends to be highly biased. On the other hand, Decision Tree gives you a non-linear decision boundary which divides the feature space into axis-parallel rectangles. This algorithm is good at handling categorical features and also visually intuitive how decision boundary divides your data but likely overfitting. Random Forest is actually an ensemble of decision trees which intends to reduce overfitting. It calculates a large number of decision trees from subsets of the data and combine the trees through a voting process. As a result, Random Forest is less overfitting models but makes it difficult to visually interpret.

Benchmark

This paper is based on the Kaggle project [5] and they set 50% prediction as benchmark. So in this paper, the benchmark is used as well.

III. Methodology

Implementation

The following flow chart shows the overview of the implementation process for creating a binary classification model. In case for reproducing this project, follow the below workflow and refer the code snippets which are cited on this paper.

image

Fig. 5 Overview of implementation flow

Data Preprocessing

As the data sets prepared for this project are separated into 2 csv files, these files should be combined into a merged data set. The action csv file contains all unique activities and each unique activity has a corresponding people ID which shows who performed the activity. Thus, the relation between activity and people ID is one-to-many so that left join method is used for merging datasets on people ID by setting action csv as the left table. The below code is showing very brief overview of this merge implementation.

image

Fig. 6 Code Snippet: Merge people data to activity data

Then, since the most of columns in the dataset is categorical data as described in Data Exploration section, these categorical data should be encoded using label encoding algorithm [10]. Note that the samples in Fig. 7 contains just a few of columns in the dataset. As the dataset actually contains more than 50 features, most of columns are omitted intentionally.

image

Fig. 7 Code Snippet: Encode dataset

image

Fig. 8 Encoded date set samples

Finally, the dataset will be splitted into training and test sets in random order. In this project, 80% of the data will be used for training and 20% for testing.

image

Fig. 9 Code Snippet: Split dataset

Model Selection

In the model selection phase, all parameters of the algorithms compared are set as default. In addition, in order to reduce the time to train algorithms, the training sample size is set to 100,000 samples.

For fitting algorithms and evaluating their predictions, the code below are implemented. Note that, where “classification_algorithm” represents supervised algorithm modules. Also, (features_train, outcome_train, features_test, outcome_test) are corresponding to the variables in Fig. 8 Code Snippet: Splitting dataset.

image

Fig. 10 Code Snippet: Fit and evaluate algorithm

IV. Results

Model Evaluation and Validation

For evaluation, Area under the ROC Curve [11] is used. AUC [4] is the size of area under the plotted curve. The closer AUC of a prediction model is getting to 1, the better the model is. Fig. 10 shows the code snippet for plotting ROC curve based on the prediction results by supervised algorithms. Note that, here “predictions_test” contains prediction results and “outcome_test” is the target score.

image

Fig. 11 Code Snippet: Plot ROC Curve

image

Fig. 12 ROC Curve and AUC of each algorithm 

Refinement

Based on the result of the model selection phase, the most desirable prediction algorithm for this binary classification model is Random Forest, whose AUC value is 0.93.

Next, using grid search method [12], the binary classification model is going to be optimized further. In order to reduce the time for Grid Search, the training sample size is set to 100,000 samples. As optimized parameters, “n_estimator” and “min_sample_leaf” are chosen.

n_estimator: Grid Search parameter set 12, 24, 36, 48, 60
“n_esimator” is the number of trees to calculate. The higher number of trees, the better performance you get, but it makes the model learn slower.

min_samples_leaf: Grid Search parameter set 1, 2, 4, 8, 16
“min_samples_leaf” is the minimum number of samples required to be at a leaf node. The more leaf at a node, the less the algorithm catches noises.

image

Fig. 13 Code Snippet: Grid Search Optimization

image

Fig. 14 Heat Map: Grid Search AUC Score

As a result of Grid Search, the best parameter for the model with the dataset is (“n_estimator”: 60, “min_samples_leaf”: 1). As you can see in Fig. 13 Heat Map, the more “n_estimator” gets bigger, the more the predictions are improved. On the other hand, the increase of “min_samples_leaf” are not effective, or rather, it decreases the prediction performance.

Justification

Finally, there is the optimized parameter set. Therefore, by training the model with the parameter sets and with the all 1,757,832 sample data, the best prediction result should be returned. As a result, the optimized model returned 0.993 AUC score and it is significantly greater than the benchmark (0.5).
In addition, to investigate if the model is robust and generalized enough (it means not overfitting), a new set of prediction results using the classification model was submitted to Kaggle competition (as this paper is based on Kaggle Project). For the submission, another dataset “act_test.csv” provided by Kaggle for the competition is used. Note that “act_test.csv” contains different data from “act_train.csv” which is used for model fitting. As a result, Kaggle evaluated the prediction made by the classification model and returned 0.863 AUC score. Therefore, the binary classification model is generalized enough to make good predictions based on unseen data.

V. Conclusion

Summary

The purpose of this project has been to build a binary classification prediction model for “identify which customers have the most potential business value for Red Hat”. Through the comparison of supervised classification algorithms and the optimization using Grid Search, finally, the best classification models, which is based on Random Forest Classifier, was built and scored 0.993 AUC score which is much higher than the benchmark score 0.5. In sum, using the prediction model, Red Hat can accurately predict which activities performed by its community members likely result in its positive business value. The prediction must be useful for planning its business strategies to maximize their return on investment.
In addition, as the code snippets for implementation is clearly stated throughout this paper, not just for reproducing the model for this specific issue but also it can be applied to similar binary classification issue with some code modification.

VI. Reference

[1] “https://techcrunch.com/2014/02/13/please-dont-tell-me-you-want-to-be-the-next-red-hat/”

[2] “http://phx.corporate-ir.net/phoenix.zhtml?c=97664&p=irol-reportsannual”
[3] “https://investors.redhat.com/news-and-events/press-releases/2016/03-22-2016-201734069”
[4] “http://scikit-learn.org/stable/modules/generated/sklearn.metrics.roc_auc_score.html”
[5] “https://www.kaggle.com/c/predicting-red-hat-business-value/data”
[6] “http://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html”
[7] “http://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LogisticRegression.html”
[8] “http://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestRegressor.html”
[9] “http://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html”
[10] “http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.LabelEncoder.html”

[11] “http://scikit-learn.org/stable/auto_examples/model_selection/plot_roc.html”
[12] “http://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html”

続きを読む

EC2にNginx + Gunicorn + SupervisorでDjangoアプリケーションをデプロイする

Nginx + Gunicorn + Supervisorの組み合わせでDjangoアプリケーションを立ち上げたので手順のメモ
今回はOSに何も入っていない状態から始めていきます

環境

OS: Amazon Linux AMI
Python: 3.6.1
Django: 1.11.4
Nginx: 1.10.3
Gunicorn: 19.7.1
Supervisor: 3.3.3

Nginxのインストール

nginxのインストール

$ sudo yum install nginx

nginx起動する

$ sudo nginx

nginx自動起動設定

$ sudo chkconfig --add nginx
$ sudo chkconfig nginx o

自動起動設定確認
以下のようになっていればok

$ chkconfig | grep nginx
nginx           0:off   1:off   2:on    3:on    4:on    5:on    6:off

http://ipアドレスにアクセスしちゃんと起動しているか確認する
以下の通りになっていればOK
スクリーンショット 2017-08-03 13.40.56.png

Python環境の構築

今回はAnacondaで構築した
こちらからPython 3.6 versionをダウンロードする
ダウンロードしたパッケージをCyberduckなどのFTPツールで/home/ec2-userにアップロードする

アップロード完了したら下記コマンドでAnacondaインストールする

$ bash Anaconda3-4.4.0-Linux-x86_64.sh

インストール完了後、Anacondaのコマンドが使えるようにPATHを通す

$ export PATH="$PATH:/home/ec2-user/anaconda3/bin"

condaのコマンドを打って確認

$ conda info -e
# conda environments:
#
root                  *  /home/ec2-user/anaconda3

良さげです

pythonも3.6になっている

$ python --version
Python 3.6.1 :: Anaconda 4.4.0 (64-bit)

Djangoプロジェクトの作成

今回は直接EC2上でプロジェクトを作成します
本来はローカルで開発したDjangoアプリケーションをgit cloneすべき
また、DBもデフォルトのSQliteを使用しますが、実際のサービスを公開するにはPostgresqlやMariaDBを使う

まずはDjangoのインストール
root環境で動かすかどうかは少し議論の分かれるところで、別に環境を作ってDjangoを動かした方がいいんじゃないか、と思ったりもしますが、とりあえず今回はroot環境でインストールしてしまいます

$ pip install django

問題なければプロジェクトを作成

$ django-admin startproject test_project

プロジェクトが作られていることを確認

$ ls -ltr
total 511032
-rw-rw-r--  1 ec2-user ec2-user 523283080 Aug  3 04:50 Anaconda3-4.4.0-Linux-x86_64.sh
drwxrwxr-x 20 ec2-user ec2-user      4096 Aug  3 04:53 anaconda3
drwxrwxr-x  3 ec2-user ec2-user      4096 Aug  3 05:05 test_project

/test_project/test_project/settings.pyのALLOW HOSTを下記の通り編集しておく

settings.py
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = ["サーバのIPアドレス"]

下記のコマンドでDjangoを起動
デフォルトだと127.0.0.1:8000がbindアドレスとして使用されているため、オプションで0.0.0.0:8000を追加する必要があります
また、事前にAWSのセキュリティグループで8000番ポートを解放しておく必要があります

$ cd test_project
$ python manage.py runserver 0.0.0.0:8000

そして、http://IPアドレス:8000にアクセスすると以下の通りDjangoアプリケーションにアクセスできる
スクリーンショット 2017-08-03 15.23.25.png

Gunicornのインストール

GunicornはPython製のWSGIサーバ
WSGIサーバというのはWebサーバとWebアプリケーションをつなぐサーバのこと
なので、Nginx <-> Gunicorn <-> Djangoというような構成をイメージしていただければと

まずはGunicornのインストールをやっていく

$ pip install gunicorn

インストールされたらGunicornでDjangoを起動させる

$ gunicorn test_project.wsgi --bind=0.0.0.0:8000

先程と同様、http://IPアドレス:8000にアクセスするとDjangoアプリケーションに接続できる

Nginxの設定の変更

/etc/nginx.confを以下の通り編集する

/etc/nginx.conf

〜中略〜

http {
    〜中略〜

    upstream app_server {
        server 127.0.0.1:8000 fail_timeout=0;
    }

    server {
        #以下4行はコメントアウト
        #listen       80 default_server;
        #listen       [::]:80 default_server;
        #server_name  localhost;
        #root         /usr/share/nginx/html;

        # 以下3行を追加
        listen    80;
        server_name     IPアドレス or ドメイン;
        client_max_body_size    4G;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
            # 以下4行を追加
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            proxy_pass   http://app_server;
        }

    〜以下略〜

編集したら下記コマンドでnginxを再起動する

$ sudo service nginx restart
Stopping nginx:                                            [  OK  ]
Starting nginx:                                            [  OK  ]

これでNginxでのリバースプロキシの設定は完了
今回はnginx.confを直接編集したけれど、設定ファイルをどこか別のところに書いてそれを読み込ませる、という方法でもOK

その後、DjangoをGunicornで立ち上げる

$ gunicorn test_project.wsgi --bind=0.0.0.0:8000

次はhttp://IPアドレスにアクセスするとDjangoの画面が表示されるはず

Supervisorでプロセスをデーモン化する

今の状態だとGunicornのコマンドを中止したり、サーバからログアウトするとアプリケーションが停止してしまう
これを解消するためにSupervisorでGunicornのプロセスをデーモン化する

早速、Supervisorをインストール、としたいところだけれど、SupervisorはPython2系でしか動作しない
そのためAnacondaでPython2系の仮想環境を構築し、その環境にSupervisorをインストールしていく

まずは下記コマンドでSupervisor用のPython2系の仮想環境を作る

$ conda create -n supervisor python=2.7

python2系の環境に切り替えてpipでsupervisorをインストール

$ source activate supervisor
$ pip install supervisor

問題なくインストールできたら、supervisorの設定ファイルを作成し、それを/etc配下に配置する

$ echo_supervisord_conf > supervisord.conf
$ sudo mv supervisord.conf /etc

次にsupervisorの設定を行うため、supervisord.confを下記の通り編集

supervisord.conf
〜中略〜
[supervisord]
logfile=/var/log/supervisord.log ; ログの場所を変更
;logfile=/tmp/supervisord.log ; main log file; default $CWD/supervisord.log #コメントアウト
logfile_maxbytes=50MB        ; max main logfile bytes b4 rotation; default 50MB
logfile_backups=10           ; # of main logfile backups; 0 means none, default 10
loglevel=info                ; log level; default info; others: debug,warn,trace
pidfile=/var/run/supervisord.pid ; 追記
;pidfile=/tmp/supervisord.pid ; supervisord pidfile; default supervisord.pid #コメントアウト

〜中略〜
# includeはコメントアウトされているのでコメント外す
[include]
files = supervisord.d/*.conf ; 起動するプロセスのconfファイルの配置場所
;files = relative/directory/*.ini

ログファイルは作っておき、パーミッションも設定しておく

$ sudo touch /var/log/supervisord.log
$ sudo chown ec2-user /var/log/supervisord.log
$ sudo chgrp ec2-user /var/log/supervisord.log
$ sudo chmod 774 /var/log/supervisord.log

あと、ログローテションも設定しておく

$ sudo sh -c "echo '/var/log/supervisord.log {
       missingok
       weekly
       notifempty
       nocompress
}' > /etc/logrotate.d/supervisor"

次にデーモン化するプロセスのコマンドを記載したファイルを作っていく
まずはそれらのファイルを配置するディレクトリを作成

$ sudo mkdir /etc/supervisord.d

/etc/supervisord.d配下にdjango_app.confを作成
ここに、Gunicornのプロセスをデーモン化するための設定を以下のように書く

django_app.conf
[program:django_app]
directory=/home/ec2-user/test_project
command=gunicorn test_project.wsgi --bind=0.0.0.0:8000
numprocs=1
autostart=true
autorestart=true
user=ec2-user
redirect_stderr=true

directoryに実行するディレクトリを指定、commandのところにプロセスを起動するためのコマンドを指定する

ここまでできたら下記のコマンドでsupervisorを立ち上げる

$ supervisord

次に、confファイルを読み込ませる
こちらは仮にconfを修正などする場合は必ず実行する

$ supervisorctl reread

なお、下記のコマンドでデーモンを再起動し、そのタイミングでもconfが読み込まれたりする

$ supervisorctl reload

下記のコマンドでGunicornのプロセスをデーモン化する

$ supervisorctl start django_app

仮にdjango_app: ERROR (already started)というメッセージが出た場合は、以下のコマンドでプロセスの再起動をしたり、停止をしてからstartしたりする

$ supervisorctl stop django_app # 停止
$ supervisorctl restart django_app # 再起動

さて、この状態でサーバからログアウトしてみる
そして、http://IPアドレスにアクセスすると、Djangoの画面が表示される
GunicornのプロセスがSupervisorによりデーモン化されていることになる

よかったですね

続きを読む

EC2(AMI)にnginx + uWSGI + supervisorでDjangoアプリケーションをデプロイする

これがベストプラクティスかどうなのかわかりませんが、おれはこうやりました、って話
もし、これでうまくいかなかったらコメントください

環境

  • Python:3.6.0(anacondaで構築)
  • Django:1.10.2
  • nginx:1.11.10
  • Amazon Linux AMI

今回はAMIでやりましたが、多分CentOSでも大丈夫なはず

大雑把な流れ

1.uWSGIのインストール & uWSGIでDjangoアプリケーションを立ち上げる
2.nginx + uWSGIでアプリケーションを立ち上げる
3.supervisorでプロセスをdaemon化する

uWSGIのインストール & uWSGIでDjangoアプリケーションを立ち上げる

まずはuWSGIをpipでインストール

$ pip install uwsgi

もしもインストールがうまくいなかったりしたらuwsgiをEC2インスタンスにインストールしようとして失敗した話 – Qiitaを参考にしてみましょう

uWSGIからDjangoアプリケーションを立ち上げる

インストールができたら、下記コマンドでuWSGIからDjangoアプリケーションを立ち上げてみる
(実行するディレクトリはDjangoプロジェクトのルートディレクトリで)

$ uwsgi --http :8000 --module プロジェクト名.wsgi

この状態でhttp://[EC2のパブリックIP]:8000にブラウザからアクセスすれば、アプリケーションに接続できるはず

nginx + uWSGIでアプリケーションを立ち上げる

nginxのuwsgiモジュール用の設定を行う

Djangoプロジェクト直下にuwsgi_paramsというファイルを作成する
ファイルの中身は下記の通り

uwsgi_param  QUERY_STRING       $query_string;
uwsgi_param  REQUEST_METHOD     $request_method;
uwsgi_param  CONTENT_TYPE       $content_type;
uwsgi_param  CONTENT_LENGTH     $content_length;

uwsgi_param  REQUEST_URI        $request_uri;
uwsgi_param  PATH_INFO          $document_uri;
uwsgi_param  DOCUMENT_ROOT      $document_root;
uwsgi_param  SERVER_PROTOCOL    $server_protocol;
uwsgi_param  REQUEST_SCHEME     $scheme;
uwsgi_param  HTTPS              $https if_not_empty;

uwsgi_param  REMOTE_ADDR        $remote_addr;
uwsgi_param  REMOTE_PORT        $remote_port;
uwsgi_param  SERVER_PORT        $server_port;
uwsgi_param  SERVER_NAME        $server_name;

nginx用のconfファイルを作成

Djangoプロジェクト直下にnginx用のconfファイルを作成
今回はmyweb_nginx.confという名前にしています

django_project/myweb_nginx.conf
upstream django {
    server 127.0.0.1:8000;
}

server { 
    listen      80;
    server_name EC2のパブリックIP or ドメイン;
    charset     utf-8;
    client_max_body_size 100M;

    location /static {
        alias /django_projectのディレクトリ(フルパス)/static;
    }

    location / {
        uwsgi_pass  django;
        include    /django_projectのディレクトリ(フルパス)/uwsgi_params;
    }

}

myweb_nginx.confを/etc/nginx/nginx.confに読み込ませる

$ sudo vi /etc/nginx/nginx.confhttp {}内を編集
include /etc/nginx/sites-enabled/*;を追加する

/etc/nginx/nginx.conf
http {
    ...中略...
    include /etc/nginx/sites-enabled/*; #ここを追加

    server {
    ...中略...

sites-enabledにシンボリックリンクを貼る

$ mkidr /etc/nginx/sites-enabledでsites-enabledを作成
さらに下記コマンドでmyweb_nginx.confを/etc/nginx/sites-enabled/にシンボリックを貼る

$ sudo ln -s /django_projectのディレクトリ(フルパス)/myweb_nginx.conf /etc/nginx/sites-enabled/

nginxを再起動し、Djangoアプリケーションを立ち上げる

$sudo /etc/init.d/nginx restartでnginxを再起動
下記のコマンドをDjangoプロジェクト直下で実行する

$ uwsgi --socket :8000 --module プロジェクト名.wsgi

この状態でhttp://[EC2のパブリックIP]にブラウザからアクセスすれば、アプリケーションに接続できるはず

補足:静的ファイルの読み込み

上記の状態でアプリケーションに接続した場合、staticディレクトリに配置しているcssなどが適用されていないはず
settings.pyにSTATC_ROOTを指定する必要がある

settings.py
STATIC_ROOT = os.path.join(BASE_DIR, "static/")

下記コマンドでstaticファイルをSATIC_ROOTで指定したディレクトリにまとめる

$ python manage.py collectstatic

supervisorでプロセスをdaemon化する

python2系への切り替え

supervisorはpython3系では動いてくれないので、anacondaでpython2.7の仮想環境を構築していく

$ conda create -n supervisor python=2.7 anaconda

仮想環境への切り替えは

$ source activate supervisor

でおこない、抜ける場合は

$ source deactivate

でおこなう

supervisorのインストール

python2系の状態でsupervisorをインストールする

$pip install supervisor

supervisord.confの生成

ホームディレクトリで$echo_supervisord_conf > supervisord.confを実行
さらに$ sudo mv supervisord.conf /etcを実行し、supervisord.confを/etcに配置する

supervisord.dディレクトリの作成

/etc配下にsupervisord.dを作成する

$ sudo mkdir /etc/supervisord.d

supervisorログの設定

/var/logにログを吐かせるため、supervisord.confを編集
/etc/supervisord.conf
[supervisord]
;logfile=/tmp/supervisord.log
logfile=/var/log/supervisor/supervisord.log

ディレクトリの作成とlogファイルの作成

$ sudo mkdir /var/log/supervisor
$ sudo vi /var/log/supervisor/supervisord.log

また、下記のコマンドでログローテションを設定する

$ sudo sh -c "echo '/var/log/supervisor/*.log {
       missingok
       weekly
       notifempty
       nocompress
}' > /etc/logrotate.d/supervisor"

pid,includeの設定

supervisord.confを編集する

/etc/supervisord.conf
[supervisord]
...中略...
# pidファイルの配置場所の指定
;pidfile=/tmp/supervisord.pid
pidfile=/var/run/supervisord.pid

# ...中略

# includeセクションがコメントアウトされているので、コメントインして下記の用に修正。
[include]
files = supervisord.d/*.conf

supervisord.d/*.confの作成

supervisord.d配下のconfファイルにデーモン化するプロセスを指定する
今回はuWSGI + nginxでのDjangoアプリケーションの立ち上げをデーモン化する

/etc/supervisord.d/django.conf
[program:django_app] ;
directory=/djangoアプリケーションのディレクトリ(フルパス)/;
command=/home/ec2-user/anaconda3/bin/uwsgi --socket :8000 --module プロジェクト名.wsgi ;
numprocs=1 ;
autostart=true ;
autorestart=true  ;
user=ec2-user  ;
redirect_stderr=true  ;

supervisorの再起動->サービス立ち上げ

$ supervisordでsupervisorのサービスを起動
$ supervisord rereadで設定ファイルの再読み込み
$ supervisord reloadでsupervisorの再起動
$ supervisord start django_appでDjangoアプリケーションの立ち上げるプロセスがデーモン化される

この状態でhttp://[EC2のパブリックIP]にブラウザからアクセスすれば、アプリケーションに接続でき、且つサーバからログアウトした状態でもプロセスが死なない

参考リンク

Supervisorで簡単にデーモン化 – Qiita
EC2上で Django + Nginx + uWSGI を試す – Qiita

続きを読む

redashでAWS Athena使おうとしたら、DataSourceに出てこなくてはまったので解決策

redashでAWS Athena使おうとしたら、はまったので解決策

使うぞって思ってたら、
Data SourceのType欄に出てこなかったので
解決策を記載しておきます:smiley:

※すべて2017/5/18現在の事象です

場面

今回は以下の場面です

  • AWSのEC2のAMIを利用
  • ソースをダウンロードしてインストール

Hostedでは、問題なく選択できました

redashのインストール

redashのインストール方法を記載しておきます

パターン1. AWS EC2でredashのAMIを利用する

  • EC2インスタンス作成時に、redashで提供されているAMIを選択する

Setting up a Redash Instance

※現時点(2017/5/18)では、1.0.1+b2833 がインストールされます

パターン2. ソースを持ってきてインストールする

  • EC2インスタンス作成時に、OSは、ubuntuを選択
  • 以下を実行

ソースゲット

cd /usr/local/src/

wget https://raw.githubusercontent.com/getredash/redash/master/setup/ubuntu/bootstrap.sh

スクリプト実行

sh bootstrap.sh

アップグレード

cd /opt/redash/current
sudo bin/upgrade

確認

ls -l /opt/redash/

※現時点(2017/5/18)では、1.0.3.b2850 にアップグレードされます

本題のAWS Athenaへの接続

現象

上記2つの方法で設定すると以下の画像のように
AWS Athenaが出てきません:cry:


redash01.png


調査

/opt/redash/redash.1.0.3.b2850/redash/query_runner/athena.py

ファイルあるしなぁと調査したり

解決策

公式のサーポートに書いてました:joy:

Support for AWS Athena

方法

/opt/redash/.env

に以下を追加

export REDASH_ADDITIONAL_QUERY_RUNNERS="redash.query_runner.athena"

再起動して、反映

/etc/init.d/supervisor reload

するとredash02.png

出てきました!:tiger::tiger::tiger:

あとは、
AWS AthenaへのKey等を設定してください~

※注意※

redashのバージョンが、0.12以下の場合はエラーになるので注意!

続きを読む

EMR の各Hadoopプロセスの起動停止方法

Upstart使ってます

EMRでの各Hadoopプロセスの起動スクリプトはUpstart形式のようで /etc/init/ 配下に配置されてます。

[root@ip-172-31-30-132 init]# ll /etc/init/
total 156
-rw-r--r-- 1 root root  412 Apr  9  2015 control-alt-delete.conf
-rw-r--r-- 1 root root  330 Dec 19 23:22 elastic-network-interfaces.conf
-rw-r--r-- 1 root root 1677 Apr  1 04:35 ganglia-rrdcached.conf
-rw-r--r-- 1 root root 1049 Apr  1 04:35 gmetad.conf
-rw-r--r-- 1 root root  979 Apr  1 04:35 gmond.conf
-rwxr-xr-x 1 root root 2928 Feb 17 18:10 hadoop-hdfs-namenode.conf
-rwxr-xr-x 1 root root 3331 Feb 17 18:10 hadoop-httpfs.conf
-rwxr-xr-x 1 root root 2856 Feb 17 18:10 hadoop-kms.conf
-rwxr-xr-x 1 root root 2989 Feb 17 18:10 hadoop-mapreduce-historyserver.conf
-rwxr-xr-x 1 root root 2944 Feb 17 18:10 hadoop-yarn-proxyserver.conf
-rwxr-xr-x 1 root root 2964 Feb 17 18:10 hadoop-yarn-resourcemanager.conf
-rwxr-xr-x 1 root root 2959 Feb 17 18:10 hadoop-yarn-timelineserver.conf
-rwxr-xr-x 1 root root 3314 Feb 17 18:17 hbase-master.conf
-rwxr-xr-x 1 root root 3302 Feb 17 18:17 hbase-rest.conf
-rwxr-xr-x 1 root root 3314 Feb 17 18:17 hbase-thrift.conf
-rwxr-xr-x 1 root root 2920 Feb 17 18:30 hive-hcatalog-server.conf
-rwxr-xr-x 1 root root 3114 Feb 17 18:30 hive-server2.conf
-rwxr-xr-x 1 root root 2922 Feb 17 18:30 hive-webhcat-server.conf
-rwxr-xr-x 1 root root 4054 Feb 17 18:59 hue.conf
[root@ip-172-31-30-132 init]# initctl list
rc stop/waiting
tty (/dev/tty3) start/running, process 2855
tty (/dev/tty2) start/running, process 2853
tty (/dev/tty1) start/running, process 2851
tty (/dev/tty6) start/running, process 2862
tty (/dev/tty5) start/running, process 2860
tty (/dev/tty4) start/running, process 2858
hbase-thrift start/running, process 12362
gmetad start/running, process 6955
update-motd stop/waiting
hadoop-mapreduce-historyserver start/running, process 5611
hadoop-yarn-timelineserver start/running, process 4929
hive-server2 start/running, process 15435
plymouth-shutdown stop/waiting
presto-server start/running, process 15790
control-alt-delete stop/waiting
hive-hcatalog-server start/running, process 16669
hive-webhcat-server start/running, process 8223
rcS-emergency stop/waiting
zookeeper-server start/running, process 8375

なので停止起動などは Upstart のお作法に沿ってあげましょう

[root@ip-172-31-30-132 init]# initctl status hue
hue start/running, process 17451
[root@ip-172-31-30-132 init]# initctl stop hue
hue stop/waiting
[root@ip-172-31-30-132 init]# ps -ef | grep hue
root     32388 13209  0 01:24 pts/0    00:00:00 grep --color=auto hue
[root@ip-172-31-30-132 init]# initctl status hue
hue stop/waiting
[root@ip-172-31-30-132 init]# initctl start hue
hue start/running, process 32488
[root@ip-172-31-30-132 init]# initctl status hue
hue start/running, process 32488
[root@ip-172-31-30-132 init]# ps -ef | grep hue
root     32489     1  2 01:24 ?        00:00:00 python2.7 /usr/lib/hue/build/env/bin/supervisor -p /var/run/hue/supervisor.pid -l /var/log/hue -d
hue      32494 32489 56 01:24 ?        00:00:03 python2.7 /usr/lib/hue/build/env/bin/hue runcherrypyserver
root     32582 13209  0 01:24 pts/0    00:00:00 grep --color=auto hue

今回は Hue.ini とか修正

Hue 3.11 でS3ブラウジングができなくなってたので、ひとまずアクセスキー・シークレットアクセスキーをコンフィグに書いて動作確認しました。
/etc/hue/conf/hue.ini を修正し、プロセス再起動。

無事閲覧できましたー

スクリーンショット 0029-04-02 10.58.03.png

続きを読む

Amazon Elastic BeanstalkでサクッとElixir製サーバーをAWSにデプロイする

はじめに

Amazon Elastic Beanstalk では、 Dockerを使ってよしなにアプリケーションをAWSにデプロイできる。
Docker ImageがS3に上がり、サーバーはEC2にデプロイされる。
これを使ってElixir製のping叩いたらpong返してくるだけのアプリをデプロイしてみる。

mix で新規プロジェクトを作成

今回はelixir:1.4.1を用いる。

$ mix new testex

ライブラリの追加

今回は cowboy(HTTPサーバ), poison (JSON ライブラリ), distillery(release 用ライブラリ)を使う。

mix.exs に以下のように追加して

defmodule Testex.Mixfile do
  use Mix.Project

  def project do
    [app: :testex,
     version: "0.1.0",
     elixir: "~> 1.4",
     build_embedded: Mix.env == :prod,
     start_permanent: Mix.env == :prod,
     deps: deps()]
  end

  def application do
    # Specify extra applications you'll use from Erlang/Elixir
    [applications: [:logger, :cowboy, :poison],
      mod: {Testex,[]}]
  end

  defp deps do
   [{:cowboy, github: "ninenines/cowboy"},
    {:poison, "~> 3.0.0"},
    {:distillery, "~> 1.1.0", runtime: false}]
  end
end
$ mix deps.get
$ mix release

$ _build/dev/rel/testex/bin/testex console

これで elixir が走るようになるはず。

cowboy で http サーバを走らせる

ポートやルーティングの設定

lib/testex.ex
defmodule Testex do
  def start(_type, _args) do
  import Supervisor.Spec, warn: false
  children = []
  dispatch = :cowboy_router.compile([
      {:_, [
           {"/ping", Testex.Handlers.Ping, []},
      ]}
    ])
    {:ok, _} = :cowboy.start_clear(:http,
                                   100,
                                   [{:port, 4000}],
                                   %{env: %{dispatch: dispatch}})
  opts = [strategy: :one_for_one, name: Testex.Supervisor]
  Supervisor.start_link(children, opts)
  end
end

ホントに pong を返すだけ

lib/testex/handlers/testex.ex

defmodule Testex.Handlers.Ping do
    def init(req, opts) do
    body = %{"type" => "pong"} |> Poison.encode!()
    req2 = :cowboy_req.reply 200, %{"content-type" => "application/json"}, body, req
    {:ok, req2, opts}
    end
end

AWS用のDocker 設定ファイルを作成

Dockerrun.aws.json
{
  "AWSEBDockerrunVersion": 1,
  "volumes": [
    {
      "name": "testex",
      "host": {
        "sourcePath": "/app"
      }
    }
  ],
  "containerDefinitions": [
    {
      "name": "testex",
      "essential": true,
      "portMappings": [
        {
          "hostPort": 80,
          "containerPort": 4000
        }
      ]
    }
  ]
}

WORKDIR として /app を明記するのがポイント

Dockerfileの作成

Dockerfile

# elixir の Docker Image を引っ張ってくる。今回は Phoenix を使わないので node 等は不要
FROM trenpixster/elixir:1.4.1

# WORKDIR の作成
RUN mkdir /app
WORKDIR /app

# mix deps.get
ADD mix.* ./
RUN MIX_ENV=prod mix local.rebar
RUN MIX_ENV=prod mix local.hex --force
RUN MIX_ENV=prod mix deps.get

# Install app
ADD . .
RUN MIX_ENV=prod mix release

# Exposes this port from the docker container to the host machine
EXPOSE 4000

# distillery の run command を実行する。今回はフォアグラウンドで
CMD MIX_ENV=prod _build/prod/rel/testex/bin/testex foreground

eb コマンドの実行

あらかじめ eb をインストールする。 pip で入る。
http://docs.aws.amazon.com/ja_jp/elasticbeanstalk/latest/dg/eb-cli3-install.html

これで、

$ eb init # awsアカウント情報を入力
$ eb create # サーバ名等を入力。Dockerfileがあるとeb側でよしなに判断してくれる。
$ eb deploy testex

すると本番にデプロイされる。

おわり

これはお試しですが、実際に運用するなら、本番・開発環境を切り分けたり、CORS対策としてAPI Gatewayなどを別途で使う必要あり。

サンプルコード

https://github.com/GigantechHQ/ex-server-sample

続きを読む