ぼくはまちちゃん!(Hatena)

  • ライブドアリーダーで読む → Subscribe with livedoor Reader
ぼくはまちちゃん!のRSSフィード

2012/06/12

Amazon EC2 を使った無限IPアドレスの作り方

こんにちはこんにちは!!

たまにIPアドレスがたくさん必要な時ってありますよね。
ぼくも先日そういう機会があって、ちょっと困りました。

で、「AmazonさんならIPいっぱいもってるのでは?」ってことで、
ちまたで話題のクラウドサービス Amazon Web Servise を試してみました!
あ、もちろんタイトルは煽りぎみで実際にはIPアドレスは有限なんですが><

正直、クラウドとかサーバーとかよくわかってなかったんですが、
とりあえず試してみたら意外と簡単にできたので、忘れないようにメモしておきます!

そうそう、Amazonのクラウドって高そうなイメージがあるけど、いまだと制限つきで無料らしいので、お得ですね!
もし無料枠こえても、無茶な使い方をしない限りはそれほど高くない。と思います。たぶん。
制限を見る限り、とりあえず一ヶ月がっつり試すだけならタダです!

必要なもの:
・クレジットカード (無料利用でも登録が必要です><)

あった方がいいもの:
・UNIXライクなOS (ぼくは実験用マシン代わりにさくらVPSを使ってます!980円のやつ)

以下その手順です!
初心者が数時間ほどでやったものなので色々間違えてるかもしれませんが、何かの参考になれば…!
あともっと良い方法があれば教えて欲しいです。

1. Amazon Web Service (AWS) に登録します (5分くらいでできます)

AWSトップページからサインアップします。

英語が苦手なぼくでもできるくらい簡単です!
フォーム横に例文が書かれてるので、その通りに電話番号とかを入力します。
すると、Amazonから自動音声(日本語)の電話がかかってくるので、暗証番号をプッシュすれば完了です!

2. インスタンスを作ってみる (5分くらいでできます)

インスタンスっていうのは、バーチャルなサーバーの機械です。
それを作ったり消したり増やしたりできるのが Amazon Web Service の EC2 です。
タダなのでとりあえず1こ作ってみましょう!

AWS登録後、右上のメニューから「Management Control」にいきます。
そこで「EC2」という項目をクリック! 管理画面がでます!

AWS Management Console

まず左上にリージョン(Region)っていうのがありますよね。
「US East (Virginia)」ってなってるかも? これはたぶんサーバーの場所です。
Japanに変更してもいいけど、とりあえずデフォルトのUS Eastのままにしておきました。

そんなことより「Launch Instance」ボタンが画面の真ん中で「押してください!」って感じでアピールしているのでクリックします!

するとウイザードっぽい作成画面がでます。これがインスタンス作る画面。
ウイザード形式は「Classic Wizard」をチョイスしました。

■OS選択
ぼくは一番上にあった Amazon Linux AMI 2012.03 の 64bit を選びました。
(amzn-ami-pv-2012.03.1.x86_64-ebs)
横に☆マークがついてるやつが無料で使えるやつみたい。

■詳細設定
Typeが micro になっているのを確認。 micro以外は有料ですよ!
次の Advanced Instance Options とか Add tags とかは、特に何もせずにそのまま進みます。

■キーペア作成
SSHの鍵をダウンロードできます。
「my_ec2_key」とかわかりやすい名前をつけておいてダウンロードしておきます。

■ファイヤーウォール設定
ここ大事です!
Create a new Security Group をチェック。
Group Name に「my_firewall」と適当な名前を入れておきます。

セレクトボックスから SSH (22) を選んで Add、
次に Custum TCP rule を選んで、ポートに 3128 (Squidのデフォルトポート) を入力して Addします。
あと今回はテスト的に、HTTP (80) も Add しておきます。

Source は 0.0.0.0/0 のままなら、どのIPアドレスからでも繋げられます。
今回はこのままで大丈夫。

Descriptionに空けたポートの説明を書いておくなどします。
「SSH, HTTP, 3128」とか。

それぞれを Add した後、右にこの3つのポートが追加されたのを確認して continue!
これで最初のインスタンスが完成しました! やった!

3. インスタンスを確認 (1分くらい)

管理画面の左メニューの Instances をクリックしましょう!

AWS Management Console

一覧の中に、さっき作ったインスタンスがいますか! (いなければ左上のリージョンを確認しましょう)
インスタンスが、数十秒待ってもペンディング状態のままなら右上のリフレッシュボタンで画面更新!

一覧の中のインスタンスをクリックすると下に詳細が表示されます。
ec2-xxx-xxx-xxx-xxx.compute-1.amazonaws.com
詳細のところにこんな青文字のアドレスがありますよね!
これが外からインスタンスに繋ぐためのアドレス(Public DNS)です!

4. さっそくつないでみる (3分くらい)

Windows(Teraterm)からつなぐ場合:
管理画面の一覧のインスタンス名をクリック → Connect
Connect from your browser using the Java SSH Client (Java Required)」をクリック。
User name を確認しておく。Amazon Linux AMI のデフォルトなら「ec2-user」です。

terateram を起動して、ホストにインスタンスの Public DNS を入れて SSH2 を選択。
User name はさっきの「ec2-user」、password は空のままで、「RSA/DSA鍵を使う」を選択します。
ファイル選択ダイアログで「すべてのファイル」を選び、さっきのpemファイル選択。
これでログインできます!

UnixライクOSから繋ぐ場合:
管理画面の一覧のインスタンス名をクリック → Connect
Connect with a standalone SSH Client」をクリックするとやり方が書いてあります。
まずダウンロードした鍵ファイルのパーミッションを変更しておきます。
変更しておかないと怒られます。

> chmod 400 my_ec2.pem

あとは画面のExampleの通り

> ssh -i pemファイルのpath/my_ec2.pem ec2-user@ec2-xxx-xxx-xxx-xxx.compute-1.amazonaws.com

これでログインできます!


ログインしたら、とりあえずめんどくさいのでrootになります。

> sudo su - 

これでパスワードなしでrootになれます。

5. 試しにWebサーバーを立ててみる (2分くらい)

ためしにWebサーバーを入れてみます。(必要ないならやらなくていいです)

# yum install httpd
...
[y/N] y

これでWebサーバーのインストール完了です。本当に簡単ですね。
さっそく立ち上げましょう!

# service httpd start

Webサーバーが起動しました!

PCのブラウザからインスタンスのアドレス(Public DNS)にアクセス!
Apacheのデフォルト画面が表示されたら成功!
ちゃんと外から繋げるみたいですね!

それが確認できたらwebサーバーを停止します。

# service httpd stop

もし再起動後もWebサーバーを立ち上げたい場合は

# chkconfig httpd on
# chkconfig httpd --list

こんな感じにします。今回は別にしなくていいです。

6. 無限IPを実現するためのProxyサーバーを入れる (10分くらい)

といってもWebサーバのセットアップと同じで数分でできます。

# yum install squid
...
[y/N] y

インストール完了!

ここから設定ファイル(squid.conf)の設定です。
viエディタ使います。

viの使い方ははぶくので、わからない人はぐぐってください。
/(検索)と、i(文字挿入)と、a(文字追加)と、A(末尾に追加)と、dd(行削除)と、ZZ(保存して終了)と、:q!(保存せずに終了)と…、
あとは、困った時のESC連打→:q!くらい知っていればなんとかなると思います。
ぼくもそのくらいしか知りません。

まず念のために元の設定ファイルをコピーしておきます。

# cp /etc/squid/squid.conf /etc/squid/squid.conf.org

ここで初心者tipsです!
/etc/squ みたいに、途中まで打ち込んだところでtabキーを押すと残りのpathが補完されますよ! べんり!

confファイルを編集します。

# vi /etc/squid/squid.conf

接続許可したいIPアドレス…つまり自分のプロバイダのIPとかを、適当な名前をつけて列挙します。

...

acl CONNECT method CONNECT
acl sakura src XXX.XXX.XXX.XXX/255.255.255.255 # (追加) 接続許可したいIPアドレス(ぼくのsakuraサーバー)
acl lan src XXX.XXX.XXX.XXX/255.255.255.255 # (追加) 接続許可したいIPアドレス(ぼくのlan)
# 自分のIPアドレスがわからない人は懐かしの確認君(http://www.ugtop.com/spill.shtml)とかで見てください

...

http_access allow localhost
http_access allow sakura # (追加) さっき追加したIPの名前
http_access allow lan # (追加) さっき追加したIPの名前
http_access deny all # ↑必ずこのdenyより上に書く

...

# 最終行に以下を追加します。Proxyの匿名性を高める設定です。
request_header_access X-Forwarded-For deny all # (追加)
request_header_access Via deny all # (追加)
request_header_access Cache-Control deny all # (追加)

confファイルの設定が終わったら、Proxyサーバーを起動します!

# service squid start

うまく立ち上がりましたか!
うまくいかない場合はconfが間違ってると思うので、エラーをググったりして修正した後、squidを再起動してください。

# service squid restart

7. Proxyを確認しよう (5分くらい)

Proxyがうまく動いてるか、ブラウザで確認してみましょう!
ブラウザのプロキシ設定に、インスタンスの Public DNS をいれて、ポート3128を設定します。
その状態でGoogleとか開けますか!

もしここで反応が返ってこなかったり、エラーが表示される場合は、やっぱり何かミスってます!

・ほんとにインスタンスのFirewallのポート3128開けましたか?
・squid.confに自分のipアドレス書きましたか? ( acl ZZZ src XXX.XXX.XXX.XXX/255.255.255.255 )
・そのipアドレス許可しましたか? ( http_access allow ZZZ )
・squidはエラーなく起動しましたか?
・squidをリスタート ( service squid restart ) してみるとどうなります?

このあたりを再チェック!
うまくいったら、懐かしのProxy診断サイト「診断君」にアクセスです!

proxyの兆候は全く見られません」と表示されればok!
匿名Proxyが完成しました!
あとはProxyサーバーを自動起動するように設定しておきましょう。

# chkconfig squid on
# chkconfig squid --list

一応、squid.confをローカルPCにも、コピペなりで保存しておくといいかもしれませんね!
あとでインスタンス作り直す時に便利かもしれません。

あと、ここまで設定できた時点で、
ぼくはAWS管理画面から、インスタンス右クリック → Create Image (EBS AMI) をやっておきました。
これをしておくと、いま設定したものと同じ状態のインスタンスを、いくつでも、すぐに立ち上げられるようになります。

Imageの作成には結構時間がかかります。数時間くらい?
でもImageから新しいインスタンスの起動は数十秒でできます! すごい!

ぼくは同じ状態のインスタンスを8つほどつくっておきました。
なぜ沢山つくったのかというと、無限IPアドレスの為の布石です。

7. IPアドレスが変化するのを確認する (2分くらい)

管理画面から、右クリックメニューで、インスタンスを stop → start すると
IPアドレスが切り替わることが確認できると思います。
間違ってterminateしちゃだめですよ。

どうやらrebootではipアドレスが変わりません。
だからIPを切り替えるにはstop→startが良いようですね!

でもいちいち管理画面からクリックしてstart-stopとかやってられません><
なのでAPIを使うことにしましょう!

8. EC2 API Tools をセットアップする (10分くらい)

APIの利用は手元のLinuxからやります。Windowsでもできるみたいだけど…。
なので以下はさくらvpsでの作業です!

公式の Amazon EC2 API Tools のページから、API Toolsをダウンロード

# wget ダウンロードのurl
# unzip ec2-api-tools.zip

解凍したディレクトリ名を「ec2-api-tools」などの簡単な名前にしておきます。

# mv ec2-api-tools-1.5.4.0 ec2-api-tools

次に API用の鍵をもらいにいきます。
AWS管理画面の右上のメニューから「Security Credentials」をクリック。

画面中央の「X.509証明書」タブをクリック。
新しい証明書を作成する」をクリック。

すると「X.509証明書が作成されました」というメッセージとともに
Download Private Key File と、
Download X.509 Certificate というボタンが出るので、
どちらもダウンロードしておき /root/ec2keys/ などにおいておきます。

APIの実行にはJavaの実行環境が必要らしいのでインストールします。

# yum install java-1.6.0-openjdk

次にAPIを使うための環境変数の設定です。
.bashrc に追記します。

# vi ~/.bashrc
export JAVA_HOME="/usr/lib/jvm/jre-1.6.0-openjdk.x86_64/"
export EC2_HOME="/root/ec2-api-tools"
export EC2_PRIVATE_KEY="/root/ec2keys/pk-*****************************.pem"
export EC2_CERT="/root/ec2keys/cert-******************************.pem"
export PATH="${PATH}:${EC2_HOME}/bin"

追記した .bashrcファイルを読み込みなおします。

# source ~/.bashrc

セットアップ完了! 動くか確認します。

# ec2ver
1.5.4.0 2012-05-01

もしここで、JAVA_HOMEないよとかエラーになるようなら、javaを探します。

JAVA_HOMEの見つけ方:

# which java
/usr/bin/java
# ls -l /usr/bin/java
lrwxrwxrwx 1 root root /usr/bin/java -> /etc/alternatives/java
# ls -l /etc/alternatives/java
lrwxrwxrwx 1 root root /etc/alternatives/java -> /usr/lib/jvm/jre-1.6.0-openjdk.x86_64/bin/java
# ls -l /usr/lib/jvm/jre-1.6.0-openjdk.x86_64/bin/java
-rwxr-xr-x 1 root root /usr/lib/jvm/jre-1.6.0-openjdk.x86_64/bin/java # ←これだ! bin/javaの手前までがJAVA_HOME

こんな感じで which の後、ls -l でリンクを最後まで追うとわかります。

9. EC2 API Tools を試してみる (10分くらい)

試しにAPIでインスタンス一覧を出してみます。

# ec2-describe-instances -region us-east-1

何か情報が表示されましたか!
もし何もでないならリージョンの設定を間違えてるのかもしれません。
リージョンの一覧はこのページとか参考になります → リージョンを固定する方法 at technote

色々やってみましょう!

インスタンスを指定してみる (i-で始まる部分はインスタンスID)
# ec2-describe-instances i-XXXXXX -region us-east-1
必要そうな行だけだしてみる
# ec2-describe-instances i-XXXXXX -region us-east-1 | grep "INSTANCE"
出力をフィルタしてみる ※startしてるインスタンスのみ出力
ec2-describe-instances -region us-east-1 -F "instance-state-code=16" | grep "INSTANCE"
※ instance-state-codeの一覧
0pending
16running
32shutting-down
48terminated
64stopping
80stopped
インスタンスを停止してみる
# ec2-stop-instances i-XXXXXX -region us-east-1
インスタンスを開始してみる
# ec2-start-instances i-XXXXXX -region us-east-1

コマンドラインから自由自在ですね!やりました!

10. プログラムからAPIを使ってみよう (30分くらい)

でもいちいちコンソールから入力していたら、
Webの管理画面でクリックしているのとそう変わりませんよね。

だからこれをプログラムから自動的に制御できるようにしてみます。
例えば、呼び出されるたびに現在のProxyを停止させて、
新しいProxyを開始させ、新しいProxyのアドレスを表示するPHPプログラムの例。

<?php
// EC2で複数のインスタンスをグルグルとStop→StartしてIP切り替えるやつ
// 呼び出されると現在のproxyをstopし、次のproxyのアドレスを表示し、次の次のrproxyをスタンバイとして起動する
// by Hamachiya2.

echo '<html><body><pre>';

// API Tools 環境変数の設定
putenv('JAVA_HOME=/usr/lib/jvm/jre-1.6.0-openjdk.x86_64/');
putenv('EC2_HOME=/root/ec2-api-tools');
// pk-*.pemファイルのありか
putenv('EC2_PRIVATE_KEY=/root/ec2keys/pk-XXXXXXXX.pem');
// cert-*.pemファイルのありか
putenv('EC2_CERT=/root/ec2keys/cert-XXXXXXXX.pem');

$api = '/root/ec2-api-tools/bin/';
$region = 'us-east-1';

// EC2インスタンスIDを列挙しておく。
$insts = array(
	'i-XXXXXXXX',
	'i-XXXXXXXX',
	'i-XXXXXXXX',
);

// proxy情報ファイルが無ければ作成
if (! file_exists('./now_proxy')) {
	fo('./now_proxy', 'w', $insts[0] . "\t");
}

// ファイルに保存してある現在のproxy情報読み込み
// 保存形式: インスタンスID [tab] PublicDNS
$row = fo('./now_proxy', 'r');

$temp = explode("\t", $row);
$now_proxy = array(
	'inst' => $temp[0],
	'pdns' => $temp[1]
);

// now_proxyの添え字を調べる
for ($now=0; $now<count($insts); $now++) {
	if ($now_proxy['inst'] == $insts[$now]) {
		break;
	}
}
message("now proxy: ${now_proxy['inst']}($now) ${now_proxy['pdns']}");

// next_proxyの添え字を知る
$next = nextKey($insts, $now);

// スタンバイとして起動しておくproxyの添え字を知る
$stanby = nextKey($insts, $next);

// nextのPublicDNSを調べる
message('check new proxy Address ...');
exec($api . 'ec2-describe-instances ' . $insts[$next] . ' -region ' . $region . ' | grep "INSTANCE"', $r);

$next_pdns = null;
if (preg_match('/ec2.+?amazonaws.com/', $r[0], $pdns)) {
	$next_pdns = $pdns[0];
} else {
	// PublicDNSが得られなかった時。nextを起動させて終了。
	message("No next PublicDNS.\nstart next: ${insts[$next]}($next)");

	exec($api . 'ec2-start-instances ' . $insts[$next] . ' -region ' . $region);
	message('exit.');
	exit();
}

// next_proxyの情報をファイル書き出し。これが新しいproxyの情報。
message("new proxy: ${insts[$next]}($next) $next_pdns");
fo('./now_proxy', 'w', $insts[$next] . "\t" . $next_pdns);

// stanby_proxyを起動しておく。
message("start stanby proxy ... ${insts[$stanby]}($stanby)");
exec($api . 'ec2-start-instances ' . $insts[$stanby] . ' -region ' . $region);

// now_proxyを停止する。
message("stop now proxy ... ${now_proxy['inst']}($now)");
exec($api . 'ec2-stop-instances ' . $now_proxy['inst'] . ' -region ' . $region);

message('done.');

// 次の添え字を返すやつ
function nextKey($a, $key) {
	$ret = 0;
	if (! ($key == (count($a)-1)) ) {
		$ret = $key + 1;
	}
	return $ret;
}

// ファイル読み書きするやつ
function fo($f, $rw, $str=null) {
	$ret = null;
	$fh = fopen($f, $rw);
	flock($fh, LOCK_EX);
	if ($rw == 'w') {
		fputs($fh, $str);
	} else if ($rw == 'r') {
		$ret = fgets($fh);
	}
	flock($fh, LOCK_UN);
	fclose($fh);

	return $ret;
}

// バッファさせずにメッセージ表示
function message($str) {
	echo $str . "\n";
	ob_flush();
	flush();
}

簡単ですが、こんな感じのプログラムと、cronや他のWebプログラムを組み合わせれば色々と自動化できますよね!
はい!
おつかれさまでした!無限IPアドレス切り替え器の完成です!

でも無料だからといって、うっかりProxy通したまま動画みたちゃったり、
インスタンス立ち上げたまま忘れたりしていると、
いつの間にか無料枠をこえて請求されるかもしれません…><
遊んだあとは、ちゃんとstopさせておきましょうね!

料金がかかっていないか心配な人は、しばらく経ってから(1日くらい?)
AWSトップページのメニューから「アカウントアクティビティ」を選べば確認することができますよ!

トラックバック - http://d.hatena.ne.jp/Hamachiya2/20120612/ec2
Connection: close