EC2のあまり触っていないところ

先日のVPCに引き続き今度は個人的にEC2のあまり触ってなかったところを触っていきます。普段ElasticBeanstalkやOpsWorksをメインで触っている事もあって細かいところはあまり試してませんでした。やっぱり自分で触りながら疑問に思ったところをググったりすると理解がだいぶ深まりますね。

Elastic Network Interface(ENI)

プライベートIPアドレスを固定する

EC2インスタンスの生成時に指定することができます。簡単ですね。ただ、いずれにしろ特定のIPアドレスに依存する作りはあまり良くないのでRoute53を利用して名前解決できるようにしたほうが良いと思います。なのであまり使わないかな…。

NewImage

複数のプライベートIPアドレスを利用する

上記のこの画面でセカンダリのIPアドレスを指定すると1つのENIで複数のプライベートなIPアドレスを持つことができます。もちろんあとからENI側の設定でもできます。追加したプライベートIPアドレスにEIPを紐付けると2種類のIPアドレスでインターネットアクセスができるようになります。

Amazon EC2編~ENI~

ちなみに下記の記事に書かれているようにOS側の設定が必要になります。

EC2インスタンスに複数IPアドレスを割り当てる

複数ENIをアタッチするとどうなるのか

ひとつのEC2インスタンスに複数のENIをアタッチする事ができます。ただ、問題がいろいろあるようでAWSの仕様上自動でパブリックなIPアドレスが振られなくなるようです。調べてるとルーティングの問題が発生しやすいので基本的にはやめましょうという事のようです。

EC2に複数のENIをアタッチする手順と制約(Public-ip,DNSが割当てられなくなる)

ENIについて考えてみた

もう一度ENIについて考えてみた(Linux編)

Elastic Block Store(EBS)

既存のEC2インスタンスにEBSを追加

EBSのメニューからボリュームを新規作成しEC2インスタンスにアタッチします。

NewImage

最初はマウントされていません。OS側で処理が必要です。

# df -h
ファイルシス   サイズ  使用  残り 使用% マウント位置
/dev/xvda1       7.8G  1.1G  6.6G   15% /
devtmpfs         490M   60K  490M    1% /dev
tmpfs            498M     0  498M    0% /dev/shm

EBSボリュームをフォーマットしてマウントします。

# mkfs -t ext4 /dev/sdf
mke2fs 1.42.12 (29-Aug-2014)
Creating filesystem with 26214400 4k blocks and 6553600 inodes
Filesystem UUID: 11c0c4c2-f508-432b-a626-60d7b1ad3fda
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
	4096000, 7962624, 11239424, 20480000, 23887872

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done   

# mkdir /data2
# mount /dev/sdf /data2

正常にマウントされました。

# df -h
ファイルシス   サイズ  使用  残り 使用% マウント位置
/dev/xvda1       7.8G  1.1G  6.6G   15% /
devtmpfs         490M   60K  490M    1% /dev
tmpfs            498M     0  498M    0% /dev/shm
/dev/xvdf         99G   60M   94G    1% /data2

再起動時もマウントが必要な場合はfstabの設定を行っておきます。

既存EC2インスタンスにEBSボリュームを追加(アタッチ)する

領域を拡張したい場合にどうするか?

追加ではなく拡張したい場合は、スナップショットを利用してボリュームを作成し直します。その際にEC2インスタンスは一旦止めておく必要があります。

Linux で EBS ボリュームのストレージ領域を拡張する

下記のような手順になります。

  1. EC2インスタンスをStopする
  2. 該当のボリュームのスナップショットを作成する
  3. スナップショットからより大きな領域を指定して新たにボリュームを作成する
  4. EC2インスタンスから古いボリュームをデタッチする
  5. 新しいボリュームを同じデバイス名でアタッチする
  6. EC2インスタンスを開始する

スナップショットのコピー

スナップショットはS3に格納されます。ただS3のメニューからどこにあるかは分からないようになっています。スナップショットのメニューからコピーで、複製したいさきのリージョンを選んでやることができます。

NewImage

AMI

普段は基本的にAWSから提供されているプレーンなAMIに対してプロビジョニングツールを実行して環境構築するという運用をしています。なので個人的にはAMIを利用するのはプロビジョニングがうまくいかない場合への備えとしてのバックアップ用途くらいです。

仮想化方式の種類(hvm, paravirtual)

提供されているAMIを見てるとhvmとかparavirtualとか種類がある事に気づきます。これは仮想化方式の違いなんですが、対応している仮想化方式はAMIによって異なります。AMIによってどちらか一方をサポートするという事のようです。流れ的にはparavirtualが元々あってhvmが主流になってきているという感じのようです。

Amazon Linux AMI インスタンスタイプマトリックス

pravirtualは準仮想化方式で、hvmはhardware assisted VMの略で完全仮想化方式と呼ばれるそうです。下記の記事が詳しいです。

仮想化方式(HVM と PV)についてまとめ

EC2はXenベースなんですね。paravitualとHVMではOSの起動シーケンスが違うようです。

HVM の場合、起動シーケンスは物理マシンに OS をインストールした場合と何ら変わりません。 ルートデバイスにあるブートローダから、デバイス内に含まれる kernel を起動していきます。

ちなみに調べてるとparavirtualからhvmへAMIを移行するという事も行われているようです。

EC2のt1.microをt2.microへ移行する

すごい大変そうというか秘伝のタレすぎてそんなAMIずっと使い続けて大丈夫なんでしょうか。こういう仮想化方式にまで依存するのはどうかと思うのでChefやAnsibleで常に構成をプロビジョニングできるようにしておくと乗り換えも本当に楽だし安全だなと思いました。

EBSタイプとインスタンスストアタイプ

AMIによってサポートされているrootデバイスが異なります。インスタンスストアが元々あってEBSタイプのほうが新しいですがもうEBSが主流なのかな。下記の記事がとても分かりやすかったです。

メモ: EBSタイプ、インスタンスストアタイプ

AMIをEBSのスナップショットベースで作っているか、S3上にあるAMIイメージから生成しているかの違いのようです。大きな違いは選べるインスタンスタイプが違う(インスタンスストアはmicroより上)なのと、停止ができるか・できないかというところが大きいです。特に理由がなければEBSタイプにするのが良いようです。

また、中の人ではありませんが、『Amazon Cloudテクニカルガイド』の著者の方も、特に理由がなければEBSタイプのAMIをすすめるスタンスのようです。

EC2停めるとデータが消えるみたいな話はこのインスタンスストアが主流だった頃の話ですよね。また、上記の記事では下記のようにインスタンスストアの利点も挙げられていますが、

たとえば、もしあるリージョンがダウンした時、AMIを作成可能な最近のデータがS3に保存されていれば、それを元にAMIを作成して、インスタンスを立ち上げることが可能です。しかし、EBSスナップショットだけに頼っていると、そのリージョンにアクセスできない限り、インスタンスを作成し直すことができません。

異なるリージョンへはスナップショットをコピーできるのでこれも今は優位点にはならなさそうです。

スナップショットとの関係

AWSで下記の4つの概念の関係を明確に教えていただけないでしょうか?

AMIというのはInstanceを起動するためのHDD構成を記述した設定ファイルだと思えば良いと思います。SnapshotやVolumeと一緒に出てきますが、その外にあり、どのSnapshotを元にしたVolumeを繋げて起動するかが書いてあるモノです。

AMIを作るとスナップショットもいっしょに作られてるよなと思ってましたがそういうことなんですね。

IAMロール

アクセスキーとシークレットをEC2上にベタ書きしなくてもロールとしてEC2に権限を委譲し権限的にAWSのサービスへのアクセスを制御するための仕組みです。IAMロールはEC2じゃなくてもLambda等の他のサービスでもよく出てきますよね。ウィザードでそのまま適切なロールを自動で作ってくれるようになっているのであまりマニュアルで作成・設定したことがありませんでした。

[AWS] EC2インスタンスにIAMロールを適用して、S3へファイルアップロードする。

上記の記事にしたがって、ロールを作成の上EC2にSSHログインしてaws s3 lsしたら自分のバケットを参照する事ができました。EC2の場合AWSコマンドやAWS SDKで有効な機能なんですね。下記の記事も参考になります。

IAM Roleの仕組みを追う – なぜアクセスキーを明記する必要がないのか

上記の記事のように下記のコマンドでロール名から有効期限付きの一時的なクレデンシャルを取得する事ができます。コマンドやSDKはこういった仕組みを利用して権限を取得してAWSのサービスの操作を実行しているという事なんですね。

$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/
default-role
 
$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/default-role
{
  "Code" : "Success",
  "LastUpdated" : "2014-07-05T06:30:19Z",
  "Type" : "AWS-HMAC",
  "AccessKeyId" : "ASIAxxx...",
  "SecretAccessKey" : "xxxxx........",
  "Token" : "xxxxxxxxxxxxxxxxxxxxx...",
  "Expiration" : "2014-07-05T13:05:33Z"
}

Auto Recovery

EC2のステータスチェック(システムステータスチェックおよびインスタンスステータスチェック)の異変時にCloudWatchの機能であるEC2アクションによってEC2の再起動を行う機能です。2015年の新機能のようですが以前はインスタンスの停止や削除しか行えなかったようです。

アプリケーション層でのチェックではなく、AWS環境のシステムチェックなのでELBのヘルスチェックのような用途では使えません。

新機能】EC2 Cloudwatchの新機能「Auto Recovery」を使ってみた

NewImage

上記の記事だとCloudWatchの画面からEC2アクションを指定していましたが今はEC2の画面内で再起動のEC2アクションを指定したアラートが作れるようです。ステータスチェックの詳細については下記が詳しいです。

ステータスチェックの種類

システムステータスのチェックはAWS側のハードウェアやネットワークが原因になりますが、インスタンスステータスのチェックは下記のようなものが原因となるようです。

  • 失敗したシステムステータスチェック
  • 正しくないネットワークまたは起動設定
  • メモリの枯渇
  • 破損したファイルシステム
  • 互換性のないカーネル

Run Command

EC2でシェルコマンドやスクリプトを実行する機能です。単体のEC2インスタンスだけでなく複数のEC2インスタンスに対して処理実行することができます。OpsWorksでレシピを実行するのに少し似てますね。こちらのRun Commandはamazon-ssm-agentというエージェントをEC2インスタンスに事前に入れておく必要があります。

EC2 Run Commandアップデート – Linuxインスタンスで利用可能に

下記の記事を見ると動画付きでどのように実行できるか見ることができます。

EC2 Run CommandがLinux対応したので簡易実行コマンドを作ってみた

用途としてはOpsWorks等を使っていない環境でEC2インスタンスが多くなってきた時にパッチをあてたりルーチン(ユーザー追加・削除等)を自動化したりするのに便利だと思います。OpsWorks使ってる人は使う必要ないと思います。

ユーザーデータとインスタンスメタデータ

マニュアルにそのままのページがあります。

インスタンスメタデータとユーザーデータ

ユーザーデータ

EC2インスタンスの生成時に指定できるデータです。下記のようにテキストかファイルの形式で入力できます。

NewImage

指定したものはEC2インスタンスにSSHログインしてるとcurl http://169.254.169.254/latest/user-data/で取得する事ができます。テキストデータは普通のテキストとして取得できますしバイナリデータもやってみたらいけました(但しサイズ上限は16KB)。

EBSタイプのEC2の場合はStopしてから「ユーザーデータの表示/変更」から変更を加える事ができます。

ちなみに169.254.169.254っていつも忘れちゃうので良い語呂合わせないのかなと思ってます。「いちろーくん、2個読む」というのを無理やり今考えました。。

インスタンスメタデータ

EC2インスタンスのメタデータ情報です。http://169.254.169.254/latest/meta-dataから取得することができます。基本的な情報は全て取得することができます。

$ curl http://169.254.169.254/latest/meta-data/    
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
hostname
instance-action
instance-id
instance-type
kernel-id
local-hostname
local-ipv4
mac
network/
placement/
public-hostname
public-ipv4
public-keys/
reservation-id
security-groups
services/

動的データ

http://169.254.169.254/latest/dynamicから取得することができるインスタンス・アイデンティティの情報です。

インスタンスが起動するときにインスタンスアイデンティティドキュメントが生成され、インスタンスメタデータを通じてインスタンスに公開されます。このドキュメントは、サブスクライブしたソフトウェア、インスタンスサイズ、インスタンスタイプ、オペレーティングシステム、AMI など、インスタンスの属性を検証します。

入っているのはインスタンスの情報及びその署名なので、情報の正当性が必要になる時に利用するのかな。

起動時のコマンド実行

シェルスクリプトあるいはcloud-initディレクティブを利用することでEC2起動時に任意の処理を実行することができます。いずれもユーザーデータに記述する事で実現します。

シェルスクリプトの場合は単純に#!/bin/bashからユーザーデータを始めれば以降はシェルスクリプトとして実行されます。

#!/bin/bash
yum update -y
yum install -y httpd24 php56 mysql55-server php56-mysqlnd
service httpd start
chkconfig httpd on
groupadd www
usermod -a -G www ec2-user
chown -R root:www /var/www
chmod 2775 /var/www
find /var/www -type d -exec chmod 2775 {} +
find /var/www -type f -exec chmod 0664 {} +
echo "<?php phpinfo(); ?>" > /var/www/html/phpinfo.php

cloud-initディレクティブの場合は下記のような形で記述します。packagesでyumインストールができるので記述がより宣言的で良いですね。

#cloud-config
repo_update: true
repo_upgrade: all

packages:
 - httpd24
 - php56
 - mysql55
 - server
 - php56-mysqlnd

runcmd:
 - service httpd start
 - chkconfig httpd on
 - groupadd www
 - [ sh, -c, "usermod -a -G www ec2-user" ]
 - [ sh, -c, "chown -R root:www /var/www" ]
 - chmod 2775 /var/www
 - [ find, /var/www, -type, d, -exec, chmod, 2775, {}, + ]
 - [ find, /var/www, -type, f, -exec, chmod, 0664, {}, + ]
 - [ sh, -c, 'echo "<?php phpinfo(); ?>" > /var/www/html/phpinfo.php' ]

ところでこのcloud-initディレクティブってElasticBeanstalkのebextensionsの構文にすごく似てますね。試しにcommands等のElasticBeanstalkで使われるディレクティブを使ってみたんでしたが無視されました。あれはやはりElasticBeanstalkを使った時だけの独自拡張なのかな。

シェルスクリプトの場合もcloud-initディレクティブの場合もログは/var/log/cloud-init-output.logで確認することができます。

プレイスメントグループ

同じアベイラビリティゾーンの中で複数のEC2インスタンスを論理的にグルーピングする事ができ、プレイスメントグループにあるEC2インスタンスは10Gbpsネットワークが利用できるようになるというオプションです。

プレイスメントグループ

低レイテンシが必要だったりネットワークのスループットが必要なアプリケーションだと使いたいオプションですね。設定の仕方はとても簡単でプレイスメントグループを作成し(名前しか入力がありません)、EC2インスンタンス生成時にプレイスメントグループを指定するだけです。ただし利用できるEC2インスタンスは限定されていて現時点だと下記になります。

汎用: m4.large | m4.xlarge | m4.2xlarge | m4.4xlarge | m4.10xlarge
コンピューティングを最適化: c4.large | c4.xlarge | c4.2xlarge | c4.4xlarge | c4.8xlarge | c3.large | c3.xlarge | c3.2xlarge | c3.4xlarge | c3.8xlarge | cc2.8xlarge
メモリを最適化: cr1.8xlarge | r3.large | r3.xlarge | r3.2xlarge | r3.4xlarge | r3.8xlarge
ストレージを最適化: d2.xlarge | d2.2xlarge | d2.4xlarge | d2.8xlarge | hi1.4xlarge | hs1.8xlarge | i2.xlarge | i2.2xlarge | i2.4xlarge | i2.8xlarge
GPU: cg1.4xlarge | g2.2xlarge | g2.8xlarge

さらに10Gbsをサポートするインスタンスは限られているようなので、ネットワーク速度に拘ろうとするとさらに高価なインスタンスが必要になります。

Auto Scaling

Auto ScalingはElasticBeanstalkを通してよく使っていたんですが、素のEC2のメニューから作成した事がなかったので試してみます。概要や手順は下記のブログがイラスト付きでとても分かりやすかったです。

Amazon EC2でオートスケーリングを行う方法 – 技術の犬小屋

起動設定

Auto Scalingで利用されるEC2の設定(AMI、ストレージ、セキュリティグループ等)です。設定はEC2インスタンスの生成時ととても似ていますが、カーネルIDやRAMディスクID等を設定することができるようです。AMIを作っても良いですがユーザーデータも指定できるので簡単なものだったらスクリプト等でインストールしてしまっても良いですね。

Auto Scalingグループ

起動設定を作ったら次にAuto Scalingグループを作成します。

作成する際に最初の「高度な詳細」の欄で、ELBを使うか使う場合はヘルスチェックをELBにするかEC2にするかが聞かれます(デフォルトだとEC2になります)。ELBを使うとELBのヘルスチェック(HTTP等)が使えるのでアプリケーションレベルでヘルスチェックができます。ヘルスチェックがEC2の場合だとAuto Recoveryのところで見たヘルスチェックと同じでサーバーインスタンスレベルになります。

希望のインスタンス数とは?

Auto Scalingグループを作成する際には出てこない項目なんですが、作成後Auto Scalingグループを参照すると項目として表示されているはずです。これ詳しいことは分からないんですが設定値でもあり、かつスケーリングポリシーによって動的に変更される値でもあるようです。

What “desired instances” is needed for? AWS Amazon Webservices AutoScaling group

たとえば最初1だった希望の値が負荷をかけて試していくとたとえば2などに値が変更されます。これはスケーリングポリシーによってインスタンスの数を増やそうとし希望の値が書き変わるようです。逆もしかりで負荷がない場合などはスケーリングポリシーによって-1などされます。マニュアルで希望の値を書き換えてもそのようにインスタンス数が自動で調整されるようです。

スケジュールされたアクション

日時設定(Cron形式, 5分毎, 毎週等)でアクションを実行し最小、最大、希望のインスタンス数を変更する事ができるようです。

終了ポリシー

スケールインする際の動作(どのインスタンスを破棄するか)についてです。デフォルトだと下記の動作をします。

  1. Auto Scaling は、複数のアベイラビリティーゾーンにインスタンスがあるかどうかを判断します。該当する場合、インスタンスが最も多く、スケールインから保護されていないインスタンスが最低 1 つあるアベイラビリティーゾーンを選択します。複数のアベイラビリティーゾーンでこのインスタンス数が同じである場合、最も古い起動設定を使用するインスタンスのあるアベイラビリティーゾーンを Auto Scaling は選択します。
  2. Auto Scaling は、選択したアベイラビリティーゾーンで、保護されていないどのインスタンスが最も古い起動設定を使用しているかを判断します。このようなインスタンスが 1 つある場合、そのインスタンスを終了します。
  3. 最も古い起動設定を使用するインスタンスが複数ある場合、Auto Scaling は次の課金時間に最も近い保護されていないインスタンスを判断します(これによって、Amazon EC2 の使用に対して課金される時間数を最小限に抑えながら、EC2 インスタンスの使用を最大化することができます)。このようなインスタンスが 1 つある場合、Auto Scaling はそのインスタンスを終了します。
  4. 次の課金時間に最も近い保護されていないインスタンスが複数ある場合、Auto Scaling はこれらのインスタンスのいずれかをランダムに選択します。

スケールイン時に Auto Scaling がどのインスタンスを終了するかを制御する

カスタマイズも可能です。

インスタンスの保護

スケールインの是非の設定です。Auto ScalingグループそのものとAuto Scalingグループに含まれる個別のEC2インスタンスに設定することができます。

スケールアウト/スケールインのテスト

CPU負荷でスケーリングポリシーを使っている場合は下記の方法でCPU負荷を上げるのがお手軽です。

LinuxでCPU負荷を上げたい場合

$ yes > /dev/null

上記のコマンドでCPU100%になります。しばらくすると新しいEC2インスタンスが生成されます。yesコマンドを止めてしばらく待ってればスケーリングポリシーが適用されてインスタンス数が減るはずです。今回は待てなかったのでスケーリングポリシーのタブメニューからDecrease Group Sizeを実行しました。

リカバリーのテスト

ELBを使ってヘルスチェックタイプをELBにした場合は、httpd等のELBのヘルスチェックを受けているプロセスを停止すると、まずELBからそのインスタンスが外れAuto Scalingの設定的にその時最低のインスタンス数に満たなければ新たにEC2インスタンスが起動設定から生成されELBから外れたEC2インスタンスは削除されます。

ヘルスチェックタイプにEC2を使ってる場合は、EC2を停めるとELBの場合と同じように新たにEC2インスタンスが起動設定から生成され停止したEC2インスタンスは削除されます。

VM Import/Export

VMware等の仮想マシンイメージからのEC2へのインポートあるいはその逆のエクスポートができる。

VMImportでVMware仮想マシンイメージをEC2インスタンスとしてインポートする

Google Compute Platformにもインポートできる模様。

Import an Amazon Machine Image