AWSのITコストを削減 Simpline

選ばれ続けること

 

エンジニアブログ

ホーム - エンジニアブログ - 2015年3月

delete-on-terminationを後から変更するのがとても大変

2015.03.23

EC2起動時にはけっこう目立つEBSボリュームのDelete on Terminationだけど、AWSマネージメントコンソールから追加Volume追加する時に設定変更できる箇所が見当たらない。設定は見えるのだけど、変更できるインターフェースがどうも無さそう。

困ったときのAWS CLI


CLIでできるかもと思ってやってみたらできました。
# 事前確認
$ aws ec2 describe-instances --instance-id $INSTANCEID \
--query Reservations[].Instances[].BlockDeviceMappings[]
[
{
"DeviceName": "/dev/xvda",
"Ebs": {
"Status": "attached",
"DeleteOnTermination": false,
"VolumeId": "vol-1503be1f",
"AttachTime": "2014-07-04T06:01:17.000Z"
}
}
]

# 上の結果からこんなファイルを用意してみる(VolumeId指定だけでも行けるかも?)
$ cat new.json
[
{
"DeviceName": "/dev/xvda",
"Ebs": {
"DeleteOnTermination": true,
"VolumeId": "vol-1503be1f"
}
}
]

# jsonファイルを指定して変更
$ aws ec2 modify-instance-attribute --instance-id $INSTANCEID \
--block-device-mappings file://new.json

# 事後確認
$ aws ec2 describe-instances --instance-id $INSTANCEID \
--query Reservations[].Instances[].BlockDeviceMappings[]
[
{
"DeviceName": "/dev/xvda",
"Ebs": {
"Status": "attached",
"DeleteOnTermination": true,
"VolumeId": "vol-1503be1f",
"AttachTime": "2014-07-04T06:01:17.000Z"
}
}
]

CLIが便利というよりも、マネージメントコンソール直した方が良さそうな気がするが、アタッチ時の指定なので、どの画面に実装するか確かに難しいところですね。

 

後からアタッチしたボリュームの削除し忘れには気を付けましょう。

AWS CLIのWaiters

2015.03.23

ちょっと更新が滞っているので、ライトなネタをいくつか。

Waiters


AWS CLI 1.6.0で追加された機能で、オプションに指定したステータスとなったらプロンプトを返してくれる。つまり、ある処理が終わって状態が遷移するまで待たせることができる。

これで、sleep&retryの実装不要!と思ったけど、ちょっと不安が。これって下手にスクリプトにしてバグったら永遠に終了しないのでは?

Waitersをtimeoutさせる


検索していたらLinuxにはこんな便利なコマンドがあることを発見。起動中のEC2インスタンスを使って試してみると。
$ timeout 5 aws ec2 wait instance-running --instance-ids $INSTANCEID
$ echo $?
0

これだとプロンプトがすぐに返ってくるのでよくわらない。ではそのままinstance-stoppedをwaitしてみると。
$ timeout 5 aws ec2 wait instance-stopped --instance-ids $INSTANCEID
$ echo $?
124

5秒してエラーになった。これでいつかは終わるスクリプトにできそうだ。Return Codeはよくわからないけど、エラー判定もできるし良い感じ。

 

バックアップの自動化案件が増えてきたので、AMIのステータスもwaitして欲しい。Exponential Backoffしないとダメなのですかねえ。

 

Windows上のディスクとAWS上のボリュームの紐付けの話

2015.03.18

こんにちは t2.micro です。

今日はAWSのWindowsサーバでイライラした話を書きます。

特定のDiskに対するAWS側の操作を自動化する必要があり
対象のDiskのVolumeIDを調べていたところ、
「OS上で見えるディスク」と
「aws management console上のボリューム」の
紐付けがわからない。

調べてみたところ、amazonのオフィシャルページがありました。

さて、どうやって確認するのか?
参考URL http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/WindowsGuide/ec2-windows-volumes.html

①GUIから目視
「Target ID 2」番号に対する表は上記参考URLを確認

WS000050


ボリュームが多くなればなるほど面倒くさい!
はい、消えたー。やりたくないー。

②powershellで確認
# List the Windows disks

# Create a hash table that maps each device to a SCSI target
$Map = @{"0" = '/dev/sda1'}
for($x = 1; $x -le 26; $x++) {$Map.add($x.ToString(), [String]::Format("xvd{0}",[char](97 + $x)))}
for($x = 78; $x -le 102; $x++) {$Map.add($x.ToString(), [String]::Format("xvdc{0}",[char](19 + $x)))}

Try {
# Use the metadata service to discover which instance the script is running on
$InstanceId = (Invoke-WebRequest '169.254.169.254/latest/meta-data/instance-id').Content
$AZ = (Invoke-WebRequest '169.254.169.254/latest/meta-data/placement/availability-zone').Content
$Region = $AZ.Substring(0, $AZ.Length -1)

#Get the volumes attached to this instance
$BlockDeviceMappings = (Get-EC2Instance -Region $Region -Instance $InstanceId).Instances.BlockDeviceMappings
}
Catch
{
Write-Host "Could not access the AWS API, therefore, VolumeId is not available.
Verify that you provided your access keys." -ForegroundColor Yellow
}

Get-WmiObject -Class Win32_DiskDrive | % {
$Drive = $_
# Find the partitions for this drive
Get-WmiObject -Class Win32_DiskDriveToDiskPartition | Where-Object {$_.Antecedent -eq $Drive.Path.Path} | %{
$D2P = $_
# Get details about each partition
$Partition = Get-WmiObject -Class Win32_DiskPartition | Where-Object {$_.Path.Path -eq $D2P.Dependent}
# Find the drive that this partition is linked to
$Disk = Get-WmiObject -Class Win32_LogicalDiskToPartition | Where-Object {$_.Antecedent -in $D2P.Dependent} | %{
$L2P = $_
#Get the drive letter for this partition, if there is one
Get-WmiObject -Class Win32_LogicalDisk | Where-Object {$_.Path.Path -in $L2P.Dependent}
}
$BlockDeviceMapping = $BlockDeviceMappings | Where-Object {$_.DeviceName -eq $Map[$Drive.SCSITargetId.ToString()]}

# Display the information in a table
New-Object PSObject -Property @{
Device = $Map[$Drive.SCSITargetId.ToString()];
Disk = [Int]::Parse($Partition.Name.Split(",")[0].Replace("Disk #",""));
Boot = $Partition.BootPartition;
Partition = [Int]::Parse($Partition.Name.Split(",")[1].Replace(" Partition #",""));
SCSITarget = $Drive.SCSITargetId;
DriveLetter = If($Disk -eq $NULL) {"NA"} else {$Disk.DeviceID};
VolumeName = If($Disk -eq $NULL) {"NA"} else {$Disk.VolumeName};
VolumeId = If($BlockDeviceMapping -eq $NULL) {"NA"} else {$BlockDeviceMapping.Ebs.VolumeId}
}
}
} | Sort-Object Disk, Partition | Format-Table -AutoSize -Property Disk, Partition, SCSITarget, DriveLetter, Boot,
VolumeId, Device, VolumeName

うごかないし、赤字が怖いし。
powershellとか触ったことないし。
なんで怒られているのか。powershell怖いよ。

>Disk = [Int]::Parse($Partition.Name.Split(",")[0].Replace("Disk #",""));

>Partition = [Int]::Parse($Partition.Name.Split(",")[1].Replace(" Partition #",""));

上の2行が怒られている。
よく読むと、日本語OSだと 「Disk が ディスク」、「Partition が パーティション」となっているから怒っているらしい。
そんなことで怒らないでおくれよ。赤文字とか、びっくりするよ。

ダサいけど、ひとまずReplaceを2回することで日本語、英語ともに対応できるはず。
# List the Windows disks

# Create a hash table that maps each device to a SCSI target
$Map = @{"0" = '/dev/sda1'}
for($x = 1; $x -le 26; $x++) {$Map.add($x.ToString(), [String]::Format("xvd{0}",[char](97 + $x)))}
for($x = 78; $x -le 102; $x++) {$Map.add($x.ToString(), [String]::Format("xvdc{0}",[char](19 + $x)))}

Try {
# Use the metadata service to discover which instance the script is running on
$InstanceId = (Invoke-WebRequest '169.254.169.254/latest/meta-data/instance-id').Content
$AZ = (Invoke-WebRequest '169.254.169.254/latest/meta-data/placement/availability-zone').Content
$Region = $AZ.Substring(0, $AZ.Length -1)

#Get the volumes attached to this instance
$BlockDeviceMappings = (Get-EC2Instance -Region $Region -Instance $InstanceId).Instances.BlockDeviceMappings
}
Catch
{
Write-Host "Could not access the AWS API, therefore, VolumeId is not available.
Verify that you provided your access keys." -ForegroundColor Yellow
}

Get-WmiObject -Class Win32_DiskDrive | % {
$Drive = $_
# Find the partitions for this drive
Get-WmiObject -Class Win32_DiskDriveToDiskPartition | Where-Object {$_.Antecedent -eq $Drive.Path.Path} | %{
$D2P = $_
# Get details about each partition
$Partition = Get-WmiObject -Class Win32_DiskPartition | Where-Object {$_.Path.Path -eq $D2P.Dependent}
# Find the drive that this partition is linked to
$Disk = Get-WmiObject -Class Win32_LogicalDiskToPartition | Where-Object {$_.Antecedent -in $D2P.Dependent} | %{
$L2P = $_
#Get the drive letter for this partition, if there is one
Get-WmiObject -Class Win32_LogicalDisk | Where-Object {$_.Path.Path -in $L2P.Dependent}
}
$BlockDeviceMapping = $BlockDeviceMappings | Where-Object {$_.DeviceName -eq $Map[$Drive.SCSITargetId.ToString()]}

# Display the information in a table
New-Object PSObject -Property @{
Device = $Map[$Drive.SCSITargetId.ToString()];
Disk = [Int]::Parse($Partition.Name.Split(",")[0].Replace("Disk #","").Replace("ディスク #",""));
Boot = $Partition.BootPartition;
Partition = [Int]::Parse($Partition.Name.Split(",")[1].Replace(" Partition #","").Replace(" パーティション #",""));
SCSITarget = $Drive.SCSITargetId;
DriveLetter = If($Disk -eq $NULL) {"NA"} else {$Disk.DeviceID};
VolumeName = If($Disk -eq $NULL) {"NA"} else {$Disk.VolumeName};
VolumeId = If($BlockDeviceMapping -eq $NULL) {"NA"} else {$BlockDeviceMapping.Ebs.VolumeId}
}
}
} | Sort-Object Disk, Partition | Format-Table -AutoSize -Property Disk, Partition, SCSITarget, DriveLetter, Boot,
VolumeId, Device, VolumeName

WS000051

とりあえず日本語OSでは動きました。
ホントにちょっとしたことでした。

Data Pipeline Roles, Tags, and Security Improvements

2015.03.02

先月末にこんなリリースがありました。まだ全く使いこなせる見込みはないけど、少し関わりがあったので、ポイントだけまとめておこうと思う。

リリースを有効化する手順


手順はrootアカウントでList Pipelinesをすると下記のポップアップが表示されるので「Opt-in」をクリックすれば良さそう。有効化すると以降の挙動が変更となるので、注意が必要。

スクリーンショット 2015-03-02 22.26.52

IAMユーザ間でPipelineジョブを共有できるようになった


PipelineにはIAM管理する上で重大な問題があって、別のIAMアカウントが作成したジョブは他のユーザから参照することさえできなかった。今回のリリースで適切な権限を有しているIAMユーザ間でジョブを共有できるようになった。

Pipelineジョブにタグ付けが可能になった


Tagを利用することができるようになった模様。まだ活用方法は調べ切れていない。

EMRクラスタに適切なIAMロールを付与することができるようになった


実はこのリリースまでData Pipelineから起動したEMRクラスタは、Pipelineジョブを作成したIAMユーザの権限で動作していた。該当IAMユーザはアクセスキー作成が必須(シークレットアクセスキーをダウンロードしたり、どこかに設定したりは不要)で、インスタンスプロファイル(IAMロール)権限で起動するEC2のように、メタデータからSTS経由で権限を取得する実装とは全く異なり、ハードコーディングに近い実装になっていたと思われる。EMR権限を設定する画面上では、「DataPipelineDefaultRole」や「DataPipelineDefaultResourceRole」を設定する操作が促されるのに、実は全くそんなものは無視されていたということになる。

 

AWSってせっかくプログラマブルなインフラなんだから、ジョブ管理の機能がショボいっていうのは非常に残念。運用管理にはもう少しLamdaの勉強しないとダメなのかなあ。クラスメソッドさんのソンナコトモアロウカト編とか、ServerworksさんのCloud Automatorなんかは上手いところをついていて素晴らしいと思うのでした。

CI&AWS-SDK-PHPベース環境構築(メモ)

2015.03.01

Webサーバ周り検証をする為、CI(Code Igniter)という軽量級PHP MVCフレームワークベース環境構築手順をメモにしておきます。

まず、前の記事と同じようにEC2インスタンスにAWSへのアクセス権限を付与する為、IAMロール「Role-WebServer」を作って下記ポリシーを付けます。

信頼ポリシー(EC2インスタンスをPrincipalにする)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}

ロールポリシー(S3フールアクセス権限付与)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
}
]
}


  • LAMPサーバ構築


「Role-WebServer」を使用してAmazon Linux EC2インスタンスを起動してLAMP構築手順に従ってLAMP環境を構築する。

システムのタイムゾーンを東京時間に設定する。
$ sudo cp /usr/share/zoneinfo/Japan /etc/localtime

php設定ファイルのタイムゾーンを東京時間に設定する。


$ sudo vi /etc/php.ini

;date.timezone =  ⇒    date.timezone = "Asia/Tokyo"


Apacheを再起動する。
$ sudo service httpd restart


  • CIソースファイルをダウンロードする


最新版CI(現時点Version2.2.1)をダウンロードして解凍する。
$ cd /var/www/html
$ sudo wget https://github.com/bcit-ci/CodeIgniter/archive/2.2.1.zip
$ sudo unzip 2.2.1.zip
$ sudo rm -f 2.2.1.zip
$ sudo mv CodeIgniter-2.2.1 demo


  • 検証用DB作成


mysqlにログインしてdemoデータベースを作成する(検証の為、一応rootユーザを使う)。
$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.5.42 MySQL Community Server (GPL)

Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>create database demo;
Query OK, 1 row affected (0.00 sec)
mysql>exit;
Bye


  • CI設定


ウェブブラウザに「EC2インスタンスのPublic DNS/demo/index.php」を入力すれば下記のようなデフォルトCIホームページが見れますが、自由に使える為いくつか設定が必要がある。

homepage_origin

①各種設定ファイルを修正する。
###自動導入設定ファイルを編集する
$ sudo vi /var/www/html/demo/application/config/autoload.php

###データベースライブラリを自動導入にする
$autoload['libraries'] = array(); ⇒
$autoload['libraries'] = array('database');

###URL解析ヘルパーを自動導入にする
$autoload['helper'] = array(); ⇒
$autoload['helper'] = array('url');

 
###データベース設定ファイルを編集する
$ sudo vi /var/www/html/demo/application/config/database.php

###DBユーザ名を指定する
$db['default']['username'] = ''; ⇒
$db['default']['username'] = 'root';

###DBユーザのパスワードを指定する
$db['default']['password'] = ''; ⇒
$db['default']['password'] = '「パスワード」';

###DB名を指定する
$db['default']['database'] = ''; ⇒
$db['default']['database'] = 'demo';

②自分のホームページindex.phpを作成する。
$ sudo vi /var/www/html/demo/application/views/index.php

ファイル内容は下記にする
<?php
echo "my index page";
echo phpinfo();
?>

③ホームパージルーティングを新規作成したファイルに切り替え。

デフォルトコントローラーはWelcomeなので、編集してそのまま使います。
$sudo vi /var/www/html/demo/application/controllers/welcome.php

###呼び出すビューを新規作成したindex.phpにする。
$this->load->view('welcome_message'); ⇒
$this->load->view('index');

これでウェブブラウザに「EC2インスタンスのPublic DNS/demo/index.php」を入力すれば下記画面になります。

homepage

 

④不要ファイルを削除する。
###元ホームページファイルを削除する
$ sudo rm -f /var/www/html/demo/application/views/welcome_message.php

###元ホームページに紐付いているユーザガイドを削除する
$ sudo rm -rf /var/www/html/demo/user_guide/

 

⑤ファイル権限を設定する。
 $sudo chown -R apache:apache /var/www/html/demo/

 

  • AWS-PHP-SDKをダウンロードする


AWS-PHP-SDKを共有ライブラリとしてインストールします。
$ sudo su -
# yum install git -y
# cd /usr/lib/
# git clone https://github.com/awslabs/aws-php-sample.git
# cd aws-php-sample
# curl -sS https://getcomposer.org/installer | php
# php composer.phar install
# mv vendor ../aws-php-sdk
# cd ..
# rm -rf aws-php-sample/

これでベース環境を構築できました。