RDSで急にパフォーマンスが悪くなったらIOPSを確認!

本番運用しているRDSのパフォーマンスが最近悪くなっている。
スロークエリを確認すると、処理時間が非常に遅いときがある。(Procedure)
とあるProcedure処理が以前は15分くらいで完了していたのだが、遅い時には100分近くかかっている。。。
処理内容は変えていないのに。。。

CPU使用率を比較してみる

グラフの凡例

  • 青線:正常
  • 赤線:処理時間が遅い時

正常時は処理が終わるとCPU使用率は下がっていた。
しかし、処理時間が遅い時は負荷が上がっている時間が短く、CPU使用率も下がりきっていない。
スクリーンショット 2017-05-22 15 (7).png

処理時間が遅いのはCPUがサボっているかららしい(笑)
なぜ、違う動きをしているのか?
実際に処理した件数はどうなっているのか?

IOPSを比較してみる

書き込み(WriteIOPS)

正常時には次の処理が走っているが、それ以外に大きな差はなさそう。
スクリーンショット 2017-05-22 15 (11).png

読み込み(ReadIOPS)

一定時間経過後にIOPSが300で横ばいとなっている。
スクリーンショット 2017-05-22 16.png

Amazon EBS ボリュームとパフォーマンス

色々と調べたところこのページに行き着きました。
http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/EBSVolumeTypes.html#EBSVolumeTypes_gp2

超ざっくりまとめると…

  • ボリュームサイズによりベースラインパフォーマンスが決まる
  • バーストすることで最大3,000 IOPSまで一時的に性能をあげられる
  • バーストするにはクレジットバランスを消費する
    • クレジットバランスは初期に配られる
    • クレジットバランスはバーストしない間に補充される
  • クレジットバランスを使い切った場合のパフォーマンスはベースラインにとどまる

自分の環境に当てはめる

私の環境はボリュームタイプが「汎用SSD」、ボリュームサイズが「100GiB」なので
ベースラインパフォーマンスは300 IOPSとなっています。

どうやらクレジットバランスを使い切ったため300 IOPSしか性能が出ていなかったようです。。。
ちなみに残クレジットバランスの確認方法はわかりませんでした。(あったら教えてください)

対応方法

対応方法として以下になると思います。
私は後者(処理間隔を空けること)で対応しています。

  • ボリュームサイズを増やす。 ※後から減らせないので要注意!
  • クレジットバランスが補充されるまで待つ

まとめ

INDEXやら色々調べてみてもわからず、この結論に行くまでに時間がかかりました。
普段、意識していない部分だと思うので何かのヒントになれば幸いです。

続きを読む

ビンパッキング問題を利用してクラウド利用料を安くする

ビンパッキング問題を利用したクラウド利用の最適化

さて、AWSやAzure、GCPのようなクラウドを利用していると、どのアプリケーションをどのサイズの仮想マシンに登載すれば効率的なのか、迷うことがあります。
アプリケーションのCPU、メモリ、ディスク利用量が判明しているとして、アプリケーションをどのサイズの仮想マシンに入れれば良いか、コロケーションした方が良いのか、分散した方が良いのか・・・いろいろと考えることはあります。
クラウド利用歴の長い技術者は経験則でどのサイズを選ぶのか、わかったりするもののようです。
しかし今回はちょっとアプローチを変えて、最適化問題として解決策を見出だせないかな、と考えてみました。

例えば以下のような状況で、どのサイズのアプリケーションをどのサイズの仮想マシンに入れれば、効率的でしょうか?

1.png

まずはおことわり

最適化問題が面白そうだったので、勉強がてら、自分にとって身近な問題で考えてみました。
最適化問題歴1週間なので、間違っている箇所やアドバイスはご指摘ください。

なお、勉強に使ったのは以下の本です。
Python言語によるビジネスアナリティクス 実務家のための最適化・統計解析・機械学習

問題設定

今回は必要な数のアプリケーションをクラウドの仮想マシンに登載した結果、費用が一番安くなる構成を、ビンパッキング問題として求めたいと思います。

ビンパッキング問題とは、ある入れ物(箱やビン、コンテナ)に荷物(重さや個数が定められている)を詰める際、必要な入れ物の最少数を求める組み合わせ最適化問題です。
例えば、引っ越しの際に荷物をダンボールに詰めると思いますが、そのダンボールの数を最少にする詰め方を解くものです。

2.png

荷物をダンボールに詰めるのであれば、ダンボール箱の体積(横×縦×高)と耐荷重量に対し、荷物の体積と重さを考慮して入れます。
これを見た時、荷物をアプリケーション、ダンボールを仮想マシンとして、体積や重さをCPU, RAM, Disk, 費用に置き換えれば、クラウドの仮想マシン利用を最適化することができる気がしたのが、今回の発端です。

環境

Pythonで最適化問題を解いてみたいと思います。
Pythonでは最適化問題を解くのに便利なライブラリが色々提供されていまして、ここに詳しく説明されています。
最適化におけるPython

今回はPython3.5(Anaconda)でopenoptを使いました。
OSはCentOS7.3です。
Openoptは数理最適化のモデルを作るライブラリです。

この環境へのopenoptのインストール方法は以下のとおりです。

conda install --channel https://conda.anaconda.org/cachemeorg funcdesigner openopt
pip install cvxopt
pip install glpk

やること

今回はアプリケーションを3種類に分けます。
小さいアプリケーション、中くらいのアプリケーション、大きいアプリケーションです。
それぞれのリソース利用量は以下とします。

小さいアプリケーション 中くらいのアプリケーション 大きいアプリケーション
CPU: 0.2 CPU: 0.5 CPU: 2.4
RAM: 256MB RAM: 512MB RAM: 2048MB
DISK: 1GB DISK: 10GB DISK: 40GB

これらを以下のEC2インスタンスサイズのうち、どれに詰め込むと一番安くなるか、ビンパッキング問題を使って解きます。

M4.4xlarge R3.2xlarge C4.2xlarge
CPU: 16vCPU CPU: 8vCPU CPU: 8vCPU
RAM: 64GB RAM: 61GB RAM: 15GB
Disk: 100GB Disk: 100GB Disk: 100GB
$1.032 / hour $0.798 / hour $0.504 / hour

なお、単価は本日(2017年5月21日)時点の東京リージョンでLinuxのオンデマンドインスタンスを使った場合の値段としています。参考
また、ディスクの費用(EBS)は含んでおりません。

プログラム

プログラム全文はこちらです。

# import openopt
from openopt import *

# 小さいアプリケーション、中くらいのアプリケーション、大きいアプリケーションの数を設定します。
small_num = 20
med_num = 12
large_num = 9

apps = []

# 各アプリケーションのリソース利用量をdictにし、リストに追加します。
for i in range(small_num):
    small_app = {
        'name': 'small%d' % i,
        'cpu': 0.2,
        'mem': 256,
        'disk': 1
        }
    apps.append(small_app)

for i in range(med_num):
    med_app = {
        'name': 'medium%d' % i,
        'cpu': 0.5,
        'mem': 512,
        'disk': 10
        }
    apps.append(med_app)

for i in range(large_num):
    large_app = {
        'name': 'large%d' % i,
        'cpu': 2.4,
        'mem': 2048,
        'disk': 40
        }
    apps.append(large_app)


# AWS EC2インスタンスのサイズを設定します。
# 各リソースを9掛けにしているのは、OSがリソースの10%を使うと仮定しているためです。
instance_sizes = [
    {
        'name': 'm4.x4large',
        'cost': 1.032 * 24 * 30,
        'size': {
            'cpu': 16 * 0.9,
            'mem': 64 * 1024 * 0.9, 
            'disk': 1000 * 0.9
        }
    },
    {
        'name': 'r3.2xlarge',
        'cost': 0.798 * 24 * 30,
        'size': {
            'cpu': 8 * 0.9,
            'mem': 61 * 1024 * 0.9, 
            'disk': 1000 * 0.9
        }
    },
    {
        'name': 'c4.2xlarge',
        'cost': 0.504 * 24 * 30,
        'size': {
            'cpu': 8 * 0.9,
            'mem': 15 * 1024 * 0.9, 
            'disk': 1000 * 0.9
        }
    }
]

# ビンパッキングです。
# openoptのBPPという関数を使います。
def bin_pack_instance(apps, instance_size):
    cost = instance_size['cost']    
    p = BPP(apps, instance_size['size'], goal = 'min')
    r = p.solve('glpk', iprint = 0)
    instances = len(r.xf)
    total_cost = instances * cost
    return r, instances, total_cost

# 実行します。
# 各インスタンスサイズでビンパッキングを行い、最も安くなるものを探します。
if __name__ == '__main__':
    list_cost = []
    for instance in instance_sizes:
        r, instances, total_cost = bin_pack_instance(apps, instance)
        list_cost.append({'instance': instance['name'], 'total_cost': total_cost})

        print("\r") 
        print("Bin packing for : {0}".format(instance['name']))
        print("Total number of apps is " + str(len(apps)))
        print("Total {0} instance used is {1}".format(instance['name'], instances))
        print("Total cost is {0}".format(total_cost))

        for i,s in enumerate(r.xf):
            print ("Instance {0} contains {1} apps".format(i, len(s)))
            print("\t CPU: {0}vCPU\t RAM: {1}MB\t Disk: {2}GB"
                  .format(r.values['cpu'][i], r.values['mem'][i], r.values['disk'][i]))
            print("\t Contains: {0}".format(r.xf[i]))

        print("\r")  

    print("Result: {0}".format(list_cost))

結果はこちらのとおりになります。

------------------------- OpenOpt 0.5625 -------------------------
problem: unnamed   type: MILP    goal: min
solver: glpk
  iter  objFunVal  log10(maxResidual)  
    0  0.000e+00               0.00 
    1  0.000e+00            -100.00 
istop: 1000 (optimal)
Solver:   Time Elapsed = 0.12   CPU Time Elapsed = 0.12
objFuncValue: 3 (feasible, MaxResidual = 0)

Bin packing for : m4.x4large
Total number of apps is 41
Total m4.x4large instance used is 3
Total cost is 2229.12
Instance 0 contains 18 apps
     CPU: 14.200000000000001vCPU     RAM: 13312.0MB  Disk: 228.0GB
     Contains: ('small0', 'small3', 'small4', 'small5', 'small6', 'small7', 'small8', 'small13', 'medium0', 'medium1', 'medium2', 'medium3', 'medium4', 'medium5', 'large3', 'large4', 'large6', 'large7')
Instance 1 contains 17 apps
     CPU: 14.4vCPU   RAM: 13312.0MB  Disk: 212.0GB
     Contains: ('small1', 'small2', 'small9', 'small10', 'small11', 'small12', 'small14', 'small15', 'small16', 'small17', 'small18', 'small19', 'large0', 'large1', 'large2', 'large5', 'large8')
Instance 2 contains 6 apps
     CPU: 3.0vCPU    RAM: 3072.0MB   Disk: 60.0GB
     Contains: ('medium6', 'medium7', 'medium8', 'medium9', 'medium10', 'medium11')


------------------------- OpenOpt 0.5625 -------------------------
problem: unnamed   type: MILP    goal: min
solver: glpk
  iter  objFunVal  log10(maxResidual)  
    0  0.000e+00               0.00 
    1  0.000e+00            -100.00 
istop: 1000 (optimal)
Solver:   Time Elapsed = 0.24   CPU Time Elapsed = 0.23
objFuncValue: 5 (feasible, MaxResidual = 0)

Bin packing for : r3.2xlarge
Total number of apps is 41
Total r3.2xlarge instance used is 5
Total cost is 2872.8
Instance 0 contains 3 apps
     CPU: 7.199999999999999vCPU  RAM: 6144.0MB   Disk: 120.0GB
     Contains: ('large0', 'large4', 'large7')
Instance 1 contains 11 apps
     CPU: 7.199999999999999vCPU  RAM: 6912.0MB   Disk: 107.0GB
     Contains: ('small5', 'small6', 'small7', 'small8', 'small9', 'small18', 'small19', 'medium0', 'medium1', 'large1', 'large2')
Instance 2 contains 13 apps
     CPU: 7.0vCPU    RAM: 6912.0MB   Disk: 91.0GB
     Contains: ('small0', 'small1', 'small2', 'small10', 'small11', 'small12', 'small13', 'small14', 'small15', 'small16', 'small17', 'large5', 'large6')
Instance 3 contains 8 apps
     CPU: 7.199999999999999vCPU  RAM: 6656.0MB   Disk: 122.0GB
     Contains: ('small3', 'small4', 'medium2', 'medium3', 'medium4', 'medium5', 'large3', 'large8')
Instance 4 contains 6 apps
     CPU: 3.0vCPU    RAM: 3072.0MB   Disk: 60.0GB
     Contains: ('medium6', 'medium7', 'medium8', 'medium9', 'medium10', 'medium11')


------------------------- OpenOpt 0.5625 -------------------------
problem: unnamed   type: MILP    goal: min
solver: glpk
  iter  objFunVal  log10(maxResidual)  
    0  0.000e+00               0.00 
    1  0.000e+00            -100.00 
istop: 1000 (optimal)
Solver:   Time Elapsed = 0.14   CPU Time Elapsed = 0.14
objFuncValue: 5 (feasible, MaxResidual = 0)

Bin packing for : c4.2xlarge
Total number of apps is 41
Total c4.2xlarge instance used is 5
Total cost is 1814.4
Instance 0 contains 7 apps
     CPU: 5.4vCPU    RAM: 5120.0MB   Disk: 100.0GB
     Contains: ('medium0', 'medium1', 'medium2', 'medium3', 'medium4', 'medium5', 'large6')
Instance 1 contains 15 apps
     CPU: 7.0vCPU    RAM: 7168.0MB   Disk: 108.0GB
     Contains: ('small8', 'small9', 'small10', 'small14', 'small16', 'small17', 'small18', 'small19', 'medium6', 'medium7', 'medium8', 'medium9', 'medium10', 'medium11', 'large0')
Instance 2 contains 14 apps
     CPU: 7.199999999999999vCPU  RAM: 7168.0MB   Disk: 92.0GB
     Contains: ('small0', 'small1', 'small2', 'small3', 'small4', 'small5', 'small6', 'small7', 'small11', 'small12', 'small13', 'small15', 'large3', 'large4')
Instance 3 contains 3 apps
     CPU: 7.199999999999999vCPU  RAM: 6144.0MB   Disk: 120.0GB
     Contains: ('large1', 'large2', 'large5')
Instance 4 contains 2 apps
     CPU: 4.8vCPU    RAM: 4096.0MB   Disk: 80.0GB
     Contains: ('large7', 'large8')

Result: [{'instance': 'm4.x4large', 'total_cost': 2229.12}, {'instance': 'r3.2xlarge', 'total_cost': 2872.8}, {'instance': 'c4.2xlarge', 'total_cost': 1814.4}]


長くなりますが、結果としてc4.2xlargeを4台に詰め込むのが最も効率が良く、月額$1814.4で済むようです。

感想

今回はアプリケーション配置を最適化問題として考えてみました。
もちろん同一サイズのインスタンスに全アプリケーションを詰め込むケースは少ないでしょうし、サブネット分離等々、アーキテクチャを考える上で考えなければならない点は多いです。
本当は複数インスタンスサイズを混ぜた構成(c4.2xlarge 3台、t2.micro 4台、みたいな)を算出したかったのですが、サイズの違う複数ビンでのパッキング方法がわからず、このような形になりました。
これは今後の課題にします。
もし詳しい方がおりましたら、教えて下さい。

参考

組合せ最適化を使おう
組合せ最適化 – 標準問題と実行方法
最適化におけるPython
ビンパッキング問題の解き方
Python言語によるビジネスアナリティクス 実務家のための最適化・統計解析・機械学習
https://github.com/PythonCharmers/OOSuite/blob/master/OpenOpt/openopt/examples/bpp_2.py

続きを読む

EC2 instance起動時にtagをつけるTagSpecifications

AWSCLIでEC2 instance起動時に同時にタグをつける方法としては、instance起動してinstance-idを取得しておいて、パイプでつないでtagをつけたり、スクリプトの中で後でタグ付けする方法があったと思います。
http://kurochan-note.hatenablog.jp/entry/2017/01/08/220155

AWSCLI EC2 Run-Instanceのなかに–tag-specificationsというoptionが入って、run-instancesの中でタグが作成できるようになりました。地味なアップデートかもしれませんが、結構うれしいです。

instanceの詳細はjsonに記述して、下記のように指定して実行します。

aws ec2 run-instances --cli-input-json file://instance.json

EC2は山ほど設定項目があるので、generate-cli-skeltonでフォーマットを出力して、必要な項目だけ入力して、不必要なものは消すとinstanceの詳細を記述したjsonの完成です。Gitにでも入れておきましょう。
http://docs.aws.amazon.com/cli/latest/userguide/generate-cli-skeleton.html

aws ec2 run-instances --generate-cli-skeleton

Instanceの設定詳細を記述したjsonサンプル

instance.json
{
    "ImageId": "<image-id>",
    "KeyName": "<my-key>",
    "SecurityGroupIds": [
        "<my-sgid>"
    ],
    "InstanceType": "<instance-type>",
    "BlockDeviceMappings": [
        {
            "VirtualName": "Root",
            "DeviceName": "/dev/sda1",
            "Ebs": {
                "VolumeSize": 100,
                "DeleteOnTermination": true,
                "VolumeType": "gp2"
            }
        }
    ],
    "Monitoring": {
        "Enabled": false
    },
    "SubnetId": "<subnet-id>",
    "DisableApiTermination": false,
    "IamInstanceProfile": {
        "Name": "<instance-iam-role>"
    },
    "TagSpecifications":[
        {
            "ResourceType": "instance",
            "Tags": [
              {
                "Key": "Name",
                "Value": "<server-name>"
              },
              {
                "Key": "ClusterName",
                "Value": "<cluster-name>"
              },
              {
                "Key": "Application",
                "Value": "<myapp>"
              },
              {
                "Key": "CostCenter",
                "Value": "<my-cost-center>"
              },
              {
                "Key": "Environment",
                "Value": "Test"
              },
              {
                "Key": "User",
                "Value": "<user-name>"
              }
            ]
        },
        {
          "ResourceType": "volume",
          "Tags": [
            {
              "Key": "Device",
              "Value": "<device-name>"
            },
{
              "Key": "CostCenter",
              "Value": "<my-cost-center>"
            },
            {
              "Key": "backup_key",
              "Value": "true"
            }
          ]
        }
    ]
}

続きを読む

Amazon Elasticsearch Service へ Embulk を使ってデータロード

はじめに

AWS ElasticSearch Serviceはフルマネージドで運用要らず、今のところ(2017/5/18)他の追随を許さ無い魅力があります(筆者はElastic社のElastic Cloudは使った事がありません)
Azureの場合、MarketPlaceからElastic-Stackが提供されて完全占有クラスターが自動構築可能です。GCPもblogにある通り、Azureとほぼ同じ。完全占有クラスターのメリット?がありそうな反面、ElasticClusterの運用/管理がtrade-offとしてつきまといます。

当初はAzureで個別クラスターを使っていましたがトラブルが続き、運用などはしたく無いのでAWSに浮気してみましたのでその記録とTipsをまとめます

環境

  • 既存の物を使い回しでAzureのVMにembulkインストール、データロード等の制御に使います
  • データは Azure Blobに保存
  • AWS ElasticSearch Service (ver5.1が選択できたのでこれ)
  • 図解
    Load

セットアップ

実行

以下の手順で実施

  • BlobにElasticSearchに投入したいログをUploadしておく
  • embulkから吸い出し、ElasticSearch Serviceへ投げ込み用のconfig.yml作成
in:
  type: azure_blob_storage
  account_name: <BLOB NAME>
  account_key: <BLOB KEY>
  container: <CONTAINER NAME>
  path_prefix: <PREFIX as you like>
  decoders:
    - {type: gzip}
  parser:
    charset: UTF-8
    newline: CRLF
    type: jsonl
    schema:

out:
  type: elasticsearch_using_url
  mode: normal
  nodes:
    - url: "<YOUR ElasticSearch Domain>.us-east-2.es.amazonaws.com:80"
  index: "sample"
  index_type: "sample"
  • 実行
$ embulk preview config.yml
$ embulk run config.yml -l warn -r resume_state_aws.yml &>> embulk_awses.log

確認

  • AWS consoleで確認
    Load OK

まとめ

  • ElasticSearchへの大量のデータロードにはembulkは最適な手段
  • AWS ElasticSearch Serviceでは 9200 portが使えない為、embulk pluginの選択に注意、http経由で実施するのがおすすめ

余談

  • およその費用比較
AWS Azure GCP
費用 \$250 – $300 程度 \$530 未確認
  • VirtulMachineのサイズ、データ量は1TB程度

    • AWS

      • EC2: t2.midium x3 , \$150
      • EBS: 1TB, \$100
      • データ通信料
    • Azure
      • VM: D2v2 , \$84.82 x6 = $505.44
      • Elastic-Stack構築時、VMサイズを選択可能だが、D1v2(default)では使い物にならなかった
      • Blob: 1TB , \$24
      • データ通信料
    • GCP
      • 未検証

続きを読む

EC2のボリューム(EBS)容量拡張方法検証 (AmazonLinux)

結論を3行で

検証

【遂に来た!】EBS でボリュームサイズを変更できるようになりました(ボリュームタイプ変更も) | Developers.IO を参考に、稼働中のインスタンスにアタッチ済みのボリュームのサイズを増やしてみます。

今回ボリュームを増やしたいインスタンスはこのような感じです。

インスタンス的には/dev/xvdaというところに30GBのボリュームがあります。

ec2-user@ip-172-31-10-224 ~ $  df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1       30G  3.8G   26G  13% /
devtmpfs        490M   56K  490M   1% /dev
tmpfs           499M     0  499M   0% /dev/shm

ec2-user@ip-172-31-10-224 ~ $  lsblk
NAME    MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
xvda    202:0    0  30G  0 disk
└─xvda1 202:1    0  30G  0 part /

ほとんど元記事のとおりですが以下のような感じです。

スクリーンショット_2017-05-18_11_30_15.png

Modify Volumeを押します

スクリーンショット 2017-05-18 11.30.31.png

今回は 30GB -> 100GBにします

スクリーンショット 2017-05-18 11.32.51.png

パフォーマンスが変更されるまで時間がかかるとのこと。。yesを押す。

スクリーンショット 2017-05-18 11.33.00.png

完了。

スクリーンショット 2017-05-18 11.34.08.png

ボリュームの状態は optimizing...0% という表示になりますが、もうこの状態で ディスクの拡張は終わっています。

スクリーンショット 2017-05-18 11.34.46.png

awscli的には $ aws ec2 describe-volumes-modifications と叩くと進捗が表示されます(引数なしでOK)

$ aws ec2 describe-volumes-modifications
{
    "VolumesModifications": [
        {
            "TargetSize": 100,
            "TargetVolumeType": "gp2",
            "ModificationState": "optimizing",
            "VolumeId": "vol-0e92fb2e26dfd9687",
            "TargetIops": 300,
            "StartTime": "2017-05-18T02:34:07.151Z",
            "Progress": 0,
            "OriginalVolumeType": "gp2",
            "OriginalIops": 100,
            "OriginalSize": 30
        }
    ]
}

"Progress": 0 ですが、lsblk を叩くともう反映されていることがわかります。

ec2-user@ip-172-31-3-117 ~ $  lsblk
NAME    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
xvda    202:0    0  100G  0 disk             # <- 100になってる
└─xvda1 202:1    0   30G  0 part /

次に resize2fs すればよいのですが、以下のような感じで怒られます。

resize2fs 1.42.12 (29-Aug-2014)
resize2fs: Device or resource busy while trying to open /dev/xvda
Couldn't find valid filesystem superblock.

今回はパーティションの設定がされているためと思われます。パーティションを利用している場合の設定はこちら。http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/storage_expand_partition.html
ただルートパーティションの場合は面倒そうなので、起動時に実行されるresize2fsに任せることにしました。

見たところAmazonLinuxの場合 /etc/cloud/cloud.cfg.d/00_defaults.cfg の中で resize2fs の記述があるので、再起動時に実行されるようです。

こうして、何も考えずにrebootすることにより、dfの結果が変わりました :tada:

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvda1       99G  9.1G   90G  10% /           # <- 99GBに増えてる
devtmpfs        490M   56K  490M   1% /dev
tmpfs           499M     0  499M   0% /dev/shm

続きを読む

AWS EBSのルートディスク拡張した際のサイズ拡張のやりかた

いつも忘れるのでメモっておく
環境はUbuntu14.04

AWSコンソール上

EBSボリュームの「アクション」⇒「Modify Volume」
指定のサイズに設定

対象インスタンス上

# root
sudo su -

# 認識されてるか確認
lsblk

# 現在のサイズ確認
df -hT

# サイズ拡張
growpart /dev/xvda 1
resize2fs /dev/xvda1

# サイズ確認
df -hT

続きを読む

EBSボリュームのサイズ変更をやってみる

環境

項目 設定
OS AmazonLinux (version 2017.03)
インスタンスタイプ t2.micro
ボリュームタイプ gp2
pythonバージョン Python 3.5.3 (pyenv)
AWS CLIバージョン aws-cli/1.11.82

その他詳細

a.拡張対象ディスクの初期状態
{
    "Volumes": [
        {
            "VolumeType": "gp2",
            "VolumeId": "vol-05c927a2a0afec131",
            "Iops": 100,
            "CreateTime": "2017-05-04T01:17:37.368Z",
            "State": "in-use",
            "Size": 10,
            "Encrypted": false,
            "AvailabilityZone": "ap-northeast-1a",
            "Attachments": [
                {
                    "VolumeId": "vol-05c927a2a0afec131",
                    "DeleteOnTermination": false,
                    "State": "attached",
                    "AttachTime": "2017-05-04T01:17:37.000Z",
                    "Device": "/dev/sdb",
                    "InstanceId": "i-074b8466302e6dc1a"
                }
            ],
            "SnapshotId": ""
        }
    ]
}
b.拡張対象ディスクの変更情報は無し
[root@ip-172-30-0-5 work]# aws ec2 describe-volumes-modifications --volume-id vol-05c927a2a0afec131 --region ap-northeast-1

An error occurred (InvalidVolumeModification.NotFound) when calling the DescribeVolumesModifications operation: Modification for volume 'vol-05c927a2a0afec131' does not exist.
c.OSから見た初期状態
[root@ip-172-30-0-5 ~]# lsblk /dev/xvdb
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
xvdb 202:16   0  10G  0 disk /mnt
[root@ip-172-30-0-5 ~]# df -h /mnt
Filesystem      Size  Used Avail Use% Mounted on
/dev/xvdb       9.8G   23M  9.2G   1% /mnt

手順

1.拡張対象のディスクを10GiB→11GiBに拡張する

コマンド
aws ec2 modify-volume --volume-id vol-05c927a2a0afec131 --size 11 --region ap-northeast-1
レスポンス
{
    "VolumeModification": {
        "TargetVolumeType": "gp2",
        "OriginalSize": 10,
        "StartTime": "2017-05-04T05:32:52.500Z",
        "TargetIops": 100,
        "TargetSize": 11,
        "OriginalVolumeType": "gp2",
        "OriginalIops": 100,
        "VolumeId": "vol-05c927a2a0afec131",
        "ModificationState": "modifying",
        "Progress": 0
    }
}

2.変更の進行状況をチェック

コマンド
aws ec2 describe-volumes-modifications --volume-id vol-05c927a2a0afec131 --region ap-northeast-1
変更リクエスト発行から間髪入れずに発行した時のレスポンス
{
    "VolumesModifications": [
        {
            "OriginalSize": 10,
            "OriginalVolumeType": "gp2",
            "TargetIops": 100,
            "TargetSize": 11,
            "StartTime": "2017-05-04T05:32:52.500Z",
            "OriginalIops": 100,
            "ModificationState": "modifying",
            "TargetVolumeType": "gp2",
            "Progress": 0,
            "VolumeId": "vol-05c927a2a0afec131"
        }
    ]
}
変更リクエスト発行からちょっと経ってから発行した時のレスポンス
{
    "VolumesModifications": [
        {
            "TargetSize": 11,
            "TargetVolumeType": "gp2",
            "Progress": 2,
            "OriginalVolumeType": "gp2",
            "VolumeId": "vol-05c927a2a0afec131",
            "OriginalSize": 10,
            "StartTime": "2017-05-04T05:32:52.500Z",
            "ModificationState": "optimizing",
            "OriginalIops": 100,
            "TargetIops": 100
        }
    ]
}

状態がoptimizingに進行。{"Progress":"2"} の部分が進捗状況。完了するとこうなる。

拡張完了後
{
    "VolumesModifications": [
        {
            "EndTime": "2017-05-04T05:38:04.434Z",
            "TargetSize": 11,
            "TargetIops": 100,
            "ModificationState": "completed",
            "StartTime": "2017-05-04T05:32:52.500Z",
            "TargetVolumeType": "gp2",
            "OriginalVolumeType": "gp2",
            "VolumeId": "vol-05c927a2a0afec131",
            "Progress": 100,
            "OriginalSize": 10,
            "OriginalIops": 100
        }
    ]
}

1GiB増やすのに05:12って結構かかるのね。
進捗状況は直前まで2%だったので、相変わらず適当なパーセントな模様。

3.OSから見た状態をチェック

コマンド
lsblk /dev/xvdb
[root@ip-172-30-0-5 work]# lsblk /dev/xvdb
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
xvdb 202:16   0  11G  0 disk /mnt

ちゃんと拡張されました。

回数制限があった気がするので、何回かやってみようとしたところ…

[root@ip-172-30-0-5 work]# aws ec2 modify-volume --volume-id vol-05c927a2a0afec131 --size 12 --region ap-northeast-1

An error occurred (VolumeModificationRateExceeded) when calling the ModifyVolume operation: You've reached the maximum modification rate per volume limit. Wait at least 6 hours between modifications per EBS volume.

あ、そういう制限だったのか。ドキュメントにもあった。

APIReference ModifyVolume

If you reach the maximum volume modification rate per volume limit, you will need to wait at least six hours before applying further modifications to the affected EBS volume.

今度気が向いたら拡張中の性能を測ってみよう。

続きを読む

【AWS】OpsWorks スタック

はじめに

タダです。
AWS認定資格の試験勉強のためにCloudFormationの情報をまとめた自分用メモになります。
あくまで個人用のメモになるので、その点はご了承ください。
※違う内容書いているなどありましたらご指摘いただけると幸いです。
※随時アップデートがあれば更新していきます。
※本記事では、OpsWorks スタック中心のまとめになります。

サービス概要

  • OpsWorksはChefを使ったAWSリソース(EC2、ELB、RDSなど)やEC2上のアプリケーションの設定・管理を行うためのサービス
  • Chefサーバーは不要で、OpsWorksスタックは、インスタンスのヘルスチェックをモニタリングし、自動復旧および Auto Scaling を使用して、必要な場合に新しいインスタンスをプロビジョニングする
  • Chefのcookbookレシピを使って、インフラの管理を自動化、アプリケーションの継続的なインストール、構成、管理、デプロイ、スケールが可能なのがChef Automate
    • Chefサーバありきだが、管理はAWS

OpsWorksエージェント

  • OpsWorksスタックで必要

    • OpsWorksの一連のコマンドを取得し、エージェントがChef Clientのローカルモードでレシピを実行

利用メリット

アプリケーションのモデル化とサポート
管理作業を自動化

CloudFormation/Elastic Beastalkとの違い

  • OpsWorksは、DevOps環境を提供することを目的におき、デプロイ、モニタリング、自動スケーリング、自動化の主要なアクティビティに対して統一された設定管理を行う
  • CloudFormationはAWSリソースのプロビジョニングと管理をJSON/YAMLで行うことを目的とする
  • Elastic BeastalkはJava、.NET、PHP、Node.js、Python、Ruby、Go、Docker で開発されたウェブアプリケーションとウェブサービスをデプロイおよびスケーリングする

制限

デフォルトでは、最大40スタックを作成できる
最大40のレイヤー、最大40のインスタンス、最大40のアプリケーションを保持できる
 

専門用語

  • スタック

    • OpsWorksの管理対象をまとめたコンポーネントで、属する全員インスタンスの構成を管理する
  • レイヤー
    • 1つ以上の Layer を追加することにより、スタックのコンポーネントを定義する
    • レイヤーは、アプリケーションへのサービス提供やデータベースサーバーのホストのような特定の目的を果たす一連のEC2インスタンスを表す
  • インスタンス
    • インスタンスのスケーリングタイプは3つある

      • 24/7インスタンス(常時稼働)
      • load-basedインスタンス
        • 負荷に対してサーバを起動することができる
        • メトリックスの閾値は次のものを定義し、インスタンスの増減をコントールできる
          • [Average CPU] – Layer の平均 CPU 使用率 (合計に対する割合)
          • [Average memory] – Layer の平均メモリ使用率 (合計に対する割合)
          • [Average load] – Layer の平均負荷
      • time-basedインスタンス
        • 時間ベースのスケーリングにより指定したスケジュールでインスタンスを起動、停止できる
        • 特定の時間または特定の曜日にレイヤーによりオンラインにされるインスタンス数を制御できる
  • App
    • アプリケーショサーバにデプロイするアプリケーション
  • レシピ
    • Chefレシピを実行して、アプリケーションの設定、アプリケーションのデプロイ、スクリプトの実行などを行う

スタックコマンド

スタック全体の構成を変更・管理するためのコマンドで以下のようなものがある
実行方法はAWSマネジメントコンソールやCLI、SDKなど

  • Update Custom Cookbook

    • リポジトリにある更新されたCookbookをそれぞれのインスタンスに展開する
  • Execute Recipes
    • 指定したレシピを指定したインスタンス上で実行する
  • Setup
    • Setupのレシピを実行する
  • Configure
    • Configureのレシピを実行する
  • Upgrade Operationg System
    • (Linuxのみ)Amazon Linuxを最新バージョンにアップグレードする

ライフサイクル

OpsWorksのインスタンスで自動的に行う処理をさす

  • Setup : 新しいインスタンスが正常にブートした後に発生する

    • ex: ロードバランサーをインストール、アプリケーションサーバをインストール、データベースをインストール
  • Configure : インスタンスがオンライン状態に移行したときとオンライン状態から移行した時にスタックのすべてのインスタンスで発生する
    • ex: アプリケーションサーバのIPをアップデート、DB接続先をアップデートして再起動、アプリケーションサーバのIPのACLをアップデート
  • Deploy : ユーザーがアプリケーションをデプロイする時に発生する
    • ex:アプリケーションコードをアップデートして再起動
  • Undeploy : アプリケーションを削除する時に発生する
    • ex:アプリケーションを削除して再起動
  • Shutdown : インスタンスの終了
    • コネクションをDrainする、ログを保存、スナップショットの保存

Opsworksと他サービスとの連携

モニタリング

スタックは次の方法で監視可能

  • CloudWatchによるスタックのインスタンスごとに詳細モニタリング
  • CloudTrailによるAPI監視
  • CloudWatch Logsでスタックのシステム・アプリケーション・カスタムログを監視する

セキュリティおよびアクセス許可

  • VPC内に展開可能
  • AWSリソースにアクセスするためのACLやインスタンスへの接続管理はIAM(ユーザー、許可、ロール)で行う

参考

更新日時

  • 2017/05/01 初回投稿

続きを読む

【AWS】CloudFormation

はじめに

タダです。

AWS認定資格の試験勉強のためにCloudFormationの情報をまとめた自分用メモになります。
あくまで個人用のメモになるので、その点はご了承ください。
※違う内容書いているなどありましたらご指摘いただけると幸いです。
※随時アップデートがあれば更新していきます。

CloudFormationとは

AWSリソースを作成したり、管理するのが役立つツールです。JSONやYAML形式でリソース定義できる

CloudFormationを使う主なメリットは以下の通り

  • AWSリソース管理が簡略化
  • インフラリソースを素早く展開/複製
  • インフラリソースの制御や変更も簡単

Elatic Beanstalkとの違い

  • Elatic Beanstalkはアプリを簡単にデプロイ及び実行できる環境を提供する

    • アプリのライフサイクルを管理するためのサービス
  • CloudFormationはAWSリソースの作成をサポートする
    • Elatic Beanstalkもサポートしている

CloudFormationの概念

  • テンプレート

    • YAMLまたはJSON形式のテキストファイルでAWSリソース作成のための設計図

      • 5種類の要素で構成される

        • テンプレートパラメータのオプションリスト
        • 出力値のオプションリスト
        • 静的な設定値を見るのに使用するデータテーブルのオプションリスト
        • AWS リソースとそれらの設定値のリスト
        • テンプレートファイルフォーマットのバージョン番号
    • 具体的には以下のようなものがテンプレート例
{
  "AWSTemplateFormatVersion" : "2010-09-09",
  "Description" : "A sample template",
  "Resources" : {
    "MyEC2Instance" : {
      "Type" : "AWS::EC2::Instance",
      "Properties" : {
        "ImageId" : "ami-2f726546",
        "InstanceType" : "t1.micro",
        "KeyName" : "testkey",
        "BlockDeviceMappings" : [
          {
            "DeviceName" : "/dev/sdm",
            "Ebs" : {
              "VolumeType" : "io1",
              "Iops" : "200",
              "DeleteOnTermination" : "false",
              "VolumeSize" : "20"
            }
          }
        ]
      }
    }
  }
}
  • スタック

    • CloudFormationの関連リソースは、スタックと呼ばれます。これを作成、変更、更新することでリソース制御を行う
    • スタックの更新には2つの方式がある
      • 直接更新(in place)と変更セットの作成(blue-green)と実行
  • 変更セット
    • スタックの更新をおこなう時の概要が変更セットと呼び、影響度を確認するためのスタック

変更セットについて

変更セットの作成

更新元のスタックをもとに変更セットを作成します
Cloudformation -> [Actions],[Create Change Set For Current Stack]を選択
その他のパラメーターは、スタックを作成するのと同じ操作で行う
CLIだと、以下のように実行する

aws cloudformation create-change-set --stack-name arn:aws:cloudformation:us-east-1:123456789012:stack/SampleStack/1a2345b6-0000-00a0-a123-00abc0abc000
--change-set-name SampleChangeSet --use-previous-template --parameters ParameterKey="InstanceType",UsePreviousValue=true ParameterKey="KeyPairName",UsePreviousValue=true ParameterKey="Purpose",ParameterValue="production"

変更セットの実行

変更セットに記述された変更をスタックに加えるには、変更セットを実行する
※変更セットを実行するとスタックに関連付けられた変更セットは削除される点は注意。
CLIだと、以下のように実行する

aws cloudformation execute-change-set --change-set-name arn:aws:cloudformation:us-east-1:123456789012:changeSet/SampleChangeSet/1a2345b6-0000-00a0-a123-00abc0abc000

CloudFormationのベストプラクティス

  • スタックは共通リソースの所有者でグルーピング

    • リソース利用の制限は行わないようにする
  • クロススタック参照で共有リソースをエクスポート
    • ネットワークリソース系
  • アクセス制限はIAMで
  • スタックの制限は200なので、注意
  • テンプレートの再利用
  • 他のスタックにネストされたテンプレートの参照
  • テンプレートに認証情報を埋め込まない
    • 埋め込んでもNoEchoプロパティを使う
  • cfn-init ヘルパースクリプトと AWS::CloudFormation::Init を使ってEC2にソフトウェアをインストールする
  • ヘルパースクリプトは常に最新のものを使う
  • テンプレートを使用する前に検証する
    • aws cloudformation validate-template
  • CloudFormationで全てのリソースを管理する
  • スタックを更新する前に変更セットを作成する
  • CloudTrailとロギング
  • コードの確認とリビジョン管理
  • Elastic Compute Cloudのパッケージは最新化する

CloudFormationのテンプレート

JSONかYAMLのどちらかでテンプレートを作成します。

テンプレートのセクション

  • Format Version(任意)

    • テンプレートバージョンを指定する
  • Desription(任意)
    • 説明文
  • Metadata(任意)
    • テンプレートに関する追加情報を提供するオブジェクト
  • Parameters(任意)
    • テンプレートに渡すことができる値を指定する

      • データ型、デフォルト値、最大最小値など型が設定可能
    • テンプレートのResources、Outputsセクションのパラメーターを参照できる
  • Mappings(任意)
    • 条件パラメーター値の指定に使用できる、キーと関連する値のマッピング(検索テーブルに類似したもの)
  • Conditions(任意)
    • 特定のリソースが作成されるかどうかや、スタックの作成または更新中に特定のリソースプロパティが値を割り当てられるかどうかを制御する条件を定義する
  • Transform(任意)
    • サーバレスアプリケーションの場合、使用するAWS SAMのバージョンを指定する
  • Resources(必須)
    • スタックで作成するリソースとそのプロパティを指定する

      • EC2やELBやRDSなど起動するサービスを指定し、リソース毎に決められたプロパティを指定する
  • Outputs(任意)
    • スタックのプロパティを確認すると返される値について説明する
  • Function
    • パラメータの参照やMapの参照などの際はFunctionを使う(Parameterの取得に利用するRef関数もFunctionの一つ)

      • Ref: パラメータの参照
      • Fn::Base64 : 文字列をBase64でエンコードする
      • Fn::FindInMap : Mapから値を取り出す
      • Fn::GetAtt :リソースに付随する値を取得する
      • Fn::GetAZs : 指定したリージョンのAZを取得する
  • 疑似パラメータ参照
    • 予め定義されたパラメータ群をRef関数で参照できる

      • AWS::Region,AWS::StackId,AWS::StackNameなど

スタックの出力値のエクスポート

  • スタック間で情報を共有するにはスタックの出力値をエクスポートする

    • 同じAWSアカウントとリージョンの他のスタックは、エクスポートされた値をインポートできる
    • WebサーバのサブネットやSecurityGroup IDをエクスポートする単一ネットワーキングスタックがあったとして、Webサーバのあるスタックは、それらのネットワーキングしリソースをインポートできる

テンプレート作成ツール

  • CloudFormer

    • 構築済みの環境からテンプレートを作成するWebツール
  • CloudFormation Designer
    • テンプレート内のリソースを可視化
  • Hava
  • Cloudcraft

CloudFormationの運用

  • 個別テンプレート、1スタック
  • 個別テンプレート、個別スタック
  • スタック間の連携

CloudFormationのリソースについて

リソース属性

CreationPolicy

  • CloudFormationが指定数の成功シグナルを受信するかまたはタイムアウト期間が超過するまでは、ステータスが作成完了にならないようにする

    • AutoScalingCreationPolicy
    • ResourceSignal

DeletionPolicy

  • スタックが削除された際にリソースを保持または (場合によっては) バックアップできる

    • Retain

      • スタック削除したくない場合は指定する

DependsOn

  • 特定のリソースが他のリソースに続けて作成されるように指定できる

UpdatePolicy属性

  • CloudFormationがAWS::AutoScaling::AutoScalingGroup リソースに対する更新を処理する方法を指定できる

    • AutoScalingReplacingUpdate

      • AutoScaling グループの置き換え更新を処理する方法を指定する時に使う
    • AutoScalingRollingUpdate
      • ローリング更新を使う場合指定する
    • AutoScalingScheduledAction
      • スケジュールされたアクションが関連付けられているAutoScalingグループを含むスタックを更新する時に使う

CloudFormationヘルパースクリプト

スタック作成の時にEC2インスタンスでソフトウェアをインストールしたりサービスを開始したりするために使用できるPythonヘルパースクリプトのセットがある

  • cfn-init

    • リソースメタデータの取得と解釈、パッケージのインストール、ファイルの作成およびサービスの開始で使用される
  • cfn-signal
    • スタック内の他のリソースと準備できたアプリケーションを同期できる
  • cfn-getmetadata
    • リソースに定義されたすべてのメタデータ、またはリソースメタデータの特定のキーやサブツリーへのパスを簡単に取得できる
  • cfn-hup
    • メタデータへの更新を確認し、変更が検出された時にカスタムフックを実行するデーモン

参考情報

サービス概要
よくある質問
ドキュメント
SlideShare

更新日時

  • 2017/04/30 初回投稿

続きを読む