コピペコードで快適生活

明日使えるソースを自分のために

CentOS6系にMySQL5.7を一撃インストール

CentOS6系にMySQL5.7をインストールした時のメモ書き。

インストール時に発行される初期パスワードをシェルで取り出してログイン。
その後パスワードを仮のものに変更(これを一度やらないと色々操作できない)。
パスワード制約をゆるくして、再度わかりやすいワードで設定し直しました。

function install {
  echo installing $1
  shift
  yum -y install "$@" >/dev/null 2>&1
}
yum install -y https://dev.mysql.com/get/mysql57-community-release-el6-11.noarch.rpm >/dev/null 2>&1
install "MySQL" mysql mysql-server mysql-devel
chkconfig --add mysqld
chkconfig --level 345 mysqld  on

echo "Start and Initialize MySQL"
service mysqld start >/dev/null 2>&1

mpw=$(cat /var/log/mysqld.log | grep "A temporary password is generated for root@localhost" | awk '{print $NF}')
mysql -uroot -p$mpw --connect-expired-password <<SQL
-- CONFIG PASSWORD POLICY --
SET PASSWORD FOR root@localhost=password('passwordPASSWORD@999');
SET GLOBAL validate_password_length=4;
SET GLOBAL validate_password_policy=LOW;
-- SET ROOT PASSWORD --
SET PASSWORD FOR 'root'@'localhost' = PASSWORD('root');
-- REMOVE ANONYMOUS USERS --
DELETE FROM mysql.user WHERE User='';
-- REMOVE REMOTE ROOT --
DELETE FROM mysql.user
WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
-- REMOVE TEST DATABASE --
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
-- RELOAD PRIVILEGE TABLES --
FLUSH PRIVILEGES;
CREATE USER 'vagrant'@'localhost' IDENTIFIED BY 'vagrant';
GRANT ALL PRIVILEGES ON *.* to 'vagrant'@'localhost';
SQL

作成したユーザは下記になります。

ID root@localhost
PW root

ID vagrant@localhost
PW vagrant

リポジトリの参照場所
https://dev.mysql.com/downloads/repo/yum/

CentOS6系にRed5サーバを構築する

Webプレイヤーの動作検証のためrtmpのストリームが必要になったので構築してみました。

インストー

cd /usr/local/src
wget https://github.com/Red5/red5-server/releases/download/v1.0.9-RELEASE/red5-server-1.0.9-RELEASE.tar.gz
tar -xzvf red5-server-1.0.9-RELEASE.tar.gz
mkdir -p /usr/local/app/
mv red5-server /usr/local/app/.
cd /usr/local/app/red5-server/

localhost以外で使う場合はアクセス制限の解除をする

vim /usr/local/app/red5-server/webapps/installer/WEB-INF/red5-web.properties

<<<<< webapp.virtualHosts=localhost, localhost:5080
>>>>> webapp.virtualHosts=localhost, localhost:5080, 192.168.11.110, 192.168.11.110:5080

起動スクリプト作成

vim /etc/init.d/red5-server

red5-server

#!/bin/bash
# For RedHat and cousins:
# chkconfig: 2345 85 85
# description: Red5 flash streaming server
# processname: red5-server

PROG=red5
RED5_HOME=/usr/local/app/red5-server
DAEMON=$RED5_HOME/$PROG.sh
PIDFILE=/var/run/$PROG.pid

# Source function library
. /etc/rc.d/init.d/functions

[ -r /etc/sysconfig/red5 ] && . /etc/sysconfig/red5

RETVAL=0

case "$1" in
  start)
  echo -n $"Starting $PROG: "
  cd $RED5_HOME
  $DAEMON >/dev/null 2>/dev/null &
  RETVAL=$?
  if [ $RETVAL -eq 0 ]; then
    echo $! > $PIDFILE
    touch /var/lock/subsys/$PROG
  fi
  [ $RETVAL -eq 0 ] && success $"$PROG startup" || failure $"$PROG startup"
  echo
  ;;
  stop)
  echo -n $"Shutting down $PROG: "
  killproc -p $PIDFILE
  RETVAL=$?
  echo
  [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$PROG
  ;;
  restart)
  $0 stop
  $0 start
  ;;
  status)
  status $PROG -p $PIDFILE
  RETVAL=$?
  ;;
  *)
  echo $"Usage: $0 {start|stop|restart|status}"
  RETVAL=1
esac

exit $RETVAL

起動設定

chmod 755 /etc/init.d/red5-server
chkconfig --add red5-server
service red5-server start

続きはこちらをご参照で。。
http://centos.server-manual.com/centos6_red5.html

参考にさせていただきました。
http://centos.server-manual.com/centos6_red5.html
http://www.84kure.com/blog/2016/02/03/red5-%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB-centos-7/
https://stackoverflow.com/questions/35332121/error-in-red5-net-status-netconnection-connect-failed#comment58416312_35349632
http://qiita.com/alingogo/items/1176a7d42b9c0b36515c

unicornのlogrotate設定サンプル

/etc/logrotate.d 配下に下記を置く。
日次ローテート + 90日間保存で設定しています。
ローテートしたログは圧縮するが、直近の1世代分はそのまま

/var/www/app/shared/log/*.log {
  daily
  missingok
  rotate 90
  dateext

  compress
  delaycompress

  lastaction
    pid=/var/www/app/shared/tmp/pids/unicorn.pid
    test -s $pid && kill -USR1 "$(cat $pid)"
  endscript
}

※メモ
Unicornには、USR1シグナルを送ると、ログファイルを開きなおす機能が備わっている。
そのため、現在のログをリネームした後、USR1シグナルを送信してログをローテートする。

serviceコマンドでunicorn起動するための設定サンプル

下記ファイル を /etc/init.d/ に配置する。

#!/bin/sh
# chkconfig: 345 99 01
# description: unicorn as Rails app server

SERVICE="unicorn"
ENV="production"

RAILS_ROOT="/var/www/app/current"
CONFIG=$RAILS_ROOT"/config/unicorn/"$ENV".rb"
PID_FILE=$RAILS_ROOT"/tmp/pids/unicorn.pid"

start() {
    START_CMD="cd $RAILS_ROOT && (RAILS_ENV=$ENV /usr/bin/env bundle exec unicorn -c $CONFIG -E $ENV -D)"
    su -l $USER -c "$START_CMD" &
    echo "service $SERVICE [start]"
}

stop() {
    STOP_CMD="cd $RAILS_ROOT && /usr/bin/env kill -s QUIT `cat $PID_FILE`"
    su -l $USER -c "$STOP_CMD" &
    echo "service $SERVICE [stop]"
}

status() {
    PID=`pgrep -f $CONFIG | wc -l`
    if [ $PID -eq 0 ]; then
        echo "$SERVICE stop"
    else
        echo "running $SERVICE ..."
    fi
}


case $1 in
start)
    start
    ;;
stop)
    stop
    ;;
restart)
    stop
    start
    ;;
status)
    status
    ;;
*)
    echo "Usage: $SERVICE [start|stop|restart|status]"
    ;;
esac
exit 0

下記コマンドで service に登録する

# /etc/init.d
# sudo chkconfig --add unicorn

使い方

# sudo service unicorn [start|stop|restart|status]

webpack+reactの環境構築メモ

npm install

$ cd my_project
$ npm init
$ npm install webpack -g
$ npm install --save react react-dom
$ npm install --save-dev webpack webpack-dev-server
$ npm install --save-dev babel-loader babel-core babel-preset-react babel-preset-es2015

webpack.config.js

const webpack = require("webpack");

module.exports = {
  // minify
  // plugins: [
  //   new webpack.optimize.UglifyJsPlugin()
  // ],

  context: __dirname + '/src',

  entry: {
    js: './js/index.js'
  },

  output: {
    path: __dirname + '/dist',
    filename: './js/app.js'
  },

  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        query: {
          presets: ['es2015']
        }
      },
      {
        test: /\.jsx$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        query: {
          presets: ['es2015', 'react']
        }
      }
    ]
  },

  devServer: {
    // contentBase: 'dist',
    host: '127.0.0.1',
    port: 8080
  },
};

ビルド

webpack

開発サーバ起動
package.jsonのscriptsに

 "start": "webpack-dev-server"

追加して

npm run start

参考
http://uraway.hatenablog.com/entry/2015/12/25/Webpack_%2B_React_%2B_ES6%E3%81%AE%E6%9C%80%E5%B0%8F%E6%A7%8B%E6%88%90%E3%82%92%E8%80%83%E3%81%88%E3%81%A6%E3%81%BF%E3%82%8B%E3%80%82

http://dackdive.hateblo.jp/entry/2016/04/13/123000#webpackconfigjs-の例

http://dackdive.hateblo.jp/entry/2016/05/07/183335

Elasticsearchことはじめ

仕事でElasticsearch使う必要があったので、GettingStarted!

これはなに?

分散型RESTful検索/分析エンジン
https://www.elastic.co/jp/products/elasticsearch

特徴

  • 速い
  • スケールが容易(クラスタ構成)
  • RESTful APIで全ての入出力が可能

検索時は条件との完全一致ではなく"関連性が高いもの"を返す
http://gihyo.jp/dev/serial/01/js-foundation/0008

RDBとの用語対応表

ElasticSearch
Index > MappingType > Document

RDB
database > Table > record

インストール

rpm -ivh https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.2.1.rpm
chkconfig --add elasticsearch
service elasticsearch start

基本操作

https://www.elastic.co/guide/en/elasticsearch/reference/5.2/getting-started.html

起動確認
curl -X GET http://localhost:9200
{
  "name" : "Ovee1U6",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "_-CFvUxgRFy_4Q4lwKWMjw",
  "version" : {
    "number" : "5.2.1",
    "build_hash" : "db0d481",
    "build_date" : "2017-02-09T22:05:32.386Z",
    "build_snapshot" : false,
    "lucene_version" : "6.4.1"
  },
  "tagline" : "You Know, for Search"
}
インデックスの登録
curl -X PUT http://localhost:9200/customer?pretty
{
  "acknowledged" : true,
  "shards_acknowledged" : true
}
インデックス一覧
curl -X GET http://localhost:9200/_cat/indices?v
health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   customer nXJXYUdyRpG_yxh-qTp7_w   5   1          0            0       650b           650b
ドキュメント登録
curl -X PUT http://localhost:9200/customer/external/1?pretty -d '
{
  "name": "John Doe"
}
'

インデックス/タイプが未作成の場合は一緒に作成される。
ID未指定の場合はPOSTメソッドを指定する。

ドキュメント確認
curl -X GET http://localhost:9200/customer/external/1
{
  "name": "John Doe"
}
インデックス削除
curl -X DELETE http://localhost:9200/customer?pretty
{
  "acknowledged" : true
}

更新操作

変更
curl -X POST http://localhost:9200/customer/external/1/_update?pretty -d '
{
  "doc": {"age": 20}
}
'

ageカラムがある場合は上書き、ない場合は追加される。
他のカラムに影響はない。
メソッドはPUTではなくPOSTなのに注意。

スクリプト使った変更
curl -X GET http://localhost:9200/customer/external/1?pretty -d '
{
  "script": "ctx._source.age += 5"
}
'
ドキュメント削除
curl -X DELETE http://localhost:9200/customer/external/1?pretty
一括登録
curl -XPOST 'localhost:9200/customer/external/_bulk?pretty&pretty' -H 'Content-Type: application/json' -d'
{"index":{"_id":"1"}}
{"name": "John Doe" }
{"index":{"_id":"2"}}
{"name": "Jane Doe" }

検索&集計

テストデータ登録
curl -X POST 'localhost:9200/bank/account/_bulk?pretty&refresh' --data-binary "@accounts.json"
curl http://localhost:9200/_cat/indices?v

サンプルjsonはここから
https://raw.githubusercontent.com/elastic/elasticsearch/master/docs/src/test/resources/accounts.json
ファイル名の前に@をつける必要がある。

書き方1
curl -XGET 'localhost:9200/bank/_search?q=*&sort=account_number:asc&pretty'
{
  "took" : 83,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 1000,
    "max_score" : null,
    "hits" : [
      {
        "_index" : "bank",
        "_type" : "account",
        "_id" : "0",
        "_score" : null,
        "_source" : {
          "account_number" : 0,
          "balance" : 16623,
          "firstname" : "Bradshaw",
          "lastname" : "Mckenzie",
          "age" : 29,
          "gender" : "F",
          "address" : "244 Columbus Place",
          "employer" : "Euron",
          "email" : "bradshawmckenzie@euron.com",
          "city" : "Hobucken",
          "state" : "CO"
        },
        "sort" : [
          0
        ]
      }, ...
    ]
  }
}

q=* -> すべてを指定
sort=account_number:asc -> ソート指定

書き方2
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "query": { "match_all": {} },
  "sort": [
    { "account_number": "asc" }
  ]
}
'
取得件数指定
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "query": { "match_all": {} },
  "sort": [
    { "account_number": "asc" }
  ],
  "from": 10,
  "size": 10
}
'
取得カラム指定
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "query": { "match_all": {} },
  "_source": ["account_number", "balance"]
}
'
完全一致検索
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "query": { "match": { "address": "mill" } }
}
'
bool queryを用いた複数条件指定
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "must": [
        { "match": { "age": "40" } }
      ],
      "must_not": [
        { "match": { "state": "ID" } }
      ],
      "filter": {
        "range": {
          "balance": {
            "gte": 20000,
            "lte": 30000
          }
        }
      }
    }
  }
}
'
集計
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"
      }
    }
  }
}
'

aggs は aggregations(集計) の略。
SQLでいうとこんな感じ。

SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC
集計(平均値を出す)
curl -XGET 'localhost:9200/bank/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword",
        "order": {
          "average_balance": "desc"
        }
      },
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}
'

ざっとこんな感じで。

JavaScript(ES5)でクラスベースっぽくオブジェクト思考する

JavaScript(ES5)でクラスベースっぽくオブジェクト思考したかったので簡単な書き方をメモ。

var MyObject = function(a){
  // アクセサっぽく
  this.a = a;

  // privateメソッドっぽく
  var privateFunction = function(){
    alert('private function! arg is ' + a);
  }

  // publicメソッドっぽく
  var publicFunction = function() {
    alert('public function! arg is ' + a);
  }
  this.publicFunction = publicFunction;
};


// 使い方
var obj = new MyObject("hoge");
obj.a                 // => "hoge";
obj.a = "fuga";
obj.a                 // => "fuga";
obj.publicFunction(); // => public function! arg is fuga