Let’s EncryptでSSLの設定〜自動更新

最近ちょくちょく使う機会が増えたのでメモ。
EC2、nginxを使用する前提です。

ダウンロード

$ sudo curl https://dl.eff.org/certbot-auto -o /usr/bin/certbot-auto
$ sudo chmod 700 /usr/bin/certbot-auto

証明書と鍵の発行

AWSのセキュリティグループでportの80(http)と443(https)を解放し、以下を実行する。

$ sudo /usr/bin/certbot-auto certonly --standalone --debug -d example.com -m example@example.com --agree-tos -n

  • –debug
    AWSは--debugがないと実行できない。

  • –standalone
    特にrootディレクトリを指定しないので --standalone オプションを設定。

  • -d
    ドメインを指定する。

  • -m
    メールアドレスを指定する。トラブルがあった場合や更新期限が近くなった際にメールが送られてる。

  • –agree-tos
    規約同意。

  • -n
    もろもろの対話入力をスキップ。

IP制限などしたい場合は解放したportを再度すぐ閉じる

nginxに証明書と鍵の設定

/etc/letsencrypt/live/ 以下に証明書と鍵が発行されるのでこれをnginxに設定

upstream example_server {
  server 127.0.0.1:3000;
}

server {
  listen 80;

  # Allow accessing /ping without https. Useful when placing behind load balancer.
  location /ping {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass       http://example_server;
  }

  location / {
    # Enforce SSL.
    return 301 https://$host$request_uri;
  }
}

server {
  listen 443 ssl;
  ssl on;
  ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

  gzip on;
  gzip_types *;
  gzip_proxied any;

  location / {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass       http://example_server;
    proxy_redirect   off;
  }
}

cronにletsencrypt自動更新、nginx再起動を設定

$ sudo vi /etc/cron.d/letsencrypt
0 1 * * * /usr/bin/certbot-auto renew --force-renew && /etc/init.d/nginx reload

参考

http://qiita.com/takahiko/items/a08895550727b95b6c36

続きを読む

AWS EC2 Mysql レプリケーション環境構築

はじめに

本番環境はRDSのMulti A-Z でレプリケーションしているのですが、selectはslaveに、FOR UPDATEはmasterになどクエリの向き先をしっかり確認しておく必要があったので勉強がてらEC2でレプリケーション環境を構築したので自分用にメモ。

やること

・ インスタンスを2つ起動
・ レプリケーション設定
・ 接続確認

EC2インスタンス起動

セキュリティ設定
2つのサーバのMysqlが互いに通信できるように、
Inboundで3306ポートに対して、互いのPrivateIPを設定します。

レプリケーション設定

Master-Server

my.conf

/etc/my.cnf
[mysqld]
server-id=101
log_bin

server-idは、1から(2^32)-1)間の正整数で、サーバ間で重複しないように設定する(任意の値でOK)
ただし、1、2はserver-idがないときのデフォルトとして使用されるため極力使わないほうがいい

Slave-ServerのUser作成とアクセスの許可

mysql > grant replication slave on *.* to 'replication'@'Slave-Srever Private IP' identified by 'password'

ステータスの確認

mysql > show master status;
+-------------------+----------+--------------+------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| mysqld-bin.000001 |     1234 |              |                  |
+-------------------+----------+--------------+------------------+

Slave-Server

my.conf

/etc/my.cnf
[mysqld]
server-id=201
replicate-do-db=db名(対象DB指定)

Master-Server登録

mysql > change master to master_host = 'Master-Server Private IP',
        master_user = 'replication',
        master_password = 'pass',
        master_log_file = 'mysqld-bin.000001', //Master-Serverの情報
        master_log_pos = 1234 //Master-Serverの情報

Slave-ServerのUser作成とアクセスの許可

mysql > grant all privileges on *.* to name@'Master-Srever Private IP' identified by 'password';

ステータスの確認

mysql > show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: Master-Server Private IP
                  Master_User: replication
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysqld-bin.000001
          Read_Master_Log_Pos: 2258
               Relay_Log_File: mysqld-relay-bin.000004
                Relay_Log_Pos: 10195
        Relay_Master_Log_File: mysqld-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

Slave_IO_Running: Yes、Slave_SQL_Running: Yesで設定OK

接続確認

各サーバーからホスト指定でログインできれば接続はできている状態となります。
下記のエラーが出る場合はEC2インスタンスのセキュリティを見直す必要があります。

ERROR 1130 (HY000): Host 'Private IP' is not allowed to connect to this MySQL server

さいごに

その都度、各mysqlの再起動や必要であれば権限の反映FLUSH PRIVILEGESが必要になるかと思います。
自分用のメモとして記述しましたが、不備がありましたらご教授いただけますと幸いです。

続きを読む

AWS + Nginx + PHP + Laravel

nginx + php + LaravelをAWS上に構築してみる

nginx

  • インストールと起動
$ sudo yum -y install nginx
・・・・・
完了しました!

$ sudo service nginx start
Starting nginx:                                            [  OK  ]
  • バージョンやconfigurationの内容を知りたいときは下記コマンド
$ nginx -V
  • configurationで使いそうなやつメモ
設定 説明 デフォルト
–error-log-path HTTPアクセスログのエラーのパス /var/log/nginx/error.log
–http-log-path HTTPアクセスログのパス /var/log/nginx/access.log
–conf-path nginxの設定ファイルのパス /etc/nginx/nginx.conf
–http-proxy-temp-path プロキシを実行している場合、ここで指定したディレクトリが一時ファイルの格納パスになる /var/lib/nginx/tmp/proxy
  • モジュールで気になるところメモあたり(他にもあったけど、メモるの面倒でdown)
モジュール名 説明 利用場面 デフォルト
http_ssl https対応(OpenSSLライブラリが必要)。 プロキシ 有効
http_realip L7ロードバランサなどの後に配置する場合有効にする必要あり。複数のクライアントが同一IPアドレスから通信してくるように見える環境で使用。 プロキシ 有効
http_geoip クライアントのIPアドレスに基づく地理的位置に応じた処理を行うための様々な変数を設定 Web、プロキシ 有効
http_stub_status Nginx自身の統計情報の収集を手助けする Web、プロキシ 有効

※有効化(–with-<モジュール名>module)、無効化(–without-<モジュール名>module)

PHP7のインストール

  • CentOS6用のPHP7のリポジトリを追加(これがないとインストールできないくさい)
$ sudo yum install --enablerepo=webtatic-testing 
                 php70w php70w-devel php70w-fpm php70w-mysql 
                 php70w-mbstring php70w-pdo
  • 他にも必要であればインストールしておく(json系とか)

nginxとphpの紐付け

  • index.phpのセット

    • /var/www/default ディレクトリ作成
    • ここにindex.phpを配置 (最初はとりあえずphpinfoを吐くだけ)
  • /etc/php-fpm.d/www.confの編集 (backupを取った上で編集)
$ diff -uN www.conf.backup_20160710 www.conf
--- www.conf.backup_20160710    2016-07-10 08:00:45.267704077 +0000
+++ www.conf    2016-07-10 08:01:38.451085053 +0000
@@ -5,9 +5,11 @@
 ; Note: The user is mandatory. If the group is not set, the default user's group
 ;       will be used.
 ; RPM: apache Choosed to be able to access some dir as httpd
-user = apache
+; user = apache
+user = nginx
 ; RPM: Keep a group allowed to write in log dir.
-group = apache
+; group = apache
+group = nginx
  • /etc/nginx/nginx.confの編集 (backupを取った上で編集)
$ diff -uN nginx.conf.backup_20160710 nginx.conf
--- nginx.conf.backup_20160710  2016-07-10 07:49:38.694839828 +0000
+++ nginx.conf  2016-07-10 07:59:49.564346085 +0000
@@ -32,13 +32,14 @@
     # for more information.
     include /etc/nginx/conf.d/*.conf;

-    index   index.html index.htm;
+    index   index.php index.html index.htm;

     server {
         listen       80 default_server;
         listen       [::]:80 default_server;
         server_name  localhost;
-        root         /usr/share/nginx/html;
+        #root         /usr/share/nginx/html;
+        root         /var/www/default;

         # Load configuration files for the default server block.
         include /etc/nginx/default.d/*.conf;
@@ -46,8 +47,17 @@
         location / {
         }

-        # redirect server error pages to the static page /40x.html
+        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
         #
+        location ~ .php$ {
+            root           /var/www/default;
+            fastcgi_pass   127.0.0.1:9000;
+            fastcgi_index  index.php;
+            fastcgi_param  SCRIPT_FILENAME  /var/www/default$fastcgi_script_name;
+            include        fastcgi_params;
+        }
+
+        # redirect server error pages to the static page /40x.html
         error_page 404 /404.html;
             location = /40x.html {
         }
@@ -64,16 +74,6 @@
         #    proxy_pass   http://127.0.0.1;
         #}

-        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
-        #
-        #location ~ .php$ {
-        #    root           html;
-        #    fastcgi_pass   127.0.0.1:9000;
-        #    fastcgi_index  index.php;
-        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
-        #    include        fastcgi_params;
-        #}
-
  • 再起動して、phpinfoページが見れればOK (http://<>)
$ sudo service php-fpm start
Starting php-fpm:                                          [  OK  ]
$ sudo service nginx restart
Stopping nginx:                                            [  OK  ]
Starting nginx:                                            [  OK  ]
  • ついでにサーバ起動時などに自動で起動するものも設定
$ sudo chkconfig nginx on
$ sudo chkconfig php-fpm on

nginxとphp-fpmの接続をsocketにする

  • php-fpmの設定変更
$ diff -uN www.conf.backup_20160710 www.conf
--- www.conf.backup_20160710    2016-07-10 08:00:45.267704077 +0000
+++ www.conf    2016-07-10 08:19:03.630366042 +0000
@@ -19,7 +21,8 @@
 ;                            (IPv6 and IPv4-mapped) on a specific port;
 ;   '/path/to/unix/socket' - to listen on a unix socket.
 ; Note: This value is mandatory.
-listen = 127.0.0.1:9000
+; listen = 127.0.0.1:9000
+listen = /var/run/php-fpm/php-fpm.sock

@@ -32,6 +35,8 @@
 ;                 mode is set to 0660
 ;listen.owner = nobody
 ;listen.group = nobody
+listen.owner = nginx
+listen.group = nginx
 ;listen.mode = 0660
  • nginxの設定変更
$ diff -uN nginx.conf.backup_20160710 nginx.conf
--- nginx.conf.backup_20160710  2016-07-10 07:49:38.694839828 +0000
+++ nginx.conf  2016-07-10 08:20:37.741301066 +0000
@@ -46,8 +47,17 @@
-            fastcgi_pass   127.0.0.1:9000;
+            fastcgi_pass   unix:/var/run/php-fpm/php-fpm.sock;
  • 再起動
$ sudo service php-fpm restart
Stopping php-fpm:                                          [  OK  ]
Starting php-fpm:                                          [  OK  ]
$ sudo service nginx restart
Stopping nginx:                                            [  OK  ]
Starting nginx:                                            [  OK  ]

Laravel5を入れてみる

  • Composerをインストール
$ curl -sS https://getcomposer.org/installer | php
$ sudo mv /home/ec2-user/composer.phar /usr/local/bin/composer
  • Laravelのインストール
$ sudo /usr/local/bin/composer global require "laravel/installer"
Changed current directory to /root/.composer
Using version ^1.3 for laravel/installer
./composer.json has been created
Loading composer repositories with package information
Updating dependencies (including require-dev)
  - Installing symfony/process (v3.1.2)
    Downloading: 100%         

  - Installing symfony/polyfill-mbstring (v1.2.0)
    Downloading: 100%         

  - Installing symfony/console (v3.1.2)
    Downloading: 100%         

  - Installing guzzlehttp/promises (1.2.0)
    Downloading: 100%         

  - Installing psr/http-message (1.0)
    Downloading: 100%         

  - Installing guzzlehttp/psr7 (1.3.1)
    Downloading: 100%         

  - Installing guzzlehttp/guzzle (6.2.0)
    Downloading: 100%         

  - Installing laravel/installer (v1.3.3)
    Downloading: 100%         

symfony/console suggests installing symfony/event-dispatcher ()
symfony/console suggests installing psr/log (For using the console logger)
Writing lock file
Generating autoload files
  • php-xmlのインストール (laravelで必要になる)
$ sudo yum install --enablerepo=webtatic-testing php70w-xml
  • プロジェクト作成
$ pwd
/var/www/default
$ sudo /usr/local/bin/composer create-project --prefer-dist laravel/laravel darmaso
Installing laravel/laravel (v5.2.31)
  - Installing laravel/laravel (v5.2.31)
    Downloading: 100%         

Created project in darmaso
> php -r "copy('.env.example', '.env');"
Loading composer repositories with package information
Updating dependencies (including require-dev)
・・・・・ (下記の結果と同じ)

$ cd darmaso
$ sudo /usr/local/bin/composer install
Loading composer repositories with package information
Updating dependencies (including require-dev)
・・・・・
Writing lock file
Generating autoload files
> IlluminateFoundationComposerScripts::postUpdate
> php artisan optimize
Generating optimized class loader

※php-xmlをインストールしておかないと、下記のようなエラーが出るので注意
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - phpunit/phpunit 4.8.9 requires ext-dom * -> the requested PHP extension dom is missing from your system.
・・・・・
    - Installation request for phpunit/phpunit ~4.0 -> satisfiable by phpunit/phpunit[4.0.0, 4.0.1, 4.0.10, 4.0.11, 4.0.12, 4.0.13, 4.0.14, 4.0.15, 4.0.16, 4.0.17, 4.0.18, 4.0.19, 4.0.2, 4.0.20, 〜
・・・・・
  To enable extensions, verify that they are enabled in those .ini files:
    - /etc/php.ini
    - /etc/php.d/bz2.ini
    - /etc/php.d/calendar.ini
・・・・・
  You can also run `php --ini` inside terminal to see which files are used by PHP in CLI mode.
  • Applicationキーの生成 (composerでインストールした場合セットされているらしいが念のため)
$ sudo php artisan key:generate
Application key [base64:YVeCf2A+5IjUbk2qVL4HhPiecBdYuo8irJrEYjJKZWY=] set successfully.
  • Laravel用にnginx設定を修正し、再起動
$ diff -uN nginx.conf.backup_20160710 nginx.conf
+        #root         /var/www/default;
+        root         /var/www/default/darmaso/public;
・・・・・
         location / {
+            try_files $uri $uri/ /index.php?$query_string;
         }
・・・・・
+            #root           /var/www/default;
+            root           /var/www/default/darmaso/public;
・・・・・
+            #fastcgi_param  SCRIPT_FILENAME  /var/www/default$fastcgi_script_name;
+            fastcgi_param  SCRIPT_FILENAME  /var/www/default/darmaso/public$fastcgi_script_name;

$ sudo service php-fpm restart
$ sudo service nginx restart
  • これで動作確認するとエラーになるので下記の設定をしてみる
$ sudo chmod -R 777 storage/
$ sudo chmod -R 777 vendor/

※本来は、サーバアカウントをちゃんと定義してやるべきだが、今回は試しなのでこのままでOKとする

  • 一部の設定を変えてみる
config/app.php
$ diff -uN config/app.php.backup_20160710 config/app.php
--- config/app.php.backup_20160710  2016-07-10 09:37:07.881735079 +0000
+++ config/app.php  2016-07-10 09:40:54.263419145 +0000
@@ -52,7 +52,7 @@
     |
     */

-    'timezone' => 'UTC',
+    'timezone' => 'Asia/Tokyo',

     /*
     |--------------------------------------------------------------------------
@@ -65,7 +65,7 @@
     |
     */

-    'locale' => 'en',
+    'locale' => 'jp',

     /*
     |--------------------------------------------------------------------------
@@ -78,7 +78,7 @@
     |
     */

-    'fallback_locale' => 'en',
+    'fallback_locale' => 'jp',

これで構築した環境にアクセスしたところ、無事いけました!
設定内容が荒いところもありますが、上記まででPHP+Nginx自体はいけちゃいますね。

Nginxの設定はあまり大したことはできませんでしたが、今後は色々と勉強してみようと思いますmm

参考

続きを読む

クラウドの力を借りて無限収入システムを構築する(はずだった)

目的

 ビットコイン等の仮想通貨の採掘をして不労所得チャリンチャリンというのは夢がありますよね。私もチャレンジしようと思ったのですが、手元の貧相な PC では電気代すらペイできないのは明らかです。
 ではクラウドの力を借りて、GPU でやってみたらどうなのか。スポット価格をうまく使えば、もしかしてクラウド利用料を賄えて夢の無限収入システムを構築できるのではないか、というチャレンジをしてみたので、その記録です。
 なお、実際に稼げるとは思ってなくて、AWS スポットインスタンス使ってみる、GPUインスタンスを使ってみる、ブロックチェーンに触れてみる、など一石三鳥なお勉強をすることが目的です。

概念図

 インスタンス利用料が安いときに仮想通貨をマイニングすれば黒字転嫁するのでは、というアイデアです。
image.png

結果

 すごい赤字になる。スポットインスタンスを活用しても インスタンス利用料の半分まかなえる程度の採掘量にとどまり利益が生まれることはなかった、通貨マイナーの世界はきびしい。
 FPGA 使えれば結果は変わるのかなー。

構築の流れ

採掘環境構築~試しに採掘まで

環境情報

  • 採掘対象

    • Ethereum
  • OS 1
    • Ubuntu Linux 16.04 / 64bit
  • インスタンスタイプ
    • g3.4xlarge or p2.xlarge
  • リージョン
    • us-east-1(インスタンス費用がたぶんいちばん安いので)
  • マイナークライアント
    • Claymore’s Dual GPU Miner 9.7
  • ウォレット
    • coincheck

ウォレットの準備

  • Coincheck にアカウント作成

    • その他、大手のbitFlyer、Zaif 等なんでもよさそうです、手数料や取り扱い通貨が違います
  • 身分証明書を送り取引可能な状態にする
    • 最大2営業日必要との記載ですが、今回は数時間で本人確認が完了しました
  • Ether入金用のアドレスを作成 する

    • アドレス:0x0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X

マイニング用AMIを作成する

Ubuntu インスタンスを作成、Calymore9.7 を導入する。

console
$ wget https://github.com/nanopool/Claymore-Dual-Miner/releases/download/v9.7/Claymore.s.Dual.Ethereum.Decred_Siacoin_Lbry_Pascal.AMD.NVIDIA.GPU.Miner.v9.7.-.LINUX.tar.gz
$ mkdir Calymore9.7
$ tar xvzf Claymore.s.Dual.Ethereum.Decred_Siacoin_Lbry_Pascal.AMD.NVIDIA.GPU.Miner.v9.7.-.LINUX.tar.gz -C ./Calymore9.7/
$ cd Calymore9.7/

不足しているライブラリをインストール

console
sudo apt-get install ocl-icd-opencl-dev
sudo apt-get install libcurl3

nvidiaのドライバをインストール

console
sudo apt-get install -y nvidia-367

以下のshを作成

Claymore9.7/miningStarter.sh
#!/bin/sh

workername1=`hostname`
workername2=`date +"%y%m%d%H%M%S"`

#export GPU_FORCE_64BIT_PTR=0 # must be comment out for amdgpu-pro
export GPU_MAX_HEAP_SIZE=100
export GPU_USE_SYNC_OBJECTS=1
export GPU_MAX_ALLOC_PERCENT=100
export GPU_SINGLE_ALLOC_PERCENT=100

export ETH_ADDR=0x0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X # Ether入金アドレス
export ETH_WORKER_NAME=$workername1$workername2 # ワーカーの名前=ホスト名+起動日時
export ETH_POOL_HOST=us1.ethermine.org:4444 #AWSリージョンと同じusを指定

cd /home/ubuntu/Claymore9.7/ #SHおいたとこ

./ethdcrminer64 
  -epool $ETH_POOL_HOST 
  -ewal $ETH_ADDR.$ETH_WORKER_NAME 
  -epsw x 
  -mode 0 
  -ftime 10 
  -etha 2 
  -allpools 1 
  -wd 0 
  -eres 4 
  -gser 2

で、sh 起動、なんかうごく。

console
sudo bash miningStarter.sh

image.png

こちらで Ethereum入金アドレス で検索すると、進捗が確認できる。
ethermine.org – The fastest way to mine Ether

ためしに採掘&オンデマンドでの結果

数時間後…
image.png

ちゃんと掘れてるみたいですが、いくらになったんでしょう…

  • AWS利用料(g3.xlarge@us-east-1)

    • $1.14 / H = $27.4 / Day
  • マイニング結果 23
    • 0.002659 ETH/Day (10 MH/s) = $0.8 / Day
  • 収支
    • -98%($-26.56/Day)の赤字

 オンデマンドインスタンス価格では赤字を垂れ流す結果となりました。自動起動設定をしたあと、AMI をとっておきます。

/etc/rc.local
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

bash /home/ubuntu/Claymore9.7/miningStarter.sh #SHのありか

exit 0
  • AMI-ID

    • ami-0X0X0X0X

スポットインスタンスで起動まで

 バージニア北部のここ一週間のスポットインスタンスの価格設定履歴より、スポットの最安値とオンデマンド比の割引率を求めました。4

インスタンスタイプ オンデマンド($/H) スポット最安($/H) 割引率
g3.4xlarge 1.14 0.23 80%
g3.4xlarge 2.28 0.4 82%
g3.4xlarge 4.56 1.04 77%
p2.xlarge 0.9 0.1 89%
p2.8xlarge 7.2 1 86%
p2.16xlarge 14.4 2.2 85%

 g3とp2はどちらがマイニングに適しているのか計測しないとわかりませんが、とりあえず「p2.xlarge」でいいかなと感覚で決め、自動入札とAutoScaleの設定をします。この割引率を見る限り、負けが見えていますが。。。

  • 起動設定:MiningLaunchConfig

    • インスタンスタイプ

      • p2.xlarge
    • スポット価格
      • $ 0.1
    • AMI ID
      • ami-0X0X0X0X
  • AutoScalingGroup設定:MiningAutoScaleGroup

    • 起動設定

      • MiningLaunchConfig
    • 希望
      • 3
    • 最小
      • 3
    • 最大
      • 3

 これで、スポットインスタンスが 0.1 以下の場合自動で入札し、その価格帯であれば常時3台 起動する設定ができました。

勝手に起動する!
image.png

勝手に採掘する!
image.png

無限にお金が、、、!!

最終結果

  • AWS利用料(p2.xlarge@us-east-1)

    • $0.098 / H = $2.35 / Day
  • マイニング結果(1台あたり)
    • 0.003244 ETH/Day (12.2 MH/s) = $ 0.97 / Day
  • 収支
    • -59%($-1.38/Day)の赤字

 無限にお金が減っていく!
 残念ながら、スポットインスタンスでも無限の収入は実現できませんでした。もっと値下げしてくれれば黒字転換するんですが、そんなうまい話ないですよね。
 無念!!

参考リンク

イーサリアムを効率良くマイニングできるClaymore’s Dual Minerの使い方・設定 | トレードステーションと株・FX自動売買で暮らす
技術者向け Ethereumの基礎知識 (イーサリアム、エセリウム) – Qiita
【2017年度版】イーサリアム(ETH)でお金を稼ごう! ~マイニング編~ | デジモノ達人
イーサリウムを GPU マイニングしてみる(2017/04/21 時点) – Qiita
GPU関連でよく使うコマンドまとめ – Qiita
ETH-USD電卓:ETH/USD Ethereum Price Calculator | CoinGecko
Mining収支電卓:Ethereum Mining Profitability Calculator
採掘量確認:Balances – ethermine.org – The fastest way to mine Ether

構築時エラー集

ocl-icd-opencl-dev ないとエラー

ethdcrminer64
./ethdcrminer64: error while loading shared libraries: libOpenCL.so.1: cannot open shared object file: No such file or directory

libcurl3 ないとエラー

ethdcrminer64
./ethdcrminer64: error while loading shared libraries: libcurl.so.4: cannot open shared object file: No such file or directory

nvidiaのドライバ ないとエラー

ethdcrminer64
ETH: 1 pool is specified
Main Ethereum pool is asia1.ethermine.org:4444
DCR: 4 pools are specified
Main Decred pool is pasc-eu2.nanopool.org:15555
AMD OpenCL platform not found 
No NVIDIA CUDA GPUs detected.
No AMD OPENCL or NVIDIA CUDA GPUs found, exit

補足


  1. GPU は Windows に最適化されているものが多く、マイナーの世界では Windows を使うのがメジャーみたいです 

  2. 1 ETH = $ 299.96 で計算しています 

  3. 数時間しか稼働させていないので、インスタンスタイプにおける MH/s は正しい平均値が取れていません 

  4. 2017/8 時点 

続きを読む

ElasticseharchのEC2 Discovery Pluginでクラスタ組むのが捗るはなし

こんばんはー

今回、ElasticsearchのクラスタをAWS上に組む際に便利なブラグインを使ってみたいと思いますー
その名も「EC2 Discovery Plugin」☆彡

調べているとAWS Cloud Pluginの使い方を書いている人は結構いるのですが、5系から提供されているEC2 Discovery Pluginはあんまいないのかなーって思いました。
なので、EC2 Discovery Pluginについてつらつら書きたいと思います( ゚Д゚)ゞビシッ

そもそもEC2 Discovery Pluginは何が便利なん?

Elasticsearchのデフォルトで用意されているZen Discoveryを利用してクラスタを組む際は、Unicastでホスト名やIPアドレス指定で組みます。
ただ、クラウド上の運用を考えるとUnicastはつらい。。
そこで、EC2 Discovery Pluginを使うとSecurityGroupを元にクラスタが組まれるのですー(d゚ω゚d)オゥイェー
Multicast Discovery pluginというのもあったのですが、5系から廃止されました

早速ですが、構成の説明したら実装方法を説明したいと思いますー

インスタンス構成

  • InstanceType:t2.medium
  • OS:Amazon Linux AMI release 2017.03
  • Node: 3台
  • ClusterName: es-cluster

こんな感じの流れで書いちゃいますー

  1. AWS準備

  2. Install Oracle JDK 1.8

  3. Install Elasticsearch

  4. Install Kibana(1台のみ)

  5. Install X-pack Elasticsearch & kibana(1台のみ)

  6. Install EC2 Discovery Plugin

  7. 動作確認

AWS準備

SecurityGroup

ElasticsearchをインストールするインスタンスにアタッチするSecurityGroupです。
ソースは、環境に合わせて設定してください。

Type Protocol Port Source Description
Custom TCP 9200 xx Elasticsearchアクセスポート
Custom TCP 9300 xx ノード間のコミュニケーションポート
Custom TCP 5601 xx KibanaのHTTP用ポート
Custom TCP 22 xx SSH用ポート

IAM Role

以下のPolicyを作成し、インスタンスにアタッチしているIAM RoleにPolicyをアタッチしてください。

{
    "Statement": [
        {
            "Action": [
                "ec2:DescribeInstances"
            ],
            "Effect": "Allow",
            "Resource": [
                "*"
            ]
        }
    ],
    "Version": "2012-10-17"
}

AWS Configure

サーバにログインしたらAWS Configureの実行をします。
Access KeyとSecret keyは利用しないため、何も入力しません。

$ aws configure
AWS Access Key ID [None]:
AWS Secret Access Key [None]:
Default region name [None]: ap-northeast-1
Default output format [None]: json

下準備が終わったので、ここからElasticsearch周りを進めたいと思いますー

Install Oracle JDK 1.8

$ java -version
java version "1.7.0_141"
OpenJDK Runtime Environment (amzn-2.6.10.1.73.amzn1-x86_64 u141-b02)
OpenJDK 64-Bit Server VM (build 24.141-b02, mixed mode)

### Install Java1.8
$ sudo yum -y install java-1.8.0-openjdk-devel

### alternativesコマンドでJavaのバージョンを切り替える
$ sudo alternatives --config java

There are 2 programs which provide 'java'.

  Selection    Command
-----------------------------------------------
*+ 1           /usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin/java
   2           /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin/java

Enter to keep the current selection[+], or type selection number: 2

### バージョン確認
$ java -version
openjdk version "1.8.0_141"
OpenJDK Runtime Environment (build 1.8.0_141-b16)
OpenJDK 64-Bit Server VM (build 25.141-b16, mixed mode)

Install Elasticsearch

Elasticsearch5.5.1を入れちゃいたいと思いますー

Install Elasticsearch

### PGP Keyをダウンロード&インストール
$ sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch

### リポジトリの登録
$ sudo vim /etc/yum.repos.d/elastic.repo
[elasticsearch-5.x]
name=Elasticsearch repository for 5.x packages
baseurl=https://artifacts.elastic.co/packages/5.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md

### Elasticsearchインストール
$ sudo yum -y install elasticsearch

### サービス起動登録
$ sudo chkconfig --add elasticsearch

### 確認
$ sudo chkconfig --list | grep elasticsearch
elasticsearch   0:off   1:off   2:on    3:on    4:on    5:on    6:off

### elasticsearch.yml設定変更
$ sudo vim /etc/elasticsearch/elasticsearch.yml
+ cluster.name: es-cluster
+ network.host: 0.0.0.0
+ http.port: 9200

### サービス起動
$ sudo service elasticsearch start
Starting elasticsearch:                                    [  OK  ]

### 起動確認
$ curl http://localhost:9200
{
  "name" : "fDpNQ4m",
  "cluster_name" : "es",
  "cluster_uuid" : "mayxoDENThSmrUltkXyRWg",
  "version" : {
    "number" : "5.5.1",
    "build_hash" : "19c13d0",
    "build_date" : "2017-07-18T20:44:24.823Z",
    "build_snapshot" : false,
    "lucene_version" : "6.6.0"
  },
  "tagline" : "You Know, for Search"
}

Install Kibana

モニタリングしたいのでKibana5.5.1をインストールします。

### Install Kibana
$ sudo yum install -y kibana
### サービス登録
$ sudo chkconfig --add kibana
$ chkconfig --list | grep kibana
kibana          0:off   1:off   2:on    3:on    4:on    5:on    6:off
### Kibana設定
$ sudo vim /etc/kibana/kibana.yml
+ server.host: 0.0.0.0
+ elasticsearch.url: "http://ES_IP_ADDR"
### サービス停止状態のままにしておきます(X-Pack入れたあとに設定変更後に起動します)
$ service kibana status
kibana is not running

Install X-Pack on Elasticsearch

Elasticsearchのノード状態などをモニタリングしたいため、X-Pack5.5をインストールします。

Install X-Pack on Elasticsearch

$ sudo /usr/share/elasticsearch/bin/elasticsearch-plugin install x-pack
-> Downloading x-pack from elastic
[=================================================] 100%  
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@     WARNING: plugin requires additional permissions     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
* java.io.FilePermission \.pipe* read,write
* java.lang.RuntimePermission accessClassInPackage.com.sun.activation.registries
* java.lang.RuntimePermission getClassLoader
* java.lang.RuntimePermission setContextClassLoader
* java.lang.RuntimePermission setFactory
* java.security.SecurityPermission createPolicy.JavaPolicy
* java.security.SecurityPermission getPolicy
* java.security.SecurityPermission putProviderProperty.BC
* java.security.SecurityPermission setPolicy
* java.util.PropertyPermission * read,write
* java.util.PropertyPermission sun.nio.ch.bugLevel write
* javax.net.ssl.SSLPermission setHostnameVerifier
See http://docs.oracle.com/javase/8/docs/technotes/guides/security/permissions.html
for descriptions of what these permissions allow and the associated risks.

Continue with installation? [y/N]y
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@        WARNING: plugin forks a native controller        @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
This plugin launches a native controller that is not subject to the Java
security manager nor to system call filters.

Continue with installation? [y/N]y
-> Installed x-pack

動作確認するのですが、Securityが有効になったため、エラーが返ってきます。
なので、今回は、Securityを無効にします。
(モニタリング用途で使いたいだけなので―)

ちなみに、X-Packについては、クラスメソッドさんが詳しく書いてますー
クラスメソッド:Elastic Stack X-Pack

X-Pack Security無効化

無効化することで、レスポンスが返ってきます。

### Security無効化
$ vim /etc/elasticsearch/elasticsearch.yml
+ xpack.security.enabled: false

### 動作確認
$ curl -u elastic http://localhost:9200
{
  "name" : "fDpNQ4m",
  "cluster_name" : "es",
  "cluster_uuid" : "mayxoDENThSmrUltkXyRWg",
  "version" : {
    "number" : "5.5.1",
    "build_hash" : "19c13d0",
    "build_date" : "2017-07-18T20:44:24.823Z",
    "build_snapshot" : false,
    "lucene_version" : "6.6.0"
  },
  "tagline" : "You Know, for Search"
}

### 再起動
$ service kibana restart
kibana stopped.
kibana started

Install X-Pack on Kibana

KibanaのX-Pack5.5もインストールします。

Install X-Pack on Kibana

$ sudo /usr/share/kibana/bin/kibana-plugin install x-pack
Attempting to transfer from x-pack
Attempting to transfer from https://artifacts.elastic.co/downloads/kibana-plugins/x-pack/x-pack-5.5.1.zip
Transferring 119276972 bytes....................
Transfer complete
Retrieving metadata from plugin archive
Extracting plugin archive
Extraction complete

Install EC2 Discovery Plugin

ここからEC2 Discovery Pluginをインストールします。
やっとここまできましたね!

$ sudo /usr/share/elasticsearch/bin/elasticsearch-plugin install discovery-ec2
-> Downloading discovery-ec2 from elastic
[=================================================] 100%  
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@     WARNING: plugin requires additional permissions     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
* java.lang.RuntimePermission accessDeclaredMembers
* java.lang.RuntimePermission getClassLoader
See http://docs.oracle.com/javase/8/docs/technotes/guides/security/permissions.html
for descriptions of what these permissions allow and the associated risks.

Continue with installation? [y/N]y
-> Installed discovery-ec2

Elasticsearch.ymlに設定します。

$ sudo vim /etc/elasticsearch/elasticsearch.yml
cluster.name: es-cluster
discovery.zen.hosts_provider: ec2
discovery.ec2.groups: "SECURITY_GROUP_NAME" or "SECURITY_GROUP_ID"
discovery.ec2.availability_zones: [ "ap-northeast-1a", "ap-northeast-1c" ]
cloud.aws.region: ap-northeast-1

### サービス再起動
service elasticsearch restart

### クラスタ状態確認
$ curl http://localhost:9200/_cluster/health?pretty
{
  "cluster_name" : "es-cluster",
  "status" : "green",
  "timed_out" : false,
  "number_of_nodes" : 1,
  "number_of_data_nodes" : 1,
  "active_primary_shards" : 0,
  "active_shards" : 0,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 0,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 100.0
}

2台目&3台目いくよ!!

2台目も上記と同じで設定を実施しますので割愛しちゃいますm(_ _)m
SecurityGroupは、1台目と同じのを使ってください。
また、ElasticsearchのX-Packは、3台すべてに入れてください。
Kibanaは、インストールしないです。

もろもろ設定して、Elasticsearchを再起動するとログにクラスタが組み込まれたことがわかります。

クラスタに組み込まれているかをログから確認

### Master側のログ
[20xx-xx-xxxx:xx:xx][INFO ][o.e.c.s.ClusterService   ] [fDpNQ4m] added {{gdRR6r1}{gdRR6r17T5iaGPmaO9wgTA}{6l3QNArhSkyBVu08jTfwYQ}{IP_ADDR}{IP_ADDR:9300},}, reason: zen-disco-receive(from master [master {dKgmQfLLg}{IP_ADDR}{IP_ADDR:9300} committed version [15]])

### Node側のログでマスタを検出したことがわかる
$ tail -f /var/log/elasticsearch/es.log
[20xx-xx-xxxx:xx:xx][INFO ][o.e.c.s.ClusterService   ] [gdRR6r1] detected_master {dKgmQfL}{dKgmQfLASM-35x0X0ulSXg}{XE4jgXEzQwqgkSfRypgoLg}{IP_ADDR}{IP_ADDR:9300}, added {{fDpNQ4m}{fDpNQ4mrRR2vN7wiTVjfIg}{aqPbmbhbTkm1X40gH1tylw}{IP_ADDR}{IP_ADDR:9300},{dKgmQfL}{dKgmQfLASM-35x0X0ulSXg}{XE4jgXEzQwqgkSfRypgoLg}{IP_ADDR}{IP_ADDR:9300},}, reason: zen-disco-receive(from master [master {dKgmQfL}{dKgmQfLASM-35x0X0ulSXg}{XE4jgXEzQwqgkSfRypgoLg}{IP_ADDR}{IP_ADDR:9300} committed version [15]])

Kibanaのモニタリングで確認するよ

Kibana [http://KIBANA_IP_ADDR:5601] にアクセスします。

「Monitoring」をクリックし、ElasticsearchにNodeが3台あることがわかりますね。
ステータス:Green

kibana01.png

「Nodes」をクリックし、Nodeの状態を確認できます。

kibana02.png

無事にクラスタを組むことができましたヽ(*゚д゚)ノ

補足#01

AWS Configureの設定とIAM Roleにポリシーをアタッチしないと以下のエラーがでます。
ちなみに、作成したクラスタ名でログが作成されちゃいます。

$ sudo /var/log/elasticsearch/es-cluster.log
[20xx-xx-xxxx:xx:xx][INFO ][o.e.d.e.AwsEc2UnicastHostsProvider] [node_id] Exception while retrieving instance list from AWS API: Unable to execute HTTP request: connect timed out

補足#02

既に存在しているNodeIDのAMIから起動すると、NodeIDがかぶっているためクラスタに組み込むことができないです。。
その際のログが以下です。

### AMIから起動したノード
$ tail -f /var/log/elasticsearch/es.log
[20xx-xx-xxxx:xx:xx][INFO ][o.e.d.z.ZenDiscovery     ] [gdRR6r1] failed to send join request to master [{fDpNQ4m}{fDpNQ4mrRR2vN7wiTVjfIg}{eHfV5HLkRrKo8_FXfgyHDA}{IP_ADDR}{IP_ADDR:9300}{ml.enabled=true}], reason [RemoteTransportException[[fDpNQ4m][IP_ADDR:9300][internal:discovery/zen/join]]; nested: IllegalArgumentException[can't add node {gdRR6r1}{gdRR6r17T5iaGPmaO9wgTA}{hzzXQXB8TM-xQVn9Uj8e2A}{IP_ADDR}{IP_ADDR:9300}{ml.enabled=true}, found existing node {gdRR6r1}{gdRR6r17T5iaGPmaO9wgTA}{9pWjYpL5Tq23yIte7WzMiw}{IP_ADDR}{IP_ADDR:9300}{ml.enabled=true} with the same id but is a different node instance]; ]

さいごに

EC2 Discovery Pluginいかがでしたか?
簡単にクラスタを組むことができたんじゃないかなと思います。

ただ、個人的には、運用を考えると自動復旧できる構成にする必要があると思ってます。
今の状態だとElasticsearchのクラスタ化する時にNodeIDがかぶっちゃうので、AMIからの自動復旧がむずかしい状態です。
なので、Elasticsearchをインストールする前のAMIからプロビジョニングして、クラスタに組み込む必要があるかなと。
(Elasticsearchインストール時にNodeIDが振られる)

うーん。。NodeIDを変更する方法が他にあればいいのですが、誰か知っている人いたら教えてくださいm(_ _)m

てことで、今回は、ElasticsearchのプラグインのEC2 Discovery Pluginについて書かせて頂きました。
ありがとうございましたー

続きを読む

Rails5アプリケーションのAWSによるネットワーク構築 Nginx+Puma+Capistranoな環境とAWS構築(VPC EC2 RDS CloudFlont Route53 etc)

はじめに

数ヶ月前に書いたRails5のAWS構築をもう少し項目を増やしてから公開しようと思っていたのですが、なかなか出来ないのでもう公開します。(ELBとかCloudFlontとかもっとちゃんと書けそう、、)
項目の追加や修正は適宜入れると思います。

Railsは5.0を使っています。(記事を書いたときの最新)

4系は以前書きました↓

構築する環境

  • VPC
  • EC2
    • Nginx + Puma
    • Capistrano
  • (S3)
  • ELB
  • RDS
  • CloudFlont
  • Route53
  • (CloudWatch)

VPC、EC2のインスタンスの作成

AWSのデザインが多少変更はありますが、以下を参考に作成出来ます。

AWS VPCによるネットワーク構築とEC2によるサーバー構築

これに追加でElastic IPの設定もしておきました。

EC2内の環境構築

作成したEC2にログインして環境を構築します。
ec2-userでまずログインしましょう。

ユーザーの作成

デフォルトではec2-userなので新たなユーザーを追加し、そのユーザーでsshログイン出来るように設定します。

$ sudo adduser shizuma #ユーザーの追加 「shizuma」の部分は好きなユーザー名にします。以後「shizuma」の部分は各自のユーザー名になります。
$ sudo passwd shizuma
#ここで、新規ユーザーのパスワードを設定します。
$ sudo visudo
-----------------------------
#vimが起動するので新規ユーザーにroot権限を与える。
root    ALL=(ALL)       ALL
shizuma ALL=(ALL)       ALL #この行を追加
-----------------------------
$ sudo su - shizuma #ユーザー切り替え
#先ほど設定したパスワード

ここでローカルに一旦戻り、鍵を作成します。

$ cd .ssh
$ ssh-keygen -t rsa
-----------------------------
Enter file in which to save the key ():first_aws_rsa #ここでファイルの名前を記述して、エンター
Enter passphrase (empty for no passphrase): #何もせずそのままエンター
Enter same passphrase again: #何もせずそのままエンター
-----------------------------
$ vi config
-----------------------------
# 以下を追記
Host first_aws
  Hostname 54.64.22.197 #自分の設定に合わせて
  Port 22
  User shizuma #先ほどのユーザー名
  IdentityFile ~/.ssh/first_aws_rsa #秘密鍵の設定
-----------------------------

次に、サーバーに戻り作成した 公開鍵 をサーバーに設定します。

$ mkdir .ssh
$ chmod 700 .ssh
$ cd .ssh
$ vi authorized_keys
-----------------------------
#localの「first_aws_rsa.pub」の中身のコピペ。(localで $ cat first_aws_rsa.pubとかすると良い)
ssh-rsa sdfjerijgviodsjcIKJKJSDFJWIRJGIUVSDJFKCNZKXVNJSKDNVMJKNSFUIEJSDFNCJSKDNVJKDSNVJNVJKDSNVJKNXCMXCNMXNVMDSXCKLMKDLSMVKSDLMVKDSLMVKLCA shizuma@shizuma-no-MacBook-Air.local
-----------------------------
$ chmod 600 authorized_keys
$ exit
$ exit

これで設定が完了したので、以降作成したユーザーでアクセスするようにします。

基本ライブラリとrubyの環境構築

$ sudo yum install 
git make gcc-c++ patch 
openssl-devel 
libyaml-devel libffi-devel libicu-devel 
libxml2 libxslt libxml2-devel libxslt-devel 
zlib-devel readline-devel 
mysql mysql-server mysql-devel 
ImageMagick ImageMagick-devel 
epel-release
$ sudo yum install nodejs npm --enablerepo=epel
$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
$ source .bash_profile
$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
$ rbenv rehash
$ rbenv install -v 2.3.1
$ rbenv global 2.3.1
$ rbenv rehash
$ ruby -v

gitの設定

最低限の設定だけしておきます。

$ vi .gitconfig
.gitignore
[user]
  name = your_name #自分の名前
  email = hoge@hoge.com #自分のメアド

[alias] #これはお好きに
  a = add
  b = branch
  ch = checkout
  st = status

[color] #色付け
  ui = true

[url "github:"] #pull、pushのための設定
    InsteadOf = https://github.com/
    InsteadOf = git@github.com:

アプリケーションフォルダの設置

/var/www/rails にアプリケーションフォルダを設置します。

$ cd /
$ sudo mkdir -p /var/www/rails
$ sudo chown -R shizuma var/www

GitHubの接続とアプリケーションのclone

$ cd ~/.ssh
$ ssh-keygen -t rsa
-----------------------------
Enter file in which to save the key ():aws_git_rsa #ここでファイルの名前を記述して、エンター
Enter passphrase (empty for no passphrase): #何もせずそのままエンター
Enter same passphrase again: #何もせずそのままエンター
-----------------------------
$ chmod 744 config
$ vi config
-----------------------------
# 以下を追記
Host github github.com
  Hostname github.com
  User git
  Port 22
  IdentityFile ~/.ssh/aws_git_rsa #秘密鍵の設定
-----------------------------
$ cat aws_git_rsa.pub
-----------------------------
ssh-rsa sdfjerijgviodsjcIKJKJSDFJWIRJGIUVSDJFKCNZKXVNJSKDNVMJKNSFUIEJSDFNCJSKDNVJKDSNVJNVJKDSNVJKNXCMXCNMXNVMDSXCKLMKDLSMVKSDLMVKDSLMVKLCA shizuma@ip-10-0-1-10
-----------------------------

ここで、これをコピペしてgithubに公開鍵を登録する。
githubへの鍵の登録がよくわからない方は以下の記事を参考に。
gitHubでssh接続する手順~公開鍵・秘密鍵の生成から~

そして、git clone する。

$ cd /var/www/rails
$ git clone https://github.com/kuboshizuma/cheerfull # 自分のアプリケーション

RDSの設定

EC2の環境構築に一区切りついたのでRDSの設定を行います。

DBサブネットの登録

RDSで使うサブネットを登録します。
この設定には異なるアベイラビリティゾーンにあるサブネットが最低1つずつ計2つ必要になります。
また、Railsアプリケーションをおいたサブネットはゲートウェイに繋がったpublicなサブネットなので、privateなサブネットを異なるアベイラビリティゾーンに一つずつ作成します。

スクリーンショット_2017-03-04_11_56_01.png

パラメータグループの設定

パラメータグループを設定します。
mysqlを使用していると設定なので、ここではmysqlを選択します。バージョンは適宜選択。
「chara…」で検索すると出て来るcharasetをutf-8に変更。

スクリーンショット_2017-03-04_12_00_57.png

設定が完了した後に、パラメータの編集を押してパラメーター変更。

スクリーンショット_2017-03-04_12_04_29.png

セキュリティグループの作成

VPCでセキュリティグループを作成します。

スクリーンショット_2017-03-04_12_08_19.png

インバウンドルールにMySQLを設定し、MySQLのアクセスのみ許可します。
「送信元」は0.0.0.0/0で設定。特定のRailsアプリケーションサーバーがあるサブネットに限定するほうがよさそう。

スクリーンショット 2017-03-04 12.55.42.png

RDSインスタンスの作成

エンジンの選択

スクリーンショット_2017-03-04_12_12_05.png

本番稼働用?

スクリーンショット_2017-03-04_12_12_45.png

DB詳細設定の指定

無料枠はt2.micro

スクリーンショット_2017-03-04_12_17_35.png

詳細設定の設定

各種作成したもので設定。

スクリーンショット_2017-03-04_12_19_44.png

スクリーンショット_2017-03-04_12_19_53.png

接続確認

hostは各自の作成したRDSインスタンスのエンドポイントをみる。

$ mysql -h hogepoge.ap-northeast-1.rds.amazonaws.com -u shizuma -P 3306 -p

接続出来たら完了!

絵文字の扱い

絵文字も登録出来るようにする場合。
以下を参考に utfmb4を採用する。

ActiveRecordをutf8mb4で動かす

MAMPでは /Applications/MAMP/conf/my.cnfmy.cnf を設置した。

Railsアプリケーションの起動のための準備

puma setting

以下を追記する。

cofig/puma.rb
# add setting for production
_proj_path = "#{File.expand_path("../..", __FILE__)}"
_proj_name = File.basename(_proj_path)
_home = ENV.fetch("HOME") { "/home/#{ENV['PUMA_USER']}" }
pidfile "#{_home}/run/#{_proj_name}.pid"
bind "unix://#{_home}/run/#{_proj_name}.sock"
directory _proj_path
# add end

ENV['PUMA_USER'] にサーバーのユーザー名が入るように環境変数を設定。

database setting

以下のように編集。

config/database.yml
production:
  <<: *default
  database: cheerfull
  username: <%= ENV['DATABASE_USER_NAME_PRODUCTION'] %>
  password: <%= ENV['DATABASE_PASSWORD_PRODUCTION'] %>
  host: <%= ENV['DATABASE_HOST_PRODUCTION'] %>

それぞれ該当の環境変数を設定。

rake secret

以下のsecret keyの箇所に値が入るように環境変数を設定。
rake secret とコマンドを打つと出て来る文字列を設定する。

config/secrets.yml
production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
$ gem install bundler
$ bundle install
$ rake db:create RAILS_ENV=production
$ rake db:migrate RAILS_ENV=production

PumaとNginxの起動

Pumaの起動

アプリケーションディレクトリにて以下を実行。

$ RAILS_SERVE_STATIC_FILES=true RAILS_ENV=production puma -w 4

「Ctr+c」でプロセス消さなければ生き残る。
プロセス消す必要があれば以下のようにする。

$ ps aux | grep puma # プロセスIDを探す
$ kill -9 (ID)

Nginx の起動

「cheerfull」の部分は自分のアプリケーションディレクトリ名に変更する。

/etc/nginx/conf.d/cheerfull.conf
  # log directory
  error_log  /var/www/rails/cheerfull/log/nginx.error.log;
  access_log /var/www/rails/cheerfull/log/nginx.access.log;
  upstream app_server {
    # for UNIX domain socket setups
    server unix:/home/shizuma/run/cheerfull.sock fail_timeout=0;
  }
  server {
    listen 80;
    server_name 12.134.156.178; # 自分のIP
    # nginx so increasing this is generally safe...
    # path for static files
    root /var/www/rails/cheerfull/public;
    # page cache loading
    try_files $uri/index.html $uri @app_server;
    location / {
      # HTTP headers
      proxy_pass http://app_server;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;
    }
    # Rails error pages
    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /var/www/rails/cheerfull/public;
    }
    client_max_body_size 4G;
    keepalive_timeout 5;
  }

ユーザーをnginxから自分のユーザー名に変更しておく。

/etc/nginx/nginx.conf
#user nginx;
user shizuma;

nginxを起動します。

$ sudo service nginx restart

これで、IPアドレスでアクセスするとアプリケーションが表示されるようになりました。

Capistranoの設定

諸々動くことが確認出来たのでデプロイが出来るように設定します。
デプロイのためにCapistranoの設定をします。
慣れてきたら、いきなりCapistranoの設定をしていけばいいと思います。

socketの場所もアプリケーションディレクトリに変更するのでnginxの設定もそれに合わせて変更します。

「cheerfull」の部分は自分のアプリケーション名に変更する。

deploy.rb
require 'dotenv'
Dotenv.load

lock "3.7.1"

set :application, "cheerfull"
set :repo_url, "git@github.com:your_gitname/cheerfull.git"
set :branch, 'master'
set :deploy_to, '/var/www/rails/protospacce'
set :linked_files, fetch(:linked_files, []).push('.env')
set :linked_dirs, fetch(:linked_dirs, []).push('log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'vendor/bundle', 'public/system')
set :keep_releases, 5
set :rbenv_ruby, '2.3.1'

# puma setting
set :puma_threads,    [4, 16]
set :puma_workers,    0
set :pty,             true
set :use_sudo,        false
set :stage,           :production
set :deploy_via,      :remote_cache
set :deploy_to,       "/var/www/rails/#{fetch(:application)}"
set :puma_bind,       "unix://#{shared_path}/tmp/sockets/#{fetch(:application)}-puma.sock"
set :puma_state,      "#{shared_path}/tmp/pids/puma.state"
set :puma_pid,        "#{shared_path}/tmp/pids/puma.pid"
set :puma_access_log, "#{shared_path}/log/puma.error.log"
set :puma_error_log,  "#{shared_path}/log/puma.access.log"
set :puma_preload_app, true
set :puma_worker_timeout, nil
set :puma_init_active_record, true

namespace :deploy do
  desc 'Create database'
  task :db_create do
    on roles(:db) do |host|
      with rails_env: fetch(:rails_env) do
        within current_path do
          execute :bundle, :exec, :rake, 'db:create'
        end
      end
    end
  end
end

実際にdeployする前に、共有ファイルは用意しておきましょう。この場合、.env

ここでpumaのセッティングをしたので、config/puma.rb はもう不要になります。
また、dotenvを使用する場合は変更を読み込むために config/deploy/templates/puma.rb.erb を用意します。以下を用意。

config/deploy/templates/puma.rb.erb
#!/usr/bin/env puma

directory '<%= current_path %>'
rackup "<%=fetch(:puma_rackup)%>"
environment '<%= fetch(:puma_env) %>'
<% if fetch(:puma_tag) %>
  tag '<%= fetch(:puma_tag)%>'
<% end %>
pidfile "<%=fetch(:puma_pid)%>"
state_path "<%=fetch(:puma_state)%>"
stdout_redirect '<%=fetch(:puma_access_log)%>', '<%=fetch(:puma_error_log)%>', true


threads <%=fetch(:puma_threads).join(',')%>

<%= puma_bind %>
<% if fetch(:puma_control_app) %>
activate_control_app "<%= fetch(:puma_default_control_app) %>"
<% end %>
workers <%= puma_workers %>
<% if fetch(:puma_worker_timeout) %>
worker_timeout <%= fetch(:puma_worker_timeout).to_i %>
<% end %>

<% if puma_preload_app? %>
preload_app!
<% else %>
prune_bundler
<% end %>

on_restart do
  puts 'Refreshing Gemfile'
  ENV["BUNDLE_GEMFILE"] = "<%= fetch(:bundle_gemfile, "#{current_path}/Gemfile") %>"
  ENV.update Dotenv::Environment.new('.env')
end

<% if puma_preload_app? and fetch(:puma_init_active_record) %>
before_fork do
  ActiveRecord::Base.connection_pool.disconnect!
end

on_worker_boot do
  ActiveSupport.on_load(:active_record) do
    ActiveRecord::Base.establish_connection
  end
end
<% end %>
$ bundle exec production cap puma:config 

これでこの設定を本番に反映。

あとはデプロイコマンドを打つ。

$ bundle exec cap production deploy

デプロイdone!

nginxのlogの位置やsocketの位置を変更します。

/etc/nginx/conf.d/cheerfull.conf
  # log directory
  error_log  /var/www/rails/cheerfull/shared/log/nginx.error.log;
  access_log /var/www/rails/cheerfull/shared/nginx.access.log;
  upstream app_server {
    # for UNIX domain socket setups
    server unix:/var/www/rails/cheerfull/shared/tmp/sockets/cheerfull-puma.sock fail_timeout=0;
  }
  server {
    listen 80;
    server_name 12.134.156.178; # 自分のIP
    # nginx so increasing this is generally safe...
    # path for static files
    root /var/www/rails/cheerfull/current/public;
    # page cache loading
    try_files $uri/index.html $uri @app_server;
    location / {
      # HTTP headers
      proxy_pass http://app_server;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;
    }
    # Rails error pages
    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /var/www/rails/cheerfull/current/public;
    }
    client_max_body_size 4G;
    keepalive_timeout 5;
  }
$ sudo service nginx restart

これで、デプロイ環境が整いました。
以前起動したpumaのプロセスはきっておきましょう。

複数サーバーへのデプロイ

multiconfig を使用します。

Gemfile
gem 'capistrano-multiconfig', '~> 3.1', require: false

Capfileのcapistrano/setupから変更。

Capfile
# require "capistrano/setup"
require 'capistrano/multiconfig'

config/deploy/production.rb から config/deploy/app1/production.rb に変更する。
以下のようにdeploy出来るようになる。

$ bundle exec cap app1:production deploy

違うサーバーにデプロイするときは同じように config/deploy/app2/production.rb を準備すればオーケー。

$ bundle exec cap app2:production deploy

これで違うサーバーにデプロイ出来る。

これまでと同様にec2サーバーをもう一度用意して2箇所にデプロイ出来るようにする。

ロードバランサー ELB

ロードバランサーをhttpsで運用したいときadmin@hoge.comのようなアドレスへのメールを受信可能のしないといけない。

以下でとりあえずzoneファイルのインポートまでする。
Amazon Route53 ネームサーバへの移行手順(お名前.comからの)

その後にこの記事にあるようにお名前.com側の設定をする。
お名前.com + Route53で独自ドメインのメールをGmailに転送する

メールの転送が出来ていることを確認する。
そして、ELBの指示に従って設定。
下記参考。
【初心者向け】ELBにSSL証明書をインストールする

そこまでしたら
Amazon Route53 ネームサーバへの移行手順(お名前.comからの)
の続きでELBとつなげる。

注意点は、ターゲットグループにトラフィックをルーティングするときのプロトコルをHTTPにすること。これでELBへはHTTPSでアクセス出来、それをアプリケーションではHTTPで扱うことが出来る。

また、以下のように nginxのサーバーネームにドメイン名を追加する必要がある。

server_name hogepoge.com 00.000.00.00 sakamichi-app-elb-000000000.ap-northeast-1.elb.amazonaws.com

CloudFront

Amazon CloudFront + ACM 独自ドメインで HTTPS (SSL) 配信設定メモ

CloudWatchとか

必要の応じて加筆。

続きを読む

EC2(スポット)インスタンス上でChainerMNのマルチノード分散学習

EC2(スポット)インスタンスでChainerMNを使う(マルチノード分散学習)

概要

  • EC2(スポット)インスタンスでChainerMNのマルチノード分散学習をする方法

    • 環境変数の設定方法
    • sshにStrictHostChecking noを追加
    • セキュリティグループの設定(VPC内からの全アクセスを許可)
  • EC2上でマルチノード分散学習する場合の注意点
    • p2.xlargeを使ってマルチノード分散学習は性能がでない
    • g3.4xlargeを利用すると良い
  • マルチノード学習した際の性能の簡単な評価
    • ImageNetの学習ではp2.8xlargeを使う時と同等かそれ以上のコストパフォーマンス

やりたかったこと

スポットインスタンスの価格が比較的安いGPU1個のインスタンス(p2.xlargeg3.4xlarge)を複数使って、ディープラーニングの学習を高速化させたかった。

学習を高速にする手段としては、マルチノードで分散する以外に、そもそも1台あたりのGPU数を増やす、という選択肢もある。
しかし、GPUを複数個積んでいるEC2のインスタンスはどれも高いし、スポットインスタンスで価格を抑えられないことがある。例えば、p2.8xlargeはオンデマンドインスタンスの場合、\$7.2/hかかる。スポットインスタンスの価格は、ここ1週間くらいはp2.8xlargeが\$2.5/h弱のようだが、ちょっと前は\$72/hに張り付いていた。
あるいは、自前で学習用計算機用意する手もあるが、GPU複数台積むマシンとなるとかなり高くつくことになる。個人の趣味の範囲内だと、電気代を抜いてもAWSを使うより高くなる可能性が高そう。

なので、p2.xlargeなどのスポットインスタンスでの値段が低め(〜\$0.3/h)で抑えられているインスタンスを複数利用して、学習を高速化させるという方針に至った。オンデマンドのp2.8xlargeと比べて、スポットインスタンスのp2.xlargeg3.4xlargeは1GPU当たりの値段で1/3ほどなので、マルチノードの分散学習の複雑さや効率の悪さはGPUの台数で補えるという目論見。

ChainerMNを使った分散学習 in AWS

環境の準備

ChainerMNのインストール

ChainerMNをインストールする方法自体は、もう多数の記事・情報があるので、詳細は省く。自分はここChainerMNのチュートリアルを参考にした。
やったことを列挙すると、以下の通り。

  • CUDA 8.0のインストール
  • cuDNN 6.0のインストール
  • NCCL 1.xのインストール
    • GitHubのページにはno longer maintainedとあるが、まだNCCL2は使えかった
  • OpenMPIのビルド・インストール
  • Chainer、ChainerMNのインストール

この作業はGPUを積んでいる中で安いインスタンス(p2.xlarge)を利用すると良い。

環境変数の設定

sshに非対話モードで入った時に、CPATHLD_LIBRARY_PATHが適切な値(具体的にはcudaのパスを含む)になっていないと学習スクリプトがうまく動かない。
/etc/bash.bashrcを以下のようにした。

/etc/bash.bashrc
export PATH=/usr/local/cuda-8.0/bin:${PATH}
export LD_LIBRARY_PATH=/usr/local/cuda-8.0/lib64:${LD_LIBRARY_PATH}
export CPATH=/usr/local/cuda-8.0/targets/x86_64-linux/include:${CPATH}

以下のコマンドを叩いた時、PATHLD_LIBRARY_PATHが適切に設定されていれば良い。

$ ssh localhost 'env'

sshの設定

マルチノード分散学習をする際、インタラクティブな操作なしに別ノードへsshで接続できる必要がある。したがって、鍵認証の設定をする。また、デフォルトでは最初に接続しようとすると、Are you sure you want to continue connecting (yes/no)?のメッセージが出て、yes/noの入力を求められるので、手間を考えるとこれも対処する必要がある。

まず、鍵認証の設定をする。

$ ssh-keygen #パスフレーズなし、~/.ssh/id_rsaに置く
$ cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

次に、.ssh/configを以下のとおりにして、yes/no入力をなくす

~/ssh/.config
Host *
    StrictHostKeyChecking no

どちらもセキュリティ上良いとは言えないが、最終的にはAWSのセキュリティグループで外部ネットワークからのインバウンドを遮断して運用すれば許容範囲と思っている。

ENAの有効化

必要なのかはわからないが、UbuntuはデフォルトではENAが有効になっていないようだったので、有効にする。最新の手順はここにあるので、これの通りに行う。
やるべきことは以下の3つ

  1. インスタンス上で、ENAのモジュールを追加
  2. インスタンスを停止
  3. ローカルからaws CLIでENAを有効化

AWS上のリソースの準備

1. VPC、サブネット、プレイスメントグループの準備

それぞれ適当な名前で準備する。VPCとサブネットは一度EC2インスタンスを起動すればついでにできるし、プレイスメントグループは、EC2のコンソールから、ネットワーク&セキュリティ → プレイスメントグループのページに行って作成すれば良い。
なお、プレイスメントグループはいるのかどうか分からないが、ネットワークの帯域幅をフルに出すには必要らしいので自分は作成した。

2. 学習ノード用のセキュリティグループの準備

セキュリティグループの準備も必要。インバウンドルールでは、「すべてのトラフィック・すべてのポート範囲へのVPCからのアクセス」を許可する。本来はもっと絞りこめると思うが、調べるのが面倒だったのでVPC内に全部公開した。
EC2コンソール上では、すべてのトラフィック すべて 0-65535 カスタム <VPCのCIDR>となっていれば良い。

3. (Optional) AMIの作成

必要はないが、ここまで終えた時点でAMIを作っておくと別のことをしたい時に無駄な出費を防げる。
AMIの作成方法は省略。

学習スクリプトなどの準備

最後に、学習用のスクリプト、データセットなどを準備する。

今回、自分はchainermnについているImageNetのサンプルを使った。
git clone --depth 1 https://github.com/chainer/chainermn.gitとして、chainermnのソースを落とすとchainermn/examples/imagenetの下にImageNetのサンプルがあるのでこれを用いる。また、自分の場合、models_v2/nin.pyをchainerのexamples/imagenet/nin.pyに置き換えないと動かなかったので、chainerのソースも落としてきてcpした。

次に、データセットを準備する。データセットの準備方法は、ここここなどが参考になる。

ここまで終えたら、インスタンスを止めてAMIを作成する。

実行方法(1ノード)

テストも兼ねて1ノードで学習を走らせる場合は、インスタンスを起動した後、sshでログインして、

$ mpiexec -n 1 python3 ~/chainermn/examples/imagenet/train_imagenet.py train.txt test.txt

などとすれば良い。ここで、train.txt、test.txtはそれぞれ準備したデータセットのパス

参考: ChainerMN チュートリアル

実行方法(マルチノード)

上で作成した学習スクリプトの入ったAMIを利用し、スポットインスタンスを適当に何個か立ち上げる。この時、VPC、プレイスメントグループ、セキュリティグループは上で準備したものを忘れず利用する。
なお、別にスポットインスタンスでなくてもいいが、費用を抑えて実験してみたいだけならスポットインスタンスの方が適していると思う。ただし、スポットインスタンスが突然中断するリスクを減らすため、高めに価格を設定しておくと安心。

また、多少値段は上がるが、p2.xlargeでなく、g3.4xlargeを使うと良い (理由は”注意点”で後述)。

以下では、2台のg3.4xlargeインスタンスを立ち上げ、それぞれのプライベートIPが172.31.41.13172.31.41.14となったとする。
まず、どちらか1台(以下では172.31.41.13の方とする)にsshでログインする。ログインしたら、以下の内容のホストファイルを~/hostfileに作成する(パスはどこでも良い)。

~/hostfile
172.31.41.13 cpu=1
172.31.41.14 cpu=1

(プライベートIPは、その時立ち上げたスポットインスタンスを見て適宜修正する必要あり。)

次に、以下のコマンドを叩くと、2台のマシンで分散学習される。

$ mpiexec -n 2 --hostfile ~/hostfile python3 ~/chainermn/examples/imagenet/train_imagenet.py train.txt test.txt

参考: ChainerMN チュートリアル

注意点(ネットワークの帯域幅を考慮する必要あり)

GPU付きインスタンスの中ではp2.xlargeが値段は安いのだが、ネットワークの帯域幅が小さく、性能が出なかった。iperfを使ってはかった結果では、1.44Gbps。一方、g3.4xlarge10Gbpsでるというスペックだし、実際iperfではかると10Gbpsでた(情報提供:https://twitter.com/grafi_tt/status/895274632177000449 )。

いくら安く分散学習させたいと言っても、p2.xlargeだと性能向上が見られなかったので、g3.4xlargeを使う方が良いと思う。

性能確認

学習が高速化できるのか確認するため簡単な性能測定をした。なお、どれも1回しか計測してないし、真面目に条件を揃えたわけではないので、数字は参考程度に。

以下のパターンで、ImageNetの学習にかかる時間を測定した。

  1. g3.4xlarge1台で、ChainerMNを利用
  2. g3.4xlarge複数台(2, 4, 6, 8, 10, 12)で、ChainerMNを利用
  3. p2.8xlarge(8GPU)で、ChainerMNを利用

結果

以下の通り。
分散すればちゃんと高速化されるし、p2.8xlargeと比べても安いまたは同等程度の値段でほぼ同じ性能を出せている。ただ、この辺は学習させるネットワークやデータセットによって色々異なるんだろうな。

表1: 1エポック当たりの時間

条件 1エポックあたりの平均時間 (sec)
g3.4xlarge*1 34.4
g3.4xlarge*2 21.8
g3.4xlarge*4 12.5
g3.4xlarge*6 9.2
g3.4xlarge*8 7.9
g3.4xlarge*10 6.3
g3.4xlarge*12 5.2
p2.8xlarge 7.9

ちゃんと分散するにつれて短い時間で学習できている。


表2: 値段 – 総実行時間

条件 値段 (\$/h) 総実行時間 (sec)
g3.4xlarge*1 0.3 344.3
g3.4xlarge*2 0.6 217.8
g3.4xlarge*4 1.2 125.2
g3.4xlarge*6 1.8 92.4
g3.4xlarge*8 2.4 79.2
g3.4xlarge*10 3.0 63.0
g3.4xlarge*12 3.6 51.7
p2.8xlarge 7.2(オンデマンド) / 2.5(スポットインスタンス利用時) 79.1

備考:g3.4xlargeのスポットインスタンスの値段は\$0.3/hとして計算

p2.8xlargeをオンデマンドで利用する場合に比べると、より安く高速な学習ができる。p2.8xlargeがスポットインスタンスの場合と比べても、ほぼ同等の性能が今回の例では出た。


グラフ1: epoch – elapsed_time
graph1.png


グラフ2: epoch-validation/main/accuracy
graph2.png

epochが少なすぎてわかりやすいデータにならなかったが、分散させるほど同エポックでの精度は悪化する傾向にあるらしい。直感的にもそんな気はする。とはいえ、マルチノードの場合とp2.8xlargeでノード内で分散した場合では大きな精度の差は見つけられない。分散学習するなら、エポックを大きめに設定する必要があるようだが、それはマルチノード分散学習の問題というより、現在のChainerMN全体の問題の可能性が高い。


その他備考
分散学習では、最初の1回のmpiexecは時間がかかるらしい。上記計測は、2回目のmpiexecで行っている。原因は、ノード間の接続を確立する時間が追加されているからではないかと思うが、詳細は不明。ただし、学習時間が長くなるにつれて、その時間は無視できるものになると思われる。

まとめとか

少なくともImageNetでは、マルチノードの分散学習でも相当の学習時間の短縮が見込める。また、8/7からChainerMNを初めて5日でここまでできたので、非常に難しい作業が必要というわけでもない。
そのため、AWS上でのディープラーニング学習を高速化させたい時、選択肢に入れる価値はあると思う。最初に書いたような、複数GPUを積んだスポットインスタンスが高い時にも使えるし、あるいはp2.8xlargeを複数使ってさらに高速化する、という使い方もマルチノードの分散学習はできるはず。

一方で、データセットが増えた時どうなるのか、モデルが複雑になった時どうなるのか、などは調べてない。実際に使ってみるとたいして高速化されなかった、みたいなケースはありそう。

要改善点

とりあえずテストするだけなら上記手順でもできたが、実際にディープラーニングを利用するプロジェクトに組み込むとなると以下の点を改善しないといけない。

学習スクリプトの実行方法

本来は、aws CLIとかSDKからスポットインスタンスを立ち上げて、自動で学習を回したい(ここみたいに)。
そのためには、UserDataのスクリプトで学習スクリプトを実行する必要があるが、以下の点に注意が必要。

  1. mpiexecをするインスタンスの決定方法
  2. ホストファイルの作成方法
  3. すべてのインスタンスが立ち上がるまでの待ち合わせ処理

1については、特定のタグを全インスタンスに付けておき、aws ec2 describe-instancesで全インスタンスのプライベートIPを取得、辞書順最小のインスタンスでmpiexecすれば解決しそう。
2は、describe-instancesした時に全部のプライベートIPがわかるんだからホストファイルもついでに生成できる。
3は、ポーリングなりなんなりでやればできるはず。この時、ついでに学習パラメータの環境変数への展開やS3からデータセットのダウンロードも待ち合わせ処理すると色々便利そう。

中断時の対処

スポットインスタンスなので、たまに強制終了させられることがある。

  1. 定期的なS3へのスナップショットアップロード(systemd-timer)
  2. 1台でも終了したら全台終了して無駄な出費の削減
  3. 学習開始時にスナップショットがあればそれを読み込み

の3つの対処が必要。

続きを読む

dynamodb-autoscaling検証

概要

先日のアップデートでdynamodbでautoscalingの機能が実装されました。
https://aws.amazon.com/jp/blogs/news/new-auto-scaling-for-amazon-dynamodb/

NoSQLデータベースのベンチマークツールであるycsbを用いてdynamodb-autoscalingの動作を検証できます。
今回は新規に追加された項目「ターゲット使用率」がどのような影響を及ぼすかについて検証します。

環境準備

環境準備に伴い、下記を参考にさせていただきました。

http://qiita.com/noralife/items/35a956f682b1aca475f6
http://dev.classmethod.jp/cloud/aws/attack_to_dynamodb_using_ycsb/
http://imai-factory.hatenablog.com/entry/2013/04/05/010858

amazon linux version

[ec2-user@dynamo-ec2 ycsb-0.12.0]$ cat /etc/system-release
Amazon Linux AMI release 2017.03

openjdk-develインストール

$ sudo yum -y install java-1.7.0-openjdk-devel

ycsb導入

・ダウンロード
$ wget https://github.com/brianfrankcooper/YCSB/releases/download/0.12.0/ycsb-0.12.0.tar.gz

・展開、移動
$ tar xfz ycsb-0.12.0.tar.gz
$ cd ycsb-0.12.0/

・ファイル用のディレクトリ準備
$ mkdir -p dynamodb/conf/

・ベンチマーク対象テーブル(testtable)のプライマリキーを確認しておく
$ aws dynamodb describe-table --table-name testtable | jq -r '.Table.AttributeDefinitions[].AttributeName'
name

YCSB概要

テストデータをdynamodbに読み込ませて

./bin/ycsb.sh load dynamodb -P workloads/dyamodb -P dynamodb/conf/dynamodb.properties

テストデータを使って負荷をかける。

./bin/ycsb.sh run dynamodb -P workloads/dyamodb -P dynamodb/conf/dynamodb.properties

設定ファイルは下記の3つ

■dynamodb/conf/dynamodb.properties
対象のDynamoDBの情報を設定。変更する部分はプライマリキーくらいかと。
クレデンシャル情報が記載されたファイルもこの中で指定する。

$ cat dynamodb/conf/dynamodb.properties
dynamodb.awsCredentialsFile = dynamodb/conf/AWSCredentials.properties
dynamodb.primaryKey = name
dynamodb.endpoint = http://dynamodb.ap-northeast-1.amazonaws.com

■dynamodb/conf/AWSCredentials.properties
クレデンシャル情報を記載。

$ cat dynamodb/conf/AWSCredentials.properties
accessKey = XXXXXXXXXXXXXXXXXXXX
secretKey = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

■workloads/(任意のファイル名)
投入するデータ、実施するベンチマークのステータスを設定。
値はテンプレートworkloads/workload_templateを参考。
※operationcountは1,000,000以上が良いかと。10,000で実行したらスケーリングする前に終わってしまいました……

$ cat workloads/dyamodb
workload=com.yahoo.ycsb.workloads.CoreWorkload #デフォルト

recordcount=1000 #テーブルにセットするレコード数
operationcount=2000000 #load時のオペレーション数

insertstart=0 #デフォルト
fieldcount=10 #フィールド数、デフォルト
fieldlength=100 #レコードの長さ、デフォルト

readallfields=true #デフォルト
writeallfields=false #デフォルト

table=testtable #テーブル名

fieldlengthdistribution=constant #デフォルト

#load時のオペレーション比率(read80%, update15%, insert5%)
readproportion=0.8
updateproportion=0.15
insertproportion=0.05

#以下テンプレートの値のまま設定
readmodifywriteproportion=0
scanproportion=0
maxscanlength=1000
scanlengthdistribution=uniform
insertorder=hashed
requestdistribution=zipfian
hotspotdatafraction=0.2
hotspotopnfraction=0.8

measurementtype=histogram
histogram.buckets=1000
timeseries.granularity=1000

検証開始

初期のdynamodbキャパシティ設定

1000レコード書き込むので、書き込み容量ユニット(以下WCU)を10確保。
WCU1だとスロットルが発生して時間がかかります……。

初期設定.PNG

テーブルにテストデータを読み込ませる

1回だけ。10分ほどかかります。

$ ./bin/ycsb.sh load dynamodb -P workloads/dyamodb -P dynamodb/conf/dynamodb.properties

auto-scaling設定

いよいよauto-scaling設定です。
RCU/WCUを下げるオペレーションは最大9回/日になっていますが条件があります。
↓の記事を参考にさせていただきました。
http://qiita.com/mokrai/items/6864b8a723a2728565fc
検証する場合は無駄に下げないように初期値を考慮しましょう。

as1.PNG

・ターゲット使用率
スケーリングの基準になる値です。以降で検証します。

・IAMロール
[新しいロール]を選択すれば問題ありません。
下記の管理ポリシーが付与されたロールが作成されます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:DescribeTable",
                "dynamodb:UpdateTable",
                "cloudwatch:PutMetricAlarm",
                "cloudwatch:DescribeAlarms",
                "cloudwatch:GetMetricStatistics",
                "cloudwatch:SetAlarmState",
                "cloudwatch:DeleteAlarms"
            ],
            "Resource": "*"
        }
    ]
}

ロールからもわかるように、auto-scalingはcloudwatchの値を評価の基準としています。
auto-scaling設定中は動的なcloudwatchメトリクスが作成され、auto-scaling設定解除後に削除されます。

ターゲット使用率70%の場合

下記設定でcloudwatchの推移を確認します。

auto-scaling設定 RCU WCU
ターゲット使用率(%) 70 70
min(ユニット) 10 10
max(ユニット) 10000 10000

キャパシティの推移

推移は下記の通り

RCU
70rcu.PNG

WCU
70wcu.PNG

ターゲット使用率20%の場合

下記設定でcloudwatchの推移を確認します。

auto-scaling設定 RCU WCU
ターゲット使用率(%) 20 20
min(ユニット) 10 10
max(ユニット) 10000 10000

20rcu.PNG

20wcu.PNG

終わりに

負荷のかけ方が一定の場合はキャパシティーの増減が安定したら変化しないので、
そのあたりの調整が必要だと感じました。
cloudwatchメトリクスが動的な値で作成され、それらが基準になってスケーリングされています。
サポートに確認したところ、閾値を超えてのキャパシティ設定もできるとのことですが、その場合は次のタイミングでスケーリングされてしまうとのことです(未検証)。

続きを読む

AWS EC2にLAMP環境を構築するまで

AWS EC2にLAMP環境を構築したときのメモです。
DBも、RDSを使用せずにEC2に入れてます。

作りたい環境

  • Amazon Linux
  • Apache2.4
  • MySQL 5.6
  • PHP7

前提

  • EC2インスタンスが起動している
  • ターミナルからSSHでログインできる

手順

必要なものをインストール

ログイン

~ $ ssh -i .ssh/your_key.pem ec2-user@{インスタンスのIP}

yumアップデート

[ec2-user@ip-***** ~]$ sudo yum update -y

Apache、MySQL、PHP、MySQLドライバのインストール

[ec2-user@ip-***** ~]$ sudo yum install -y httpd24 php70 mysql56-server php70-mysqlnd

Apache、PHP、MySQLのバージョン確認

# Apache
[ec2-user@ip-***** ~]$ httpd -v
Server version: Apache/2.4.25 (Amazon)
Server built:   Jan 19 2017 16:55:49

# PHP
[ec2-user@ip-***** ~]$ php -v
PHP 7.0.16 (cli) (built: Mar  6 2017 19:45:42) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies

# MySQL
[ec2-user@ip-***** ~]$ sudo service mysqld start
...
...
...
Starting mysqld:                                           [  OK  ]

[ec2-user@ip-***** ~]$ mysql --version
mysql  Ver 14.14 Distrib 5.6.36, for Linux (x86_64) using  EditLine wrapper

Apacheの設定

起動・スタートページの表示

# サービス開始 (起動はするが ServerNameを設定してください と出る(一旦スルー))
[ec2-user@ip-***** ~]$ sudo service httpd start
Starting httpd: AH00557: httpd: apr_sockaddr_info_get() failed for ip-******
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1. Set the 'ServerName' directive globally to suppress this message
                                                           [  OK  ]
#ブラウザで EC2のIPアドレスにアクセスして、Apaceのスタートページが表示されることを確認する

# ドキュメントルートの確認
[ec2-user@ip-***** ~]$ sudo cat /etc/httpd/conf/httpd.conf | less

# 「/DocumentRoot」 で検索
DocumentRoot "/var/www/html"

# 起動設定
[ec2-user@ip-***** ~]$ sudo chkconfig httpd on

# 確認 (2, 3, 4, 5がONになっていればOK)
[ec2-user@ip-***** ~]$ chkconfig
httpd           0:off   1:off   2:on    3:on    4:on    5:on    6:off

グループ設定

# ec2-user を apache グループに追加
[ec2-user@ip-***** ~]$ sudo usermod -a -G apache ec2-user

# 一旦ログアウトして再度ログイン
[ec2-user@ip-***** ~]$ groups
ec2-user wheel apache

# /var/www以下の権限確認
[ec2-user@ip-***** ~]$ ls -l /var/www/
total 20
drwxr-xr-x 2 root root 4096 Jan 19 16:56 cgi-bin
drwxr-xr-x 3 root root 4096 Jun 26 06:18 error
drwxr-xr-x 2 root root 4096 Jan 19 16:56 html
drwxr-xr-x 3 root root 4096 Jun 26 06:18 icons
drwxr-xr-x 2 root root 4096 Jun 26 06:18 noindex

# apacheグループに /var/www 所有・書き込み権限付与
[ec2-user@ip-***** ~]$ sudo chown -R ec2-user:apache /var/www
[ec2-user@ip-***** ~]$ sudo chmod 2775 /var/www/

# /var/www 以下のディレクトリの権限変更
[ec2-user@ip-***** ~]$ find /var/www -type d -exec sudo chmod 2775 {} ;

# /var/www 以下のファイルの権限変更
[ec2-user@ip-***** ~]$ find /var/www -type f -exec sudo chmod 0664 {} ;

httpd.confの設定

/etc/httpd/conf/httpd.conf.conf
# サーバ管理者メールアドレス 変更 87行目あたり
ServerAdmin your_email@example.com

# サーバ名 (ドメイン設定してから)

# クロスサイトトレーシング対策 追記
TraceEnable Off

# ディレクトリ一覧を非表示 変更 145行目あたり
Options -Indexes FollowSymLinks

# cgi-bin使用しない 248〜260行目あたり
#    ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"

#<Directory "/var/www/cgi-bin">
#    AllowOverride None
#    Options None
#    Require all granted
#</Directory>

security.confの設定(新規作成)

/etc/httpd/conf.d/security.conf
ServerTokens Prod
Header unset X-Powered-By
# httpoxy 対策
RequestHeader unset Proxy
# クリックジャッキング対策
Header append X-Frame-Options SAMEORIGIN
# XSS対策
Header set X-XSS-Protection "1; mode=block"
Header set X-Content-Type-Options nosniff
# XST対策
TraceEnable Off

<Directory /var/www/html>
    # .htaccess の有効化
    AllowOverride All
    # ファイル一覧出力の禁止
    Options -Indexes
</Directory>

Welcomeページ非表示

/etc/httpd/conf.d/welcome.conf 中身をコメントアウト

Apache再起動

[ec2-user@ip-***** ~]$ sudo service httpd restart

phpinfoの設置

[ec2-user@ip-***** ~]$ vi /var/www/html/phpinfo.php
<?php
    echo phpinfo();
?>
# ブラウザで IPアドレス/phpinfo.php にアクセス
# 確認後、phpinfo.phpを削除
[ec2-user@ip-***** ~]$ rm /var/www/html/phpinfo.php

PHP設定

[ec2-user@ip-***** ~]$ sudo cp /etc/php.ini /etc/php.ini.org
/etc/php.ini
# タイムゾーン設定
- ;date.timezone =
+ date.timezone = Asia/Tokyo

# 日本語設定
- ;mbstring.internal_encoding =
+ mbstring.internal_encoding = UTF-8

- ;mbstring.language = Japanese
+ mbstring.language = Japanese

- ;mbstring.http_input =
+ mbstring.http_input = auto

- ;bstring.detect_order = auto
+ bstring.detect_order = auto

MySQLの設定

起動設定

[ec2-user@ip-***** ~]$ sudo chkconfig mysqld on

初期設定

[ec2-user@ip-***** ~]$ sudo mysql_secure_installation
...
...
Enter current password for root (enter for none):
# Enterキー

Set root password? [Y/n]
# rootのパスワードを変更するか。
# Y

New password:
# 任意のパスワード入力

Re-enter new password:
# もう一度入力

Password updated successfully!

Remove anonymous users? [Y/n]
# 匿名ユーザーを削除するかどうか。
# Y

Disallow root login remotely? [Y/n]
# rootユーザーのリモートホストからのログインを無効化するかどうか。
# Y

Remove test database and access to it? [Y/n]
# testデータベースを削除するか。
# Y

Reload privilege tables now? [Y/n]
# これらの変更を即座に反映するか。
# Y

...
Thanks for using MySQL!

Cleaning up...

mysqlへログイン

[ec2-user@ip-***** ~]$ mysql -u root -p
Enter password:
# 初期設定で設定したパスワード

Welcome to the MySQL monitor.  Commands end with ; or g.
Your MySQL connection id is 14
Server version: 5.6.36 MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
...
mysql>

アプリケーション用データベース追加

# 現在の状態を確認
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
+--------------------+

# データベース「test_app_db」を追加
mysql> create database test_app_db character set utf8;

# 確認
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| test_app_db  |
+--------------------+

アプリケーションユーザ追加

# 現在のユーザ設定確認
mysql> select Host, User, Password  from mysql.user;
+-----------+------+-------------------------------------------+
| Host      | User | Password                                  |
+-----------+------+-------------------------------------------+
| localhost | root | *1234567890ABCDEFGHIJ0987654321KLMNOPQRST|
| 127.0.0.1 | root | *1234567890ABCDEFGHIJ0987654321KLMNOPQRST|
| ::1       | root | *1234567890ABCDEFGHIJ0987654321KLMNOPQRST|
+-----------+------+-------------------------------------------+

# ユーザ「app_user」を追加 (ユーザ名は16文字以内)
mysql> create user 'app_user'@'localhost' identified by  '任意のパスワード';

# データベース「test_app_db」にのみアクセス可能
# 権限は、ALL
mysql> grant ALL on test_app_db.* to 'app_user'@'localhost';

# 設定の反映
mysql> flush privileges;

# 権限の確認
mysql> show grants for 'app_user'@'localhost';
+--------------------------------------------------------------------------------------------------------------------+
| Grants for app_user@localhost                                                                                   |
+--------------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'app_user'@'localhost' IDENTIFIED BY PASSWORD '*ABCDEFGHIJ0987654321KLMNOPQRST1234567890' |
| GRANT ALL PRIVILEGES ON `test_app_db`.* TO 'app_user'@'localhost'                                         |
+--------------------------------------------------------------------------------------------------------------------+

#  ログアウト
mysql> quit
Bye

# アプリケーションユーザでログイン
[ec2-user@ip-***** ~]$ mysql -u app_user -p

# データベースの確認
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| test_app_db  |
+--------------------+

mysql> quit

phpMyAdminのインストール

# 「EPEL」リポジトリ有効化
[ec2-user@ip-***** ~]$ sudo yum-config-manager --enable epel

# phpMyAdminインストール
[ec2-user@ip-***** ~]$ sudo yum install -y phpMyAdmin

# エラーになった
Error: php70-common conflicts with php-common-5.3.29-1.8.amzn1.x86_64
Error: php56-common conflicts with php-common-5.3.29-1.8.amzn1.x86_64
Error: php56-process conflicts with php-process-5.3.29-1.8.amzn1.x86_64
 You could try using --skip-broken to work around the problem
 You could try running: rpm -Va --nofiles --nodigest

# 手動でインストール
[ec2-user@ip-***** ~]$ cd /var/www/html
[ec2-user@ip-*****  html]$ sudo wget https://files.phpmyadmin.net/phpMyAdmin/4.6.6/phpMyAdmin-4.6.6-all-languages.tar.gz
[ec2-user@ip-*****  html]$ sudo tar xzvf phpMyAdmin-4.6.6-all-languages.tar.gz
[ec2-user@ip-*****  html]$ sudo mv phpMyAdmin-4.6.6-all-languages phpMyAdmin
[ec2-user@ip-*****  html]$ sudo rm phpMyAdmin-4.6.6-all-languages.tar.gz
[ec2-user@ip-*****  html]$ cd phpMyAdmin
[ec2-user@ip-*****  phpMyAdmin]$ sudo cp config.sample.inc.php config.inc.php

# IPアドレス/phpMyAdmin でアクセス
# PHPの「mbstring」拡張が無いというエラーが出るのでインストール
[ec2-user@ip-***** ~]$ sudo yum install -y php70-mbstring

# Apace再起動
[ec2-user@ip-***** ~]$ sudo service httpd restart

# .htaccessでphpMyAdminへのアクセス制限
[ec2-user@ip-*****  phpMyAdmin]$ sudo vi .htaccess

order deny,allow
deny from all
allow from **.***.***.***

# ブラウザで [IPアドレス]/phpMyAdmin にアクセスしてログインできるか確認

phpMyAdminの環境保護領域設定

ブラウザでアクセスした際、画面下に「phpMyAdmin 環境保管領域が完全に設定されていないため、いくつかの拡張機能が無効になっています。」というメッセージが表示されていた場合、初期設定が必要。


# rootアカウントでログインする
# phpMyAdminのディレクトリ内にある create_tables.sql を流す
# /phpMyAdmin/sql/create_tables.sql

# アプリケーションユーザに phpMyAdminテーブルへのアクセス権を付与する
[ec2-user@ip-***** ~]$ mysql -u root -p

# 現在の権限確認
mysql> show grants for 'app_user'@'localhost';
+--------------------------------------------------------------------------------------------------------------------+
| Grants for app_user@localhost                                                                                   |
+--------------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'app_user'@'localhost' IDENTIFIED BY PASSWORD '*ABCDEFGHIJ0987654321KLMNOPQRST1234567890' |
| GRANT ALL PRIVILEGES ON `test_app_db`.* TO 'app_user'@'localhost'                                         |
+--------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.00 sec)

# select, insert, update ,deleteの権限を付与
mysql> grant select, insert, update, delete on phpmyadmin.* to 'app_user'@'localhost';

# 設定を反映
mysql> flush privileges;

# 確認
mysql> show grants for 'app_user'@'localhost';
+--------------------------------------------------------------------------------------------------------------------+
| Grants for app_user@localhost                                                                                   |
+--------------------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'app_user'@'localhost' IDENTIFIED BY PASSWORD '*ABCDEFGHIJ0987654321KLMNOPQRST1234567890' |
| GRANT SELECT, INSERT, UPDATE, DELETE ON `phpmyadmin`.* TO 'app_user'@'localhost'                                |
| GRANT ALL PRIVILEGES ON `test_app_db`.* TO 'app_user'@'localhost'                                         |
+--------------------------------------------------------------------------------------------------------------------+
3 rows in set (0.00 sec)

# config.inc.php の編集
[ec2-user@ip-***** ~]$ sudo vi /var/www/html/phpMyAdmin/config.inc.php
# 以下の記述のコメントアウトを解除する
/* Storage database and tables */
// $cfg['Servers'][$i]['pmadb'] = 'phpmyadmin';
// $cfg['Servers'][$i]['bookmarktable'] = 'pma__bookmark';
// $cfg['Servers'][$i]['relation'] = 'pma__relation';
// $cfg['Servers'][$i]['table_info'] = 'pma__table_info';
// $cfg['Servers'][$i]['table_coords'] = 'pma__table_coords';
// $cfg['Servers'][$i]['pdf_pages'] = 'pma__pdf_pages';
// $cfg['Servers'][$i]['column_info'] = 'pma__column_info';
// $cfg['Servers'][$i]['history'] = 'pma__history';
// $cfg['Servers'][$i]['table_uiprefs'] = 'pma__table_uiprefs';
// $cfg['Servers'][$i]['tracking'] = 'pma__tracking';
// $cfg['Servers'][$i]['userconfig'] = 'pma__userconfig';
// $cfg['Servers'][$i]['recent'] = 'pma__recent';
// $cfg['Servers'][$i]['favorite'] = 'pma__favorite';
// $cfg['Servers'][$i]['users'] = 'pma__users';
// $cfg['Servers'][$i]['usergroups'] = 'pma__usergroups';
// $cfg['Servers'][$i]['navigationhiding'] = 'pma__navigationhiding';
// $cfg['Servers'][$i]['savedsearches'] = 'pma__savedsearches';
// $cfg['Servers'][$i]['central_columns'] = 'pma__central_columns';
// $cfg['Servers'][$i]['designer_settings'] = 'pma__designer_settings';
// $cfg['Servers'][$i]['export_templates'] = 'pma__export_templates';

設定ファイル用パスフレーズの設定

ログイン時に「設定ファイルに、暗号化 (blowfish_secret) 用の非公開パスフレーズの設定を必要とするようになりました。」というメッセージが表示されている場合、設定ファイルにパスフレーズを追記する必要がある。


[ec2-user@ip-***** ~]$ sudo vi /var/www/html/phpMyAdmin/config.inc.php

# 下記の部分に任意の文字列(32文字以上)を入力
/**
 * This is needed for cookie based authentication to encrypt password in
 * cookie. Needs to be 32 chars long.
 */
$cfg['blowfish_secret'] = ''; /* YOU MUST FILL IN THIS FOR COOKIE AUTH! */

パスワード自動生成

その他

時刻設定

[ec2-user@ip-***** ~]$ sudo vi /etc/sysconfig/clock
ZONE="Asia/Tokyo"
UTC=false

[ec2-user@ip-***** ~]$ sudo cp /usr/share/zoneinfo/Japan /etc/localtime
[ec2-user@ip-***** ~]$ sudo /etc/init.d/crond restart
[ec2-user@ip-***** ~]$ date
Tue Jun 27 10:20:25 JST 2017

git

[ec2-user@ip-***** ~]$ sudo yum install -y git
[ec2-user@ip-***** ~]$ git --version
git version 2.7.5

composer

[ec2-user@ip-***** ~]$ curl -sS https://getcomposer.org/installer | php
All settings correct for using Composer
Downloading...

Composer (version 1.4.2) successfully installed to: /home/ec2-user/composer.phar
Use it: php composer.phar

[ec2-user@ip-***** ~]$ sudo mv composer.phar /usr/local/bin/composer

[ec2-user@ip-***** ~]$ composer
   ______
  / ____/___  ____ ___  ____  ____  ________  _____
 / /   / __ / __ `__ / __ / __ / ___/ _ / ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
____/____/_/ /_/ /_/ .___/____/____/___/_/
                    /_/
Composer version 1.4.2 2017-05-17 08:17:52

参考URL

続きを読む