MacOSX python 3.4.3 インストール

概要

機械学習養成読本という素晴らしい本を頂き早速学習を深めています。

115ページ 第2部 第1章
「Pythonのインストール」がすんなりいかなかったのでメモです。

pyenv install 3.4.3 を実行すると以下のようなエラー出ませんでしたか?

1
2
3
4
5
6
7
8
9
Downloading Python-3.4.3.tgz...
-> https://www.python.org/ftp/python/3.4.3/Python-3.4.3.tgz
Installing Python-3.4.3...
ERROR: The Python ssl extension was not compiled. Missing the OpenSSL lib?

Please consult to the Wiki page to fix the problem.
https://github.com/yyuu/pyenv/wiki/Common-build-problems

BUILD FAILED (OS X 10.11.2 using python-build 20150519)

環境

  • MacOSX ElCapitan 10.11.2(15C50)
  • Homebrew 0.9.5
1
2
3
4
5
6
7
8
$ brew install sqlite3
$ brew install readline
$ brew install openssl
$ brew install pyenv
$ export CFLAGS="-I$(brew --prefix openssl)/include"
$ export LDFLAGS="-L$(brew --prefix openssl)/lib -L$(brew --prefix sqlite3)/lib"
$ export CPPFLAGS="-I$(brew --prefix sqlite3)/include"
$ pyenv install 3.4.3

以下コンパイラに渡す変数の設定が肝でした。

  • CFLAGS
  • LDFLAGS
  • CPPFLAGS

10.3 Variables Used by Implicit Rules

気をつければいけないのはMacにデフォルトでインストールされているPython
Python のPATH(/usr/local/bin)から外す

1
2
3
4
$ which python
/usr/local/bin/python

$ mv /usr/local/bin/python /usr/local/bin/python2.7.10

pip もインストール済みであるならば同様にパスから外す。

1
2
3
4
$ which pip
/usr/local/bin/pip

$ mv /usr/local/bin/pip /usr/local/bin/pip2.7

他にPythonのPATHをexportしていなければ
pyenv でインストールしたPythonにパスが通るはずです。

1
2
$ which python
/Users/kenzo/.pyenv/shims/python ←このように表示されればOK♪

Pythonエラー対応: UnicodeEncodeError: 'ascii' codec can't encode characters

結論

Pythonの文字コードを utf-8 に設定する。

概要

python で以下のような画像URLから画像をダウンロードする処理を実装した所
掲題のエラーが発生しました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# -*- coding: utf-8 -*-

import urllib
import urllib2
import os.path
import sys
from HTMLParser import HTMLParser

def download(url):
img = urllib.urlopen(url)
localfile = open(os.path.basename(url),'wb')
localfile.write(img.read())
img.close()
localfile.close()
  • 具体的にはここでこけてました。
1
localfile.write(img.read())

環境

  • CentOS Linux release 7.0.1406 (Core)
  • Python 2.7.5

文字コード確認

以下対話式で確認してみると ascii と表示されました。
これを utf-8 に変更します。

1
2
3
4
$ python
>>> import sys
>>> sys.getdefaultencoding()
'ascii'

pip パス確認

バージョン確認時にパスが出力されます。

1
2
$ pip --version
pip 7.1.0 from /usr/lib/python2.7/site-packages (python 2.7)

site-packages配下に sitecustomize.py を作成

1
vi /usr/lib/python2.7/site-packages/sitecustomize.py
1
2
import sys
sys.setdefaultencoding('utf-8')

上記内容で保存。

再度文字コード確認

utf-8 になりました。

1
2
3
4
$ python
>>> import sys
>>> sys.getdefaultencoding()
'utf-8'

これで掲題のエラーが解決されました。

no-ipでAWSインスタンスの動的ip更新対応 ~いつも同じドメイン名でアクセスしたい~

概要

AWSの起動停止をするとElasticIPを設定していない限り
Public IPが変更されてしまいます。

ElasticIPは設定するとAWSを停止していても費用が発生します。

検証用環境など一時的に利用するインスタンスについて
起動時にIPが変更したことを関係者に周知するなどの手間が掛かります。

その為No-IPを利用しドメインを固定しIP変更に対応するようにしました。

No-IPは無料のドメインサービスで動的IP変更を検知するLinux用モジュールも配布しています。

環境

  • Amazon Linux AMI release 2015.09
  • noip 2.1.9

手順

まずnoipサイトで会員登録し利用したいドメインを登録します。
ipはとりあえず適当で良いです。

http://www.noip.com/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// rootユーザで実行
$ sudo su
# cd /usr/local/src

// noipモジュール
# wget http://www.no-ip.com/client/linux/noip-duc-linux.tar.gz
# tar xzf noip-duc-linux.tar.gz
# cd noip-2.1.9
# make
# make install

// 起動スクリプト作成
# cp redhat.noip.sh /etc/init.d/noip
# chmod 755 /etc/init.d/noip

// 起動設定
# /sbin/chkconfig noip on

// 起動
# /etc/init.d/noip start

起動後、no-ipのコンソール上で指定ドメインのIPが
1分もしない程度で切り替わっていることが確認できます。

今後

No-IPはMicroSoftによりマルウェアの温床となっておりユーザを保護すべく
22のNO-IPドメイン差し止めを連邦裁判所に申し立て、受理されましたが

No-IP側としては相談していただければ対応もできた、とし申し立て後
対応し随時ドメインの復活を果たしています。

ある程度セキュリティを加味して利用する必要がありますね。
今の所、AWSのセキュリティグループで特に外部アクセスはなく
問題なく動作しています。

また、
以下のようなGREEさんの記事がありました。

AWS EC2 での最強の Public IP 取得方法

内部関係者に聞いてみたいと思います。

===追記===

GREEさんの記事の件、内部関係者に聞いた所ubuntuのみで利用しているそうです。

CentOS7用 Revel(Golang)フレームワークの起動スクリプト 書いてみた。

CentOS7用 Revel(Golang)フレームワークの起動スクリプト 書いてみた。

起動スクリプト作成

まず成果物から

1
# vim /usr/lib/systemd/system/revel.service
1
2
3
4
5
6
7
8
9
10
[Unit]
Description=RevelBuildScript
After=nginx.service mysqld.service

[Service]
Type=simple
ExecStart=/bin/bash /var/golang/run.sh

[Install]
WantedBy=multi-user.target

※After … 上記では nginx と mysqld 起動後に revel を起動させるという設定です。

※ExecStart … /bin/bash /var/golang/run.sh については
以前の記事でローカルビルドによる
デプロイ方法を採用しているというお話をしましたが
その際に作成される run.sh のパスを指しています。

起動設定

1
# systemctl enable revel.service

起動

1
# systemctl start revel.service

停止

1
# systemctl start revel.service

以上です。

導入経緯

AWS での運用をしていると検証環境は
検証時のみに利用し余計なコストは掛けたくないものです。

なので、しょっ中、起動・停止を繰り返します。

Revel フレームワークは起動スクリプトが標準装備されていない為
インスタンス起動時に手動で起動する手間が発生していました。

その為、デザインの修正でもシステムさんお願いします〜というような依頼があり
相互に手間が発生していたのでその解決として作成しました。

現在は Slack 経由で hubot から Jenkins ジョブを実行させ
Revel の乗ってる AWS インスタンスの起動・停止できるようにしています。

ip も ElasticIP は使用せず、No-IP を利用して Public IP が変更されても
同ドメインでアクセスできるようにしています。

こちらもインスタンス起動時にドメイン管理している No-ip へ Public IP を通知し
動的にドメインと IP を紐付けるようにしています。

http://www.noip.com/

極力費用を抑えた、AWS における検証環境構築の参考にもしていただければと思います。

以上です。

※ 検証環境 はローカル開発環境と異なり、あくまで本番デプロイ前の検証用という認識です。

MySQLトラブルシューティング - mysqldump: Couldn't execute 'FLUSH TABLES': Access denied; you need (at least one of) the RELOAD privilege(s) for this operation (1227)

概要

以下のように mysqldump コマンド実行時に掲題のエラーが発生しました。

1
2
3
$ mysqldump --lock-all-tables --events -h <host_name> -u <user> -p<password> --no-create-info <db_name> <table, ...> > output.sql

mysqldump: Couldn't execute 'FLUSH TABLES': Access denied; you need (at least one of) the RELOAD privilege(s) for this operation (1227)

対策

エラー文の通り、RELOAD権限を付与する。

1
2
mysql> GRANT RELOAD ON *.* TO '<user>'@'<host_name>';
mysql> FLUSH PRIVILEGES;

以上

MySQLトラブルシューティング - ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)

概要

ローカルでMacOSXでMAMPを使っていてある日誤った操作により以下のようなエラーが発生した為
対応まとめました。

1
2
$ mysql -u root
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)

ローカル環境でrootユーザのアクセス権を誤って削除してしまったときなどに発生します。

対策

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// mysql停止
$ service mysqld stop

// rootユーザのアクセス権限が失われている
// → テーブル権限をスキップ(無視)して作業するオプション付きでセーフモードでmysql起動
$ mysqld_safe --skip-grant-tables &

// rootユーザでアクセス
$ mysql -u root

// 現状の権限設定テーブルを空にする
mysql> TRUNCATE TABLE mysql.user;
Query OK, 0 rows affected (0.00 sec)

// 権限反映
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.01 sec)

// rootユーザにlocalhostの全DBアクセス権限付与
mysql> GRANT ALL PRIVILEGES on *.* to root@localhost IDENTIFIED BY '(root's password)' WITH GRANT OPTION;
Query OK, 0 rows affected (0.01 sec)

// 権限反映
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

// 権限設定確認
mysql> SELECT host, user FROM mysql.user;

// mysql CLIモード停止 (Ctl+c)でもOK
mysql> quit;

// safe modeで起動させたmysql 関連psをkillする
$ ps aux | grep mysql | grep -v grep | awk '{print "kill -9", $2}'|sh

// mysql 起動
$ service mysqld start

// rootユーザでmysqlアクセス
$ mysql -u root -p(root's password)
mysql>

rootユーザに権限が失われお手上げ状態になったとき、困ったときに safe_mode 使えます。

以上

Hubot + Slack on Amazon Linux

Prerequisite

  • Amazon Linux AMI 2015.09.1 (HVM), SSD Volume Type(t2.nano)
  • npm 1.3.6
  • hubot 2.17.0
  • coffeescript 1.10.0

I use t2.nano released at December 2015.

first to do.

  • summarized in the following site.

AWS EC2 Amazon Linuxインスタンス起動後、最初にやることまとめ

Install npm

1
2
3
4
$ sudo yum install -y npm --enablerepo=epel

$ npm -v
1.3.6

Install hubot, coffee-script, yo, generator-hubot

1
2
3
4
5
6
7
$ sudo npm install -g hubot coffee-script yo generator-hubot

$ hubot -v
2.17.0

$ coffee -v
CoffeeScript version 1.10.0

create hubot

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
$ mkdir mybot
$ cd mybot
$ yo hubot

? ==========================================================================
We're constantly looking for ways to make yo better!
May we anonymously report usage statistics to improve the tool over time?
More info: https://github.com/yeoman/insight & http://yeoman.io
========================================================================== (Y/n) n
_____________________________
/ \
//\ | Extracting input for |
////\ _____ | self-replication process |
//////\ /_____\ \ /
======= |[^_/\_]| /----------------------------
| | _|___@@__|__
+===+/ /// \_\
| |_\ /// HUBOT/\\
|___/\// / \\
\ / +---+
\____/ | |
| //| +===+
\// |xx|

? Owner (User <user@example.com>) tech@xxxxxxxx.jp
? Bot name (mybot) hubot
? Description xxxxxxx's hubot
? Bot adapter slack
...
...
hubot-maps@0.0.2 node_modules/hubot-maps

$ ls
Procfile bin hubot-scripts.json package.json
README.md external-scripts.json node_modules scripts

こんなエラーが出たときは

/root/.config へのアクセス権限がないと言われています。

1
2
3
4
5
6
7
8
9
10
11
Error: EACCES, permission denied '/root/.config'
at Object.fs.mkdirSync (fs.js:654:18)
at sync (/usr/lib/node_modules/yo/node_modules/configstore/node_modules/mkdirp/index.js:71:13)
at Function.sync (/usr/lib/node_modules/yo/node_modules/configstore/node_modules/mkdirp/index.js:77:24)
at Object.create.all.get (/usr/lib/node_modules/yo/node_modules/configstore/index.js:38:13)
at Object.Configstore (/usr/lib/node_modules/yo/node_modules/configstore/index.js:27:44)
at new Insight (/usr/lib/node_modules/yo/node_modules/insight/lib/index.js:37:34)
at Object.<anonymous> (/usr/lib/node_modules/yo/lib/cli.js:156:11)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
  • 全権限付与
1
2
# mkdir /root/.config
# chmod -R 0777 /root/.config

上記で問題なくyo コマンドが通りました。ほっ(-o-)

  • Initial setting hubot.
Item Value
Owner E-mail address
Bot name same the hubot integrated slack
Descriiption -
Bot adapter slack

Imgur

Install hubot-slack

1
$ sudo npm install hubot-slack --save

modify external-scripts.json

1
2
3
4
5
$ echo '[]' > external-scripts.json

// confirm setting.
$ cat external-scripts.json
[]

Add to bin/hubot

1
$ vim bin/hubot
  • run hubot via port 80
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/sh

set -e

npm install
export PATH="node_modules/.bin:node_modules/hubot/node_modules/.bin:$PATH"

# add start
export HUBOT_SLACK_TOKEN=xoxb-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
export PORT=80
# add end

exec node_modules/.bin/hubot --name "hubot" "$@"

creat hubot script

1
$ vim scripts/hello.coffee

save the belowing scripts as scripts/hello.coffee

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Description:
# hubot basic command.
#
# Commands:
# hubot who are you - I'm hubot!
# hubot hello
# hubot who am I - You are <user_name>
# hubot what is this <*> - This is <$1>

module.exports = (robot) ->
robot.respond /who are you/i, (msg) ->
msg.send "I'm hubot!"

robot.hear /HELLO$/i, (msg) ->
msg.send "hello!"

robot.respond /who am I/i, (msg) ->
msg.send "You are #{msg.message.user.name}"

robot.respond /what is this (.*)/i, (msg) ->
msg.send "This is #{msg.match[1]}"

run hubot

sudo is required and in order to access http port.
You will require hubot integrated with outside site - ex) JIRA etc…

1
2
3
4
5
$ sudo bin/hubot -a slack

[Wed Jan 13 2016 13:43:08 GMT+0900 (JST)] INFO Connecting...
[Wed Jan 13 2016 13:43:10 GMT+0900 (JST)] INFO Logged in as hubot of RUBY GROUPE, but not yet connected
[Wed Jan 13 2016 13:43:11 GMT+0900 (JST)] INFO Slack client now connected
  • no sudo execution result …(>_<)
    Error occured!!
1
2
3
4
5
6
7
8
9
10
11
12
13
$ bin/hubot -a slack

[Wed Jan 13 2016 16:40:59 GMT+0900 (JST)] INFO Connecting...
[Wed Jan 13 2016 16:40:59 GMT+0900 (JST)] ERROR Error: listen EACCES
at errnoException (net.js:905:11)
at Server._listen2 (net.js:1024:19)
at listen (net.js:1065:10)
at net.js:1147:9
at dns.js:72:18
at process._tickCallback (node.js:442:13)

[Wed Jan 13 2016 16:41:00 GMT+0900 (JST)] INFO Logged in as hubot of RUBY GROUPE, but not yet connected
[Wed Jan 13 2016 16:41:02 GMT+0900 (JST)] INFO Slack client now connected

Invite hubot at Slack

ex) botname=hubot

1
/invite @hubot

Imgur

Input text at Slack

1
2
[me]    hubot hello
[hubot] hello!

Imgur


daemonize hubot

Install forever

1
2
3
4
$ sudo npm install --save forever

$ forever --version
v0.15.1

set path as not root user.

1
2
$ echo 'export PATH=$PATH:/home/<user>/mybot/node_modules/forever/bin' >> ~/.bashrc
$ source ~/.bashrc
  • root user too.
1
2
3
4
5
6
// change to super user.
$ sudo su
# echo 'export PATH=$PATH:/home/<user>/mybot/node_modules/forever/bin' >> ~/.bashrc
# source ~/.bashrc
# echo $PATH
.......:/home/<user>/mybot/node_modules/forever/bin:......

Modify bin/hubot

daemonize start hubot - sudo bin/hubot -a slack

1
$ sudo bin/hubot start

stop daemonized hubot

1
$ sudo bin/hubot stop

restart hubot

1
$ sudo bin/hubot restart

check forever list

1
2
3
4
5
6
$ sudo su
# forever list

info: Forever processes running
data: uid command script forever pid id logfile uptime
data: [0] sICk coffee node_modules/.bin/hubot -a slack 30494 30496 /root/.forever/sICk.log 0:0:5:35.399

another way stop forever process

  • check process. kill -9 process
1
2
3
4
5
6
7
$ ps aux | grep hubot | grep -v grep

root 31144 0.3 3.1 723820 32392 ? Ssl 17:58 0:00 /usr/bin/node /home/hu/mybot/node_modules/forever/bin/monitor node_modules/.bin/hubot
root 31146 1.1 6.7 979588 69196 ? Sl 17:58 0:00 node node_modules/hubot/node_modules/.bin/coffee /home/hu/mybot/node_modules/.bin/hubot -a slack

// kill forcibly process
$ sudo kill -9 31146
  • another one.
1
# ps aux | grep hubot | grep -v grep | awk '{print "kill -9", $2}' | sh

Thanks.

pod install で ASSERSION対策

pod install で ASSERSION対策

概要

pod install 実行時に正常にインストール処理ができなかったのでメモ。

冬休み中にSwift2.0をほんきで学ぶ為、以下書籍購入してチャレンジ。

これの LESSON 31 でCocoaPodsインストール手順がありますが
その通りに進めた際にエラー発生したので対策をまとめました。

この手のエラーは環境依存が主ですし、
書籍の執筆時も技術は日進月歩進んでおりますので書籍を責めず
CocoaPodsオフィシャルサイトやStackOverFlowなどで情報探ってみるのが
精神衛生上も良いかもしれないです。

環境情報

  • Xcode 7.2 (7C68)
  • ruby 2.0.0p645
  • gem 2.5.0

書籍に記載されているコマンド

CocoaPodsインストール

1
$ sudo gem install -n /usr/local/bin cocoa pods

エラー内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$ pod install
[!] Unable to load a specification for the plugin `/opt/homebrew-cask/Caskroom/cocoapods/0.37.0/CocoaPods.app/Contents/Resources/bundle/lib/ruby/gems/2.2.0/gems/cocoapods-plugins-install-0.0.1`
Analyzing dependencies

CocoaPods 1.0.0.beta.1 is available.
To update use: `sudo gem install cocoapods --pre`
[!] This is a test version we'd love you to try.

For more information see http://blog.cocoapods.org
and the CHANGELOG for this version http://git.io/BaH8pQ.

Downloading dependencies
Installing Realm (0.97.0)
Installing RealmSwift (0.97.0)
Generating Pods project
2015-12-31 10:51:38.680 ruby[6275:47591] [MT] DVTAssertions: ASSERTION FAILURE in /Library/Caches/com.apple.xbs/Sources/IDEFrameworks/IDEFrameworks-9548/IDEFoundation/Initialization/IDEInitialization.m:590
Details: Assertion failed: _initializationCompletedSuccessfully
Function: BOOL IDEIsInitializedForUserInteraction()
Thread: <NSThread: 0x7fc66d067980>{number = 1, name = main}
Hints: None
Backtrace:
0 0x000000010e001f7f -[DVTAssertionHandler handleFailureInFunction:fileName:lineNumber:assertionSignature:messageFormat:arguments:] (in DVTFoundation)
1 0x000000010e00170c _DVTAssertionHandler (in DVTFoundation)
2 0x000000010e001978 _DVTAssertionFailureHandler (in DVTFoundation)
3 0x000000010e0018da _DVTAssertionFailureHandler (in DVTFoundation)
4 0x0000000110e5154d IDEIsInitializedForUserInteraction (in IDEFoundation)
5 0x000000011393a631 +[PBXProject projectWithFile:errorHandler:readOnly:] (in DevToolsCore)
6 0x000000011393c1b6 +[PBXProject projectWithFile:errorHandler:] (in DevToolsCore)
7 0x00007fff93b2af14 ffi_call_unix64 (in libffi.dylib)
zsh: abort pod install

対策

1
2
3
4
5
# 既にインストール済みのCocoaPodsをアンインストールする
$ sudo gem uninstall cocoapods

# 再度 `cocoapods` をインストールする。
$ sudo gem install -n /usr/local/bin cocoapods

実行確認

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$  pod install
Updating local specs repositories

CocoaPods 1.0.0.beta.1 is available.
To update use: `gem install cocoapods --pre`
[!] This is a test version we'd love you to try.

For more information see http://blog.cocoapods.org
and the CHANGELOG for this version http://git.io/BaH8pQ.

Analyzing dependencies
Downloading dependencies
Installing Realm (0.97.0)
Installing RealmSwift (0.97.0)
Generating Pods project
Integrating client project

[!] Please close any current Xcode sessions and use `Chapter6.xcworkspace` for this project from now on.
Sending stats
Pod installation complete! There is 1 dependency from the Podfile and 2 total pods
installed.

~/honki_swift/Chapter6/LESSON31/before/Chapter6

無事、 .xcworkspace, Podfile.lock, Pods が作成されました。

1
2
3
4
5
6
7
8
[~/honki_swift/Chapter6/LESSON31/before/Chapter6]$ tree -L 1
.
├── Chapter6
├── Chapter6.xcodeproj
├── Chapter6.xcworkspace
├── Podfile
├── Podfile.lock
└── Pods

以上です。

AWS Multi-AZにおける Pacemaker + Corosync による Elastic IP の付け替え

概要

Pacemaker & Corosync による
AWS での Multi-AZ 間のEIP付け替えによる
フェイルオーバーについて実装したのでまとめます。

以下イメージです。

  • 通常状態

Normal

  • Avalavility Zone A に配置された Instance A で障害が発生した場合
    Avalavility Zone B に配置された Instance B に EIPを付け替え

Accident occured

ToDo

  • VPC, Subnet 設定
  • Pacemaker & Corosync インストール / 設定
  • Cluster 構築
  • EIP付け替えスクリプト作成
  • フェイルオーバー試験

環境

  • CentOS 7 (x86_64) with Updates HVM (t2.micro)
    ※ 検証用の為、 t2.microで実施しています。

VPC, Subnet 構築

以下記事にて非常によくまとめて頂いているので参考にしていただき
この設定を以降そのまま利用します。

0から始めるAWS入門①:VPC編

念のため、以下 VPC, Subnet 設定です。
  • VPC 設定
項目
Name tag 任意
CIDR 10.0.0.0/16
tenancy Default
  • Subnet 設定
項目 Subnet 1 Subnet 2
Name tag 任意(VPCのタグ名と関連付けたほうが管理しやすい) 任意(VPCのタグ名と関連付けたほうが管理しやすい)
VPC 上記で作成したVPCを選択する 上記で作成したVPCを選択する
Availability Zone ap-northeast-1a ap-northeast-1c
CIDR 10.0.0.0/24 10.0.1.0/24

上記VPC設定に基づき以下設定していきます。

構築するイメージは以下になります。

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

今回作成するインスタンス2つにアタッチするセキュリティグループを事前に作成します。

マイIPからのSSHログイン許可

項目 設定値
セキュリティグループ名 VPC-for-EIP(任意)
説明 VPC-for-EIP(任意)
VPC 上記で作成したVPCを選択する

作成したセキュリティグループ編集

  • フィルターで検索

※以下は環境により変更してください。

  • 送信元を作成したグループIDとし以下追加し保存
タイプ プロトコル ポート範囲 送信元 用途
すべてのTCP TCP 0 - 65535 作成したセキュリティグループID 今回は検証用の為、全解放。適宜設定変更してください。
すべてのICMP ICMP 0 - 65535 作成したセキュリティグループID ping疎通確認用。今回は検証用の為、全解放 適宜設定変更してください。
すべてのUDP UDP 0 - 65535 作成したセキュリティグループID corosyncで必要なポートはデフォルトで 5404 - 5405。 環境により設定変更する場合は注意が必要です。今回は検証用の為、全解放。適宜設定変更してください。
SSH TCP 20 マイIP 自PC端末からSSHログイン用。実環境で設定する必要はありません。
HTTP TCP 80 マイIP FailOver検証用。実環境で設定する必要はありません。

以上でインスタンスに適用するセキュリティグループの作成が完了しました。


ポリシー作成

今回、以下コマンドを実行する必要があります。

コマンド 用途
aws ec2 associate-address ElasticIPをインスタンスに関連付ける
aws ec2 disassociate-address ElasticIPをインスタンス関連付け解除
aws ec2 describe-addresses IPアドレスについて詳細取得
Identity & Access Management ページにアクセス
「ポシリー作成」クリック
独自ポリシー作成
独自ポリシー情報入力
  • ポリシー名(任意)

floatingElasticIP

  • ポリシードキュメント
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:Describe*",
"ec2:DisassociateAddress",
"ec2:AssociateAddress"
],
"Resource": [
"*"
]
}
]
}
確認

IAMロール作成

ElasticIPの付け替え権限を持ったロールを作成します。

新しいロールの作成 をクリック
ロール名の設定
ロールタイプの選択

Amazon EC2 の「選択」ボタンをクリック

ポリシーのアタッチ
登録内容を確認しロールの作成
作成されたか確認

以上でインスタンスに適用するIAMロールの作成が完了しました。

ユーザ作成

Identity & Access Management ページにアクセス
メニューからユーザクリック & 新規ユーザの作成 ボタンクリック
ユーザ名入力し作成ボタンクリック
認証情報をダウンロードクリック

Access Key IdSecret Access Key が記載されたCSVがダウンロードされます。
大切に保管しましょう。

作成されたユーザーにアクセス
ポリシーのアタッチ開始
ポリシーにチェックを入れアタッチ

以上で
AmazonEC2FullAccess 権限を持ったユーザ floatingIP ユーザが作成されました。

上記ユーザの認証情報は 手順 aws-cli インストール で利用します。


インスタンスの作成

  • 上記で作成したVPCのSubnet (ap-northeast-1a)にインスタンス (以降Instance A)を作成します。

「インスタンスの作成」をクリック

マシンイメージ選択

今回は CentOS 7 (x86_64) with Updates HVM を選択します。

インスタンスタイプ選択

今回は検証用で無料枠として利用したいので t2.micro を選択します。

インスタンスの詳細の設定

ap-northeast-1a に作成する Instance A のプライマリIPを
10.0.0.20 とします。

ストレージの追加

特に変更することなく次の手順へ

インスタンスのタグ付け

Name タグに Instance A と指定します。
※ 任意なのでわかりやすいテキストであれば良いです。

セキュリティグループの設定

  • 事前に作成したセキュリティグループを選択

インスタンス作成の確認

以上で Insntace A の作成が完了しました。

同様に Instance B 作成

Instance A との主な変更点
  • Subnet 10.0.1.0/24 を選択
  • インスタンスのタグは Instance B とする
Instance B 設定時注意点
  • セキュリティグループInstance B でも同様 Instance A で設定した
    セキュリティグループ を選択する。

送信元/送信先の変更チェックを無効化

※上記 Instance A, B 共に Source/Destination Check (ネットワーク > 送信元/送信先の変更チェック) を Disabled (無効) に設定する必要があります。

インスタンス SSHログイン後まずやること

最低限必要なモジュールインストール

※ git は ElasticIP付け替え時のシェルをインストールする際に必要になります。

1
2
3
4
5
[Instance A & B ]# yum install -y git

[Instance A & B ]# git --version

git version 1.8.3.1

Fail Over 検証用に httpd, php インストール

あくまで Fail Over 時の動きを見る為の確認用にインストールし起動しています。
※必須工程ではありません。

1
2
3
4
5
6
[Instance A & B ]# yum --disableexcludes=main install -y gcc
[Instance A & B ]# yum install -y gmp gmp-devel
[Instance A & B ]# yum install -y php php-mysql httpd libxml2-devel net-snmp net-snmp-devel curl-devel gettext
[Instance A & B ]# echo '<?php print_r($_SERVER["SERVER_ADDR"]); ?>' > /var/www/html/index.php
[Instance A & B ]# systemctl start httpd
[Instance A & B ]# systemctl enable httpd

system clock 調整 JST設定

OS内の時間が現実の時間とずれていると
aws-cliが正常に動作しない可能性があるので
念の為、調整しておきます。

1
2
3
4
5
6
7
8
9
10
11
12
13
# バックアップ確保
[Instance A & B ]# cp /etc/sysconfig/clock /etc/sysconfig/clock.org

# 再起動しても設定維持する様にする。
[Instance A & B ]# echo -e 'ZONE="Asia/Tokyo"\nUTC=false' > /etc/sysconfig/clock

# バックアップ確保
[Instance A & B ]# cp /etc/localtime /etc/localtime.org

# Asia/Tokyo を localtime に設定
[Instance A & B ]# ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

[Instance A & B ]# date

Elastic IP作成

Elastic IPを作成し Server A に関連付けます。

新しいアドレスを割り当てる
確認ポップアップで「関連付ける」をクリック
成功確認
インスタンスに関連付け
関連するインスタンス選択
確認

以上で Instance A に ElasticIP が関連付けされました。

Instance A & B に SSHログイン

  • Instance A に SSHログイン

    1
    [Local PC]# ssh -i aws.pem centos@<Instance AのPublic IP>
  • Instance B に SSHログイン

    1
    [Local PC]# ssh -i aws.pem centos@<Instance BのPublic IP>

/etc/hosts設定

1
2
[Instance A ]# uname -n
ip-10-0-0-10.ap-northeast-1.compute.internal
1
2
[Instance B ]# uname -n
ip-10-0-1-10.ap-northeast-1.compute.internal
1
2
3
4
5
6
7
[Instance A & B ]# vi /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6

# 以下追加
10.0.0.20 ip-10-0-0-20.ap-northeast-1.compute.internal
10.0.1.20 ip-10-0-1-20.ap-northeast-1.compute.internal

Pacemaker & Corosync インストール

  • pcsは旧来のcrmshに代わるPacemakerクラスタ管理ツールであり、RHEL/CentOS7においてはpcsの使用が推奨されている。
1
[Instance A & B ]# yum -y install pcs fence-agents-all
  • バージョン確認
1
2
3
4
5
6
7
8
9
10
[Instance A & B ]# pcs --version
0.9.143

[Instance A & B ]# pacemakerd --version
Pacemaker 1.1.13-10.el7
Written by Andrew Beekhof

[Instance A & B ]# corosync -v
Corosync Cluster Engine, version '2.3.4'
Copyright (c) 2006-2009 Red Hat, Inc.

hacluster パスワード設定

corosyncパッケージインストール時に自動で hacluster ユーザが追加される。
その hacluster のパスワードを設定する。

1
2
3
4
5
[Instance A & B ]# passwd hacluster
ユーザー hacluster のパスワードを変更。
新しいパスワード:
新しいパスワードを再入力してください:
passwd: すべての認証トークンが正しく更新できました。

pcsd 起動

cluster監視を実施する為

1
2
3
[Instance A & B ]# systemctl start pcsd
[Instance A & B ]# systemctl enable pcsd
[Instance A & B ]# systemctl status pcsd

cluster認証

クラスタを組む各ホストへのアクセス認証を検証します。

どちらか一方のInstanceから実行します。
以下はInstance Aから実行しています。

1
2
3
4
5
[Instance A ]# pcs cluster auth ip-10-0-0-20.ap-northeast-1.compute.internal ip-10-0-1-20.ap-northeast-1.compute.internal
Username: hacluster
Password:
ip-10-0-1-20.ap-northeast-1.compute.internal: Authorized
ip-10-0-0-20.ap-northeast-1.compute.internal: Authorized

上記のように Authorized (認証済み) と出力されていれば問題ありませんが
以下のような Unable to Communicate というエラーが出力されている場合は
各Instance の設定を見直してください。

  • 認証エラーの例
    1
    2
    3
    [Instance A ]# pcs cluster auth ip-10-0-0-20.ap-northeast-1.compute.internal ip-10-0-1-20.ap-northeast-1.compute.internal -u hacluster -p ruby2015
    Error: Unable to communicate with ip-10-0-0-20.ap-northeast-1.compute.internal
    Error: Unable to communicate with ip-10-0-1-20.ap-northeast-1.compute.internal

cluster設定

クラスタ設定をします。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Instance A ]# pcs cluster setup --name aws-cluster ip-10-0-0-20.ap-northeast-1.compute.internal ip-10-0-1-20.ap-northeast-1.compute.internal --force

Shutting down pacemaker/corosync services...
Redirecting to /bin/systemctl stop pacemaker.service
Redirecting to /bin/systemctl stop corosync.service
Killing any remaining services...
Removing all cluster configuration files...
ip-10-0-0-20.ap-northeast-1.compute.internal: Succeeded
ip-10-0-1-20.ap-northeast-1.compute.internal: Succeeded
Synchronizing pcsd certificates on nodes ip-10-0-0-20.ap-northeast-1.compute.internal, ip-10-0-1-20.ap-northeast-1.compute.internal...
ip-10-0-0-20.ap-northeast-1.compute.internal: Success
ip-10-0-1-20.ap-northeast-1.compute.internal: Success

Restaring pcsd on the nodes in order to reload the certificates...
ip-10-0-0-20.ap-northeast-1.compute.internal: Success
ip-10-0-1-20.ap-northeast-1.compute.internal: Success

cluster起動

全ホストに向け クラスタ起動します。

1
2
3
4
[Instance A ]# pcs cluster start --all

ip-10-0-1-20.ap-northeast-1.compute.internal: Starting Cluster...
ip-10-0-0-20.ap-northeast-1.compute.internal: Starting Cluster...

aws-cli インストール

手順: ユーザ作成 でダウンロードした credentials.csv に記載された
Access Key Id Secret Access Key を使用します。

1
2
3
4
5
6
7
8
9
10
11
[Instance A & B ]# rpm -iUvh http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm
[Instance A & B ]# yum -y install python-pip
[Instance A & B ]# pip --version
pip 7.1.0 from /usr/lib/python2.7/site-packages (python 2.7)

[Instance A & B ]# pip install awscli
[Instance A & B ]# aws configure
AWS Access Key ID [None]: *********************
AWS Secret Access Key [None]: **************************************
Default region name [None]: ap-northeast-1
Default output format [None]: json

EIP 付け替えリソース作成

heartbeat で問題検知した際に起動するリソースとして登録します。

OCF_ROOT が定数として指定されているが、存在しない為

1
2
3
4
5
6
7
[Instance A & B ]# cd /tmp
[Instance A & B ]# git clone https://github.com/moomindani/aws-eip-resource-agent.git
[Instance A & B ]# cd aws-eip-resource-agent
[Instance A & B ]# sed -i 's/\${OCF_ROOT}/\/usr\/lib\/ocf/' eip
[Instance A & B ]# mv eip /usr/lib/ocf/resource.d/heartbeat/
[Instance A & B ]# chown root:root /usr/lib/ocf/resource.d/heartbeat/eip
[Instance A & B ]# chmod 0755 /usr/lib/ocf/resource.d/heartbeat/eip

pacemaker 設定

stonish 無効化
1
[Instance A ]# pcs property set stonith-enabled=false
split-brain (スプリット・ブレイン) が発生しても quorum (クォーラム) が特別な動作を行わないように設定
1
[Instance A ]# pcs property set no-quorum-policy=ignore

split-brain とは
ハートビート通信を行うネットワークに断線などの問題が発生した場合、ホストに障害が起こったと勘違いし、
本来立ち上がってほしくないスタンバイ側のホストがアクティブになってしまうというもの

属性値更新時の待ち時間( crmd-transition-delay )を 0s(秒) 設定
1
[Instance A ]# pcs property set crmd-transition-delay="0s"
自動フェイルバックなし、同一サーバでリソースの再起動を試みる回数を 1 回に設定
1
[Instance A ]# pcs resource defaults resource-stickiness="INFINITY" migration-threshold="1"
EIP切り替え設定

今回作成し Instance A に関連付けした ElasticIP は 52.192.203.215 です。
以下設定に反映させます。

1
2
3
4
5
6
[Instance A ]# pcs resource create eip ocf:heartbeat:eip \
params \
elastic_ip="52.192.203.215" \
op start timeout="60s" interval="0s" on-fail="stop" \
op monitor timeout="60s" interval="10s" on-fail="restart" \
op stop timeout="60s" interval="0s" on-fail="block"

cluster 設定確認

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
[Instance A ]# pcs config

pcs config
Cluster Name: aws-cluster
Corosync Nodes:
ip-10-0-0-20.ap-northeast-1.compute.internal ip-10-0-1-20.ap-northeast-1.compute.internal
Pacemaker Nodes:
ip-10-0-0-20.ap-northeast-1.compute.internal ip-10-0-1-20.ap-northeast-1.compute.internal

Resources:
Resource: eip (class=ocf provider=heartbeat type=eip)
Attributes: elastic_ip=52.192.203.215
Operations: start interval=0s timeout=60s on-fail=stop (eip-start-interval-0s)
monitor interval=10s timeout=60s on-fail=restart (eip-monitor-interval-10s)
stop interval=0s timeout=60s on-fail=block (eip-stop-interval-0s)

Stonith Devices:
Fencing Levels:

Location Constraints:
Ordering Constraints:
Colocation Constraints:

Resources Defaults:
resource-stickiness: INFINITY
migration-threshold: 1
Operations Defaults:
No defaults set

Cluster Properties:
cluster-infrastructure: corosync
cluster-name: aws-cluster
crmd-transition-delay: 0s
dc-version: 1.1.13-10.el7-44eb2dd
have-watchdog: false
no-quorum-policy: ignore
stonith-enabled: false

Fail Over 実行確認

手順 Fail Over 検証用に httpd, php インストール にて
DocumentRoot (/var/www/html/) に
Private IP ($_SERVER["SERVER_ADDR"]) を表示させるindex.phpファイルを
配置しました。

ブラウザから Private IP を元に Instance A or B どちらのInstance に
アクセスしているかがわかります。

ブラウザから ElasticIP にアクセス

ElasticIP 52.192.203.215 にアクセスすると
Private IP 10.0.0.20 が表示されていることがわかります。

現状、ElasticIP は Instance A に関連付いていることがわかります。

Instance A の corosync 停止
1
[Instance A]# systemctl stop corosync
再度ブラウザから ElasticIP にアクセス

先ほど表示させていたブラウザを幾度かリロードすると
Private IP 10.0.1.20 が表示されていることがわかります。

ElasticIP は Instance B に関連付けられたことがわかります。

ElasticIP が Instance A から関連付けが解放され、 Instance B に関連付けされるようになりました。

コンソールページ上でも確認することができます。

以上で簡易的ではありますが
Cloud Design Pattern の floating IP (ElasticIP) が実現できました。

以上です。

参考

pingを通すiptableの設定

環境

  • CentOS 5.8

実現したいこと

Server AServer B からのみ ping を通す

1
2
3
4
5
+----------+  Ping Request   +----------+
| | <-------------- | |
| Server A | | Server B |
| | --------------> | |
+----------+ Ping Response +----------+

特定IPからの ping を通す許可設定

以下設定を Server A で実施する。

1
2
3
[Server A]# iptables -A INPUT -p icmp --icmp-type 8 -s <Server B の IP Address> -j ACCEPT
[Server A]# iptables -A OUTPUT -p icmp --icmp-type 0 -s <Server B の IP Address> -j ACCEPT
[Server A]# service iptables restart
  • --icmp-type 8Echo request (エコー要求) を許可
  • --icmp-type 0Echo Reply (エコー応答) を許可

Server Bから ping実行

1
2
3
4
5
6
7
8
9
10
[Server B]# ping <Server A の IP Address>

PING (<Server A の IP Address>): 56 data bytes
64 bytes from (<Server A の IP Address>): icmp_seq=0 ttl=58 time=4.411 ms
64 bytes from (<Server A の IP Address>): icmp_seq=1 ttl=58 time=4.079 ms
64 bytes from (<Server A の IP Address>): icmp_seq=2 ttl=58 time=4.027 ms
^C
--- (<Server A の IP Address>) ping statistics ---
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 4.027/4.172/4.411/0.170 ms

icmp-type List

以下asahi-net Appendix C. ICMPタイプより参照

TYPE CODE 意味 問合せ エラー 参照先
0 0 Echo Reply (エコー応答) x RFC792
3 0 Network Unreachable (ネットワーク到達不能) x RFC792
3 1 Host Unreachable (ホスト到達不能) x RFC792
3 2 Protocol Unreachable (プロトコル到達不能) x RFC792
3 3 Port Unreachable (ポート到達不能) x RFC792
3 4 Fragmentation needed but no frag. bit set (フラグメント必要だがフラグメント禁止ビットあり) x RFC792
3 5 Source routing failed (ソースルーティング失敗) x RFC792
3 6 Destination network unknown (宛先ネットワーク発見できず) x RFC792
3 7 Destination host unknown (宛先ホスト発見できず) x RFC792
3 8 Source host isolated (送信元ホストへのルートなし) (廃) x RFC792
3 9 Destination network administratively prohibited (宛先ネットワークは設定によりアクセス禁止) x RFC792
3 10 Destination host administratively prohibited (宛先ホストは設定によりアクセス禁止) x RFC792
3 11 Network unreachable for TOS (TOS種別によりネットワーク到達不能) x RFC792
3 12 Host unreachable for TOS (TOS種別によりホスト到達不能) x RFC792
3 13 Communication administratively prohibited by filtering (フィルタリング設定により通信禁止) x RFC1812
3 14 Host precedence violation (ホスト優先順位侵害) x RFC1812
3 15 Precedence cutoff in effect (優先順位により遮断発動) x RFC1812
4 0 Source quench (輻輳発生による発信抑制) RFC792
5 0 Redirect for network (指定ネットワークへのリダイレクト要求) RFC792
5 1 Redirect for host (指定ホストへのリダイレクト要求)
5 2 Redirect for TOS and network (TOSとネットワークのリダイレクト要求) RFC792
5 3 Redirect for TOS and host (TOSとホストのリダイレクト要求) RFC792
8 0 Echo request(エコー要求) x RFC792
9 0 Router advertisement - Normal router advertisement (ルータ広告 - 通常通知) RFC1256
9 16 Router advertisement - Does not route common traffic (ルータ広告 - 通常トラフィックはルーティング不可) RFC2002
10 0 Route selection (ルート選択) RFC1256
11 0 TTL equals 0 during transit (搬送中にTTLが0に) x RFC792
11 1 TTL equals 0 during reassembly (再構成時の欠損フラグメント待機中に時間超過) x RFC792
12 0 IP header bad (catchall error) (IPヘッダ異常) (あらゆるエラーに共通) x RFC792
12 1 Required options missing (必要なオプションが欠如) x RFC1108
12 2 IP Header bad length (IPヘッダ長の異常) x RFC792
13 0 Timestamp request (obsolete) (タイムスタンプ要求) (廃) x RFC792
14 Timestamp reply (obsolete) (タイムスタンプ応答) (廃) x RFC792
15 0 Information request (obsolete) (情報要求) (廃) x RFC792
16 0 Information reply (obsolete) (情報応答) (廃) x RFC792
17 0 Address mask request (ネットマスク通知要求) x RFC950
18 0 Address mask reply (ネットマスク通知応答) x RFC950
20-29 Reserved for robustness experiment (信頼性試験のための予約域) Zaw-Sing Su
30 0 Traceroute x RFC1393
31 0 Datagram Conversion Error (データグラム変換エラー) x RFC1475
32 0 Mobile Host Redirect (移動体ホストのリダイレクト) David Johnson
33 0 IPv6 Where-Are-You (IPv6位置確認要求) x Bill Simpson
34 0 IPv6 I-Am-Here (IPv6位置確認応答) x Bill Simpson
35 0 Mobile Registration Request (移動体登録要求) x Bill Simpson
36 0 Mobile Registration Reply (移動体登録応答) x Bill Simpson
39 0 SKIP Tom Markson
40 0 Photuris RFC2521