SSブログ
前の10件 | -

LVMを店じまいする(解除・後始末) [Linux(LVM/RAID/Storage)]

 またえらく久しぶりに記事を追加する気がしますが、LVMで構成したストレージ領域を「店じまい」(解除というか後始末というか)する手順を紹介しておきます。
 ぶっちゃけ、「アンマウントしてディスク外せば終わりじゃん!」っていう感じではあるんですけども、ディスクを外しただけだとrebootした時等にまだLVM領域が見えてしまい困るケースも無い訳では無いので、次にそのディスクを接続する事があっても、LVMとして全く認識されなくする必要が発生する…ことがある…かもしれないということで。

 基本的な手順としては、
 ① そのディスク領域を使用しているプロセス・デーモンを停止する
 ② そのディスク領域に保存されているデータをどうにかする(必要に応じてコピーする等)
 ③ アンマウントする
 ④ 論理ボリュームを削除する
 ⑤ ボリュームグループを削除する
 ⑥ 物理エクステントを削除する

 このうち、⑤と⑥については一つのボリュームグループ内に複数の論理ボリュームが存在し、その論理ボリュームを削除してもなお他の論理ボリュームが残っている場合には実施しません。(というかやったら消えるけどそもそもエラーになります)

 では、手順を追っていきます。

① そのディスク領域を使用しているプロセス・デーモンを停止する
 多分、sambaなりapacheなりnginxなりgitなりなにがしかのデーモンがそういう領域を使っていると思いますので、そいつらを始末します。
 必要に応じてchkconfig あるいは systemctl でデーモンを自動起動しないようにするとか忘れずに実行します。

② そのディスク領域に保存されているデータをどうにかする(必要に応じてコピーする等)
 当然、LVMの論理ボリュームを削除したらその中にあるデータも消し飛んでしまいますので、必要ならrsyncするなりscpするなり tar / cpio するなりしてデータをバックアップしておくとかコピーしておくとか実施します。

③ アンマウントする
 いよいよアンマウントします。

umount /mnt/local/storage

 とかそんな感じで。エラーになるようならfuserコマンドで原因となるプロセスを特定してkillしてやりましょう。
 よくあるミスとしては、「自分自身がそこにcd コマンドで移動していた」なんていう事です。(大笑)
 あと、/etc/fstabとかその辺も忘れずに修正しましょう。/etc/exportsとかも忘れがちだよ~。

④ 論理ボリュームを削除する
 lvdisplay コマンドでサーバ上に存在するLVM論理ボリュームが確認できます。削除したい「LV Path」を確認しておきます。

[root@peorth ~]# lvdisplay
--- Logical volume ---
LV Path /dev/vgStorage/lvPrivate
LV Name lvPrivate
VG Name vgStorage
LV UUID xulASs-wZ0N-1bnl-IXxq-3yQm-vAnT-t4iM93
LV Write Access read/write
LV Creation host, time peorth, 2018-10-15 10:23:36 +0900
LV Status available
# open 1
LV Size <7.28 TiB
Current LE 1907599
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 8192
Block device 253:2

 ここでは、「/dev/vgStorage/lvPrivate」が必要な論理ボリューム名になります。なお、LVM論理ボリュームはOSによってはインストール時にインストーラが自動でいくつかのLVM論理ボリュームを作成します。それを間違って削除しないように気をつけましょう。(アンマウントしていなければえらーになるはずだけどね)多分、酷い目に遭います。(笑)

 論理ボリュームを削除するコマンドは、 lvremove になります。このコマンドに先ほどの論理ボリューム名(LV Path)を指定して実行します。

Do you really want to remove active logical volume vgStorage/lvPrivate? [y/n]:

 と、聞かれると思うので、本当に削除しても良いのなら「y」を入力しましょう。

 コマンドを実行すると、 lvdisplay でももはや先ほどの論理ボリュームは表示されないはずです。

⑤ ボリュームグループを削除する
 必要に応じてボリュームグループを削除します。ボリュームグループの確認方法は vgdisplay コマンドです。

[root@peorth ~]# vgdisplay
--- Volume group ---
VG Name vgStorage
System ID
Format lvm2
Metadata Areas 1
Metadata Sequence No 5
VG Access read/write
VG Status resizable
MAX LV 0
Cur LV 0
Open LV 0
Max PV 0
Cur PV 1
Act PV 1
VG Size <7.28 TiB
PE Size 4.00 MiB
Total PE 1907599
Alloc PE / Size 0 / 0
Free PE / Size 1907599 / <7.28 TiB
VG UUID X8BIeD-jWLi-NVT7-jnER-h3XW-5yfC-JjMw9b

 このボリュームグループは、もはや全くの未使用状態になりました(Alloc PE / Size が「0」になっている)ので、遠慮なく削除します。削除する際にはボリュームグループ名が必要となりますので、「VG Name」の項目を確認しておきます。削除に用いるコマンドは vgremove です。

[root@peorth ~]# vgremove vgStorage
Volume group "vgStorage" successfully removed

 これで vgdisplay コマンドを使ってもボリュームグループは表示されないはずです。

⑥ 物理エクステントを削除する
 最後に、ボリュームグループに加わっていたディスクの上から物理エクステントを削除します。
 物理エクステントを確認するコマンドは pvdisplay です。

[root@peorth ~]# pvdisplay
--- Physical volume ---
PV Name /dev/sdb
VG Name
PV Size <1.89 TiB
Allocatable NO
PE Size 0
Total PE 0
Free PE 0
Allocated PE 0
PV UUID sg4Q5g-HSXp-fyBF-aIVi-rVNy-3KOA-3WKGfg

 Allocated PE の項目が「0」になっている物理ボリュームは全くの未使用状態になっています。そのボリュームの「PV Name」を確認しておきます。複数のディスクを束ねているような場合には、複数ボリューム分のAllocated PEとPV Nameとを確認しておきましょう。
 物理エクステントを削除するコマンドは、 pvremove です。

[root@peorth ~]# pvremove /dev/sdb
Labels on physical volume "/dev/sdb" successfully wiped.

 複数の物理ボリュームを指定することができます。(別に、1個ずつ実行しても害は無いけどね)

 これで pvdisplay コマンドで物理ボリューム名が表示されなくなれば完了です。
 当該ボリュームはもうLVMとして認識されることはありません。

 「私たち、普通の女の子に戻ります!」

 って感じで普通のボリュームに戻りました。(年齢踏み絵

nice!(1)  コメント(0) 
共通テーマ:パソコン・インターネット

google Chromeさんが壊れた~格闘日記 [PC(ソフトウェア)]

google Chromeでなにかファイルが壊れたらしい。が、google先生であれこれ検索をして各種掲示板を参照しても現象が改善しない。ひとまずここにメモを残しておく。

○ 現象
 google Chromeを起動すると、


Google Chrome

ユーザー設定ファイルを読み込むことができません。一部
の機能が利用できない可能性があります。また、設定への
変更は保存できません。

 と表示される。最初はブックマークのバーも表示されるが、サイトを移動するとブックマークのバー等も表示されなくなる。

○ 環境
Windows 7 (64bit)
PCは会社のものでBTOで組まれた物なのでいわゆる「メーカー品」ではない。

○ 最近したこと
そういえば、Skypeをインストールして、邪魔くさいのでアンインストールをしたかなあ…という程度。あとはWindows Updateをしたでしょうか。その他でアプリを入れましたという操作はしていない。と、思う。

○ 悪戦苦闘ログ
第1ラウンド:まず最初に、設定ファイルが壊れている可能性があるということなので、以下の手順を試した。

手順1:Chromeを全て終了する。タスクマネージャーでも「Chrome.exe」が一つも存在しないことを確認した。
手順2:c:\ユーザー\(自分のユーザー名)\AppData\Local\Google\Chrome ディレクトリにある 「User Data」を「User Data.bak」にリネームする
手順3:Chromeを起動

× 効果無し。エラーがでる。

 正確には、最初のChromeへのログイン画面がでる。この時はエラーなくChromeにログインできる。ところがログインしてブックマークがインポートされた後にChromeを一旦終了して再度Chromeを起動すると


Google Chrome

ユーザー設定ファイルが壊れているか無効です。設定を復
元できません。


と出る。また、このChromeを閉じて再度起動すると今度はこの記事冒頭のエラーになる。


Google Chrome

ユーザー設定ファイルを読み込むことができません。一部
の機能が利用できない可能性があります。また、設定への
変更は保存できません。



第2ラウンド:Chromeをアンインストールして再インストールしてみる。以下の手順を試した。

手順1:Chromeを全て終了。やはりタスクマネージャーでChrome.exeが全く存在しないことを確認した。
手順2:コントロールパネル→プログラムと機能 でGoogle Chromeをアンインストール。なお、アンインストール時には「閲覧データも削除しますか?」と、「既定のブラウザを変更」にもチェックを付けてアンインストールを実行。
    ※Internet Explorerで「Chromeヘルプ」というページが立ち上がるが、日本語では情報提供していないらしい。
手順3:c:\ユーザー\(自分のユーザー名)\AppData\Local\Google\Chrome ディレクトリを削除。
手順4:念のためPCを再起動
手順5:再起動後Chromeを再インストール。

× 効果無し。エラーがでる。

 このケースでも第1ラウンドと同じく、初回はChromeへのログイン画面が出る。gmailアカウントでいつも使っているアカウントでログイン後、ブックマークがインポートされるのを確認してからChromeを一旦終了し、再度Chromeを起動すると


Google Chrome

ユーザー設定ファイルが壊れているか無効です。設定を復
元できません。


と出る。また、このChromeを閉じて再度起動すると今度はこの記事冒頭のエラーになる。


Google Chrome

ユーザー設定ファイルを読み込むことができません。一部
の機能が利用できない可能性があります。また、設定への
変更は保存できません。


と、現象変わらず。

なお、Chromeをインストールする段階で、32bit版・64bit版の両方をインストールして試しているがどちらも減少は全く同じ。

もー、訳がわからん。
そんな訳でこの記事は久しぶりにInternet Explorerで書きました。(笑)
それにしても、使いづらいブラウザーですねえ!!
Chromeがトラブってるんで仕方が無いんですが。つーか、情報なさ過ぎ(滝涙
格闘の記録は何か進展ありましたらここに追記すると思います。多分。
また、何かご存じの方、「これ試してみたら?」系のコメントは絶賛大歓迎でございます。m(__)m どうか哀れなオッサンをお助けくださいまし。

帰ってきた・たぶん難しくないApache2・挑戦!RewriteRule・活用編 ~「メンテナンス中です」ページを出してみよう~ [Linux(Apache)]

 いろいろ方法はあるんですが、RewriteRule活用のヒントとして、「メンテナンス中です」ページを出す例を紹介します。

#確か、このblogの趣旨としては「ご家庭の(ry

 シチュエーションとしてはこんな感じ。
 あるディレクトリ (ここでは 「/var/www/html/maintenance」とします)配下に、「現在メンテナンス中につきご利用いただけません」的なページを一式用意します。画像とかcssとかもね。
 そして、そのサーバにあるあらゆるリクエストについて、全て「メンテナンス中です」のページを出すようにします。

 まあ、ErrorDocumentを使う方法とかCGIで出しちゃえばいいじゃん的な方法もあるんですが、ここではあえてRewriteRuleを主役に据えて実施してみたいと思います。



① まずは「メンテナンス中です」のページを用意しましょう。

 すでに書いた通り、 /var/www/html/maintenance ディレクトリ配下にメンテナンス中ですページを一式用意しましょう。cssファイルが必要なら、cssというサブディレクトリを作成してその下に、画像ファイルが必要なら、imgというサブディレクトリを作成してその下に置くことにしましょう。
 「メンテナンス中です」ページの名前は index_maintenance.html とします。(まあ、名前は何でも良いんですがw)

② メンテナンス中ですページは誰でも見られるようにする必要があるのでそのように設定します。

 apache2.2系までならこんな感じでバッチコイ設定を入れます。
<Directory    "/var/www/html/maintenance">
    Order  Deny,Allow
    AllowOverride  None
    Options  None
<Directory>


 apache2.4系ならこんな感じです。
<Directory    "/var/www/html/maintenance">
    Require all    granted
    AllowOverride  None
    Options  None
<Directory>


 で、このディレクトリをドキュメントルートにしましょう。

DocumentRoot    "/var/www/html/maintenance"


③ で、RewriteRuleの出番です
 基本的な考え方としては、「とにかくindex_maintenance.htmlに読み替える」ことになるでしょう。
 サーバ上にはhtmlファイルの他に各種のCGIもあるでしょうし、「http://server/」とか「http://server/somdirectory/」のようにサーバ名やディレクトリ名だけで終わっている可能性もあります。このため、基本的にはありとあらゆるリクエストを読み替えることになるでしょう。ということは、まずは
RewriteRule    .*    /index_maintenance.html    [L]

 というRewriteRuleが登場すべきなのはガチという所でしょう。
 しかし、index_maintenance.htmlに貼ってある画像とかcssファイルとかまでindex_maintenance.htmlに読み替えるのはまずいので、それらは読み替えず、またindex_maintenance.html自身へのアクセスも読み替える必要は無いと言えます。
 そのような訳で、「css/配下とimg/配下へのリクエストは読み替えない」「ファイルが実在する場合は読み替えない」「index_maintenance.htmlへのリクエストは読み替えない」という感じの例外は入れたいと思います。
 RewriteCondディレクティブを用意します。
RewriteCond    %{REQUEST_URI}    !img/
RewriteCond    %{REQUEST_URI}    !css/
RewriteCond    %{REQUEST_URI}    !index_maintenance\.html$
RewriteCond    %{REQUEST_FILENAME}    !-f


 というあたりをRewriteRuleの前に書き足してやれば良いです。(多少、手抜きしてるのでアレですがw)

④ マニアックな需要のための対応
 ところで、③のRewriteRuleで対応すると、かなりそのスジな方から苦情(?)が上がる可能性があります。それは、CDNサービスのようなWebページをキャッシュするサービスを利用している場合です。
 実は③のRewruteRuleではメンテナンスページが200番応答で出力されてしまうため、そのメンテナンス中のページがキャッシュされてしまうという問題を引き起こします。ということは、メンテナンスが終了してもキャッシュされたページが出力されてしまうため、メンテが終わった後の素敵なページが閲覧出来ないという事態を引き起こす恐れがあります。

 このような場合、世間様的には500番系の応答を返してメンテナンス中ですのページを出すのが一般的…らしいです。そんな訳で、③を改良してメンテナンス中ですページを503番応答で出力させてみます。

 まず、RewriteRule本体を次のように改めます。
RewriteRule    .*    -    [L,R=503]


 そして、503番エラーが発生したときのためのエラードキュメントを設定します。
ErrorDocument    503    /index_maintenance.html


 こうすることで、応答が503になるので、多くのCDNサービスやらキャッシュサーバ等はメンテナンス中のページをキャッシュしなくなります。…なるはずです。(笑)

#Akamaiさんはキャッシュしなかったよー。

帰ってきた・たぶん難しくないApache2・挑戦!RewriteRule・その4~楽しいProxy~ [Linux(Apache)]

 本来なら、Proxyしたい場合はそれ用のディレクティブ「Proxy」等があるので、そちらを使うのがスジです。
 しかし、RewriteRuleでもProxyすることが出来たりしますし、むしろこっちの方が便利だということもあったりする訳なのです。そこで、RewriteRuleでProxyする方法を解説しておきます。



その1:反則技編 ~とにかくProxyする~

 まずはいきなり反則技から行きたいと思います。
 とにかくProxyします。このような場合、本当なら「Proxy」ディレクティブを使うのがスジです。RewriteRuleを使うべきではありません。しかし、解説としてはこれが一番判りやすいのでコレから先に解説したいと思います。
 なお、セキュリティ上の問題を多分に孕んでいますので、これで事故が起こったとしても当方は一切関知しませんので念のため。

 RewriteRule ^/(.*) http://otherserver/$1 [P]

 こんだけ。
 Proxyディレクティブを使う場合はもうちょっと指定が必要になるんですが、RewriteRuleディレクティブでやる場合はたったこんだけで終了です。これで、このサーバにきた全てのリクエストが、別のサーバ「otherserver」に中継されます。リダイレクトじゃありません。中継です。大事なことなので(ry

 ポイントになるのはRewriteRuleディレクティブの第3パラメータである[P]です。こいつが「Proxy」を意味しています。ここが[R]の場合はリダイレクトされます。つまり、ブラウザがotherserverにアクセスしなおすことになるんですが、今回はここが[P]なので、このサーバがotherserverにアクセスを中継してデータを取得するということをします。



その2:アレはProxyする。コレはProxyしない。

 RewriteRuleディレクティブを使ってProxyする最大の意義は、RewriteCondディレクティブやRewriteMapディレクティブといった機能を組み合わせてProxyする・しないを制御出来ること、あるいはProxy先を自在に書き換えることが出来ることです。

 たとえば、RewriteCondと組み合わせて、「自サーバにファイルがあればそれをクライアントに返し、なければProxyとしてotherserverに取りに行く」みたいなシナリオを想定してみます。するとこんな感じに。

 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteRule ^/?(.*) http://otherserver/$1 [P}

 RewriteCondが今まで説明しなかったような記述なんで説明します。
 サーバ上にその名前のファイルがあるかどうかを判定する場合、-fという記述ができます。これに「!」を付けた場合には否定の意味を持ちますので、「REQUEST_FILENAME」に指定されているファイルが無い場合にRewroteCondが成立することになります。
 ファイルが存在する場合は続くRewriteRuleは実行されませんので、他に無ければ自サーバ上にあるファイルをそのままクライアントに返します。ファイルが無ければRewriteRuleが実行されますから、otherserverにファイルを取得しにいくことになります。

 また、User-Agentに応じてproxy先を変更するなんてこともRewriteRuleならお手の物です。

 RewriteCond %{HTTP_USER_AGENT} iPhone
 RewriteRule ^/?(.*) http://otherserver/iphone/$1 [P]
 RewriteRule ^/?(.*) http://otherserver/$1 [P]

 とかやっておけば、(判定がちょっと雑ですがw)iPhoneとそれ以外のUAとでProxy先を変更することも出来ます。


その3:そもそもproxy先をひん曲げたい

 CGIが動作するサーバを直接インターネットに曝すなんてとんでもない!というしごく真っ当なサーバ管理者なら、CGIサーバの前にリバースProxyサーバを立ててそこからCGIにアクセスするようにしたいなんていう需要もあるでしょうね。当然、静的なhtmlページや画像ファイルはそのままWebサーバから配信し、プログラムが必要な所ではCGIサーバに代理アクセスをしてクライアントのその結果だけ返すなんてことをしたくなるわけです。
 ひとまず、単純に、「ファイルがあればそれを返し、ファイルが無ければURL部分をパラメータ化してCGIに処理を渡す」なんてことを表現するならこんな感じでしょうか。

RewriteCond    %{REQUEST_FILENAME}    !-f
RewriteRule    ^/?(.*)    http://cgi-server/program.cgi?param=$1    [P]


 このような場合、例えばhttp://myserver/index.html というファイルが存在すればそのファイルをクライアントに返します。しかし、http://myserver/shop/item/54 みたいなリクエストが来た時にそのようなファイルが存在しないときは、CGIサーバにリクエストを中継します。その時のURIは http://cgi-server/program.cgi?param=shop/item/54 という具合になります。CGIが出力する結果は自サーバを経由してクライアントに送信される…ということになります。

帰ってきた・たぶん難しくないApache2・挑戦!RewriteRule・その3~RewriteMapを使う~ [Linux(Apache)]

 そうか…。もう6年とか経過していたのか…。
 何もかもが懐かしい…。(遠い目


 URLの読み替えをしたい場合にRewriteRuleを使う…という話をしてましたが、ファイルが決め打ちできるとか、正規表現で一定のルールに従って読み替えができる…というようなケースでは割と簡単にお役に立ってくれました。
 ところが…。
 たまに有りませんか?

 サイトのデザインを一新したんだけど、ページにリンクされている画像ファイルとかバナーとかも全部差し替えたい。でも、他のサイトで直リンクしているバナーもあるようなんだけどもう把握出来ていないので、古いバナーについては新しいバナーにサーバ側で読み替えて欲しいんですけど。

 …みたいな話。で、『あ…。シンボリックリンクを張っておくかRewriteRuleで読み替えちゃえばいいかな…』なんて考えていたら読み替えるべきファイル名が数百個もあった件について…みたいな事例。
 しかも、正規表現で美しく読み替えようにもそんなこと出来ませんよセンセイ…みたいな事例。

 …え?ない?
 …ソウデスカ…アリマセンカ…orz

 ここでは、「あー。あるある!」と大人の対応をした人に向けて、「RewriteMap」を簡単に使って解決する方法を書いておきたいと思います。


 例えば、たった一つのファイルを読み替えたいときはどうするか?を考えます。
 img/fileA.jpg を、img/fileB.jpg に読み替えるとしましょう。この場合はチョー簡単です。

 RewriteRule img/fileA.jpg img/fileB.jpg [L]

 とかやっておけば事足ります。ところが、これを何百個も書きたくない訳です。このような場合には、「RewriteMap」ディレクティブを使います。手順としてはこんな感じです。

手順①:旧ファイル名 → 新ファイル名の読み替え一覧をテキストファイルで作成する
手順②:手順①で作成したテキストファイルをdbm型式に変換する
手順③:手順②のファイルを、「RewriteMap」ディレクティブで読み込み、条件を設定してRewriteRuleで読み替える


手順①:旧ファイル名 → 新ファイル名の読み替え一覧をテキストファイルで作成する

 まず、新旧ファイル名の読み替えをする一覧をテキストファイルに作成します。フォーマットは、「旧ファイル名」と「新ファイル名」とを1行に記述します。半角スペースやタブで区切ります。

img/fileA.jpg    img/fileB.jpg
img/fileC.jpg    img/fileX.jpg
img/fileD.jpg    img/fileY.jpg
img/fileE.jpg    img/fileZ.jpg


 なお、半角「#」がコメントとして使用可能です。


手順②:手順①で作成したテキストファイルをdbm型式に変換する
 次に、手順①で作成したテキストファイルをdbm型式に変換します。実のところ、変換しなくてもいけるんですが、読み替えるべきファイルが多い場合は変換した方がサーバ負荷が下がってオススメです。
 コマンドとしては、httxt2dbmコマンドを使用します。

 httxt2dbm -i (入力ファイル名) -o (出力ファイル名)

 です。入力ファイルには手順①で作成したファイル名を指定します。出力ファイル名にはdbm型式のファイル名をそれっぽい名前で指定すればよいでしょう。
 このコマンドを実行すると、拡張子「.dir」というファイルと「.pag」というファイルが作成されます。


手順③:手順②のファイルを、「RewriteMap」ディレクティブで読み込み、条件を設定してRewriteRuleで読み替える

 次に、httpd.confを調製します。
 まず、手順②で指定したdbm型式のファイルをRewriteMapディレクティブで読み込みます。

 RewriteMap imgurl dbm:/usr/local/apache2/conf/yomikaelist

 imgurlは単なる識別子です。次のRewriteRuleディレクティブで使用しますが名前は何でも構いません。
 dbm:/usr/local/apache2/conf/yomikaelistは、「dbm:」に続いて手順②で作成したファイル名を指定します。拡張子は必要ありません。

 で、これをRewriteRuleディレクティブで実際に読み替えます。

 RewruteRule ^/?(img/.*\.(gif|jpe?g)) /${imgurl:$1|$1} [L]

 これくらいの正規表現はちゃっちゃと読めないとねー。(笑)
 まず、RewruteRuleディレクティブの最初のパラメータ^/?(img/.*\.(gif|jpe?g))は、「img/」ディレクトリの下にある「ナントカ.gif」「ナントカ.jpg」「ナントカ.jpeg」を読み替えたいのでこのような記述をしています。ここで、丸括弧が2組出ているのが「なんじゃこりゃ」の原因になっていると思いますので解説しておきます。
 RewriteRuleの過去の記事にもしれっと記述してたりするんですが、丸括弧で囲んだ範囲はRewriteRuleディレクティブの内部的な「変数」に格納することが出来ます。(img/.*\.(gif|jpe?g))の外側の部分はそのための丸括弧で、丸括弧の中身は「$1」という変数に格納されます。
 内側の丸括弧部分(gif|jpe?g)/font>は拡張子「gif」または「jpe?g」のどちらかという記号「|」の範囲を特定するための物です。

 で、この正規表現によって、次のようなリクエストがあったなら、赤文字の部分が変数$1に格納されることとなります。

 http://server/img/fileA.jpg

 さて。この赤文字部分。そういえば手順①で作成したファイルの中にありましたよね?

img/fileA.jpg    img/fileB.jpg
img/fileC.jpg    img/fileX.jpg
img/fileD.jpg    img/fileY.jpg
img/fileE.jpg    img/fileZ.jpg


 この変数$1の内容をRewriteMapディレクティブで読み込んだアレに渡すと、見事img/fileB.jpgに化けて出てくる…という処理をしているのが、RewriteRuleディレクティブの二つ目の引数である /${imgurl:$1|$1} です。

 ${(RewriteMapの識別子名):(読み替え前の名前)}

 としておくと、読み替え前の名前を読み替えた後の名前が取得できます。つまり、

 ${imgurl:img/fileA.jpg}

 という指定をすれば、この変数は結果的にimg/fileB.jpgという値になって機能するということなのです。

 ただし、ここで一つ注意すべきポイントがあります。それは…

 読み替え「前」の名前が無い場合は、空っぽの値が返ってくる

 という点です。つまり、

 ${imgurl:img/fileAHO.jpg}

 という指定をした場合、この結果は「」という状態になってしまいます。このため、RewriteMapで読み込んだファイルの中に記述が無い場合は、RewriteRuleが「」に読み替えようとしてしまいますので非常に都合が悪いのです。

#そもそも、「読み替えたいファイルの一覧」があるということは、
#その中に「無い」ファイルは「読み替えて欲しくない
#と解釈すべきでしょ?

 と言うわけで、imgurlに値が「ない」場合の振る舞いも一緒に指定しておく必要があります。そのための記述が、「|$1」の部分なのです。

 ${imgurl:img/fileAHO.jpg|img/fileAHO.jpg}

 という指定をすると、imgurlに「img/fileAHO.jpg」があれば、読み替えたその文字列を返す。(「|」の前の部分)
 しかし、imgurlで読み替えた結果が「空っぽ」だった場合は「img/fileAHO.jpg」を返す。(「|」の後ろの部分)

 という処理を行うことになります。
 実際には、RewriteRuleで使用している変数「$1」の中身に応じて読み替えをしたいので、結果的に/${imgurl:$1|$1}という指定になっている訳です。



 これで、ファイルが読み替えるべき対象であるならファイル名を読み替え、そうでない(リストに無い)場合はそのままの名前でアクセスを通す…という事が出来るようになります。

EC2 SpotInstanceを使う [Amazon AWS]

Amazon EC2 のSpotInstanceは割とお安い訳ですよ。例えば、c3.2xlargeなら、定価0.511ドル/時のところ、SpotInstance価格ではなんと0.108ドル/時!!(この記事かいてる時点での価格)金利手数料はジャp(チガウ

SpotInstanceの仕組みとしては、Amazonさんの余剰リソースを安く使わせてもらおうというコンセプトのようで、その時のAmazonさんのリソースの空き具合に応じて「時価」が変動しますが、その時価よりも高い「スポット価格」を提示(入札)しているインスタンスに限って、リソースを使用してインスタンスを実行できるというもの。
例えば、今0.108ドル/時なので、「スポット価格」として0.2ドル/時を提示していれば、そのインスタンスは実行できるという感じ。
時折その時の「時価」がボーンと跳ね上がることがありますので、永続的に使用したいなーっていうのには向かないみたいですね。
一時的なバッチ処理をしたいとか、開発テストに使いたいとかそういう用途なら結構イケそうです。(Amazonさんもそう言ってますし。)

で、それを使ってみたいじゃないですか。コマンドラインから

という訳で試してみました。

スポットインスタンスはシャットダウン等するとインスタンス自体がTerminatedになってしまう模様(違ったらすんません)なので、1からインスタンスを立てて使おうという用途よりも、すでにあるインスタンスをスポットインスタンスで使うという感じが向いているのでしょうか。(違ったらすんません)

そんな訳でここでは「既存のEC2インスタンスからAMIを作成して、それをスポットインスタンスとして起動する」という作戦で実験したいと思います。

手順としてはこんな感じ。

① 既存のインスタンスからAMIを作成する
② (AMIの作成には時間がかかるので完成するのを待つ)
③ スポットインスタンスをリクエストする
④ (スポットリクエストが「履行中」のステータスになるのを待つ)
⑤ 必要に応じてタグを付けたりする



① 既存のインスタンスからAMIを作成する

 まず、既存のインスタンスからAMIを作成します。使用するコマンドは aws ec2 create-imageです。先に、既存のインスタンスのインスタンスIDを調べておく必要があります。

 aws ec2 create-image --instance-id (複製元となるインスタンスID) --name (AMIに付ける名前) --description (AMIに付ける説明文) --no-reboot

 「--no-reboot」オプションを省略すると、複製元となるインスタンスが強制的にリブートされます。問答無用です。このため、業務で使用中のインスタンスを指定した時などは悲しい思いをするかも知れないので要注意です。
 今のところ「--no-reboot」を付けたせいで問題になったということは経験していませんが、もしかしたら問題が発生するかもしれない?的な覚悟は一応しておいてください。(AmazonLinux以外の場合は特に…。)

 awsコマンドの実行結果は標準出力にjson型式で表示されますので、コイツを jqコマンドでパースしてやれば、AMIのIDが取得できます。取得すべき項目名は「.ImageId」です。


② (AMIの作成には時間がかかるので完成するのを待つ)

 AMIの作成には割と時間がかかりますね。ストレージの大きさにもよりますが。AmazonLinuxの標準(?)サイズの8GBでも数分はかかります。長いと10分以上要する事もあったりなかったり…。

 コマンドラインから完成したかどうかを確認したい場合は、aws ec2 describe-imagesコマンドで確認できます。

 aws ec2 describe-images --image-ids (AMIのID)

 作成が完了すると、「.Images[].State」に「available」が入ります。


③ スポットインスタンスをリクエストする

 はい。この記事の本丸です。(笑)
 スポットインスタンスをリクエストします。スポットインスタンスをリクエストすると、「リクエスト」が生成され、それにインスタンスが紐付く形になります。複数のインスタンスを同時に起動することも出来ますが、その場合は1個のインスタンスに1個のリクエストが関連付く格好になるので、スポットリクエストも複数作成されることとなります。スクリプトで処理する場合は配列処理するなり、ループ処理するなりしてください。

 使用するコマンドはaws ec2 request-spot-instancesです。
 ひとまず必要最低限のオプションとしてはこんな感じです。
 aws ec2 request-spot-instances --spot-price (提示する入札価格) --launch-specification (インスタンスをローンチするための情報)

 「提示する入札価格」は、お好みでどうぞ。単位はドル/時っぽいです。
 「インスタンスをローンチするための情報」には、最低でも次のような情報を指定することになります。
{
  "ImageId": "(AMIのID)",
  "InstanceType": "(インスタンスの種類)",
  "IamInstanceProfile": {
    "Arn": "(AMIインスタンスロールのArn)"
    },
  "SecurityGroupIds": ["(セキュリティグループID)"]
}


 VPCの中に入れたい時などは、VPCIDとかサブネットIDとかそういった情報も必要になってくると思います。(まだVPCの中に入れてテストしていないので…^^;)

 インスタンスをローンチするための情報をjson型式でファイルに書き出したら、file:///tmp/launch.json とかそんな感じで指定してコマンドに渡してやります。

 このコマンドを実行すると、実行結果がこれまたjson型式で返ってきますので、これまたjqコマンドで適宜パースしてやります。なお、「リクエストID」がこの後に必要となりますから、保存することをお忘れ無く。(リクエストIDは「.SpotInstanceRequests[].SpotInstanceRequestId」という項目に入ってきます。)


④ (スポットリクエストが「履行中」のステータスになるのを待つ)
 スポットインスタンスを生成した直後はまだインスタンスは存在しません。
 スポットリクエストが「履行中」というステータスになるのを待つ必要があります。確認するコマンドはaws ec2 describe-spot-instance-requestsです。コマンドラインで特定のリクエストIDだけ表示することが出来ないっぽいので、jqコマンドで必要な項目だけselectしてやる必要があります。
 おそらくこんな感じ。

aws ec2 describe-spot-instance-requests | jq '.SpotInstanceRequests[] | select ( .SpotInstanceRequestId == "(スポットインスタンスのリクエストID)" ) | .Status.Code'

 「.SpotInstanceRequests[].Status.Code」という項目にスポットインスタンスの状態が入っています。こいつが「fulfilled」になると、インスタンスが使用可能な状態となっていることを表します。
 また、スポットインスタンスの状態が「fulfilled」になった時、そのリクエストの「.SpotInstanceRequests[] .InstanceId」という項目を見ると、このリクエストに紐付いているEC2インスタンスのインスタンスIDが判明します。


⑤ 必要に応じてタグを付けたりする
 当たり前のように、ローンチされたばかりのEC2インスタンスにはタグも何も無いので(Nameタグすらない!!)、適宜タグを付けてあげましょう。



なお、注意点としては…
・インスタンスをshutdownするとインスタンスがterminatedになるっぽい
・スポットインスタンスの上限は20個まで(インスタンスサイズによっては10とかいう場合も有る)
・必ずしも「定価」より安いとは限らない模様
・Amazonさんの余剰リソースの状況によっては突然terminatedになる恐れがあるらしい

スポットインスタンスの上限を拡大してもらえるのかどうかは不明です。申請フォームには無かったようですが…??(私の目が節穴である可能性に注意)

それにして、安いよねー。

#トラフィック課金は高いけどなー。

うーん…firewalld…。。。 [Linux(Network/その他)]

 CentOS7 をいろいろお試し中。
 firewalldの設定に盛大に躓く。

 まず、NICが複数ある環境。そのうちの一つはグローバルなネットワークに接続があるので、環境設定が完了するまで外部からのアクセスは全て拒否したい。しかし、中から外へのアクセスは通したい。(yumしたりするし。)
 …ということは、「block」ゾーンを適用すれば良い。残りのNICは内部のネットワークなので、だいたい自由にアクセスを通したい。(今のところはまだsshだけあればいいのだけど。)

[root@nana ~]# firewall-cmd --get-active-zones
public
  interfaces: ens32 ens33 ens34


 初期状態ではこのような状態。このうち、ens34をblockゾーンに変更したい。
 google先生で検索した結果、

[root@nana ~]# firewall-cmd --zone=block --change-interface=ens34
success
[root@nana ~]# firewall-cmd --get-active-zones
public
  interfaces: ens32 ens33
block
  interfaces: ens34


 これでゾーンの変更は出来る。ただしまだこのままでは「永続化」されないのでrebootするとこの設定は消えて無くなってしまうとのこと。このため、「--permanent」オプションを付けて同じコマンドを再度実行する必要があるらしいということは判った。なお、この--permanentオプションはコマンドの直後、全てのオプション・引数の先頭に付ける必要があるらしい。
 というわけで…

[root@nana ~]# firewall-cmd --permanent --zone=block --change-interface=ens34
success
[root@nana ~]# firewall-cmd --reload
success
[root@nana ~]# firewall-cmd --get-active-zones
public
  interfaces: ens32 ens33
block
  interfaces: ens34


 reloadして再度確認してみる。ens34は最初のコマンドで動的にblockゾーンに変更されているので、特に変化は無い。
 これでOKなのかと思ってrebootしたりすると…

[root@nana ~]# reboot
Connection to nana closed by remote host.
Connection to nana closed.
[root@lelouch ~]# slogin nana
Last login: Thu Sep  4 10:52:21 2014 from lelouch.office.**********.co.jp
[root@nana ~]# firewall-cmd --get-active-zones
public
  interfaces: ens32 ens33 ens34


 エー?

 落ち着け。manページを再確認するんだ…。だいたいこう言うのはどこかチョンボしているに違いない。
 というわけで、 man firewall-cmd してみたら案の定!!

(略)
       [--permanent] [--zone=zone] --add-interface=interface
           Bind interface interface to zone zone. If zone is omitted, default zone will be used.

       [--zone=zone] --change-interface=interface
           Change zone the interface interface is bound to to zone zone. If zone is omitted, default zone will be used. If old and new zone are the
           same, the call will be ignored without an error. If the interface has not been bound to a zone before, it will behave like
           --add-interface.

       [--permanent] [--zone=zone] --query-interface=interface
           Query whether interface interface is bound to zone zone. Returns 0 if true, 1 otherwise.

       [--permanent] [--zone=zone] --remove-interface=interface
           Remove binding of interface interface from zone zone. If zone is omitted, default zone will be used.
(略)


 --change-interface オプションでは --permanent オプションが使えないっぽい?
 HAHAHA!! そりゃーうまくいかないよな!! (successとか出すなよな!!)

 これを見る限りでは、ens34インタフェースをpublicからblockに変更するなら、removeしてaddすればよさそう?

 …というわけで、試して見た。

 まずは永続化しないでコマンド実行

[root@nana ~]# firewall-cmd --zone=public --remove-interface=ens34
success
[root@nana ~]# firewall-cmd --zone=block --add-interface=ens34
success
[root@nana ~]# firewall-cmd --get-active-zones
public
  interfaces: ens32 ens33
block
  interfaces: ens34


 うむ。ここまではOK。これを永続化したいのです。

[root@nana ~]# firewall-cmd --permanent --zone=public --remove-interface=ens34
success
[root@nana ~]# firewall-cmd --permanent --zone=block --add-interface=ens34
success
[root@nana ~]# firewall-cmd --reload
success
[root@nana ~]# firewall-cmd --get-active-zones
public
  interfaces: ens32 ens33
block
  interfaces: ens34


 で、レッツ・再起動!!

[root@nana ~]# reboot
Connection to nana closed by remote host.
Connection to nana closed.
[root@lelouch ~]# slogin nana
Last login: Thu Sep  4 11:00:01 2014 from lelouch.office.**********.co.jp
[root@nana ~]# firewall-cmd --get-active-zones
public
  interfaces: ens32 ens33 ens34


 …。
 うそつきーーーーー!!!!!

 ちなみに、/etc/sysconfig/network-scripts/ifcfg-* に、

ZONE=block


 と書けば、再起動後そのゾーンに所属した状態で起動してくることは確認出来ている。

[root@nana ~]# firewall-cmd --get-active-zones
public
  interfaces: ens32 ens33 ens34
[root@nana ~]# vi /etc/sysconfig/network-scripts/ifcfg-ens34
[root@nana ~]# cat /etc/sysconfig/network-scripts/ifcfg-ens34
TYPE=Ethernet
BOOTPROTO=none
(略)
ZONE=block
[root@nana ~]# reboot
Connection to nana closed by remote host.
Connection to nana closed.
[root@lelouch ~]# slogin nana
Last login: Thu Sep  4 11:15:34 2014 from lelouch.office.**********.co.jp
[root@nana ~]# firewall-cmd --get-active-zones
public
  interfaces: ens32 ens33
block
  interfaces: ens34


 しかし、これじゃあそもそもfirewalldを使う意味が全く無いよね!!!

 もしかすると、blockとかdropとかこの辺のゾーンはそもそも永続化できないゾーンなのかもしれない?
 試しに、ens34をexternalゾーンに所属を変更してみて永続化し、rebootしてどうなるか確認してみよう。

[root@nana ~]# firewall-cmd --get-active-zones
public
  interfaces: ens32 ens33 ens34
[root@nana ~]# firewall-cmd --zone=public --remove-interface=ens34
success
[root@nana ~]# firewall-cmd --zone=external --add-interface=ens34
success
[root@nana ~]# firewall-cmd --get-active-zones
external
  interfaces: ens34
public
  interfaces: ens32 ens33


 で、永続化。

[root@nana ~]# firewall-cmd --permanent --zone=public --remove-interface=ens34
success
[root@nana ~]# firewall-cmd --permanent --zone=external --add-interface=ens34
Error: ZONE_CONFLICT


 おや?

[root@nana ~]#  firewall-cmd --zone=external --list-interfaces
[root@nana ~]#  firewall-cmd --zone=block --list-interfaces
[root@nana ~]#  firewall-cmd --zone=public --list-interfaces
ens32 ens33 ens34


 もう、何が何やら…。。。

 ひとまず、ifcfg-ens*に ZONE=block と書いて回避することに…orz

 なにか違うのだろうけど何が違うのやら情報も少ないしさっぱりポンですわもう。

Amazon EC2 インスタンスを1からコマンドラインで立ててみる(その4:環境を整える) [Amazon AWS]

 ぶっちゃけ、ここから先はありがちなLinuxセットアップのお話なんですが、EC2特有の問題がちょっとあるので、そこらへんを片付けてしまいましょう。

① ec2-user【以外】のログインアカウントを作成して、ec2-userは潰す
 まず、ログインアカウントのお話です。
 個人的にはec2-userは最初にログインする時「だけ」使うべきだと思っています。インスタンスにログインできたら、それ以降は自分のアカウントを作成してそちらを使うべきだと思っています。多分、キーペアも削除するべきなんだろうなあとか思ったりもしていますが。

 そんな訳で、useraddで新しくアカウントを作成します。

[root@maya ~]# slogin -i piro791key.pem -l ec2-user  ec2-54-199-31-204.ap-northeast-1.compute.amazonaws.com
Last login: Tue Aug 26 05:37:21 2014 from fs76eed40f.tkyc201.ap.nuro.jp

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2014.03-release-notes/
9 package(s) needed for security, out of 28 available
Run "sudo yum update" to apply all updates.
[ec2-user@piro791 ~]$ sudo useradd piro791
[ec2-user@piro791 ~]$ sudo passwd piro791
ユーザー piro791 のパスワードを変更。
新しいパスワード:
新しいパスワードを再入力してください:
passwd: 全ての認証トークンが正しく更新できました。
[ec2-user@piro791 ~]$
[ec2-user@piro791 ~]$
[ec2-user@piro791 ~]$ su - piro791
パスワード:
最後の失敗ログイン: 2014/08/26 (火) 05:42:57 UTC日時 pts/0
最後の正しいログインの後に 1 回の失敗ログインの試行があります
[piro791@piro791 ~]$


 で、新しいログインアカウントでssh鍵を忘れずに作成しておきましょう。

[piro791@piro791 ~]$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/piro791/.ssh/id_rsa):
Created directory '/home/piro791/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
(略)
[piro791@piro791 ~]$ cd .ssh
[piro791@piro791 .ssh]$ cat id_rsa.pub > authorized_keys
[piro791@piro791 .ssh]$ chmod 400 authorized_keys


 また、お好みに応じてrootにパスワードを設定するのも良いと思います。
 ssh鍵認証だけでパスワードを使用しないなら、rootの鍵も作成するとか鍵交換を済ませておくとかするとよいと思います。まあ、本来ならrootのパスワードも設定すべきですが。
 なお、rootのauthorized_keysに仕掛けがしてあります。このため、rootでいきなりログインしたいとかsshしたいとかscpしたいとかいうような場合は、rootのキーペアファイルを作成して(デフォルトでは存在しない)authorized_keysファイルの内容を差し替える必要があります。


② タイムゾーンとか言語設定とか
 日本人が使うのに困らないように変更しておきましょう。


③ yum update
 忘れずにね!!


④ お好みに応じてswapを追加する
 詳しい手順は Linuxのswap領域を追加する方法 を見てね!!

Amazon EC2 インスタンスを1からコマンドラインで立ててみる(その3:EC2インスタンスを作成する) [Amazon AWS]

 では、いよいよEC2インスタンスを作成したいと思います。使用するコマンドは aws ec2 run-instances です。
 ここまでに用意した、IAMロール、セキュリティグループ、そしてキーペアを指定してEC2インスタンスを作成すればいいんですが、ここでちょっと悩ましい問題が発生します。

 aws ec2 run-instances --image-id (イメージID) --key-name (キーペア名) --security-groups (セキュリティグループ名) --instance-type (インスタンスの種類) --iam-instance-profile (インスタンスプロファイル名)

 最低限、必要なオプションはこれくらいなんですが、この他に指定すべきオプションがあります。

 --user-data ユーザーデータ



1.「イメージID」とはなんぞ??

 「AMI」と呼ばれる、仮想マシンのイメージファイルに対するIDのことをいいます。全てのEC2インスタンスは「AMI」を作成することができ、AMIにはAmazonさんがあらかじめ用意している物もあります。Amazonさんがあらかじめ用意しているAMIは、たいていの場合は「OSをインストールしてごく最低限のセットアップだけを施した状態」で提供されています。
 また、この他にもAmazon AWSの利用者が便利な機能を盛り込んだAMIを提供しており、これを用いることもできます。 (個人的には全く使用する気にはなれませんが…
 Amazonさん純正のAMIを使用して「OSインストール直後」のインスタンスを用意することになります。

 で、それをどーやって調べるのか?というと…これもコマンドラインから調べることになります。(全部1行でね!)

 aws ec2 describe-images --filters "Name=owner-alias,Values=amazon,Name=description,Values=Amazon Linux AMI x86_64 PV EBS"

 で、良いはずなんですが、困った事に、OSのイメージはバージョンアップ等の理由でどんどん新しい物が「追加」されてしまいます。ということは、日を追う毎にこのコマンドで表示されるAMIイメージの数はどんどん増える一方。なので、よーく見ないと「ついうっかり古いバージョンの環境でインスタンスを立てちゃった」なんてことにもなりかねません。

 そんな訳で、jqコマンドと組み合わせて古い順にソートするのがオススメです。
 コマンドラインから実行するとこんな感じ。(全部1行でね!)

 aws ec2 describe-images --filters "Name=owner-alias,Values=amazon,Name=description,Values=Amazon Linux AMI x86_64 PV EBS" | jq '.Images | sort_by(.ImageLocation)'

 これで、一番最後に表示されたイメージの情報のIDを使うのがタブン正解。(今のところ。)

  {
    "Description": "Amazon Linux AMI x86_64 PV EBS",
    "ImageType": "machine",
    "Public": true,
    "RootDeviceName": "/dev/sda1",
    "OwnerId": "137112412989",
    "KernelId": "aki-176bf516",
    "ImageLocation": "amazon/amzn-ami-pv-2014.03.2.x86_64-ebs",
    "Architecture": "x86_64",
    "VirtualizationType": "paravirtual",
    "Name": "amzn-ami-pv-2014.03.2.x86_64-ebs",
    "Hypervisor": "xen",
    "ImageOwnerAlias": "amazon",
    "ImageId": "ami-25dd9324",
    "RootDeviceType": "ebs",
    "State": "available",
    "BlockDeviceMappings": [
      {
        "Ebs": {
          "Encrypted": false,
          "VolumeType": "standard",
          "VolumeSize": 8,
          "SnapshotId": "snap-e70ea007",
          "DeleteOnTermination": true
        },
        "DeviceName": "/dev/sda1"
      }
    ]
  }
]


 「 "ImageId": "ami-25dd9324",」って書いてある箇所がお目当ての情報になります。この記事を書いている時点での最新のものは「ami-25dd9324」ということになります。
 ちなみに、今回インストールしようとしているOSのイメージは、Amazonさんが用意しているカスタムメイドなLinuxである、「Amazon Linux(64ビット版)」です。Windows Serverとか、Red Hat Linuxとか、SUSE Linuxとか、Ubuntuとかもあるんですが、物によってはOSのライセンス使用料金がかかったりこともあるので、Linuxでサクッとお試しするのであれば、「Amazon Linux」が良いんじゃないかなーと思ったりします。はい。Red Hat Linux系を扱い慣れている人ならコレがいいかもー。



2.インスタンスの種類 とはなんぞや?

 Amazon AWS EC2の人気の秘けつの一つに、「豊富なインスタンスの種類がある」ことが挙げられるとおもいます。ここでいう「インスタンスの種類」とは、

① CPUのコア数
② 搭載しているメモリの量
③ インスタンスストレージサイズ
④ IO性能

 といったものの組み合わせをいい、それぞれにユニークな名前が割り当てられています。
 くわしいことは、 http://aws.amazon.com/jp/ec2/instance-types/ を見てくださいな。

 当然、提供されるリソースが大きくなればなるほど、お値段もお高くなってきますので、そこら辺はお財布と相談した上で決定してみてください。
 で、個人用途しては、t1.microとかをチョイスすることになると思います。



 「ユーザーデータ」はちょっと横においておくとして、ここまでの情報でインスタンスをローンチできますので、実際にやってみたいと思います。なお、このままでは若干不便なのでもうちょっと待った方がいいよ!
 実行すると、こんな感じになります。

[root@maya tmp]# aws ec2 run-instances --image-id ami-25dd9324 --security-groups piro791sg --instance-type t1.micro --key-name piro791key --iam-instance-profile Arn=arn:aws:iam::XXXXXXXXXXXX:instance-profile/piro791profile
{
    "OwnerId": "XXXXXXXXXXXX",
    "ReservationId": "r-XXXXXXXX",
    "Groups": [
        {
            "GroupName": "piro791sg",
            "GroupId": "sg-cd170ccc"
        }
    ],
    "Instances": [
        {
            "Monitoring": {
                "State": "disabled"
            },
            "PublicDnsName": null,
            "KernelId": "aki-176bf516",
            "State": {
                "Code": 0,
                "Name": "pending"
            },
            "EbsOptimized": false,
            "LaunchTime": "2014-08-25T05:04:56.000Z",
            "ProductCodes": [],
            "StateTransitionReason": null,
            "InstanceId": "i-989e2881",
            "ImageId": "ami-25dd9324",
            "PrivateDnsName": null,
            "KeyName": "piro791key",
            "SecurityGroups": [
                {
                    "GroupName": "piro791sg",
                    "GroupId": "sg-cd170ccc"
                }
            ],
            "ClientToken": null,
            "InstanceType": "t1.micro",
            "NetworkInterfaces": [],
            "Placement": {
                "Tenancy": "default",
                "GroupName": null,
                "AvailabilityZone": "ap-northeast-1c"
            },
            "Hypervisor": "xen",
            "BlockDeviceMappings": [],
            "Architecture": "x86_64",
            "StateReason": {
                "Message": "pending",
                "Code": "pending"
            },
            "IamInstanceProfile": {
                "Id": "AIPAIPOFVOGVSDWV2Y73A",
                "Arn": "arn:aws:iam::XXXXXXXXXXXX:instance-profile/piro791profile"
            },
            "RootDeviceName": "/dev/sda1",
            "VirtualizationType": "paravirtual",
            "RootDeviceType": "ebs",
            "AmiLaunchIndex": 0
        }
    ]
}


 注目するのは、「"InstanceId": "i-989e2881",」という部分。これがそのインスタンスを表す「インスタンスID」になります。これを使ってあれこれ操作することが多くなります。
 次に、「"State"」のブロック。「"Name": "pending"」となっていますが、これは作業中であることを示しています。ここが「Running」になれば、インスタンスの作成が完了して起動したことになります。インスタンスの作成には数十秒~数分程度かかります。インスタンスの作成が完了したかどうか確認するには、先ほど確認したインスタンスIDを指定して確認します。

[root@maya tmp]# aws ec2 describe-instances --instance-ids i-989e2881 | jq '.Reservations[].Instances[].State'
{
  "Name": "running",
  "Code": 16
}


 上記例でrunningになったことが確認できましたので、インスタンスが完成し、起動しているということが判ります。



 では、さっそくsshでログインしましょう。
 …どうやって?(笑)

 アドレスを調べないことにはどうしようもありませんので(あたりまえ)、それを調べます。
 ちなみに、VPCを使用しないインスタンスは、基本的にインスタンスを起動する度にアドレスが変わるので、その都度調べなければなりません。インスタンスを停止しないかぎり、rebootだけでアドレスは変化しません。
 コマンドは、 aws ec2 describe-instances --instance-ids (インスタンスID) | jq '.Reservations[].Instances[].PublicDnsName' です。

[root@maya tmp]# aws ec2 describe-instances --instance-ids i-989e2881 | jq '.Reservations[].Instances[].PublicDnsName'
"ec2-54-95-17-129.ap-northeast-1.compute.amazonaws.com"


 ということなので、このアドレスを使ってインスタンスにアクセスします。
 sshでログインする際には、作成・保存しておいたキーペアを使用します。また、ログインするアカウントは「ec2-user」という物を使用します。

[root@maya ~]# ssh -i piro791key.pem -l ec2-user ec2-54-95-17-129.ap-northeast-1.compute.amazonaws.com
The authenticity of host 'ec2-54-95-17-129.ap-northeast-1.compute.amazonaws.com (54.95.17.129)' can't be established.
ECDSA key fingerprint is 03:3c:ae:33:b2:02:df:4b:92:b5:69:0d:af:35:80:0c.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'ec2-54-95-17-129.ap-northeast-1.compute.amazonaws.com,54.95.17.129' (ECDSA) to the list of known hosts.

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2014.03-release-notes/
9 package(s) needed for security, out of 28 available
Run "sudo yum update" to apply all updates.
[ec2-user@ip-10-126-162-87 ~]$


 というわけで、ちゃんとログインできましたね!!



 ところで…。

[ec2-user@ip-10-126-162-87 ~]$ uname -a
Linux ip-10-126-162-87 3.10.42-52.145.amzn1.x86_64 #1 SMP Tue Ju
 n 10 23:46:43 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
[ec2-user@ip-10-126-162-87 ~]$


 「このインスタンスの名前が気に入らないクマ。」

 …という人も多いと思います。(笑)
 また、インスタンスが1個しか無いうちは問題になりませんが、インスタンスが増えてくると…

 「お前は一体何者なんだ!?」

 …という事態に陥ります。(笑)そこで、インスタンスに名前を付けておく必要性が高くなります。そしてその名前をhostnameに反映したいと思うようになります。
 このblogでは、GUIを使っていないのですが、GUIでインスタンスの一覧を管理する場合、インスタンスには「Name」という『タグ』を使用するルールになっています。(Nameでなくても差し支えないが、他のサービスとの兼ね合いでNameを使用することが強く推奨されます)

 では、Nameタグを使って名前を付けたいと思います。コマンドは、
 aws ec2 create-tags --resources (インスタンスID) --tags Key=Name,Value=(インスタンス名) です。

[root@maya ~]# aws ec2 create-tags --resources i-989e2881 --tags Key=Name,Value=piro791
{
    "return": "true"
}
[root@maya ~]#


 そして、このNameタグからhostnameを付けるようにします。方法は二つあります。一つは、/etc/rc.local にその処理をベッタリと書き込むか、もう一つは「ユーザーデータ」を使用してインスタンス起動時にその処理を行う方法です。
 まあ、/etc/rc.localにベッタリと書いてしまってもバチはあたりませんが、ここではもっと「それらしく」振る舞うこととしてユーザーデータを使用してインスタンス起動時にhostnameを設定させたいと思います。

 ユーザーデータは、「インスタンスを作成する時」か、または「インスタンスが停止中」にだけ設定・編集することができます。なお、ユーザーデータの動作について詳しい事は、「ggrks」の精神でお願いします。(笑)

 では、設定してみましょう。

 まず、「Nameタグ」からインスタンスの名前を獲得して、hostnameとして設定するシェルスクリプトを作成します。

#cloud-boothook
#!/bin/sh

export AWS_ACCESS_KEY="HOGEHOGE"
export AWS_SECRET_KEY="HOGEHOGEHOGEHOGE"
export EC2_URL=https://ec2.ap-northeast-1.amazonaws.com
export EC2_REGION=ap-northeast-1
export AWS_DEFAULT_REGION=$EC2_REGION
export EC2_HOME=/opt/aws/apitools/ec2
export JAVA_HOME=/usr/lib/jvm/jre

INSTANCE_ID=`/opt/aws/bin/ec2-metadata | /bin/awk '/^instance-id/{print $2}'`
TAG_NAME=`/opt/aws/bin/ec2-describe-instances $INSTANCE_ID | /bin/awk '/^TAG.*Name/{print $5}'`

hostname $TAG_NAME

echo $INSTANCE_ID":"$TAG_NAME | /usr/bin/tee /tmp/cloud-init.log



 通常は、1行目にシェバングが来るところですが、それよりも先に、「#cloud-boothook」とかくのがミソです。あとはよくあるシェルスクリプトです。アクセスキーとシークレットキーは適切に設定してください。(個人的にはここに書きたくないので、ロールでどうにかなるかな?と思ったり思わなかったり…。それはまたの機会に!!)

 これを適当なファイルに保存します。なお、シェルスクリプトとして実行するわけでは無いので、実行権とかそんなのどーでも良いです。はい。
 そして、このファイルを、Base64でエンコードしておきます。base64コマンドが使えればソレで。

[root@maya tmp]# base64 user-data > user-data.base64
[root@maya tmp]# cat user-data.base64
I2Nsb3VkLWJvb3Rob29rCiMhL2Jpbi9zaAoKZXhwb3J0IEFXU19BQ0NFU1NfS0VZPSJBS0lBSlVN
U1VRUFhXTFo2VEk3USIKZXhwb3J0IEFXU19TRUNSRVRfS0VZPSJEUkQyMk1kTkptVk54bVlCeVI3
(略)
b3N0bmFtZSAkVEFHX05BTUUKCmVjaG8gJElOU1RBTkNFX0lEIjoiJFRBR19OQU1FIHwgL3Vzci9i
aW4vdGVlIC90bXAvY2xvdWQtaW5pdC5sb2cKCg==
[root@maya tmp]#


 で、このファイルをaws ec2 run-instances コマンドに --user-data オプションを付けて渡してやります。

[root@maya tmp]# aws ec2 run-instances --image-id ami-25dd9324 --security-groups piro791sg --instance-type t1.micro --key-name piro791key --iam-instance-profile Arn=arn:aws:iam::XXXXXXXXXXXX:instance-profile/piro791profile --user-data file://user-data.base64
{
    "OwnerId": "XXXXXXXXXXXX",
    "ReservationId": "r-XXXXXXXX",
    "Groups": [
        {
            "GroupName": "piro791sg",
            "GroupId": "sg-cd170ccc"
        }
    ],
    "Instances": [
        {
            "Monitoring": {
                "State": "disabled"
            },
            "PublicDnsName": null,
            "KernelId": "aki-176bf516",
            "State": {
                "Code": 0,
                "Name": "pending"
            },
            "EbsOptimized": false,
            "LaunchTime": "2014-08-25T07:28:16.000Z",
            "ProductCodes": [],
            "StateTransitionReason": null,
            "InstanceId": "i-88883e91",
            "ImageId": "ami-25dd9324",
(以下略)
[root@maya tmp]# aws ec2 create-tags --resources i-88883e91 --tags Key=Name,Value=piro791
{
    "return": "true"
}
[root@maya tmp]#


 なお、Nameタグを付けるのはインスタンス作成中でも可能です。
 インスタンスの作成が完了したらログインしてみます。なお、Nameタグを付けたタイミングによってはうまくhostnameが変わらないことがありますので、その場合にはインスタンスを1回リブートしてみてください。

[root@maya ~]# ssh -i piro791key.pem -l ec2-user ec2-54-168-166-3.ap-northeast-1.compute.amazonaws.com
The authenticity of host 'ec2-54-168-166-3.ap-northeast-1.compute.amazonaws.com (54.168.166.3)' can't be established.
ECDSA key fingerprint is 35:8b:b1:e2:45:29:d2:77:ef:89:e6:3a:64:b3:6e:3a.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'ec2-54-168-166-3.ap-northeast-1.compute.amazonaws.com,54.168.166.3' (ECDSA) to the list of known hosts.

       __|  __|_  )
       _|  (     /   Amazon Linux AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-ami/2014.03-release-notes/
9 package(s) needed for security, out of 28 available
Run "sudo yum update" to apply all updates.
[ec2-user@piro791 ~]$ uname -a
Linux piro791 3.10.42-52.145.amzn1.x86_64 #1 SMP Tue Jun 10 23:46:43 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
[ec2-user@piro791 ~]$


 と、うまいことhostnameが付きました。

 次のアーティクルでは、このインスタンスを調き…じゃない、きちんとセットアップして育ててみたいと思います。

Amazon EC2 インスタンスを1からコマンドラインで立ててみる(その2の追加:EC2インスタンスを立てる前にすることの追加) [Amazon AWS]

 サーセン。2個、インスタンスを1から立てるに当たっての、重要な作業が漏れていました。

◎ キーペアを作成する

 EC2インスタンスにsshでログインするにあたっては、キーペアファイルが当然必要になります。特に、一番最初はコレが無いともうどうしようもない訳ですよ。
 そこで、キーペアを作成し、秘密鍵ファイルを入手することにします。

 コマンド一発…なんですが、若干の細工が必要です。(笑)

 ちなみに、使用するコマンドは aws ec2 create-key-pair --key-name (キーペアの名前) です。

 これをそのまま実行すると、JSON型式でこんな風に結果が返ってきてしまいます。

{
    "KeyMaterial": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA3jVtbfQ76gJtyv+6R15/AjAV3d/13m+UILhXEsxJG3Hbr6An2sDMw3rmAYFA\nUm+1G77gkD8O3RbIPo4BUUASqxHeCl7rltcfsEpQAOVSK0PoopSaDnPwOrVXM7uSdwqn804I2QzD\nIsZA/yf+uxsUCGzS6Jvow1v8qGTacLkrTCK6BPa/DNK2KzhxiLzrVnPiwhzH5A8TS2MaI0in8hTb\nceCejGUEXmcixYzZi6F(以下略)
    "KeyName": "piro791test",
    "KeyFingerprint": "XX:XX:XX:XX:XX:XX:XX:XX:ad:46:ba:b6:19:84:3b:36:65:9a:22:67"
}


 「KeyMaterial」というところに、秘密鍵ファイルの情報がガガーっと1行で記述されます。改行部分は「\n」に置き換えられているので、これを美しいフォーマットにしてファイルに保存しておく必要があります。そこで、jq とecho の出番です。こうしましょう。

[root@atago src]# echo -e `aws ec2 create-key-pair --key-name piro791key | jq '.KeyMaterial' | tr -d '"'`
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAsILSse+hGW4ioDi7yLGJFMIeluHaJ9VkMdCFmMfRZnptA24Lb379V2H/kNCN
JB0w9tQMV4XeoE2l9UgtZJDP6n5YiWjSSM64MalTISKoGdtnOSoCighb8KVXc+gzwJIeUq8EUuUq
yyS90mwZXr9GfKfD6YpSDjQjeSvWHzi37pqzvtPX/MIQcw9XK3hKzwlmCf0AjshYZ9YX3vxwwea1
(以下略)


 で、これをファイルに保存しておけば良い訳です。
 なお、必要の無くなったキーペアは削除しておきましょう。あるいは、キーペアの名前が気に入らないとかいう場合にも削除しておきましょう。削除の方法は、 aws ec2 delete-key-pair --key-name (削除したいキーペアの名前) です。

[root@atago src]# aws ec2 delete-key-pair --key-name piro791key
{
    "return": "true"
}


◎ロールをインスタンスプロファイルに割り当てる
 カラッポのロールを作成しましたが、これをインスタンスプロファイルと呼ばれる物に割り当てる必要があります。

 ・カラッポのインスタンスプロファイルを作成する
 ↓
 ・ロールを割り当てる

 という手順を踏みます。まず、カラッポのインスタンスプロファイルを作成します。

 aws iam create-instance-profile --instance-profile-name (インスタンスプロファイル名)

[root@maya tmp]# aws iam create-instance-profile --instance-profile-name piro791profile
{
    "InstanceProfile": {
        "InstanceProfileId": "AIPAIPOFVOGVSDWV2Y73A",
        "Roles": [],
        "CreateDate": "2014-08-25T04:57:13.759Z",
        "InstanceProfileName": "piro791profile",
        "Path": "/",
        "Arn": "arn:aws:iam::XXXXXXXXXXXX:instance-profile/piro791profile"
    }
}


 そしたら、ここにすでに作成してあるロールを割り当てます。
 aws iam add-role-to-instance-profile --instance-profile-name (作成したプロファイル名) --role-name (割り当てるロール名)

[root@maya tmp]# aws iam add-role-to-instance-profile --instance-profile-name piro791profile --role-name piro791role
[root@maya tmp]#


 これ、何も結果を返さないんですよね。念のため 「 echo $? 」 を実行してみると0が返ってくるので大丈夫なんだと思います。タブン。

前の10件 | -

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。