深淵の闇から逃れる為のMariaDB Galera Cluster 5.5 入門(2 node編)

昔つかってたHatena Blog より転載

MariaDB Galera Cluster 5.5を試す

oujiにMySQLの深淵の闇(マスタ昇格とかマスタ昇格とか)から逃れたいと相談したところ MariaDB Galera Clusterが良いと教えてもらったのでやっとこさ試した記録を残します。

RDS最高なのですが、選定できないと思われるケースもあるのでこっちが利用できたらいいな。

MariaDB Galera Clusterって何

デュアルマスタ構成が可能なデータベースクラスタらしいです。最高。

今回はMySQL 5.5からMariaDBへの移行を考え MariaDB Galera Clusterは5.5で試しています。

MariaDB 5.5はMySQL 5.5と互換性があるので、アプリケーションやデータベースを変更せずmysqldumpで移行できると思います。

詳しい資料は

こことか

日本語で詳しいのはさくらインターネット研究所さんの記事だと思います。

資料を熟読してないのですが今回はインストールとMaster破損時の挙動確認をしてみたいとおもいます。

Galera Cluster 5.5 ServerとClientのインストール

今回はEC2(t2.micro)*2をVagrantで準備し、それぞれの内部IPを以下にして検証しています。OSはAmazon Linuxです。

役割 IPアドレス
Master 10.0.0.245
Secondary 10.0.0.67

参考資料

  • リポジトリの準備

Amazon Linux用のリポジトリは提供されていませんが、動RHEL向けのリポジトリを使いました

$ sudo cat /etc/yum.repos.d/mariadb.repo << EOF
# MariaDB 5.5 RedHat repository list - created 2014-09-20 02:09 UTC
# http://mariadb.org/mariadb/repositories/
[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/5.5/rhel6-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
EOF
  • Galera Clusterのインストール
$ sudo yum install --enablerepo=mariadb MariaDB-Galera-server galera MariaDB-Client

Galera Clusterの事前準備

  • Master Nodeの設定
$ sudo vi /etc/my.cnf.d/server.cnf
[galera]
# Mandatory settings
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_address=gcomm://
wsrep_node_address=10.0.0.245
wsrep_slave_threads=1
binlog_format=row
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
query_cache_size=0
  • Secondary Nodeの設定
$ sudo vi /etc/my.cnf.d/server.cnf
[galera]
# Mandatory settings
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_address=gcomm://10.0.0.245
wsrep_node_address=10.0.0.67
wsrep_slave_threads=1
binlog_format=row
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
query_cache_size=0

mysqldの起動

Master Node

  • Master Nodeのmysqld起動
$ sudo service mysql start
  • サンプルデータベースの作成
$ mysql -u root -e "create database orenomaria"
$ mysql -u root -e "show databases"
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| orenomaria         |
| performance_schema |
| test               |
+--------------------+
$ mysql -u root -e "create table orenomaria.test( col varchar(10))"
$ mysql -u root -e "insert into orenomaria.test values('galera')"
$ mysql -u root -e "select * from orenomaria.test"
+--------+
| col    |
+--------+
| galera |
+--------+

Secondary Node

  • Secondary Nodeのmysqld起動

Master Nodeが起動済みでないと同期できず起動しない

$ sudo service mysql start
Starting MySQL.....SST in progress, setting sleep higher. SUCCESS!``
  • 同期確認
$ sudo mysql -u root -e "show databases"
$ mysql -u root -e "select * from orenomaria.test"
+--------+
| col    |
+--------+
| galera |
+--------+

Secondary Node 起動後の確認

Master Node

  • wsrep系パラメータの確認
$ mysql -u root -e "show status like  'wsrep_%'"
+------------------------------+--------------------------------------+
| Variable_name                | Value                                |
+------------------------------+--------------------------------------+
| wsrep_local_state_uuid       | 3f056461-4076-11e4-a2b8-6216b1337d22 |
| wsrep_protocol_version       | 5                                    |
| wsrep_last_committed         | 0                                    |
| wsrep_replicated             | 0                                    |
| wsrep_replicated_bytes       | 0                                    |
| wsrep_repl_keys              | 0                                    |
| wsrep_repl_keys_bytes        | 0                                    |
| wsrep_repl_data_bytes        | 0                                    |
| wsrep_repl_other_bytes       | 0                                    |
| wsrep_received               | 23                                   |
| wsrep_received_bytes         | 1821                                 |
| wsrep_local_commits          | 0                                    |
| wsrep_local_cert_failures    | 0                                    |
| wsrep_local_replays          | 0                                    |
| wsrep_local_send_queue       | 0                                    |
| wsrep_local_send_queue_avg   | 0.000000                             |
| wsrep_local_recv_queue       | 0                                    |
| wsrep_local_recv_queue_avg   | 0.043478                             |
| wsrep_local_cached_downto    | 18446744073709551615                 |
| wsrep_flow_control_paused_ns | 0                                    |
| wsrep_flow_control_paused    | 0.000000                             |
| wsrep_flow_control_sent      | 0                                    |
| wsrep_flow_control_recv      | 0                                    |
| wsrep_cert_deps_distance     | 0.000000                             |
| wsrep_apply_oooe             | 0.000000                             |
| wsrep_apply_oool             | 0.000000                             |
| wsrep_apply_window           | 0.000000                             |
| wsrep_commit_oooe            | 0.000000                             |
| wsrep_commit_oool            | 0.000000                             |
| wsrep_commit_window          | 0.000000                             |
| wsrep_local_state            | 4                                    |
| wsrep_local_state_comment    | Synced                               |
| wsrep_cert_index_size        | 0                                    |
| wsrep_causal_reads           | 0                                    |
| wsrep_cert_interval          | 0.000000                             |
| wsrep_incoming_addresses     | 10.0.0.245:3306,10.0.0.67:3306       |
| wsrep_cluster_conf_id        | 10                                   |
| wsrep_cluster_size           | 2                                    |
| wsrep_cluster_state_uuid     | 3f056461-4076-11e4-a2b8-6216b1337d22 |
| wsrep_cluster_status         | Primary                              |
| wsrep_connected              | ON                                   |
| wsrep_local_bf_aborts        | 0                                    |
| wsrep_local_index            | 0                                    |
| wsrep_provider_name          | Galera                               |
| wsrep_provider_vendor        | Codership Oy <info@codership.com>    |
| wsrep_provider_version       | 25.3.5(rXXXX)                        |
| wsrep_ready                  | ON                                   |
| wsrep_thread_count           | 2                                    |
+------------------------------+--------------------------------------+
  • Master Node に Anther Node が接続される時のログ

Cluster UUID [3f056461-4076-11e4-a2b8-6216b1337d22]に新しいメンバーがJoinしてwsrep_sst_rsyncが走っている

$ cat /dev/null > `hostname`.err
140920 12:47:18 [Note] WSREP: declaring d193920e-4078-11e4-9422-86a0381f90eb stable
140920 12:47:18 [Note] WSREP: Node 3f04f808-4076-11e4-a830-1bcc73dcf244 state prim
140920 12:47:18 [Note] WSREP: view(view_id(PRIM,3f04f808-4076-11e4-a830-1bcc73dcf244,10) memb {
        3f04f808-4076-11e4-a830-1bcc73dcf244,0
        d193920e-4078-11e4-9422-86a0381f90eb,0
} joined {
} left {
} partitioned {
})
140920 12:47:18 [Note] WSREP: New COMPONENT: primary = yes, bootstrap = no, my_idx = 0, memb_num = 2
140920 12:47:18 [Note] WSREP: STATE_EXCHANGE: sent state UUID: d1e0b305-4078-11e4-a8ed-16954c252dca
140920 12:47:18 [Note] WSREP: STATE EXCHANGE: sent state msg: d1e0b305-4078-11e4-a8ed-16954c252dca
140920 12:47:18 [Note] WSREP: STATE EXCHANGE: got state msg: d1e0b305-4078-11e4-a8ed-16954c252dca from 0 ()
140920 12:47:19 [Note] WSREP: STATE EXCHANGE: got state msg: d1e0b305-4078-11e4-a8ed-16954c252dca from 1 ()
140920 12:47:19 [Note] WSREP: Quorum results:
        version    = 3,
        component  = PRIMARY,
        conf_id    = 9,
        members    = 1/2 (joined/total),
        act_id     = 0,
        last_appl. = 0,
        protocols  = 0/5/3 (gcs/repl/appl),
        group UUID = 3f056461-4076-11e4-a2b8-6216b1337d22
140920 12:47:19 [Note] WSREP: Flow-control interval: [23, 23]
140920 12:47:19 [Note] WSREP: New cluster view: global state: 3f056461-4076-11e4-a2b8-6216b1337d22:0, view# 10: Primary, number of nodes: 2, my index: 0, protocol version 3
140920 12:47:19 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.
140920 12:47:19 [Note] WSREP: REPL Protocols: 5 (3, 1)
140920 12:47:19 [Note] WSREP: Service thread queue flushed.
140920 12:47:19 [Note] WSREP: Assign initial position for certification: 0, protocol version: 3
140920 12:47:19 [Note] WSREP: Service thread queue flushed.
140920 12:47:21 [Note] WSREP: Member 1.0 () requested state transfer from '*any*'. Selected 0.0 ()(SYNCED) as donor.
140920 12:47:21 [Note] WSREP: Shifting SYNCED -> DONOR/DESYNCED (TO: 0)
140920 12:47:21 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.
140920 12:47:21 [Note] WSREP: Running: 'wsrep_sst_rsync --role 'donor' --address '10.0.0.67:4444/rsync_sst' --auth '(null)' --socket '/var/lib/mysql/mysql.sock' --datadir '/var/lib/mysql/' --defaults-file '/etc/my.cnf' --gtid '3f056461-4076-11e4-a2b8-6216b1337d22:0''
140920 12:47:21 [Note] WSREP: sst_donor_thread signaled with 0
140920 12:47:21 [Note] WSREP: Flushing tables for SST...
140920 12:47:21 [Note] WSREP: Provider paused at 3f056461-4076-11e4-a2b8-6216b1337d22:0 (25)
140920 12:47:21 [Note] WSREP: Tables flushed.
140920 12:47:22 [Note] WSREP: resuming provider at 25
140920 12:47:22 [Note] WSREP: Provider resumed.
140920 12:47:22 [Note] WSREP: 0.0 (): State transfer to 1.0 () complete.
140920 12:47:22 [Note] WSREP: Shifting DONOR/DESYNCED -> JOINED (TO: 0)
140920 12:47:22 [Note] WSREP: Member 0.0 () synced with group.
140920 12:47:22 [Note] WSREP: Shifting JOINED -> SYNCED (TO: 0)
140920 12:47:22 [Note] WSREP: Synchronized with group, ready for connections
140920 12:47:22 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.
140920 12:47:25 [Note] WSREP: 1.0 (): State transfer from 0.0 () complete.
140920 12:47:25 [Note] WSREP: Member 1.0 () synced with group.

Secondary Node

  • Secondary Node起動後のwsrep系パラメータ
+------------------------------+--------------------------------------+
| Variable_name                | Value                                |
+------------------------------+--------------------------------------+
| wsrep_local_state_uuid       | 3f056461-4076-11e4-a2b8-6216b1337d22 |
| wsrep_protocol_version       | 5                                    |
| wsrep_last_committed         | 0                                    |
| wsrep_replicated             | 0                                    |
| wsrep_replicated_bytes       | 0                                    |
| wsrep_repl_keys              | 0                                    |
| wsrep_repl_keys_bytes        | 0                                    |
| wsrep_repl_data_bytes        | 0                                    |
| wsrep_repl_other_bytes       | 0                                    |
| wsrep_received               | 3                                    |
| wsrep_received_bytes         | 203                                  |
| wsrep_local_commits          | 0                                    |
| wsrep_local_cert_failures    | 0                                    |
| wsrep_local_replays          | 0                                    |
| wsrep_local_send_queue       | 0                                    |
| wsrep_local_send_queue_avg   | 0.000000                             |
| wsrep_local_recv_queue       | 0                                    |
| wsrep_local_recv_queue_avg   | 0.000000                             |
| wsrep_local_cached_downto    | 18446744073709551615                 |
| wsrep_flow_control_paused_ns | 0                                    |
| wsrep_flow_control_paused    | 0.000000                             |
| wsrep_flow_control_sent      | 0                                    |
| wsrep_flow_control_recv      | 0                                    |
| wsrep_cert_deps_distance     | 0.000000                             |
| wsrep_apply_oooe             | 0.000000                             |
| wsrep_apply_oool             | 0.000000                             |
| wsrep_apply_window           | 0.000000                             |
| wsrep_commit_oooe            | 0.000000                             |
| wsrep_commit_oool            | 0.000000                             |
| wsrep_commit_window          | 0.000000                             |
| wsrep_local_state            | 4                                    |
| wsrep_local_state_comment    | Synced                               |
| wsrep_cert_index_size        | 0                                    |
| wsrep_causal_reads           | 0                                    |
| wsrep_cert_interval          | 0.000000                             |
| wsrep_incoming_addresses     | 10.0.0.245:3306,10.0.0.67:3306       |
| wsrep_cluster_conf_id        | 10                                   |
| wsrep_cluster_size           | 2                                    |
| wsrep_cluster_state_uuid     | 3f056461-4076-11e4-a2b8-6216b1337d22 |
| wsrep_cluster_status         | Primary                              |
| wsrep_connected              | ON                                   |
| wsrep_local_bf_aborts        | 0                                    |
| wsrep_local_index            | 1                                    |
| wsrep_provider_name          | Galera                               |
| wsrep_provider_vendor        | Codership Oy <info@codership.com>    |
| wsrep_provider_version       | 25.3.5(rXXXX)                        |
| wsrep_ready                  | ON                                   |
| wsrep_thread_count           | 2                                    |
+------------------------------+--------------------------------------+
  • Secondary Node起動後のログ

wsrepによりMaster Nodeからデータを同期した後(今回の同期方式はデフォルトのwsrep_sst_rsync)

mysqldが起動している

$ cat /var/lib/mysql/`hostname`.err
140920 12:47:15 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql
140920 12:47:15 mysqld_safe WSREP: Running position recovery with --log_error='/var/lib/mysql/wsrep_recovery.pkbACS' --pid-file='/var/lib/mysql/ip-10-0-0-67-recover.pid'
140920 12:47:18 mysqld_safe WSREP: Recovered position 00000000-0000-0000-0000-000000000000:-1
140920 12:47:18 [Note] WSREP: wsrep_start_position var submitted: '00000000-0000-0000-0000-000000000000:-1'
140920 12:47:18 [Note] WSREP: Read nil XID from storage engines, skipping position init
140920 12:47:18 [Note] WSREP: wsrep_load(): loading provider library '/usr/lib64/galera/libgalera_smm.so'
140920 12:47:18 [Note] WSREP: wsrep_load(): Galera 25.3.5(rXXXX) by Codership Oy <info@codership.com> loaded successfully.
140920 12:47:18 [Note] WSREP: CRC-32C: using hardware acceleration.
140920 12:47:18 [Warning] WSREP: Could not open saved state file for reading: /var/lib/mysql//grastate.dat
140920 12:47:18 [Note] WSREP: Found saved state: 00000000-0000-0000-0000-000000000000:-1
140920 12:47:18 [Note] WSREP: Passing config to GCS: base_host = 10.0.0.67; base_port = 4567; cert.log_conflicts = no; debug = no; evs.inactive_check_period = PT0.5S; evs.inactive_timeout = PT15S; evs.join_retrans_period = PT1S; evs.max_install_timeouts = 1; evs.send_window = 4; evs.stats_report_period = PT1M; evs.suspect_timeout = PT5S; evs.user_send_window = 2; evs.view_forget_timeout = PT24H; gcache.dir = /var/lib/mysql/; gcache.keep_pages_size = 0; gcache.mem_size = 0; gcache.name = /var/lib/mysql//galera.cache; gcache.page_size = 128M; gcache.size = 128M; gcs.fc_debug = 0; gcs.fc_factor = 1.0; gcs.fc_limit = 16; gcs.fc_master_slave = no; gcs.max_packet_size = 64500; gcs.max_throttle = 0.25; gcs.recv_q_hard_limit = 9223372036854775807; gcs.recv_q_soft_limit = 0.25; gcs.sync_donor = no; gmcast.segment = 0; gmcast.version = 0; pc.announce_timeout = PT3S; pc.checksum = false; pc.ignore_quorum = false; pc.ignore_sb = false; pc.npvo = false; pc.version = 0; pc.wait_prim = true; pc.wait_prim_timeout = P30S; pc.weight = 1; protonet.b
140920 12:47:18 [Note] WSREP: Service thread queue flushed.
140920 12:47:18 [Note] WSREP: Assign initial position for certification: -1, protocol version: -1
140920 12:47:18 [Note] WSREP: wsrep_sst_grab()
140920 12:47:18 [Note] WSREP: Start replication
140920 12:47:18 [Note] WSREP: Setting initial position to 00000000-0000-0000-0000-000000000000:-1
140920 12:47:18 [Note] WSREP: protonet asio version 0
140920 12:47:18 [Note] WSREP: Using CRC-32C (optimized) for message checksums.
140920 12:47:18 [Note] WSREP: backend: asio
140920 12:47:18 [Note] WSREP: GMCast version 0
140920 12:47:18 [Note] WSREP: (d193920e-4078-11e4-9422-86a0381f90eb, 'tcp://0.0.0.0:4567') listening at tcp://0.0.0.0:4567
140920 12:47:18 [Note] WSREP: (d193920e-4078-11e4-9422-86a0381f90eb, 'tcp://0.0.0.0:4567') multicast: , ttl: 1
140920 12:47:18 [Note] WSREP: EVS version 0
140920 12:47:18 [Note] WSREP: PC version 0
140920 12:47:18 [Note] WSREP: gcomm: connecting to group 'my_wsrep_cluster', peer '10.0.0.245:'
140920 12:47:18 [Note] WSREP: declaring 3f04f808-4076-11e4-a830-1bcc73dcf244 stable
140920 12:47:18 [Note] WSREP: Node 3f04f808-4076-11e4-a830-1bcc73dcf244 state prim
140920 12:47:18 [Note] WSREP: view(view_id(PRIM,3f04f808-4076-11e4-a830-1bcc73dcf244,10) memb {
        3f04f808-4076-11e4-a830-1bcc73dcf244,0
        d193920e-4078-11e4-9422-86a0381f90eb,0
} joined {
} left {
} partitioned {
})
140920 12:47:19 [Note] WSREP: gcomm: connected
140920 12:47:19 [Note] WSREP: Changing maximum packet size to 64500, resulting msg size: 32636
140920 12:47:19 [Note] WSREP: Shifting CLOSED -> OPEN (TO: 0)
140920 12:47:19 [Note] WSREP: Opened channel 'my_wsrep_cluster'
140920 12:47:19 [Note] WSREP: Waiting for SST to complete.
140920 12:47:19 [Note] WSREP: New COMPONENT: primary = yes, bootstrap = no, my_idx = 1, memb_num = 2
140920 12:47:19 [Note] WSREP: STATE EXCHANGE: Waiting for state UUID.
140920 12:47:19 [Note] WSREP: STATE EXCHANGE: sent state msg: d1e0b305-4078-11e4-a8ed-16954c252dca
140920 12:47:19 [Note] WSREP: STATE EXCHANGE: got state msg: d1e0b305-4078-11e4-a8ed-16954c252dca from 0 ()
140920 12:47:19 [Note] WSREP: STATE EXCHANGE: got state msg: d1e0b305-4078-11e4-a8ed-16954c252dca from 1 ()
140920 12:47:19 [Note] WSREP: Quorum results:
        version    = 3,
        component  = PRIMARY,
        conf_id    = 9,
        members    = 1/2 (joined/total),
        act_id     = 0,
        last_appl. = -1,
        protocols  = 0/5/3 (gcs/repl/appl),
        group UUID = 3f056461-4076-11e4-a2b8-6216b1337d22
140920 12:47:19 [Note] WSREP: Flow-control interval: [23, 23]
140920 12:47:19 [Note] WSREP: Shifting OPEN -> PRIMARY (TO: 0)
140920 12:47:19 [Note] WSREP: State transfer required:
        Group state: 3f056461-4076-11e4-a2b8-6216b1337d22:0
        Local state: 00000000-0000-0000-0000-000000000000:-1
140920 12:47:19 [Note] WSREP: New cluster view: global state: 3f056461-4076-11e4-a2b8-6216b1337d22:0, view# 10: Primary, number of nodes: 2, my index: 1, protocol version 3
140920 12:47:19 [Warning] WSREP: Gap in state sequence. Need state transfer.
140920 12:47:21 [Note] WSREP: Running: 'wsrep_sst_rsync --role 'joiner' --address '10.0.0.67' --auth '' --datadir '/var/lib/mysql/' --defaults-file '/etc/my.cnf' --parent '21327''
140920 12:47:21 [Note] WSREP: Prepared SST request: rsync|10.0.0.67:4444/rsync_sst
140920 12:47:21 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.
140920 12:47:21 [Note] WSREP: REPL Protocols: 5 (3, 1)
140920 12:47:21 [Note] WSREP: Service thread queue flushed.
140920 12:47:21 [Note] WSREP: Assign initial position for certification: 0, protocol version: 3
140920 12:47:21 [Note] WSREP: Service thread queue flushed.
140920 12:47:21 [Warning] WSREP: Failed to prepare for incremental state transfer: Local state UUID (00000000-0000-0000-0000-000000000000) does not match group state UUID (3f056461-4076-11e4-a2b8-6216b1337d22): 1 (Operation not permitted)
         at galera/src/replicator_str.cpp:prepare_for_IST():447. IST will be unavailable.
140920 12:47:21 [Note] WSREP: Member 1.0 () requested state transfer from '*any*'. Selected 0.0 ()(SYNCED) as donor.
140920 12:47:21 [Note] WSREP: Shifting PRIMARY -> JOINER (TO: 0)
140920 12:47:21 [Note] WSREP: Requesting state transfer: success, donor: 0
140920 12:47:22 [Note] WSREP: 0.0 (): State transfer to 1.0 () complete.
140920 12:47:22 [Note] WSREP: Member 0.0 () synced with group.
WSREP_SST: [INFO] Joiner cleanup. (20140920 12:47:23.479)
WSREP_SST: [INFO] Joiner cleanup done. (20140920 12:47:23.987)
140920 12:47:23 [Note] WSREP: SST complete, seqno: 0
140920 12:47:23 InnoDB: The InnoDB memory heap is disabled
140920 12:47:23 InnoDB: Mutexes and rw_locks use GCC atomic builtins
140920 12:47:23 InnoDB: Compressed tables use zlib 1.2.3
140920 12:47:23 InnoDB: Using Linux native AIO
140920 12:47:23 InnoDB: Initializing buffer pool, size = 128.0M
140920 12:47:24 InnoDB: Completed initialization of buffer pool
140920 12:47:24 InnoDB: highest supported file format is Barracuda.
InnoDB: Log scan progressed past the checkpoint lsn 1598129
140920 12:47:24  InnoDB: Database was not shut down normally!
InnoDB: Starting crash recovery.
InnoDB: Reading tablespace information from the .ibd files...
InnoDB: Restoring possible half-written data pages from the doublewrite
InnoDB: buffer...
InnoDB: Doing recovery: scanned up to log sequence number 1598283
140920 12:47:24  InnoDB: Waiting for the background threads to start
140920 12:47:25 Percona XtraDB (http://www.percona.com) 5.5.38-MariaDB-35.2 started; log sequence number 1598283
140920 12:47:25 [Note] Plugin 'FEEDBACK' is disabled.
140920 12:47:25 [Note] Server socket created on IP: '0.0.0.0'.
140920 12:47:25 [Note] Event Scheduler: Loaded 0 events
140920 12:47:25 [Note] WSREP: Signalling provider to continue.
140920 12:47:25 [Note] WSREP: SST received: 3f056461-4076-11e4-a2b8-6216b1337d22:0
140920 12:47:25 [Note] /usr/sbin/mysqld: ready for connections.
Version: '5.5.39-MariaDB-wsrep'  socket: '/var/lib/mysql/mysql.sock'  port: 3306  MariaDB Server, wsrep_25.10.r4014
140920 12:47:25 [Note] WSREP: 1.0 (): State transfer from 0.0 () complete.
140920 12:47:25 [Note] WSREP: Shifting JOINER -> JOINED (TO: 0)
140920 12:47:25 [Note] WSREP: Member 1.0 () synced with group.
140920 12:47:25 [Note] WSREP: Shifting JOINED -> SYNCED (TO: 0)
140920 12:47:25 [Note] WSREP: Synchronized with group, ready for connections
140920 12:47:25 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.

Multi Masterの確認

Secondary Nodeに同期されたサンプルデータベースのテーブルにデータを挿入します

Secondary Node

$ mysql -u root -e "insert into orenomaria.test values('galera')"
$ mysql -u root -e "select * from orenomaria.test"
+--------+
| col    |
+--------+
| galera |
| galera |
+--------+

Master Node

確認

$ mysql -u root -e "select * from orenomaria.test"
+--------+
| col    |
+--------+
| galera |
| galera |←最高
+--------+

非常に簡単にMulti Masterを構成することが出来ました。

Master Nodeを壊す

Master Node

Master Nodeのmysqldatadirを削除してプロセスをkillします

$ ps -ef|grep mysql |grep -v grep
root     23107     1  0 14:57 pts/1    00:00:00 /bin/sh /usr/bin/mysqld_safe --datadir=/var/lib/mysql --pid-file=/var/lib/mysql/ip-10-0-0-245.pid
mysql    23338 23107  0 14:57 pts/1    00:00:00 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --user=mysql --wsrep-provider=/usr/lib64/galera/libgalera_smm.so --log-error=/var/lib/mysql/ip-10-0-0-245.err --pid-file=/var/lib/mysql/ip-10-0-0-245.pid --wsrep_start_position=3f056461-4076-11e4-a2b8-6216b1337d22:14
$ sudo rm -rf /var/lib/mysql
$ ll mysql
ls: mysql にアクセスできません: そのようなファイルやディレクトリはありません
$ sudo kill -9 23107 23338
$ ps -ef|grep mysql
root     23552 22176  0 15:06 pts/0    00:00:00 grep mysql

死にました

Secondary Node

  • Master破損時のログ
$ cat /var/lib/mysql/`hostname`.err
140920 15:06:50 [Note] WSREP: (b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, 'tcp://0.0.0.0:4567') turning message relay requesting on, nonlive peers: tcp://10.0.0.245:4567
140920 15:06:51 [Note] WSREP: (b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, 'tcp://0.0.0.0:4567') reconnecting to 11c5fdd2-408b-11e4-8712-53af37cbe2b9 (tcp://10.0.0.245:4567), attempt 0
140920 15:06:54 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, OPERATIONAL, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:06:55 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:06:55 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:06:56 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:06:56 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:06:57 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:06:57 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:06:58 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:06:58 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:06:59 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:06:59 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:07:00 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:07:00 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:07:01 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:07:01 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:07:02 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:07:02 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:07:03 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:07:03 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:07:04 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) suspecting node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:07:04 [Note] WSREP: evs::proto(b9f4ed9f-408b-11e4-b85d-53a5bbcd3048, GATHER, view_id(REG,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4)) detected inactive node: 11c5fdd2-408b-11e4-8712-53af37cbe2b9
140920 15:07:05 [Note] WSREP: view(view_id(NON_PRIM,11c5fdd2-408b-11e4-8712-53af37cbe2b9,4) memb {
        b9f4ed9f-408b-11e4-b85d-53a5bbcd3048,0
} joined {
} left {
} partitioned {
        11c5fdd2-408b-11e4-8712-53af37cbe2b9,0
})
140920 15:07:05 [Note] WSREP: New COMPONENT: primary = no, bootstrap = no, my_idx = 0, memb_num = 1
140920 15:07:05 [Note] WSREP: Flow-control interval: [16, 16]
140920 15:07:05 [Note] WSREP: Received NON-PRIMARY.
140920 15:07:05 [Note] WSREP: Shifting SYNCED -> OPEN (TO: 19)
140920 15:07:05 [Note] WSREP: New cluster view: global state: 3f056461-4076-11e4-a2b8-6216b1337d22:19, view# -1: non-Primary, number of nodes: 1, my index: 0, protocol version 3
140920 15:07:05 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.
140920 15:07:05 [Note] WSREP: view(view_id(NON_PRIM,b9f4ed9f-408b-11e4-b85d-53a5bbcd3048,5) memb {
        b9f4ed9f-408b-11e4-b85d-53a5bbcd3048,0
} joined {
} left {
} partitioned {
        11c5fdd2-408b-11e4-8712-53af37cbe2b9,0
})
140920 15:07:05 [Note] WSREP: New COMPONENT: primary = no, bootstrap = no, my_idx = 0, memb_num = 1
140920 15:07:05 [Note] WSREP: Flow-control interval: [16, 16]
140920 15:07:05 [Note] WSREP: Received NON-PRIMARY.
140920 15:07:05 [Note] WSREP: New cluster view: global state: 3f056461-4076-11e4-a2b8-6216b1337d22:19, view# -1: non-Primary, number of nodes: 1, my index: 0, protocol version 3
140920 15:07:05 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.
  • データ確認

Master Nodeが破損したためかクエリを受け付けなくなっています

$ mysql -u root -e "select count(*) from orenomaria.test"
ERROR 1047 (08S01) at line 1: WSREP has not yet prepared node for application use

復旧

Secondary Node

  • Secondary NodeのMaster化

Secondary Nodeのwsrep_cluster_addressをgcomm://に変更します

mysql -u root -e "set global wsrep_cluster_address='gcomm://'"

検索できるようになりました。データの挿入もOKっぽいです

$ mysql -u root -e "select count(*) from orenomaria.test"
+----------+
| count(*) |
+----------+
|       15 |
+----------+
$ mysql -u root -e "insert into orenomaria.test values('galera')"
$ mysql -u root -e "select count(*) from orenomaria.test"
+----------+
| count(*) |
+----------+
|       16 |
+----------+
  • ログの確認

Masterが停止しwsrep_cluster_addressを変更するまでのログを確認してみます。
WSREP: Quorum: No node with complete state: などとかでてますね。
AIX触っていた頃のVG Quorumを思い出します。

やつも確かQuorum50%以下になったらVGがinactiveになるので3本以上のDiskでVG構成すると良いよとかあったような(うるおぼえ)

Quorum型ってことは3node以上でGalera Clusterを作っておけば1台死んでもトランザクションは止まらないのかしら?

140920 15:10:00 [Note] WSREP: Stop replication
140920 15:10:00 [Note] WSREP: Closing send monitor...
140920 15:10:00 [Note] WSREP: Closed send monitor.
140920 15:10:00 [Note] WSREP: gcomm: terminating thread
140920 15:10:00 [Note] WSREP: gcomm: joining thread
140920 15:10:00 [Note] WSREP: gcomm: closing backend
140920 15:10:00 [Note] WSREP: view((empty))
140920 15:10:00 [Note] WSREP: Received self-leave message.
140920 15:10:00 [Note] WSREP: gcomm: closed
140920 15:10:00 [Note] WSREP: Flow-control interval: [0, 0]
140920 15:10:00 [Note] WSREP: Received SELF-LEAVE. Closing connection.
140920 15:10:00 [Note] WSREP: Shifting OPEN -> CLOSED (TO: 19)
140920 15:10:00 [Note] WSREP: RECV thread exiting 0: Success
140920 15:10:00 [Note] WSREP: New cluster view: global state: 3f056461-4076-11e4-a2b8-6216b1337d22:19, view# -1: non-Primary, number of nodes: 0, my index: -1, protocol version 3
140920 15:10:00 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.
140920 15:10:00 [Note] WSREP: applier thread exiting (code:0)
140920 15:10:00 [Note] WSREP: recv_thread() joined.
140920 15:10:00 [Note] WSREP: Closing replication queue.
140920 15:10:00 [Note] WSREP: Closing slave action queue.
140920 15:10:02 [Note] WSREP: rollbacker thread exiting
140920 15:10:02 [Note] WSREP: Start replication
140920 15:10:02 [Note] WSREP: Setting initial position to 3f056461-4076-11e4-a2b8-6216b1337d22:19
140920 15:10:02 [Note] WSREP: protonet asio version 0
140920 15:10:02 [Note] WSREP: Using CRC-32C (optimized) for message checksums.
140920 15:10:02 [Note] WSREP: backend: asio
140920 15:10:02 [Note] WSREP: GMCast version 0
140920 15:10:02 [Note] WSREP: (c2657b9f-408c-11e4-9081-e700f8703e0a, 'tcp://0.0.0.0:4567') listening at tcp://0.0.0.0:4567
140920 15:10:02 [Note] WSREP: (c2657b9f-408c-11e4-9081-e700f8703e0a, 'tcp://0.0.0.0:4567') multicast: , ttl: 1
140920 15:10:02 [Note] WSREP: EVS version 0
140920 15:10:02 [Note] WSREP: PC version 0
140920 15:10:02 [Note] WSREP: gcomm: connecting to group 'my_wsrep_cluster', peer ''
140920 15:10:02 [Note] WSREP: Node c2657b9f-408c-11e4-9081-e700f8703e0a state prim
140920 15:10:02 [Note] WSREP: view(view_id(PRIM,c2657b9f-408c-11e4-9081-e700f8703e0a,1) memb {
        c2657b9f-408c-11e4-9081-e700f8703e0a,0
} joined {
} left {
} partitioned {
})
140920 15:10:02 [Note] WSREP: gcomm: connected
140920 15:10:02 [Note] WSREP: Changing maximum packet size to 64500, resulting msg size: 32636
140920 15:10:02 [Note] WSREP: Shifting CLOSED -> OPEN (TO: 19)
140920 15:10:02 [Note] WSREP: Opened channel 'my_wsrep_cluster'
140920 15:10:02 [Note] WSREP: New COMPONENT: primary = yes, bootstrap = no, my_idx = 0, memb_num = 1
140920 15:10:02 [Note] WSREP: STATE_EXCHANGE: sent state UUID: c265d73a-408c-11e4-a52c-2a7ddfe1c27a
140920 15:10:02 [Note] WSREP: STATE EXCHANGE: sent state msg: c265d73a-408c-11e4-a52c-2a7ddfe1c27a
140920 15:10:02 [Note] WSREP: STATE EXCHANGE: got state msg: c265d73a-408c-11e4-a52c-2a7ddfe1c27a from 0 ()
140920 15:10:02 [Warning] WSREP: Quorum: No node with complete state:


        Version      : 3
        Flags        : 0x1
        Protocols    : 0 / 5 / 3
        State        : NON-PRIMARY
        Prim state   : SYNCED
        Prim UUID    : ba41f234-408b-11e4-b1fa-d37de606186c
        Prim  seqno  : 4
        First seqno  : -1
        Last  seqno  : 19
        Prim JOINED  : 2
        State UUID   : c265d73a-408c-11e4-a52c-2a7ddfe1c27a
        Group UUID   : 3f056461-4076-11e4-a2b8-6216b1337d22
        Name         : ''
        Incoming addr: '10.0.0.67:3306'

140920 15:10:02 [Note] WSREP: Partial re-merge of primary ba41f234-408b-11e4-b1fa-d37de606186c found: 1 of 2.
140920 15:10:02 [Note] WSREP: Quorum results:
        version    = 3,
        component  = PRIMARY,
        conf_id    = 4,
        members    = 1/1 (joined/total),
        act_id     = 19,
        last_appl. = 0,
        protocols  = 0/5/3 (gcs/repl/appl),
        group UUID = 3f056461-4076-11e4-a2b8-6216b1337d22
140920 15:10:02 [Note] WSREP: Flow-control interval: [16, 16]
140920 15:10:02 [Note] WSREP: Restored state OPEN -> SYNCED (19)
140920 15:10:02 [Note] WSREP: New cluster view: global state: 3f056461-4076-11e4-a2b8-6216b1337d22:19, view# 5: Primary, number of nodes: 1, my index: 0, protocol version 3
140920 15:10:02 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.
140920 15:10:02 [Note] WSREP: REPL Protocols: 5 (3, 1)
140920 15:10:02 [Note] WSREP: Service thread queue flushed.
140920 15:10:02 [Note] WSREP: Assign initial position for certification: 19, protocol version: 3
140920 15:10:02 [Note] WSREP: Service thread queue flushed.
140920 15:10:02 [Note] WSREP: Synchronized with group, ready for connections
140920 15:10:02 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.

破損したMaster NodeをSecondaryとして起動

  • Master NodeのSecondary化

wsrep_cluster_addressを新Master(10.0.0.67)に変更します

$ vi /etc/my.cnf.d/server.conf
# Mandatory settings
wsrep_provider=/usr/lib64/galera/libgalera_smm.so
wsrep_cluster_address=gcomm://10.0.0.67
wsrep_node_address=10.0.0.245
wsrep_slave_threads=1
binlog_format=row
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
query_cache_size=0
  • 起動と確認

SSTにより新Master(10.0.0.67)からデータが転送されてSuccessが返ります。

データも同期され、新しいデータの挿入もOKです

$ sudo service mysql start
Starting MySQL.......SST in progress, setting sleep higher. SUCCESS!
mysql -u root -e "select count(*) from orenomaria.test"
+----------+
| count(*) |
+----------+
|       16 |
+----------+
$ mysql -u root -e "insert into orenomaria.test values('galera')"
$ mysql -u root -e "select count(*) from orenomaria.test"
+----------+
| count(*) |
+----------+
|       17 |
+----------+

新Master Nodeでの確認

  • データの確認

新Secondaryで挿入したデータは反映されてます。最高です

$ mysql -u root -e "select count(*) from orenomaria.test"
+----------+
| count(*) |
+----------+
|       17 |
+----------+
  • ログの確認

新しいメンバー通知が走りwsrep_sst_rsyncが行われています。

完了後にmemberとしてJOINしています。

140920 15:31:37 [Note] WSREP: REPL Protocols: 5 (3, 1)
140920 15:31:37 [Note] WSREP: Service thread queue flushed.
140920 15:31:37 [Note] WSREP: Assign initial position for certification: 20, protocol version: 3
140920 15:31:37 [Note] WSREP: Service thread queue flushed.
140920 15:31:37 [Warning] WSREP: Releasing seqno 20 before 21 was assigned.
140920 15:31:39 [Note] WSREP: Member 1.0 () requested state transfer from '*any*'. Selected 0.0 ()(SYNCED) as donor.
140920 15:31:39 [Note] WSREP: Shifting SYNCED -> DONOR/DESYNCED (TO: 20)
140920 15:31:39 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.
140920 15:31:39 [Note] WSREP: Running: 'wsrep_sst_rsync --role 'donor' --address '10.0.0.245:4444/rsync_sst' --auth '(null)' --socket '/var/lib/mysql/mysql.sock' --datadir '/var/lib/mysql/' --defaults-file '/etc/my.cnf' --gtid '3f056461-4076-11e4-a2b8-6216b1337d22:20''
140920 15:31:39 [Note] WSREP: sst_donor_thread signaled with 0
140920 15:31:39 [Note] WSREP: Flushing tables for SST...
140920 15:31:39 [Note] WSREP: Provider paused at 3f056461-4076-11e4-a2b8-6216b1337d22:20 (16)
140920 15:31:39 [Note] WSREP: Tables flushed.
140920 15:31:41 [Note] WSREP: resuming provider at 16
140920 15:31:41 [Note] WSREP: Provider resumed.
140920 15:31:41 [Note] WSREP: 0.0 (): State transfer to 1.0 () complete.
140920 15:31:41 [Note] WSREP: Shifting DONOR/DESYNCED -> JOINED (TO: 20)
140920 15:31:41 [Note] WSREP: Member 0.0 () synced with group.
140920 15:31:41 [Note] WSREP: Shifting JOINED -> SYNCED (TO: 20)
140920 15:31:41 [Note] WSREP: Synchronized with group, ready for connections
140920 15:31:41 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.
140920 15:31:43 [Note] WSREP: 1.0 (): State transfer from 0.0 () complete.
140920 15:31:43 [Note] WSREP: Member 1.0 () synced with group.

以上でMariaDB Galera Clusterのデュアルマスタ機能を試すことが出来ました。

引き続き検証を続けたいと思います。

最高。

続きを読む

AWS X-RayでSolrの検索処理をトレースする

AWS X-Ray(プレビュー版)を使ってSolrの検索処理をトレースしてみる。
Solrへリクエストを投げるところからトレースを開始する。

システム構成

サーバ

使用するインスタンスは2台。
Amazon Linuxを使う。

  • Webサーバ(express/node.js – t2.micro)
  • 検索エンジン(Solr/Jetty – t2.medium)

サービスマップ

こんな感じになる。
localhostと書いてあるけどSolrへのリクエスト。

servicemap.png

サーバの構築

共通

セキュリティグループ

ローカルマシン→Webサーバの80番ポートは開けておく。
Webサーバ→検索エンジンの80番ポートも開けておく。
ローカルマシン→Solrにアクセスするならそちらの8983番ポートも開けておく。

IAMロール/インスタンスプロファイル

後述のX-RayデーモンがAWS X-Rayサービスにデータを送るので書き込み権限を設定してあげる。
インスタンスに関連付けるIAMロールを適当に作り、AWSマネージドポリシーからAWSXrayWriteOnlyAccessポリシーをアタッチする。
ポリシーの内容はこんな感じ。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "xray:PutTraceSegments",
                "xray:PutTelemetryRecords"

            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

X-Rayデーモン

X-Rayデーモンのインストール。
もう起動してる。気が早い。

$ curl -sL https://s3.amazonaws.com/aws-xray-assets.us-east-1/xray-daemon/aws-xray-daemon-1.x.rpm -o /home/ec2-user/xray.rpm
$ sudo yum install -y xray.rpm
$ sudo initctl status xray
xray start/running, process 2607

インストール内容はこんな感じ。
xrayデーモンはGolang製の模様。
systemdの設定もあるようだがデフォルトだとUpstartで起動している。

$ rpm -ql xray
/etc/amazon/xray/cfg.yaml
/etc/init/xray.conf
/etc/systemd/system/xray.service
/usr/bin/xray

設定はデフォルトのままでいじらず。

Webサーバ

検索エンジンのIPアドレスをxray-solrとしてを/etc/hostsに登録した。

node.js

epelからインストールすると0.10系になるので最新版になる方法でインストールする。
レポジトリを登録。

$ curl -sL https://rpm.nodesource.com/setup_7.x | sudo bash -

## Installing the NodeSource Node.js 7.x repo...


## Inspecting system...

+ rpm -q --whatprovides redhat-release || rpm -q --whatprovides centos-release || rpm -q --whatprovides cloudlinux-release || rpm -q --whatprovides sl-release
+ uname -m

## Confirming "el7-x86_64" is supported...

+ curl -sLf -o /dev/null 'https://rpm.nodesource.com/pub_7.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm'

## Downloading release setup RPM...

+ mktemp
+ curl -sL -o '/tmp/tmp.OHBteTsWWV' 'https://rpm.nodesource.com/pub_7.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm'

## Installing release setup RPM...

+ rpm -i --nosignature --force '/tmp/tmp.OHBteTsWWV'

## Cleaning up...

+ rm -f '/tmp/tmp.OHBteTsWWV'

## Checking for existing installations...

+ rpm -qa 'node|npm' | grep -v nodesource

## Run `yum install -y nodejs` (as root) to install Node.js 7.x and npm.
## You may also need development tools to build native addons:
##   `yum install -y gcc-c++ make`

v7.6.0をインストール。

$ sudo yum install -y nodejs
$ node -v
v7.6.0

yarn

npmpackage.jsonを管理する気があるのかないのか分からないのでyarnをインストールする。

$ sudo curl -sL https://dl.yarnpkg.com/rpm/yarn.repo -o /etc/yum.repos.d/yarn.repo
$ sudo yum install -y yarn

express

/home/ec2-user/web以下にプロジェクトを作った。

$ yarn init -y
$ yarn add express aws-sdk aws-xray-sdk

ここまででpackage.jsonはこんな感じ。

{
  "name": "web",
  "version": "1.0.0",
  "main": "index.js",
  "repository": {},
  "license": "MIT",
  "dependencies": {
    "aws-sdk": "^2.12.0",
    "aws-xray-sdk": "^1.0.4-beta",
    "express": "^4.14.1"
  }
}

リクエストが来たら検索エンジンで検索するWebアプリを書く。

/home/ec2-user/web/index.js
const express = require('express');
const app = express();

const AWSXRay = require('aws-xray-sdk');
AWSXRay.config([AWSXRay.plugins.EC2]);

const http = require('http');
AWSXRay.captureHTTPs(http);


app.use(AWSXRay.express.openSegment('xray-web'));

app.get('/', (req, res) => {
  const options = {
    hostname: 'xray-solr',
    port: 8983,
    path: '/solr/xray/select?indent=on&q=*:*&wt=json'
  };
  http.get(options, (response) => {
    let data = '';
    response.on('data', (chunk) => data += chunk);
    response.on('end', () => {
      res.send(data);
    });
  });
});

app.use(AWSXRay.express.closeSegment());


app.listen(80);

EC2プラグインを指定するとAWS X-Rayに渡される情報にインスタンス情報が付加される。
今のところインスタンスIDとAZのみ。

AWSXRay.config([AWSXRay.plugins.EC2]);

サンプリングルールの設定も出来る模様。

AWSXRay.setSamplingRules('sampling-rules.json');

公式ドキュメントに記載されている形式だとエラーで動かないので下記のような形式にすると動いた。
ただDefaultの設定しか反映されないので、どこか間違っていそう。
毎秒fixed_target数のリクエストをトレース、その後はrateの割合でトレース。

sampling-rules.json
{
  "rules": {
    "1": {
      "service_name": "*",
      "http_method": "*",
      "url_path": "*",
      "fixed_target": 10,
      "rate": 0.1
    },
    "Default": {
      "fixed_target": 10,
      "rate": 0.1
    }
  }
}

express用のミドルウェアが用意されているので使わせて頂く。
これでWebサーバに来たリクエストをトレース出来る。

app.use(AWSXRay.express.openSegment('xray-web'));
  :
app.use(AWSXRay.express.closeSegment());

httphttpsを使った通信をトレースすることが出来る。
内部的にhttp.requestを置き換えている。
これで検索エンジンとの通信をトレース出来る。

AWSXRay.captureHTTPs(http);

http.get('http://.../')のようにURLを直接渡すとhttp://localhost/へのリクエストが無限ループになって死ぬ。
接続先が未知の場合はlocalhostに設定されるのはnode.jsの仕様らしい。誰が喜ぶんだこれ。
今のところoptionsはハッシュで渡されることが期待されている。

const options = {
  hostname: 'xray-solr',
  port: 8983,
  path: '/solr/xray/select?indent=on&q=*:*&wt=json'
};
http.get(options, (response) => {...});

検索エンジン

自分のIPアドレスをxray-solrとしてを/etc/hostsに登録した。

node.js

SolrへのプロキシとしてWebサーバと同様に node.js + express をインストールした。
コードはWebサーバとほぼ同じだが、検索エンジンのクライアントは色々ある前提でDynamic Naming Modeにしてみた。
defaultNameを与えないとエラーになった。

AWSXRay.middleware.enableDynamicNaming();
app.use(AWSXRay.express.openSegment('defaultName'));

java

1.8以上が必要らしい。

$ sudo yum install java-1.8.0-openjdk
$ sudo alternatives --config java

2 プログラムがあり 'java' を提供します。

  選択       コマンド
-----------------------------------------------
*+ 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 を押して現在の選択 [+] を保持するか、選択番号を入力します:2

Solr

/home/ec2-user/solr/以下にSolrをインストールした。

$ curl -sL 'http://ftp.jaist.ac.jp/pub/apache/lucene/solr/6.4.1/solr-6.4.1.tgz' -o /home/ec2-user/solr.tgz
$ tar zxf solr.tgz
$ mv solr-6.4.1 solr

デフォルトの8983番ポートで起動。

$ cd solr
$ ./bin/solr start

コアを新規作成する。
solrコマンドのヘルプは./bin/solr create_core -helpなどと打てば見られる。

$ ./bin/solr create_core -c xray -d sample_techproducts_configs

Servlet Filter

GradleやMavenでのビルド方法がよく分からないので、とりあえず必要そうなJARを持ってきてぶち込んだ。

$ curl -sL 'http://central.maven.org/maven2/com/amazonaws/aws-xray-recorder-sdk-core/1.0.4-beta/aws-xray-recorder-sdk-core-1.0.4-beta.jar' -o aws-xray-recorder-sdk-core-1.0.4-beta.jar
$ curl -sL 'http://central.maven.org/maven2/com/amazonaws/aws-java-sdk-core/1.11.91/aws-java-sdk-core-1.11.91.jar' -o aws-java-sdk-core-1.11.91.jar
$ curl -sL 'http://central.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.8.6/jackson-databind-2.8.6.jar' -o jackson-databind-2.8.6.jar
$ curl -sL 'http://central.maven.org/maven2/com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.8.6/jackson-dataformat-cbor-2.8.6.jar' -o jackson-dataformat-cbor-2.8.6.jar
$ curl -sL 'http://central.maven.org/maven2/commons-logging/commons-logging/1.2/commons-logging-1.2.jar' -o commons-logging-1.2.jar
$ curl -sL 'http://central.maven.org/maven2/joda-time/joda-time/2.9.7/joda-time-2.9.7.jar' -o joda-time-2.9.7.jar
$ curl -sL 'http://central.maven.org/maven2/software/amazon/ion/ion-java/1.0.2/ion-java-1.0.2.jar' -o ion-java-1.0.2.jar
$ curl -sL 'http://central.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.8.6/jackson-annotations-2.8.6.jar' -o jackson-annotations-2.8.6.jar
$ curl -sL 'http://central.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.8.6/jackson-core-2.8.6.jar' -o jackson-core-2.8.6.jar
$ mv *.jar /home/ec2-user/solr/server/solr-webapp/webapp/WEB-INF/lib/

/home/ec2-user/solr/server/solr-webapp/webapp/WEB-INF/web.xmlAWSXRayServletFilterの設定を追加。
SolrRequestFilterの手前に入れた。

web.xml
<filter>
  <filter-name>AWSXRayServletFilter</filter-name>
  <filter-class>com.amazonaws.xray.javax.servlet.AWSXRayServletFilter</filter-class>
  <init-param>
    <param-name>fixedName</param-name>
    <param-value>xray-solr</param-value>
  </init-param>
</filter>

<filter-mapping>
  <filter-name>AWSXRayServletFilter</filter-name>
  <url-pattern>/solr/*</url-pattern>
</filter-mapping>

リクエストとトレースの確認

node.jsとSolrを起動してxray-webにリクエストを投げてみる。
トレース結果は下記のようになった。

trace.png

時間がずれるとこううまく表示されないのが気持ち悪い。
なにが悪いのか・・・

trace2.png

続きを読む

[Grafana] Grafanaで、AWSのリザーブドインスタンス(RI)を監視してみた。

こんにちは。
最近開発にも手を出し始めた元インフラのjkkitakita。

とりあえず
何か書きたい衝動に駆られたので
ちょっと前に、遊び感覚でやっていたことをつらつらと。

はじめに

ざっくりでも以下の知識があるとよいかも。

  1. リザーブドインスタンス

  2. Grafana + Influxdb
  3. telegrafのExec Input Pluginについて

各種サービスのバージョン

  • Telegraf – Version 0.10.3
  • InfluxDB shell 0.10.3
  • Grafana v 2.6.0

背景

  1. EC2、RDS、Redshiftの台数が増えてきて、コストが結構かかる。
  2. Trusted Advisorを見れば、現状の最適化は検討できるが、次いつリザーブドを購入すればいいのか把握したい。(cf. 会社のキャッシュフロー)
  3. 現状のオンデマンド/リザーブドの比率をグラフで一目で確認したい。

特に3.が大きい。
「毎月1回、EC2の画面を見て、1日かけて確認する」
的な運用でカバーはまず論外で

その他、頑張ってやろうとすると
– Cost Visualizerを導入する
https://dev.smt.docomo.ne.jp/?p=common_page&p_name=cost_visualizer
– エクセルとかで、毎日編集する

とかって話になって、それはそれで、コスト・手間がかかる。
ぶっちゃけ、これもだるい。めんどくさい。(笑)

めんどくさいなーめんどくさいなーと
ボソボソ言いながら、ふと

「もうサーバーの傾向監視を
telegraf + influxdb + Grafanaでやってるから
RIもそこに入れて、ダッシュボードにしちゃえ!!!!」

ってことで
取り急ぎ、telegraf + bashでいけそうだったので
telegrafの設定開始(`・ω・´)キリッ

telegrafの設定してみる

とりあえず、confにinput.execを追記。

/etc/telegraf/telegraf.conf

# EC2
[[inputs.exec]]
  command = "/etc/telegraf/telegraf.d/exec/count-instances"
  data_format = "influx"
  interval = "3600s"

[[inputs.exec]]
  command = "/etc/telegraf/telegraf.d/exec/reserved_instance.sh"
  data_format = "influx"
  interval = "3600s"

# RDS
[[inputs.exec]]
  command = "/etc/telegraf/telegraf.d/exec/rds_reserved_nodes.sh"
  data_format = "influx"
  interval = "3600s"

# Redshift
[[inputs.exec]]
  command = "/etc/telegraf/telegraf.d/exec/redshift_reserved_nodes.sh"
  data_format = "influx"
  interval = "3600s"

あとは、bashをちょこちょこ書くだけ。

■ EC2
1.全体(オンデマンドとリザーブド)の数

/etc/telegraf/telegraf.d/exec/count-instances.sh
#!/bin/bash

### check instance status is running
/usr/bin/aws ec2 describe-instances --filters "Name=instance-state-name,Values=running" |
jq -r  '[ .Reservations[] | .Instances[] | { InstanceType } ]| group_by(.InstanceType) | .
[]|.[0] + { "Count": length}| .InstanceType, .Count'|sed 'N;s/n/ value=/'|sed 's/^/instan
ces,instance_type=/'

2.リザーブドの数

/etc/telegraf/telegraf.d/exec/reserved_instance.sh
#!/bin/bash

/usr/bin/aws ec2 describe-reserved-instances --filters "Name=state,Values=active" | jq -r
'.ReservedInstances[] | [.InstanceType, .AvailabilityZone, (.InstanceCount|tostring), .End
] | join(",")' | sed 's/T.*//g' | awk -F, '{print "reserved_instances,instance_type=" $1 "
,AvailabilityZone=" $2 ",end_date=" $4 " RI_count=" $3}' | sed 's/=,/=-,/g'

■ RDS
・全体(オンデマンドとリザーブド)とリザーブドの数

/etc/telegraf/telegraf.d/exec/rds_reserved_nodes.sh
#!/bin/bash

# count of rds db instaces group by instance_type
/usr/bin/aws rds describe-db-instances --output json | jq -r '[.DBInstances[] | { DBInstan
ceClass }] | group_by(.DBInstanceClass) | .[] | .[0] + { "Count": length } | [.DBInstanceC
lass, (.Count|tostring)] | join(",")' | sed 's/^/rds_db_instances,db_instance_type=/g'| aw
k -F, '{print $1 "," $2 " values=" $3}'

# count of reserved rds db instances group by instance_type
/usr/bin/aws rds describe-reserved-db-instances --output json | jq -r '.ReservedDBInstance
s[] | select(.State == "active") | [.DBInstanceClass, (.DBInstanceCount|tostring), .StartT
ime] | join(",")' | sed -E 's/^(.*T.*)..*$/1/g' | awk -F, '{print "rds_reserved_instance
s,db_instance_type=" $1 ",start_time=" $3 " RI_count=" $2}'

■ Redshift(dc1.largeのみ)
・全体(オンデマンドとリザーブド)とリザーブドの数

/etc/telegraf/telegraf.d/exec/redshift_reserved_nodes.sh
#!/bin/bash

# count of redshift nodes
/usr/bin/aws redshift describe-clusters --output json | jq -r '[.Clusters[] | select(.Node
Type == "dc1.large") | .NumberOfNodes] | add' | sed 's/^/redshift_cluster_nodes,node_type=
dc1.large values=/g'

# count of reserved redshift nodes
/usr/bin/aws redshift describe-reserved-nodes --output json | jq -r '.ReservedNodes[] | se
lect(.State == "active") | [.NodeType, (.NodeCount|tostring), .StartTime] | join(",")' | s
ed -E 's/^(.*T.*)..*$/1/g' | awk -F, '{print "redshift_reserved_nodes,node_type=" $1 ",s
tart_time=" $3 " RI_count=" $2}'

jq,sed,awkでワンライナーでごり押し。(笑)

もっといい感じにかけるはずだけど
まぁ一旦現状、こんな感じでいけそう。

telegrafの再起動。

/etc/init.d/telegraf restart

InfluxDBの中身確認してみる。
とりあえず、うまくいってそう。

  • EC2

influxdb_instances.png

influxdb_reserved_instances.png

  • RDS

influxdb_rds_instances.png

influxdb_rds_reserved_instances.png

  • Redshift

influxdb_redshift_nodes.png

influxdb_redshift_reserved_nodes.png

Grafanaでダッシュボードつくる

1.各種サービスのリザーブド終了日付を一覧で把握
Grafana_RI_1.png

2.各種サービスのリザーブド数の傾向監視(EC2は、インスタンスタイプ毎)- オンデマンド - リザーブド
Grafana_RI_2.png

お、おう。。。めっちゃコスト削減できそう。。。
とりあえず、私の給料分の何倍かは。。。笑

さいごに

やはり、なんかあったら、Grafanaが一番。笑
特にモニタリングするには。

しかも
Kapatitorとか使えば
AWSサービスとか他のSaaSではできない
詳細なコスト監視も実現できそうなので
本格的に運用する気持ちになったらやってみようと思います!

続きを読む

AWS E2 G2インスタンス上にKeras環境を構築する 2017年2月版

はじめに

Deep Learningをやろうと思ったらでかい計算資源が必要なのが当たり前なのだけど、手持ちのPCのスペックで十分とかそうそうありはしないので、EC2のGPUインスタンスをささっと立てて使うのも手だと思う。

FrameworkはKerasでバックエンドはTensorFlow GPUバージョン。それをpyenv仮想環境でセットアップする構成とした。先日TensorFlow 1.0がリリースされてtf.kerasが実装されたみたいだけどまだ試してないので普通にKeras使うことにする。

環境構築についてはこちらを参考にさせていただいた。
AWSのGPUインスタンスでTensorFlowを動かす

インスタンスの作成

EC2 Instance: クイックスタートにある Ubuntu Server 16.04 LTS (HVM), SSD Volume Type
Type : g2.2xlarge
ストレージなどはとりあえず標準構成(メモリ15GB, ストレージ8GB)

セットアップ

まずはSSHでログインする

ssh -i ~/[ec2key].pem ubuntu@[Instance IP]

エフェメラルストレージを作業ディレクトリにするためシンボリックリンクを作成する

CUDAとかけっこうでかいので作業の途中で空き容量が足りなくなる。/mnt/tmp/へのシンボリックリンクを作成してエフェメラルストレージを作業領域に使う。

sudo mkdir /mnt/tmp
sudo chmod 777 /mnt/tmp
sudo rm -rf /tmp
sudo ln -s /mnt/tmp /tmp
cd /tmp

Ubuntuを最新にアップグレードする

sudo apt-get update
sudo apt-get upgrade -y

ロケールを設定する

upgrade後ロケール関係のwarningが出てうざいので

sudo apt-get install language-pack-ja
sudo update-locale LANG=ja_JP.UTF-8

セットアップに必要なモジュールをインストールする

sudo apt-get install python
sudo apt-get install -y build-essential python-pip python-dev git python-numpy swig python-dev default-jdk zip zlib1g-dev ipython

NVIDIAドライバとの衝突をさけるため、Nouveauのブラックリストを追加する

echo -e "blacklist nouveau\nblacklist lbm-nouveau\noptions nouveau modeset=0\nalias nouveau off\nalias lbm-nouveau off\n" | sudo tee /etc/modprobe.d/blacklist-nouveau.conf
echo options nouveau modeset=0 | sudo tee -a /etc/modprobe.d/nouveau-kms.conf
sudo update-initramfs -u
sudo reboot

再起動後、ログインしてlinux-image-extra-virtualをインストールする。

ssh -i ~/[ec2key].pem ubuntu@[Instance IP]
sudo apt-get install -y linux-image-extra-virtual
sudo reboot

再起動後、ログインしてlinux-headersをインストールする。

ssh -i ~/[ec2key].pem ubuntu@[Instance IP]
sudo apt-get install -y linux-source linux-headers-`uname -r`

CUDA Toolkit v8 をセットアップする

現時点での最新バージョンは 8.0。
ダウンロードしてインストールする

cd /tmp
wget https://developer.nvidia.com/compute/cuda/8.0/prod/local_installers/cuda_8.0.44_linux-run
chmod +x cuda_8.0.44_linux-run
./cuda_8.0.44_linux-run  -extract=`pwd`/nvidia_installers
cd nvidia_installers/
sudo ./NVIDIA-Linux-x86_64-367.48.run
# Acceptを選択する。kernelセットアップはプログレスバーが100%になってからしばらく時間がかかる
# OK を選択する
# OK を選択する
# Yes を選択する
# OK を選択する
sudo modprobe nvidia
sudo ./cuda-linux64-rel-8.0.44-21122537.run
# Readmeが表示されるので q で終了する
# accept と入力してエンター
# install Path: default
# shortcut?: default

cuDNN をセットアップ

https://developer.nvidia.com/cudnn からcuDNNを一度ローカルにDownloadする
cuDNNはDeveloperサインアップしないと落とせないため。仕方がない。

ローカルのターミナルからダウンロードしたcuDNNをEC2インスタンスに転送する

scp -i [ec2key].pem cudnn-8.0-linux-x64-v5.1.tgz ubuntu@[Instance IP]:/tmp

EC2インスタンスにもどる

cd /tmp
tar -xzf cudnn-8.0-linux-x64-v5.1.tgz
sudo mv ./cuda/lib64/* /usr/local/cuda/lib64/
sudo mv ./cuda/include/* /usr/local/cuda/include/

~/.bashrcに以下を追記する

# cuDNN
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/cuda/lib64"
export CUDA_HOME=/usr/local/cuda
source ~/.bashrc

Python 仮想環境の構築

python -V
Python 2.7.12
sudo apt-get install git gcc make openssl libssl-dev libbz2-dev libreadline-dev libsqlite3-dev
git clone https://github.com/yyuu/pyenv.git ~/.pyenv
git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv

~/.bash_profileを作成して以下を記載する

# pyenv
export PYENV_ROOT=$HOME/.pyenv
export PATH=$PYENV_ROOT/bin:$PATH
eval "$(pyenv init -)"
# virtualenv
eval "$(pyenv virtualenv-init -)"
export PYENV_VIRTUALENV_DISABLE_PROMPT=1
source ~/.bash_profile

Keras用仮想環境をつくる

pyenv install 3.5.3
pyenv virtualenv 3.5.3 keras
pyenv activate keras
python -V
Python 3.5.3

Tensorflowをインストールする

pip install tensorflow-gpu

TensorFlowのバージョンを確認してみて以下のようになってたらGPUが使えるようになっている。

python -c 'import tensorflow as tf; print(tf.__version__)'
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcublas.so.8.0 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcudnn.so.5 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcufft.so.8.0 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcuda.so.1 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcurand.so.8.0 locally
1.0.0

Kerasをインストールする

pip install pillow
pip install h5py
pip install matplotlib
pip install keras

keras examplesを実行してみる

cd /tmp
git clone https://github.com/fchollet/keras.git
cd keras/examples

とりあえずMNISTをCNNで解くやつを実行してみる

python mnist_cnn.py
Using TensorFlow backend.
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcublas.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcudnn.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcufft.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcuda.so.1 locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcurand.so locally
Downloading data from https://s3.amazonaws.com/img-datasets/mnist.pkl.gz
X_train shape: (60000, 28, 28, 1)
60000 train samples
10000 test samples
Train on 60000 samples, validate on 10000 samples
Epoch 1/12
I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
I tensorflow/core/common_runtime/gpu/gpu_device.cc:885] Found device 0 with properties: 
name: GRID K520
major: 3 minor: 0 memoryClockRate (GHz) 0.797
pciBusID 0000:00:03.0
Total memory: 3.94GiB
Free memory: 3.91GiB
I tensorflow/core/common_runtime/gpu/gpu_device.cc:906] DMA: 0 
I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 0:   Y 
I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GRID K520, pci bus id: 0000:00:03.0)
60000/60000 [==============================] - 13s - loss: 0.3770 - acc: 0.8839 - val_loss: 0.0932 - val_acc: 0.9709
Epoch 2/12
60000/60000 [==============================] - 11s - loss: 0.1363 - acc: 0.9603 - val_loss: 0.0632 - val_acc: 0.9801
Epoch 3/12
60000/60000 [==============================] - 11s - loss: 0.1064 - acc: 0.9687 - val_loss: 0.0509 - val_acc: 0.9835
Epoch 4/12
60000/60000 [==============================] - 11s - loss: 0.0900 - acc: 0.9736 - val_loss: 0.0443 - val_acc: 0.9857
Epoch 5/12
60000/60000 [==============================] - 11s - loss: 0.0769 - acc: 0.9775 - val_loss: 0.0405 - val_acc: 0.9865
Epoch 6/12
60000/60000 [==============================] - 11s - loss: 0.0689 - acc: 0.9795 - val_loss: 0.0371 - val_acc: 0.9870
Epoch 7/12
60000/60000 [==============================] - 11s - loss: 0.0649 - acc: 0.9803 - val_loss: 0.0361 - val_acc: 0.9881
Epoch 8/12
60000/60000 [==============================] - 11s - loss: 0.0594 - acc: 0.9823 - val_loss: 0.0356 - val_acc: 0.9886
Epoch 9/12
60000/60000 [==============================] - 11s - loss: 0.0547 - acc: 0.9841 - val_loss: 0.0321 - val_acc: 0.9889
Epoch 10/12
60000/60000 [==============================] - 11s - loss: 0.0525 - acc: 0.9841 - val_loss: 0.0320 - val_acc: 0.9889
Epoch 11/12
60000/60000 [==============================] - 11s - loss: 0.0506 - acc: 0.9850 - val_loss: 0.0323 - val_acc: 0.9892
Epoch 12/12
60000/60000 [==============================] - 11s - loss: 0.0471 - acc: 0.9856 - val_loss: 0.0314 - val_acc: 0.9897
Test score: 0.0314083654978
Test accuracy: 0.9897

実行時間は: 2:23 (データのダウンロード時間除く)。手持ちのMBAでは35分ほどかかったので10倍以上速い。
1epochあたり10秒くらいかよ。

調子に乗ってIMDBのLSTMという重たそうなやつもやってみた。

python imdb_cnn_lstm.py
Using TensorFlow backend.
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcublas.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcudnn.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcufft.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcuda.so.1 locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcurand.so locally
Loading data...
25000 train sequences
25000 test sequences
Pad sequences (samples x time)
X_train shape: (25000, 100)
X_test shape: (25000, 100)
Build model...
Train...
Train on 25000 samples, validate on 25000 samples
Epoch 1/2
I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
I tensorflow/core/common_runtime/gpu/gpu_device.cc:885] Found device 0 with properties: 
name: GRID K520
major: 3 minor: 0 memoryClockRate (GHz) 0.797
pciBusID 0000:00:03.0
Total memory: 3.94GiB
Free memory: 3.91GiB
I tensorflow/core/common_runtime/gpu/gpu_device.cc:906] DMA: 0 
I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 0:   Y 
I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GRID K520, pci bus id: 0000:00:03.0)
   30/25000 [..............................] - ETA: 1397s - loss: 0.6936 - acc: 0.4333I tensorflow/core/common_runtime/gpu/pool_allocator.cc:247] PoolAllocator: After 3811 get requests, put_count=2890 evicted_count=1000 eviction_rate=0.346021 and unsatisfied allocation rate=0.530307
I tensorflow/core/common_runtime/gpu/pool_allocator.cc:259] Raising pool_size_limit_ from 100 to 110
  360/25000 [..............................] - ETA: 160s - loss: 0.6935 - acc: 0.4833I tensorflow/core/common_runtime/gpu/pool_allocator.cc:247] PoolAllocator: After 2156 get requests, put_count=2374 evicted_count=1000 eviction_rate=0.42123 and unsatisfied allocation rate=0.373377
I tensorflow/core/common_runtime/gpu/pool_allocator.cc:259] Raising pool_size_limit_ from 256 to 281
  870/25000 [>.............................] - ETA: 94s - loss: 0.6925 - acc: 0.5287I tensorflow/core/common_runtime/gpu/pool_allocator.cc:247] PoolAllocator: After 4249 get requests, put_count=4491 evicted_count=1000 eviction_rate=0.222668 and unsatisfied allocation rate=0.192281
I tensorflow/core/common_runtime/gpu/pool_allocator.cc:259] Raising pool_size_limit_ from 655 to 720
25000/25000 [==============================] - 63s - loss: 0.3815 - acc: 0.8210 - val_loss: 0.3519 - val_acc: 0.8456
Epoch 2/2
25000/25000 [==============================] - 60s - loss: 0.1970 - acc: 0.9238 - val_loss: 0.3471 - val_acc: 0.8534
24990/25000 [============================>.] - ETA: 0sTest score: 0.347144101623
Test accuracy: 0.853440059948

実行時間: 2:25 (データのダウンロード時間除く)。MBAでこれも40分以上かかったやつなので圧倒的。

さらに調子に乗ってもっと重たそうなやつをやってみる。mnist_acgan.pyはMNISTをACGAN(Auxiliary Classifier Generative Adversarial Network)というやつで解くみたい。DCGANの親戚か?詳しくはここに載ってるみたいだけど難しいので後回しにする。
とりあえずGANなので重いだろう。どんなもんだろうか。

python mnist_acgan.py
Using TensorFlow backend.
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcublas.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcudnn.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcufft.so locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcuda.so.1 locally
I tensorflow/stream_executor/dso_loader.cc:128] successfully opened CUDA library libcurand.so locally
Epoch 1 of 50
  0/600 [..............................] - ETA: 0sI tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
I tensorflow/core/common_runtime/gpu/gpu_device.cc:885] Found device 0 with properties: 
name: GRID K520
major: 3 minor: 0 memoryClockRate (GHz) 0.797
pciBusID 0000:00:03.0
Total memory: 3.94GiB
Free memory: 3.91GiB
I tensorflow/core/common_runtime/gpu/gpu_device.cc:906] DMA: 0 
I tensorflow/core/common_runtime/gpu/gpu_device.cc:916] 0:   Y 
I tensorflow/core/common_runtime/gpu/gpu_device.cc:975] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GRID K520, pci bus id: 0000:00:03.0)
W tensorflow/core/common_runtime/bfc_allocator.cc:217] Ran out of memory trying to allocate 3.74GiB. The caller indicates that this is not a failure, but may mean that there could be performance gains if more memory is available.
599/600 [============================>.] - ETA: 1s   
Testing for epoch 1:
component              | loss | generation_loss | auxiliary_loss
-----------------------------------------------------------------
generator (train)      | 3.88 | 1.49            | 2.39 
generator (test)       | 3.36 | 1.04            | 2.32 
discriminator (train)  | 2.11 | 0.53            | 1.58 
discriminator (test)   | 2.12 | 0.70            | 1.43 
Epoch 2 of 50
 44/600 [=>............................] - ETA: 732s

1epoch終わるのに 15分ほどかかった。あと48epochある。。果てしないしお金かかるので途中でやめた。まあでも半日回せば結果出そう。すごいな。

作業後のディスク空き状況

df -k
Filesystem     1K-blocks    Used Available Use% Mounted on
udev             7679880       0   7679880   0% /dev
tmpfs            1539900    8800   1531100   1% /run
/dev/xvda1       8117828 6149060   1533492  81% /
tmpfs            7699496       0   7699496   0% /dev/shm
tmpfs               5120       0      5120   0% /run/lock
tmpfs            7699496       0   7699496   0% /sys/fs/cgroup
/dev/xvdb       66946696 3017852  60521484   5% /mnt
tmpfs            1539904       0   1539904   0% /run/user/1000

システムディスクの使用量は81%。エフェメラルストレージはインスタンスがstopすると揮発するのでデフォルトの8GBが不安ならストレージ要領を拡張しとくとよい。

AMIにしてからg2.xlargeインスタンスを作成してみたらエラーになる

構築できたインスタンスのスナップショットをとって、AMIからg2.xlargeインスタンスを作成してみた。ちゃんと動くか試行。

pyenv activate keras
python -V
 Python 3.5.3
python -c 'import tensorflow as tf; print(tf.__version__)'
Traceback (most recent call last):
  File "/home/ubuntu/.pyenv/versions/keras/lib/python3.5/site-packages/tensorflow/python/__init__.py", line 61, in <module>
    from tensorflow.python import pywrap_tensorflow
  File "/home/ubuntu/.pyenv/versions/keras/lib/python3.5/site-packages/tensorflow/python/pywrap_tensorflow.py", line 28, in <module>
    _pywrap_tensorflow = swig_import_helper()
  File "/home/ubuntu/.pyenv/versions/keras/lib/python3.5/site-packages/tensorflow/python/pywrap_tensorflow.py", line 24, in swig_import_helper
    _mod = imp.load_module('_pywrap_tensorflow', fp, pathname, description)
  File "/home/ubuntu/.pyenv/versions/3.5.3/lib/python3.5/imp.py", line 242, in load_module
    return load_dynamic(name, filename, file)
  File "/home/ubuntu/.pyenv/versions/3.5.3/lib/python3.5/imp.py", line 342, in load_dynamic
    return _load(spec)
ImportError: libcudart.so.8.0: cannot open shared object file: No such file or directory

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/home/ubuntu/.pyenv/versions/keras/lib/python3.5/site-packages/tensorflow/__init__.py", line 24, in <module>
    from tensorflow.python import *
  File "/home/ubuntu/.pyenv/versions/keras/lib/python3.5/site-packages/tensorflow/python/__init__.py", line 72, in <module>
    raise ImportError(msg)
ImportError: Traceback (most recent call last):
  File "/home/ubuntu/.pyenv/versions/keras/lib/python3.5/site-packages/tensorflow/python/__init__.py", line 61, in <module>
    from tensorflow.python import pywrap_tensorflow
  File "/home/ubuntu/.pyenv/versions/keras/lib/python3.5/site-packages/tensorflow/python/pywrap_tensorflow.py", line 28, in <module>
    _pywrap_tensorflow = swig_import_helper()
  File "/home/ubuntu/.pyenv/versions/keras/lib/python3.5/site-packages/tensorflow/python/pywrap_tensorflow.py", line 24, in swig_import_helper
    _mod = imp.load_module('_pywrap_tensorflow', fp, pathname, description)
  File "/home/ubuntu/.pyenv/versions/3.5.3/lib/python3.5/imp.py", line 242, in load_module
    return load_dynamic(name, filename, file)
  File "/home/ubuntu/.pyenv/versions/3.5.3/lib/python3.5/imp.py", line 342, in load_dynamic
    return _load(spec)
ImportError: libcudart.so.8.0: cannot open shared object file: No such file or directory


Failed to load the native TensorFlow runtime.

See https://github.com/tensorflow/tensorflow/blob/master/tensorflow/g3doc/get_started/os_setup.md#import_error

for some common reasons and solutions.  Include the entire stack trace
above this error message when asking for help.

TensorFlowがエラーを吐く。よくわからないけどCUDA関係か?
AMI化ができるかどうかはあとで検討が必要かも。断続的に使う場合はインスタンスをstopして置いとくのがいいかもしれない。

まとめ

上記Kerasの環境構築までは一時間以内でできる。インスタンスstopして置いとくのもいいけど、使いたい時にサラから構築してもそんなに手間ではない。
使用頻度とかケースに応じて考えるのがいいだろう。つーかTensorFlow GPUの環境構築以前と比べてめっちゃ楽になったな。

続きを読む

AWS Let’s Encrypt 証明書の自動発行とALBへの自動登録

こちらの記事を参考にさせて頂き設定したが、ALBの場合うまく行かなかったので、やり方を記載

ポイントは、ALBはELBのAPIとは異なり、さらにパラメーターが違うということ。
それにより、以下の違いがある

  • ALBはaws elb → aws elbv2
  • 対象ロードバランサーの指定方法が、ELB_NAMEでの指定ではなくLISTNER_ARNになった、SSLポートの方を指定
  • メソッドもaws elb set-load-balancer-listener-ssl-certificateからaws elbv2 modify-listenerへ
  • はまりポイントとしては一応aws elb describe-load-balancersでもALBのロードバランサーもリストに出て来るがelb set-load-balancer-listener-ssl-certificateを実行すると、そんなロードバランサーは存在しないと言われてしまう。

AWS CLI elbv2(ALB) modify-listener の APIリファレンスはこちら

SSL証明書自動更新スクリプトの変更点

この部分を

# ELB に新しいサーバー証明書を設定
$EXEC_AWS elb set-load-balancer-listener-ssl-certificate \
  --load-balancer-name $ELB_NAME \
  --load-balancer-port 443 \
  --ssl-certificate-id $SERVER_CERT_ARN

# ELB に新しいサーバー証明書を設定
$EXEC_AWS elbv2 modify-listener \
  --listener-arn $LISTNER_ARN \
  --port 443 \
  --protocol HTTPS \
  --certificates CertificateArn=$SERVER_CERT_ARN

に変更

SSL証明書自動更新スクリプト全体

#!/bin/bash
set -e
cd $(dirname $0)

# 現在日付のYYYYMMDD
DATE_CURRENT_YMD=$(date '+%Y%m%d')

# AWS Profile 名
AWS_PROFILE=elb_update_cert

# 独自ドメイン
DOMAINS=(
  "example.com"
)

# IAM 上のサーバー証明書名。後ろに "-" + $DATE_CURRENT_YMD が付く。
CERT_NAME="letsencrypt-cert"

# 対象 ELB のロードバランサーARN
LISTNER_ARN="arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxxxxxxxx"

# aws-cli 実行コマンド
EXEC_AWS="aws --profile elb_update_cert"

# Let's Encrypt の連絡用メールアドレス
LE_EMAIL=info@example.com

# Let's Encrypt Client を clone したパス
LE_HOME=/usr/local/certbot

# letsencrypt-auto 実行コマンド
EXEC_LE_AUTO="${LE_HOME}/cert-auto --email $LE_EMAIL --agree-tos"

# 取得した証明書ファイルのリンク群が配置されるディレクトリ
# letsencrypt-auto に与えた最初のドメイン名が採用される
LE_FILES_ROOT=/etc/letsencrypt/live/${DOMAINS[0]}

# 証明書ファイル群のシンボリックリンクのパス
CERT_PATH=$LE_FILES_ROOT/cert.pem
CHAIN_PATH=$LE_FILES_ROOT/chain.pem
FULLCHAIN_PATH=$LE_FILES_ROOT/fullchain.pem
PRIVKEY_PATH=$LE_FILES_ROOT/privkey.pem

# DOMAINS を "-d" とペアで繋げたパラメータ (-d "yourdomain.com" -d "www1.yourdomain.com" ... )
LE_PARAM_DOMAINS=()
for domain in "${DOMAINS[@]}"; do
  LE_PARAM_DOMAINS+=("-d" "$domain")
done
LE_PARAM_DOMAINS="${LE_PARAM_DOMAINS[@]}"

# 証明書を(再)発行。
$EXEC_LE_AUTO certonly --webroot \
    --renew-by-default \
    -w /var/www/letsencrypt \
    $LE_PARAM_DOMAINS

# 現時点のサーバー証明書名リストを取得
OLD_SERVER_CERT_NAMES=$($EXEC_AWS iam list-server-certificates | jq -r ".ServerCertificateMetadataList[] | select(.ServerCertificateName | contains(\"${CERT_NAME}\")).ServerCertificateName")

# 新しい証明書のサーバー証明書名
NEW_SERVER_CERT_NAME="${CERT_NAME}-${DATE_CURRENT_YMD}"

# 新しい証明書を IAM にアップロード
$EXEC_AWS iam upload-server-certificate --server-certificate-name $NEW_SERVER_CERT_NAME \
  --certificate-body file://$CERT_PATH \
  --private-key file://$PRIVKEY_PATH \
  --certificate-chain file://$CHAIN_PATH

# 反映を待つ
sleep 15

# 新しい証明書の ARN を取得
SERVER_CERT_ARN=$($EXEC_AWS iam list-server-certificates | jq -r ".ServerCertificateMetadataList[] | select(.ServerCertificateName == \"${NEW_SERVER_CERT_NAME}\").Arn")

# ELB に新しいサーバー証明書を設定
$EXEC_AWS elbv2 modify-listener \
  --listener-arn $LISTNER_ARN \
  --port 443 \
  --protocol HTTPS \
  --certificates CertificateArn=$SERVER_CERT_ARN

# 反映を待つ
sleep 15

# 古い証明書を削除
for cert_name in $OLD_SERVER_CERT_NAMES; do
  $EXEC_AWS iam delete-server-certificate --server-certificate-name $cert_name
done

続きを読む

Redhat7にnginxのインストールとバーチャルホストの設定

インストール

# yum install nginx

# nginx -v
nginx version: nginx/1.10.2

バーチャルホストの設定

今後の規約として、

  • バーチャルホストの設定ファイルは、/etc/nginx/conf.dに、[ドメインのFQDN].confの名前で運用する。
  • バーチャルホストのドキュメントルートは、/var/www/vhosts/[ドメインのFQDN]とする。

上記のルールに従って、/etc/nginx/conf.dの下に、example.com.confという設定ファイルを作りました。

server {
    listen       80 default;
    server_name  ec2-xx-xxx-xxx-xx.xx-xxxx-2.compute.amazonaws.com;

    charset utf-8;

    location / {
        root   /var/www/vhosts/example.com;
        index  index.html index.htm;
    }

    error_page 404 /404.html;
        location = /40x.html {
    }

    error_page 500 502 503 504 /50x.html;
        location = /50x.html {
    }

    location ~ /.ht {
        deny  all;
    }
}

今後、このドメインをnginxのデフォルトサービスにしますので、defaultの設定をしています。

設定ファイルのシンタックスチェック

# nginx -t
nginx: [emerg] could not build server_names_hash, you should increase server_names_hash_bucket_size: 64
nginx: configuration file /etc/nginx/nginx.conf test failed

来ましたこれ。バーチャルホストの、server_nameが長いと怒られています。今回AWSのパプリックドメインをとりあえずそのまま使っているので、たしかに長いです。

で、エラーメッセージ通りに、nginx.confの、server_names_hashに、64を設定してあげてもやはり同じエラーが出ます。

なので、最終的に以下のようにhttpディレクティブの設定を修正しクリアしました。

http {
    server_names_hash_bucket_size 128;

確認。

# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

成功!

デーモンの起動設定と、手動での起動

# systemctl enable nginx.service
# systemctl start nginx.service

続きを読む

RedHat7にPHP7のインストール

あるサーバーにPHP7を入れてほしいという依頼が来た。

インスタンスの情報収集

$ uname -a
Linux xxx.compute.internal 3.10.0-514.el7.x86_64 #1 SMP Wed Oct 19 11:24:13 EDT 2016 x86_64 x86_64 x86_64 GNU/Linux
$ cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.3 (Maipo)
$ cat /proc/version
Linux version 3.10.0-514.el7.x86_64 (mockbuild@x86-039.build.eng.bos.redhat.com) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC) ) #1 SMP Wed Oct 19 11:24:13 EDT 2016
項目 内容
OS Red Hat Enterprise Linux Server 7.3
アーキテクチャ x86_64
gcc 4.8.5

wgetのインストール

wgetが入っていなかったのでインストール。rpmファイルの取得に使います。

# yum install wget

yumリポジトリの追加

リポジトリはAWSのデフォルトのまま。

# yum repolist
Loaded plugins: amazon-id, rhui-lb, search-disabled-repos
repo id                                                                repo name                                                                             status
rhui-REGION-client-config-server-7/x86_64                              Red Hat Update Infrastructure 2.0 Client Configuration Server 7                            6
rhui-REGION-rhel-server-releases/7Server/x86_64                        Red Hat Enterprise Linux Server 7 (RPMs)                                              13,838
rhui-REGION-rhel-server-rh-common/7Server/x86_64                       Red Hat Enterprise Linux Server 7 RH Common (RPMs)                                       209
repolist: 14,053

epelのリポジトリの追加

epelとは、Extra Packages for Enterprise Linuxの略称で、RedHatやCentOSは保守的で使えるrpmパッケージ自体やそのバージョンが限られているので、新しいものを使いたい場合は、epelをリポジトリに追加することにより、Fadoraと同様のパッケージの利用が可能になる。
詳しくは、https://fedoraproject.org/wiki/About_EPEL/ja

# wget http://ftp-srv2.kddilabs.jp/Linux/distributions/fedora/epel/7/x86_64/e/epel-release-7-9.noarch.rpm
# rpm -ivh epel-release-7-9.noarch.rpm

リポジトリを確認。epelが追加された。

# yum repolist
Loaded plugins: amazon-id, rhui-lb, search-disabled-repos
repo id                                                                repo name                                                                             status
epel/x86_64                                                            Extra Packages for Enterprise Linux 7 - x86_64                                        11,184
rhui-REGION-client-config-server-7/x86_64                              Red Hat Update Infrastructure 2.0 Client Configuration Server 7                            6
rhui-REGION-rhel-server-releases/7Server/x86_64                        Red Hat Enterprise Linux Server 7 (RPMs)                                              13,838
rhui-REGION-rhel-server-rh-common/7Server/x86_64                       Red Hat Enterprise Linux Server 7 RH Common (RPMs)                                       209
repolist: 25,237

remiのリポジトリの追加

remiリポジトリを追加するためには、epelリポジトリの追加を先にしておく必要がある。

# rpm --import http://rpms.famillecollet.com/RPM-GPG-KEY-remi
# rpm -ivh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm

リポジトリの確認。remiが追加されている。

# yum repolist
Loaded plugins: amazon-id, rhui-lb, search-disabled-repos
remi-safe                                                                                                                                   | 2.9 kB  00:00:00
remi-safe/primary_db                                                                                                                        | 906 kB  00:00:03
repo id                                                                repo name                                                                             status
epel/x86_64                                                            Extra Packages for Enterprise Linux 7 - x86_64                                        11,184
remi-safe                                                              Safe Remi's RPM repository for Enterprise Linux 7 - x86_64                             2,000
rhui-REGION-client-config-server-7/x86_64                              Red Hat Update Infrastructure 2.0 Client Configuration Server 7                            6
rhui-REGION-rhel-server-releases/7Server/x86_64                        Red Hat Enterprise Linux Server 7 (RPMs)                                              13,838
rhui-REGION-rhel-server-rh-common/7Server/x86_64                       Red Hat Enterprise Linux Server 7 RH Common (RPMs)                                       209
repolist: 27,237

念のためリポジトリのデータベースの参照も確認。
なんかたくさん入ってるぞ!

# ls /etc/yum.repos.d/
epel.repo          redhat.repo                     redhat-rhui.repo  remi-php70.repo  remi.repo       rhui-load-balancers.conf
epel-testing.repo  redhat-rhui-client-config.repo  remi-php54.repo   remi-php71.repo  remi-safe.repo

PHPのインストール

さて下準備が長くなりましたが、本題のPHP7のインストールです。
開発に必要と思われるものを一気に入れちゃいます。

# yum install --enablerepo=epel,remi-php70 php php-mbstring php-pear php-fpm php-mcrypt php-mysql

確認。

# php -v
PHP 7.0.16 (cli) (built: Feb 14 2017 17:22:12) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies

でけた!

続きを読む

初心者がAWS(EC2)にアプリをデプロイする際に対峙したエラーとその対応

はじめに

デプロイの際に遭遇したエラーたちとの奮闘記です。
まとまってませんが、皆さんのエラー解決のヒントになれば幸いです。

Version等

Ruby: 2.3.1
Rails: 5.0.1
AWS(EC2)・Nginx・Unicorn・Mysqlの組み合わせ。

① rails コマンドが使えない

terminal
[ec2-user@ip-XXX-XX-XX-XXX teatapp]$ rails secret
-bash: rails: コマンドが見つかりません

解決策

exitで一回ec2を出て入り直すとコマンドが使えるようになる。
なんか変なこと起きたらとりあえず再起動しよう。ド初歩 …。

② Mysql2::Error: Can’t connect to local MySQL server through socket ‘/tmp/mysql.sock’ (2)

「’/tmp/mysql.sock’のソケットじゃ、MySQLと通信できません」とのエラー。アプリケーションが指定しているソケットと、データベース側のソケットが食い違っているために通信ができない模様。
ソケットに関しては以下でざっくり掴めると思います。
IT用語辞典e-Words
「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

terminal
$ mysql_config --socket

このコマンドでmysql側のソケットタイプが調べられるので調べてみると、

terminal
[ec2-user@ip-XXX-XX-XX-XXX ~]$ mysql_config --socket
/var/lib/mysql/mysql.sock

/var/lib/mysql/mysql.sockこういうタイプのソケットらしい。
一方、アプリ側のソケットを調べてみると、

database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  password:
  socket: /tmp/mysql.sock

/tmp/mysql.sockと、Mysql側のソケットとタイプが異なる。

解決策

ということでアプリ側のソケットの記述を以下のように修正。

database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  password:
  socket: /tmp/mysql.sock

 (中略)

production:
  <<: *default
  database: testapp_production
  username: testapp
  password: <%= ENV['TESTAPP_DATABASE_PASSWORD'] %>
  socket: /var/lib/mysql/mysql.sock

default部分の記述は残したままで、productionの方に加筆すればOK。
これで、ソケットタイプが合致してアプリとデータベースが通信できるようになりました。

と、思いきや

③ ERROR — : Access denied for user ‘testapp’@’localhost’ (using password: NO) (Mysql2::Error)

terminal
[ec2-user@ip-XXX-XX-XX-XXX testapp]$ unicorn_rails -c config/unicorn.rb -E production

のコマンドでunicornを作動しても、うまく立ち上がらず。

何が起こっているのか、エラーの詳細を確認するために、以下のコマンドを実行。

terminal
[ec2-user@ip-XXX-XX-XX-XXX testapp]$ less log/unicorn.stderr.log

log/unicorn.stderr.logのログを辿ると、以下のような記述が。

log/unicorn.stderr.log
ERROR -- : Access denied for user 'testapp'@'localhost' (using password: NO) (Mysql2::Error)

using password: NOということで、どうやら環境変数で設定したパスワードが読み込まれていない模様。
①アプリ側の環境変数を読み込んでいるところの記載
②EC2側の環境変数を書き込んでいるところの記載
をチェックしてみると…

database.yml
production:
  <<: *default
  database: testapp_production
  username: testapp
  password: <%= ENV['TESTAPP_DATABASE_PASSWORD'] %>
  socket: /var/lib/mysql/mysql.sock

アプリ側は、password: <%= ENV['TESTAPP_DATABASE_PASSWORD'] %>との記述。
一方EC2側はの記載を以下のコマンドでチェックしてみると、

terminal
$ sudo vim /etc/environment
etc/environment
DATABASE_PASSWORD='XXXXXXXXXXXXXXX'
SECRET_KEY_BASE='XXXXXXXXXXXXXXX'

DATABASE_PASSWORD='XXXXXXXXXXXXXXX'との記述。

変数がアプリ側とEC2側で食い違ってました。

解決策

ということで、アプリ側の記述を以下のように変更。

database.yml
production:
  <<: *default
  database: testapp_production
  username: testapp
  password: <%= ENV['DATABASE_PASSWORD'] %>   # 「TESTAPP_」を削除
  socket: /var/lib/mysql/mysql.sock

これで環境変数が正しく読み込まれるようになりました。
ちなみにですが、
① Mysqlのroot user passwordの先頭が「0」で始まる場合、環境変数の読み込みがうまくいかない場合がある
② 環境変数名に「-」(ハイフン)を含めると、環境変数の読み込みがうまくいかない場合がある
みたいです。

環境変数を

etc/environment
NEW-APP_DATABASE_PASSWORD='01234567'
SECRET_KEY_BASE='XXXXXXXXXXXXXXX'

のように変数名にハイフンを含めており、パスワードの先頭を0で始めていて、大っ変痛い目に会いました。

ちなみのちなみに、環境変数がちゃんと読み込まれているか確認するには、

terminal
[ec2-user@ip-XXX-XX-XX-XXX testapp]$ rails c

でコンソールを開いて、

terminal
irb(main):001:0> ENV['DATABASE_PASSWORD']
=> "XXXXXXXX"

と環境変数を打ってあげればちゃんと読み込めているか確認できます。

さて、これでunicornが使えるかと思いきやまたMysqlのエラー。

④ ERROR — : Access denied for user ‘testapp’@’localhost’ (using password: YES) (Mysql2::Error)

ソケットも合わせて、
環境変数も読み込めるようにして、
でもエラー。エラー文を見てみると、なんかユーザーのところが「testapp」になっている。ここが原因。

database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  password:
  socket: /tmp/mysql.sock

 (中略)

production:
  <<: *default
  database: testapp_production
  password: <%= ENV['TESTAPP_DATABASE_PASSWORD'] %>
                                                                                   # productionのuser部分を削除。
  socket: /var/lib/mysql/mysql.sock

解決策

productionのuser部分を削除(するとdefaultのusername、つまりrootがproductionでも読み込まれるようになる)。

これで、

terminal
$ unicorn_rails -c config/unicorn.rb -E production

をしてあげるとunicornが立ち上がりました。Mysqlとの通信もうまくいっている模様。でも、

⑤ Unicornは動いているのにページが表示されない

http:// ~Elastic IP~ :3000/でページにアクセスしても、ロードが続くだけで表示されず。

スクリーンショット 2017-02-16 18.28.12.png

と出てきてしまう。ううう…。

これは原因は単純でポートの開け忘れでした。

スクリーンショット 2017-02-16 18.29.40.png

AWSでポート3000を開けてあげて、

ページが表示されました。

参考サイト

IT用語辞典e-Words
「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

続きを読む

AmazonLinuxに古いバージョンのnginxをインストールする

2017/2/15現在、AmazonLinux(2016.09)で sudo yum install nginxとやると バージョン1.10.1がインストールされます。
1.8が入れたかったのでその際の作業メモです。

nginxのリポジトリを追加

公式ドキュメントに書いてあるけど、一応説明。
http://nginx.org/packages/
上記から自分の環境にあったものを追加する。
AmazonLinuxはCentOS6互換なので、baseurlは http://nginx.org/packages/centos/6/$basearch/  が正解。

/etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/6/$basearch/
gpgcheck=0
enabled=1

失敗

これで sudo yum install nginx-1.8.1とやれば終了〜:raised_hands:とはならない。
amzn-mainリポジトリにnginxが存在しており、amzn-mainリポジトリには以下のようにpriorityが設定してある。

/etc/yum.repos.d/amzn-main.repo
[amzn-main]
name=amzn-main-Base
mirrorlist=http://repo.$awsregion.$awsdomain/$releasever/main/mirror.list
mirrorlist_expire=300
metadata_expire=300
priority=10
failovermethod=priority
fastestmirror_enabled=0
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-amazon-ga
enabled=1
retries=5
timeout=10
report_instanceid=yes

[amzn-main-debuginfo]
name=amzn-main-debuginfo
mirrorlist=http://repo.$awsregion.$awsdomain/$releasever/main/debuginfo/mirror.list
mirrorlist_expire=300
metadata_expire=300
priority=10
failovermethod=priority
fastestmirror_enabled=0
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-amazon-ga
enabled=0
retries=5
timeout=10
report_instanceid=yes

nginxリポジトリにはpriorityを設定していないので、amzn-mainリポジトリ > nginxリポジトリ となり、
amzn-mainリポジトリでnginxが見つかるのでnginxリポジトリを見に行かない→1.10.1がインストールされる。
なので、以下のようにamzn-mainを一時的に無効化しておく。

インストールできるバージョンの確認

yum --showduplicates --disablerepo=amzn-main list nginx

結果
nginx.x86_64                            1.8.0-1.el6.ngx                             nginx
nginx.x86_64                            1.8.1-1.el6.ngx                             nginx
nginx.x86_64                            1.10.0-1.el6.ngx                            nginx
nginx.x86_64                            1.10.1-1.el6.ngx                            nginx
nginx.x86_64                            1.10.2-1.el6.ngx                            nginx
nginx.x86_64                            1.10.3-1.el6.ngx                            nginx

インストール

sudo yum install -y --disablerepo=amzn-main nginx-1.8.1

バージョン確認

nginx -v

結果
nginx version: nginx/1.8.1

参考情報

CentOSにちょっと古いバージョンのNginxをインストールする
Amazon Linux で Nginx & PHP の最新版をインストールした際の記録

続きを読む

zabbixを使ってRDS for Auroraの内部ステータスを取得してみました。

目的

Aurora のステータス情報をzabbixで取得したい

手法

Auroraををzabbixで直接参照することはできない(RDSにzabbix-Agentは入らないので)
代替えのインスタンスを起動して、EC2のAgentを使ってAWS Auroraから値を取得する。

検証環境

・Aurora 5.6.10a
・Auroraエンドポイント用のEC2インスタンス(zabbixサーバへ登録済み)
・zabbixサーバ

詳しい手順

Auroraへzabbix監視ユーザの登録

grant process on *.* to 'zabbix'@'%' identified by 'zbxpass';

EC2インスタンスに.my.cnfの作成

$ sudo mkdir /var/lib/zabbix
$ sudo vim /var/lib/zabbix/.my.cnf
$ sudo chmod 400 /var/lib/zabbix/.my.cnf
$ sudo chown -R zabbix:zabbix /var/lib/zabbix

.my.cnfの中身

[client]
user = zabbix
password= zbxpass

/etc/zabbix/zabbix_agentd.d/userparameter_mysql.confの編集

変更前
UserParameter=mysql.status[*],echo "show global status where Variable_name='$1';" | HOME=/var/lib/zabbix mysql -N | awk '{print $$2}'
変更後
UserParameter=mysql.status[*],echo "show global status where Variable_name='$1';" | HOME=/var/lib/zabbix mysql -hxxxxxxx.cluster-xxxxxxx.ap-northeast-1.rds.amazonaws.com -N | awk '{print $$2}'
変更前
UserParameter=mysql.size[*],bash -c 'echo "select sum($(case "$3" in both|"") echo "data_length+index_length";; data|index) echo "$3_length";; free) echo "data_free";; esac)) from information_schema.tables$([[ "$1" = "all" || ! "$1" ]] || echo " where table_schema="$1"")$([[ "$2" = "all" || ! "$2" ]] || echo "and table_name="$2"");" | HOME=/var/lib/zabbix mysql -N'
変更後
UserParameter=mysql.size[*],bash -c 'echo "select sum($(case "$3" in both|"") echo "data_length+index_length";; data|index) echo "$3_length";; free) echo "data_free";; esac)) from information_schema.tables$([[ "$1" = "all" || ! "$1" ]] || echo " where table_schema="$1"")$([[ "$2" = "all" || ! "$2" ]] || echo "and table_name="$2"");" | HOME=/var/lib/zabbix mysql -hxxxxxxx.cluster-xxxxxxx.ap-northeast-1.rds.amazonaws.com -N'
変更前
serParameter=mysql.ping,HOME=/var/lib/zabbix mysqladmin ping | grep -c alive
変更後
serParameter=mysql.ping,HOME=/var/lib/zabbix mysqladmin -hxxxxxxx.cluster-xxxxxxx.ap-northeast-1.rds.amazonaws.com ping | grep -c alive

これで疑似的にEC2上で動くMySQLとして認識されるのでRDSでTemplate App MySQLを利用することができる。

クラスタエンドポイントや、読み込みエンドポイントをそれぞれ指定すれば
両方のステータス値が取得できる。

デメリットとして、RDSが複数ある場合、その台数分の代替えインスタンスが必要になるが
zabbix-agentを動かすだけなら、t2.nanoでも十分かも。

続きを読む