share facebook facebook2 twitter menu hatena pocket slack

2015.01.09 FRI

ElastiCache のスナップショットを取得するコマンドラインツールを作ったメモ(おれん(俺の) ElastiCache Snapshot)

川原 洋平

WRITTEN BY川原 洋平

ども、cloudpackかっぱ (@inokara) です。(福岡県出身ではありません)

はじめに

ElastiCache for Redis を触る機会に恵まれて、検証中 Snapshot を API 経由で取る際にムラムラっとしたのでエイやって作ってみました。せっかくなんでコマンドラインツールっぽくしたかったのでThorもソーっと使って RubyGems に公開してみました。

尚、このツールを作るにあたっていくつか勉強になったことがありますので合わせて書いていきたいと思います。(記事中の「☆」印がポイントです…もちろん、ドキュメントに書かれていることです。)

おれんコマンドツールくさ

ギットハヴとルビィジェムズ

「おれん」は博多弁で「俺の」という意味です。

機能

詳細は README.md を御覧下さい

  • スナップショット一覧を取得する
  • スナップショットを作成する(クラスタ内で最も最近作成されたノードで且つレプリカノードから作成)
  • スナップショットを削除する

スナップショット一覧を取得する

以下のように実行します。

bundle exec bin/elasticache_snapshot list

以下のように出力されます。

+---------------------+-------------------------+
| SNAPSHOT Name       | SNAPSHOT Create time    |
+---------------------+-------------------------+
| snapshot-1420457086 | 2015-01-05 11:25:01 UTC |
| snapshot-1420457295 | 2015-01-05 11:28:31 UTC |
| snapshot-1420461070 | 2015-01-05 12:31:21 UTC |
+---------------------+-------------------------+

テーブル表示は自己満足です。

スナップショットを作成する

以下のように実行します。

bundle exec bin/elasticache_snapshot create

スナップショット名を指定することも可能ですが、指定しない場合には snapshot-#{UNIX 時間} となります。(☆1)

スナップショットはクラスタ内で最も作成日付が新しいノードで且つレプリカノードから取得します。(※このあたりが十分に動作確認が出来ていない部分ですので引続き手を入れていきます)尚、これは、スナップショット作成時のマスターノードへの負荷軽減を目的としています。(☆2)

実行すると以下のようにスナップショット名とどのノードから取得したかが表示されます。(☆3)

% bundle exec bin/elasticache_snapshot create hoge-20150105
Create hoge-20150105 from kappa-test-003...

一覧を確認すると以下のようにスナップショット一覧に名を連ねます。

+---------------------+-------------------------+
| SNAPSHOT Name       | SNAPSHOT Create time    |
+---------------------+-------------------------+
| hoge-20150105       | 2015-01-05 16:34:18 UTC |
| snapshot-1420455477 | 2015-01-05 10:58:07 UTC |
| snapshot-1420455721 | 2015-01-05 11:02:11 UTC |
| snapshot-1420475287 | 2015-01-05 16:28:20 UTC |

スナップショットを削除する

bundle exec bin/elasticache_snapshot delete xxxx-xxxx

xxxx-xxxx には削除したいスナップショット名を指定します。もちろん、スナップショット名を指定し忘れると…

ERROR: "elasticache_snapshot delete" was called with no arguments
Usage: "elasticache_snapshot delete SNAPSHOT_NAME"

Thor にソーッと叱られます。

たったこんだけの機能ですが…

ダメ出しお願い致します。

目標と言う名の todo

  • ちゃんとしたエラー処理を入れる
  • 出来るだけ綺麗なコードにする
  • クラスタ及びノードの一覧の取得が出来るようにする
  • スナップショットを取得するノードを任意で指定出来るようにする

おれんメモ

参考

コマンドラインツールを作る上で学んだこと

  • スナップショット名(☆1)
  • スナップショット対象ノードの選定とスナップショット取得時のステータス(☆2 ☆3)
  • describe snapshots に含まれる情報
  • Thor でコマンドラインツールを作る方法(初歩的な使い方)

スナップショット名

スナップショットを取得する際に適当な名前だと怒られてしまいます。例えば、以下のように2015010601 のような日付の羅列の場合には…

aws elasticache create-snapshot --cache-cluster-id kappa-test-003 --snapshot-name 2015010601

以下のようなエラーとなります。

A client error (InvalidParameterValue) occurred when calling the CreateSnapshot operation: The parameter SnapshotIdentifier is not a valid identifier. Identifiers must begin with a letter; must contain only ASCII letters, digits, and hyphens; and must not end with a hyphen or contain two consecutive hyphens.

ざっくり訳すと…

  • ASCII 文字と数字とハイフンを含めましょう
  • ハイフンで終わるのと連続したハイフンはダメよダメダメ

とのことです。

スナップショット対象ノードの選定とスナップショット取得時のステータス

今回、スナップショット対応ノードの選定に際しては以下のような条件を想定しました。(この条件が一般的かは定かではありませんが…)

  • レプリカノードであること
  • クラスタ内で最も若い(作成時間が最新であること)

この条件でノードを抽出するにあたっては describe_cache_clusters に含まれる :cache_cluster_create_time を利用して並べ替えを行っています。(※以下、抜粋)

...
(snip)
      elc.describe_cache_clusters.cache_clusters.each do |i|
        cluster << { :cluster_id => i.cache_cluster_id, :create_time => i.cache_cluster_create_time, :cache_cluster_status => i.cache_cluster_status }
      end

      puts cluster
      sorted = cluster.sort {|x, y| y[:create_time] <=> x[:create_time]}
(snip)
...

エイヤ!で考えたロジックなので色々と不安でツメが必要かなと思っていますが、SDK のレスポンスに色々と情報が盛られているのでこれらを組み合わせることが出来そうです。

また、スナップショット作成を行った場合にノード(cluster_id)のステータスは以下のようなレスポンスが得られます

{:cluster_id=>"kappa-test-003", :create_time=>2015-01-05 04:27:10 UTC, :cache_cluster_status=>"snapshotting"}

上記は SDK のレスポンスから必要な部分を抜き出して配列に突っ込んだものですので実際のレスポンスとは異なりますが、スナップショット取得中のノード(cluster_id)の :cache_cluster_statussnapshotting というステータスとなります。この snapshotting の状態である場合にはスナップショットを取得することは出来なくなります。尚、:cache_cluster_status はクラスタの状態により以下のような値を返却します。

  • available
  • creating
  • deleted
  • deleting
  • incompatible-network
  • modifying
  • rebooting cache cluster nodes
  • restore-failed
  • snapshotting

若干、解り辛いですがこちらに記載されています。

describe snapshots に含まれる情報

describe snapshots に含まれる情報は以下のような情報が含まれます。(読みやすくする為に JSON で出力させました)

{
  "num_cache_nodes": 1,
  "snapshot_window": "14:00-15:00",
  "cache_subnet_group_name": "default",
  "cache_cluster_create_time": "2015-01-05 04:27:10 UTC",
  "preferred_availability_zone": "ap-northeast-1a",
  "engine": "redis",
  "cache_node_type": "cache.m1.small",
  "cache_parameter_group_name": "test",
  "port": 6379,
  "cache_cluster_id": "kappa-test-003",
  "node_snapshots": [
    {
      "cache_size": "19 MB",
      "cache_node_id": "0001",
      "cache_node_create_time": "2015-01-05 04:27:10 UTC",
      "snapshot_create_time": "2015-01-05 16:28:20 UTC"
    }
  ],
  "engine_version": "2.8.6",
  "snapshot_source": "manual",
  "auto_minor_version_upgrade": true,
  "preferred_maintenance_window": "thu:15:30-thu:16:30",
  "snapshot_name": "snapshot-1420475287",
  "vpc_id": "vpc-xxxxxxxxxx",
  "snapshot_retention_limit": 0,
  "snapshot_status": "available"
}

スナップショット作成日は取得したノードの情報などがレスポンスとして返ってきています…。

ということで、ほんのちょっと API に触れてみた分際で恐縮ですが API って楽しいですな。

Thor でコマンドラインツールを作る方法(初歩的な使い方)

Thor については以下の記事などを参考にさせて頂きました。

以下のように thorrequire して Thor クラスを継承したおれん(俺の)クラスを作りメソッドを書いていけばメソッド自体がコマンドになるという筋書きです。

require 'thor'
class HagenoCLI < Thor
  desc "zura usage", "zura desc"
  def zura(name)
    puts "zura #{name}"
  end
end

HagenoCLI.start(ARGV)

引数ナシで実行すると以下のように…

% ruby zura.rb
Commands:
  zura.rb help [COMMAND]  # Describe available commands or one specific command
  zura.rb zura usage      # zura desc

コマンド zura を付けて実行すると…

% ruby zura.rb zura
ERROR: "zura.rb zura" was called with no arguments
Usage: "zura.rb zura usage"

コマンド zura に引数を付けて実行すると…

% ruby zura.rb zura de_fusafusa
zura de_fusafusa

上記のように zura コマンドの引数 de_fusafusa を出力しました。

超初歩的な Thor の使い方を書きましたが、普段から利用している UNIX コマンドのような --foo 又は -f のような指定も可能ですし、デフォルト値なども定義出来るようなのでちょっとしたコマンドラインツールを作る際には是非覚えておきたいツール!、ソー(そう)、ソーれが(それが)、Thor(ダジャレ三連発)。ということで詳細は上記の参考記事やオフィシャルサイト を御覧ください。

ということで…

ちょっとしたツールを作ることで色々と勉強になりましたが、Redis っぽい側面については触れられていないので引続き触れていきたいと思います。尚、紹介したツールは引続き手を入れていきたいなと思います!

元記事はこちらです。
ElastiCache のスナップショットを取得するコマンドラインツールを作ったメモ(おれん(俺の) ElastiCache Snapshot)