深淵の闇から逃れる為の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のデュアルマスタ機能を試すことが出来ました。

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

最高。

続きを読む

Terraform で AWS環境を実運用する上で困ったことと、その対処

忘備録的なもの。
2017年2月時点、Terraformは0.8.6.

操作用AWSアカウントの認証情報の扱い

困ったこと

ネットの参考情報だと、awsの認証情報(credentials)を直接書くサンプルが非常に多かった。
しかし、tfファイルを書き換える運用だと、いつか間違えてcommit & pushしてインシデントになりそう。

Terraformを最初に動かすためのユーザーの認証情報は、その性質上大きな権限を持っていることが多いと思うので、慎重になりたい。

解決策

AWS-CLIのNamed Profile使おう。

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

事前にこうして設定しておけば、認証情報は$home/.aws/credentialsに名前付きで入る。

スクリプトからはこう参照する。これならばcommitしてしまっても問題ない。

example1.tf
provider "aws" {
  profile = "my-profile-name"
}

あとは、上記の設定手順をREADME.md なんかに書いて、KEYIDとSECRET自体はいつも通り正しく管理してあげればいい。

.tfstateファイルの扱い

困ったこと

.tfstateファイルを紛失してしまうと、作成したインスタンスを、Terraformから管理できなくなってしまうので、最重要ファイルだ。
かといって、gitにcommitするルールだと、commit忘れが怖いし、その際pullし忘れるとつらい。
一方、手動であちこち引き回しても同じことで、別の開発者が古いstateに基づいて、重複したインスタンスを立ててしまうかもしれない…

解決策

Backendの、remote state機能使おう。

ちゃんと公式ドキュメントある。 https://www.terraform.io/docs/state/remote/s3.html

こんな感じ。profileも指定できるので、そちらにregionを書いておけば省略できる。

$ terraform remote config 
    -backend=s3 
    -backend-config="bucket=my-tfstate-store-name-at-s3" 
    -backend-config="key=hogehoge/terraform.tfstate" 
    -backend-config="profile=my-profile-name"

これを実行した時点で、存在していたterraform.tfstateは、./.terraform/terraform.tfstate に移動されるようだ。

あとは自動でtfstateファイルをアップロード、ダウンロードしてくれる。
指定するバケットはacl=privateにしておくこと!!
あと、上記リンクでは、S3のversioningとかもつけておくことを勧めている。(私はやらなかった)

S3以外にも、いろいろ手段は用意されているようだ。

環境ごとのvariableの扱い

困ったこと

ステージングと本番、みたいに分けようと思って、環境ごとにvariableで設定値を与えられるようにしたけど、
-var オプションで引数に全部指定するの辛い

解決策

共通の設定ならば、terraform.tfvars という名前のファイルに書いておけば、指定しないでも勝手に読み込んでくれるとのこと。
https://www.terraform.io/intro/getting-started/variables.html#from-a-file

環境ごとに違う変数は、-var-fileオプションを使ってスイッチするのがよさそうだ。

$ terraform plan -var-file staging.tfvars
$ terraform plan -var-file production.tfvars

的な。

varは後ろに指定したものが有効(上書きされる)とのことなので、上手に使えば強いはず。

Packerで作ったAMIでEC2インスタンスを生成したい

困ったこと

auto-scalingを考えたときに、元となるAMIをちゃんと運用したい。
(注意、私はAWSのAutoScaling をよくわかっていないかも。)

そこで、Packerでイミュータブルなイメージ作ったらすごーいはず。
イミュータブルということは、イメージにDB接続情報がないといけない気がする。
よって、Terraformで先にRDS立てないといけないけど、そのTerraform側でAMIを使いたいからこういう話になっているわけで…
循環参照してしまう。

そもそも、AutoScaling配下のインスタンスを入れ替える際に全インスタンスを落とさないようにする、というのがなかなか厳しいようだ。
AutoScalingとの相性は、改善まち、という感じか。

参考: http://qiita.com/minamijoyo/items/e32eaeebc906b7e77ef8

準解決策1 null_resource

最終的にはうまくいかなかったが、最初に試した方法

null_resourceというものがある。
https://www.terraform.io/docs/provisioners/null_resource.html

何もしない代わりに、自身の状態(=変更が起きるトリガー)を定義するtriggers属性と、provisionerを設定できるリソースだ。
これを使って、

example2.tf
variable "ami_name_prefix" {}

resource "null_resource" "packer" {
  triggers {
    db_host = "${aws_db_instance.hogehoge.address}"
  }

  provisioner "local-exec" {
    command = <<EOS
packer build 
  -var 'DB_HOST=${aws_db_instance.hogehoge.address}' 
  -var 'AMI_NAME_PREFIX=${ami_name_prefix}' 
  packer.json"
EOS
  }
}

data "aws_ami" "packer_ami" {
  most_recent = true
  name_regex = "^${var.ami_name_prefix}.*"
  owners = ["self"]
  depends_on = ["null_resource.packer"]
}

resource "aws_instance" "hoge" {
  ami_id = "${data.aws_ami.packer_ami.id}"
  ...
}

とこんな感じ。

しかし、Terraform 0.8.6だと、triggersの中にinterpolationを混ぜると、問答無用でcomputed扱いになってしまうようで、
この記述では毎回AMIが作成されてしまって、差分のみ実行というTerraformの観点からは、使えなかった。

準解決策2 イミュータブルを諦める

オートスケーリング自体はこのパターンでは不可能か。AMI化を再度行う必要があると思う。

ほぼ完成品のAMIを組み立てておいて、aws_instanceのprovisionerで最後の仕上げをする。
Dockerなんかは、環境変数で外部情報を読み込ませる、なんてことをするらしいので、この手法に踏み切った。

// .envが欠けた状態でAMIをつくる
$ packer packer.json
example3.tf
data "aws_ami" "packer_ami" {
  most_recent = true
  name_regex = "^packer-ami-.*$"
  owners = ["self"]
  depends_on = ["null_resource.packer"]
}

data "template_file" "envfile" {
  # template = "${file(./env.tpl)}" などとした方が望ましいが例示のため。
  template = <<EOS
export DB_HOST="${db_host}"
export DB_PORT="${db_port}"
....
EOS

  vars {
    db_host = "${aws_db_instance.main.address}"
    db_port = "${aws_db_instance.main.port}"
  }
}

resource "aws_instance" "ec2" {
  ami_id = "${data.aws_ami.packer_ami.id}"
  ...

  # envファイルをuploadする。envファイルはdirenvとかdotenvとかで読み込まれるようにしておく。
  provisioner "file" {
    content = "${data.template_file.envfile.rendered}"
    destination = "/home/ec2-user/.env"
  }

  # 上で入れた環境変数を使ってサービスを立ち上げる。
  provisioner "remote-exec" {
    inline = ["sudo service unicorn start"]
  }

  # provisionerは、実行した環境からssh(のgolang実装。sshコマンドではない)で接続することになる。
  # 当然security_groupとvpc_internet_gatewayが適切に設定されている必要がある。
  connection {
    type = "ssh"
    ...
  }
}

tfファイルを構造化したい

困ったこと

コピペや反復は悪だし、再利用性も下がる。

COUNT

COUNT = nで配列のように同じタイプのリソースを複数作れる。
それぞれ微妙に違う値を書きたいなら、

COUNT = 2
ATTR = "${element(list("a", "b", "c", "d"), count.index)}"

などとできる。
listは変数化するとなおよい。

module

複数のリソースにまたがっての反復パターンなら、module化してしまうとよい。
module自体の書き方はここでは説明しないが、

./modules/my_module/variables.tf
./modules/my_module/main.tf
./modules/my_module/output.tf

を作り、

example4.tf
module "use_of_my_module" {
  source = "./my_module"
  var1 = ...
  var2 = ...
}

と書くことで使用。

$ terraform get

で、モジュールをterraformに読み込ませる準備をさせる。(./.terraform/modules/ にsym-linkが作成されるようだ)

様々に公開されているmoduleもあるようなので、むしろ自分でresourceを書かないほうが良いのかもしれない。

その他

また何かあれば書く。

続きを読む

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

続きを読む

Railsでcarrierwaveを使ってAWS S3に画像をアップロードする手順を画像付きで説明する

概要

タイトルまま。そのままやれば10分でrailsに画像アップローダー機能が追加されるはず。

前提

  • railsインストール済
  • AWSアカウント作成済み

手順

AWSでユーザーを作成し、S3バケットを作成する。次に、railsでcarriewaveの設定する。

AWS

IAM設定

IAMユーザ作成

  • AWSコンソールにログインしてIAMサービスにアクセスする
    https://gyazo.com/2fb2114c4f300d6633fc1ab79d862a5c

  • ユーザを追加する
    https://gyazo.com/a90614dd9d284f1ae6ad699b60e89b4a

  • ユーザー名を入力し、アクセスの種類をプログラムによるアクセスにする
    https://gyazo.com/115afc09d7e3513c791af3156ffbbdd5

  • 上記で作成したユーザにS3へアクセスできる権限を追加
    https://gyazo.com/f0eb22ad0774f2015b75c151a33aeca4

  • 設定を確認しユーザ作成を完了する
    https://gyazo.com/165d7e2f55a98625df0c9e55e62f646a

IAMユーザのアクセスキーを入手する

  • ユーザーを選択
    https://gyazo.com/d691057f84a01f438cd8407d3196fe0c

  • アクセスキーを追加
    https://gyazo.com/7948222e4e7510dfd5ec88f83ad5dd60

  • アクセスキーとシークレットアクセスキーをメモする。(下記キーは事例のため開示しているけど、本来は絶対に秘密にすべき文字列です。)
    https://gyazo.com/adcc51e0a8fb0a888ca11c94f28675ca

S3バケット作成

  • S3にアクセスする
    https://gyazo.com/e6b273c94aa5e94641b5b8daf9f48200
    https://gyazo.com/85cba09f8cb838412908d1d5ecc3ffd5

  • バケット名を入力して、リージョンを選択して、作成する
    https://gyazo.com/9a1ec4f4c0cceb94eb1911be478962f9

rails & carrierwave

photoモデルをつくって、imageカラムに画像をアップロード出来るように設定します。

gemインストール

carrierwave gemを追加してインストールします。

# for image uploader with AWS S3
gem 'carrierwave'
gem 'fog'
$ bundle install

画像保存用のモデル作成

photoモデルを追加して、imageカラムを設定します。

$ rails g model photo
db/migrate/20170101010101_create_photos.rb
class CreatePhotos < ActiveRecord::Migration
  def change
    create_table :photos do |t|
      t.string :image
      t.timestamps
    end
  end
end

$ rake db:migrate

carrierwaveの設定

Uploaderクラスを追加します。名前はなんでもいいです。今回はImageにします。

rails generate uploader Image

最低限の設定をする。(ほぼデフォルト)。今回は、developmentとtest環境はlocalファイル、それ以外(productionやstaging)はS3を使う設定をする。重要なのは、最初の2-8行。

app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
  if Rails.env.development?
    storage :file
  elsif Rails.env.test?
    storage :file
  else
    storage :fog
  end

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  def extension_whitelist
    %w(png jpg)
  end

  def filename
    original_filename if original_filename
  end
end

前半で設定した内容を元に設定する
* aws_access_key_id S3用に用意したIAMユーザーのアクセスキー
* aws_secret_access_key S3用に用意したIAMユーザーのシークレットアクセスキー
* region S3のリージョン
* config.fog_directory S3のバケット名

config/initializers/carrierwave.rb
CarrierWave.configure do |config|
  config.fog_credentials = {
    provider: 'AWS',
    aws_access_key_id: 'AKIAJMOPEQF3VXSKWXOQ',
    aws_secret_access_key: '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',
    region: 'ap-northeast-1'
  }

  config.fog_directory  = 'rails-photo-123'
  config.cache_storage = :fog
end

画像用モデルをcarrierwave用に修正する

photoモデルのimageカラムにmount_uploaderを設定する。

app/models/photo.rb
class Photo < ActiveRecord::Base
  mount_uploader :image, ImageUploader
end

これで終了。

使い方

アップロード

mount_uploaderを設定したカラムをfile_fieldで呼び出せばstore_dirに保存されます。

app/views/photos/new.html.erb
<%= f.file_field :image %>

画像表示

image.to_sで画像表示用のリンクが取得できます。

app/views/photos/show.html.erb
<%= image_tag photo.image.to_s %>

複数のカラム

image.to_sで画像表示用のリンクが取得できます。

app/views/photos/show.html.erb
<%= image_tag photo.image.to_s %>

アップロード用のカラムを追加

さらにアップロードしたいカラムを追加したい場合は、migrationで普通にstring属性のカラムを追加して、モデルでmount_uploaderを追加するだけ。

app/models/photo.rb
class Photo < ActiveRecord::Base
  mount_uploader :image, ImageUploader
  mount_uploader :kudamono, ImageUploader
  mount_uploader :yasai, ImageUploader
  mount_uploader :okazu, ImageUploader
end

store_dirの説明

"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  • modelがモデル。ここでははphoto
  • mounted_asがカラム。ここではimage
  • ローカルファイルに保存する場合はpublic配下に保存される。

続きを読む

[AWS] EC2 で OpenVPN サーバを起動する

OpenVPN サーバ作る必要があったので、作業メモ

OpenVPN サーバのローンチ

MarketPlace に AMI があるので、それから作るのが簡単です。
Launch on EC2: OpenVPN Access Server
上のリンクからローンチすればセキュリティグループも作ってくれるけど、自分でセキュリティグループ作りたい場合は、インバウンドで最低限以下を許可するように設定。

Connection Method Protocol Port Range Source (IP or Group)
SSH tcp 22 Anywhere or IP Range
HTTPS tcp 443 Anywhere
tcp 943 Anywhere
udp 1194 Anywhere

起動したら EIP 割り当てておけば、後々便利。

しばらくすると EC2 起動してくるので、ssh 接続してイニシャルセッティングする。

$ ssh -i ~/.ssh/openvpn.pem openvpnas@xxx.xxx.xxx.xxx
Welcome to OpenVPN Access Server Appliance 2.1.4b

To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

user-data not available: HTTP Error 404: Not Found: util/ec2:12,util/ec2:7,python2.7/urllib2:154,python2.7/urllib2:437,python2.7/urllib2:550,python2.7/urllib2:475,python2.7/urllib2:409,python2.7/urllib2:558 (urllib2.HTTPError)

          OpenVPN Access Server
          Initial Configuration Tool
------------------------------------------------------
OpenVPN Access Server End User License Agreement (OpenVPN-AS EULA)
 ()

Please enter 'yes' to indicate your agreement [no]: yes

Once you provide a few initial configuration settings,
OpenVPN Access Server can be configured by accessing
its Admin Web UI using your Web browser.

Will this be the primary Access Server node?
(enter 'no' to configure as a backup or standby node)
> Press ENTER for default [yes]: yes

Please specify the network interface and IP address to be
used by the Admin Web UI:
(1) all interfaces: 0.0.0.0
(2) eth0: 192.168.0.1
Please enter the option number from the list above (1-2).
> Press Enter for default [2]: 2

Please specify the port number for the Admin Web UI.
> Press ENTER for default [943]: 943

Please specify the TCP port number for the OpenVPN Daemon
> Press ENTER for default [443]: 443

Should client traffic be routed by default through the VPN?
> Press ENTER for default [no]: no

Should client DNS traffic be routed by default through the VPN?
> Press ENTER for default [no]: yes

Use local authentication via internal DB?
> Press ENTER for default [yes]: yes

Private subnets detected: ['19.168.0.0/16']

Should private subnets be accessible to clients by default?
> Press ENTER for EC2 default [yes]: yes

To initially login to the Admin Web UI, you must use a
username and password that successfully authenticates you
with the host UNIX system (you can later modify the settings
so that RADIUS or LDAP is used for authentication instead).

You can login to the Admin Web UI as "openvpn" or specify
a different user account to use for this purpose.

Do you wish to login to the Admin UI as "openvpn"?
> Press ENTER for default [yes]: yes 
(admin ユーザ名変えたい時は、ここで no 答えて、次の質問で変えたい名前を入力)

Type the password for the 'openvpn' account:
Confirm the password for the 'openvpn' account:

> Please specify your OpenVPN-AS license key (or leave blank to specify later): 


Initializing OpenVPN...
Adding new user login...
useradd -s /sbin/nologin "openvpn"
Writing as configuration file...
Perform sa init...
Wiping any previous userdb...
Creating default profile...
Modifying default profile...
Adding new user to userdb...
Modifying new user as superuser in userdb...
Getting hostname...
Hostname: xxx.xxx.xxx.xxx
Preparing web certificates...
Getting web user account...
Adding web group account...
Adding web group...
Adjusting license directory ownership...
Initializing confdb...
Generating init scripts...
Generating PAM config...
Generating init scripts auto command...
Starting openvpnas...

NOTE: Your system clock must be correct for OpenVPN Access Server
to perform correctly.  Please ensure that your time and date
are correct on this system.

Initial Configuration Complete!

You can now continue configuring OpenVPN Access Server by
directing your Web browser to this URL:

https://xxx.xxx.xxx.xxx:943/admin
Login as "openvpn" with the same password used to authenticate
to this UNIX host.

During normal operation, OpenVPN AS can be accessed via these URLs:
Admin  UI: https://xxx.xxx.xxx.xxx:943/admin
Client UI: https://xxx.xxx.xxx.xxx:943/

See the Release Notes for this release at:
   http://www.openvpn.net/access-server/rn/openvpn_as_2_1_4b.html

openvpnas@openvpnas2:~$ sudo apt-get update && sudo apt-get upgrade

これで https://{public IP Address}:943/admin にアクセスすることで、ローンチした OpenVPN サーバの管理パネルに接続できます。
(自己署名証明書による HTTPS 接続なので、セキュリティ例外追加しないと接続できないので注意)

OpenVPN サーバで接続用のユーザ作成

https://{public IP Address}:943/admin から管理パネルにログインして [User Management] の [User Permitions] でユーザを追加。
[Allow Auto-login] にチェックしておくと、ユーザの設定が簡略化されるのでオススメ。

他の設定とか諸々はドキュメント参照。

OpenVPN クライアントのインストールと設定

Tunnelblick あたりをインストールしておけばいいです。
上の設定で VPN 接続用のユーザを作成してあるのであれば https://{public IP Address}:943/ にログイン。
Screen Shot 2017-02-22 at 12.54.03.png

すると、以下のような画面が表示されるので [Yourself (autologin profile)] ってリンクから ovpn ファイルをダウンロード。
Screen Shot 2017-02-22 at 12.54.13.png

ダウンロードした ovpn ファイルをダブルクリックすると Tunnelblick が起動して、よしなに設定してくれます。

iPhone とかでも VPN 接続したい場合は iPhoneやiPad (iOS) でOpenVPNを使ってみよう! を参考にしてみましょう。

MarketPlace にある AMI 使うと簡単にできて便利すなぁ。

参考 URL

続きを読む

【アップデート】AWS Config Rulesにマネージドルールが追加されました!!!(ACMの有効期限確認など …

Config芸人の森永です。 お待ちかねのConfig Rulesマネージドルール追加です!! 今回も運用担当垂涎のルールが数多く追加されていますよ! AWS Config … 続きを読む

AWS Config Rulesのマネージドルール作成用CloudFormationテンプレートが公開されました!!!

【アップデート】AWS Config Rulesのマネージドルール作成用CloudFormationテンプレートが公開されました!!! AWS特集 CloudFormation Config …続きを … 続きを読む

【アップデート】AWS Config Rulesのマネージドルール作成用CloudFormationテンプレートが公開されまし …

Config芸人の森永です。 Config RulesにはマネージドルールというAWSが用意したルールが存在します。 「全環境に導入したいけどマネジメントコンソール … 続きを読む

CloudWatch エージェントは SSM エージェントと呼ばれる別のエージェントに移行されましたとさ

ログは外に出しますよね

EC2 の Windows インスタンスでイベントログやアプリケーションログを CloudWatch Logs に転送して運用しています。
ログを見るためにいちいちインスタンスに入る必要もないし、必要なログがインスタンス外にあることで AutoScaling でインスタンスが勝手に破棄されても大丈夫という設計です。

これまで

ログ転送設定を C:Program FilesAmazonEc2ConfigServiceSettingAWS.EC2.Windows.CloudWatch.json に書いて EC2Config サービスを再起動することでインスタンスごとにログ転送の仕方を設定していました。
これを CodeDeploy の Hook スクリプトで行い、アプリケーションの配置と同時にログが指定した(アプリケーションごとの)ロググループにロストすることなく集めることができていました。
ちなみに Windows Server 2012 R2 です。

EC2Config ログ転送やめるってよ

あるとき、こんな記事を見つけました。
Windows ServerのCloudWatch LogsをSSMで行う | Developers.IO

従来のEC2 Configの設定を行っても、CloudWatch Logsへログの転送が行われないので注意してください。

え?まじで?
試しに新しい AMI で試してみましたがやっぱりログは転送されません。
今後は SSM で設定しなくちゃいけないのかと調べましたが、どうもやりたいことができません。
やりたいことって何よ?を書くと長くなりそうなんで書きませんが、とにかく、インスタンスに置いたローカルファイルからログ転送設定をしたいんです。

どうも SSMAgent です

EC2Config バージョン履歴的なドキュメント を確認したらなんだかローカル設定ファイルを使えそうな雰囲気が・・・

ローカル設定ファイル (AWS.EC2.Windows.CloudWatch.json) を使用して、インスタンスで CloudWatch の統合を有効にしている場合、SSM エージェントと連携して動作するようファイルを設定する必要があります。詳細については、「Windows Server 2016 インスタンスで CloudWatch 統合用のローカル設定ファイルを使用する」を参照してください。

お?・・・え? Windows Server 2016 だけなん?

結局、サポートに問い合わせて回答をいただきました。

CloudWatch Logsの設定方法

これまでと同様にローカルのファイルをお使い頂けますが、CloudWatchもしくはCloudwath Logsの設定変更が必要な場合には、下記の手順を実施頂くようお願いいたします。

  1. Amazonssmagent サービスを停止します。
    コマンドプロンプトで net stop amazonssmagent を実行することで停止できます。
  2. C:Program FilesAmazonSSMPluginsawsCloudWatchAWS.EC2.Windows.CloudWatch.json を削除いたします。
  3. C:Program FilesAmazonEc2ConfigServiceSettingAWS.EC2.Windows.CloudWatch.json の内容を編集いたします。
  4. Amazomssmagent サービスを開始します。
    コマンドプロンプトで net start amazonssmagent を実行することで開始できます。

新しい設定が反映されますと、AWS.EC2.Windows.CloudWatch.json の内容が C:Program FilesAmazonSSMPluginsawsCloudWatchAWS.EC2.Windows.CloudWatch.json に出力されます。
テキストファイルの改行コードが変わり、Headerが追加されますが、影響はございませんので、無視頂くようお願いいたします。

・・・ふむ。
これ通りに試したところ、無事にログ転送がされました。

極端なことを言ってしまえば僕のケースでは、再起動するサービスを EC2Config から SSMAgent に変えるだけで良かったと言う話です。(担当部署が変わったからそっちに聞いて的な)
でもあくまで設定ファイルの大本は今まで通り EC2Config の下にあるファイルで、それを読み込んで SSM の下のワークスペース的なところに保持するって感じなんですね。

まとめ

  • 新しい Windows AMI でも CloudWatch Logs のログ転送設定をローカルファイルで行える
  • ただし扱うサービスは SSMAgent
  • ファイルの置き場に注意
  • AWS のドキュメントはやっぱり追いつくのが遅い
  • AWS のサポートは丁寧で助かる

続きを読む