ようへいの日々精進XP

よかろうもん

AutoScaling Group のパラメータをいじるコマンドラインツール asg を更新しました

ti;dr

業務に asg を導入しようと思っていたら, 足りない機能があったので追加実装したのでメモ. まさに, 業務ドリブン OSS 開発.

github.com

バージョンは 0.0.6 です.

追加要件

1. 稼働中のインスタンス台数 + N 台を追加したい

一時的にスケーリンググループ内のインスタンス台数を N 台増やしたいという要件が発生しました.

asg には --desired オプションがあり, --desired=3 を指定して実行すると, スケーリンググループ内のインスタンスを 3 台に調整します.

$ asg --group=my-autoscaing-group --desired=3

この --desired オプションはスケーリンググループ内のインスタンス数を指定した数に調整するオプションであり, 例えば, 4 台で稼働しているスケーリンググループ内に対して, --desired=3 を指定すると 3 台に台数が減ることになります.

[ EC2 ] [ EC2 ] [ EC2 ] [ EC2 ]
    ↓
    ↓ asg --group=my-autoscaing-group --desired=3
    ↓
[ EC2 ] [ EC2 ] [ EC2 ]

ところが, 単純にインスタンスの台数を増やしたい場合, 現在稼働しているインスタンスの台数が解らないと --desired オプションを使ってインスタンスの数を調整することは出来ません.

( EC2 ) ( EC2 ) ( EC2 ) ※  EC2 が何台起動しているのか解らない...
    ↓
    ↓ 2 台追加したいんだけど...
    ↓ asg --group=my-autoscaing-group --desired=???
    ↓
( EC2 ) ( EC2 ) ( EC2 )  [ EC2 ] [ EC2 ]

バッチ処理等で, 自動的に台数を増やしたい場合等, 現在稼働しているインスタンスの台数を取得してから --desired オプションを利用してインスタンスを増やすという処理を書かなければいけない... ということで, --append オプションを追加しました.

AutoScaling Group my-autoscaing-groupインスタンスを 2 台追加したい場合, 以下のように実行します.

$ asg --group=my-autoscaing-group --append=2

実行すると, 現時点のインスタンス台数をチェックして, --append で指定した値を加算して内部的に --desired オプションに渡してインスタンスの台数を調整します.

2. スケーリンググループにインスタンスの追加が完了するまで待機する

スケーリンググループ内のインスタンス台数が Desired Capacity の値と同値になるまで待機するオプションを追加しました.

$ asg --group=my-autoscaing-group --wait=60

--wait オプションには秒数を指定します. 指定した秒数待機します. 待機している間, 以下のように出力されます.

$ asg --group=my-autoscaing-group -wait=60
Waiting...59
  Desired Capacity : 0
  Instances        : 1

状態の変化を待機する場合, 以下のように WaitUntilGroupInService のような関数がちゃんと用意されています.

docs.aws.amazon.com

しかし, 今回はこの関数が自分の要件にあっているのか判らず, 且つ, 自分の実装力が足りないので, 今回は利用しておらず, DescribeAutoScalingGroups をぐるぐる回して Desired Capacity の値とスケーリンググループ内のインスタンス台数を比較しています.

...
        waitTime, _ := strconv.Atoi(*argWait)
        writer := uilive.New()
        writer.Start()
        for i := 0; i < waitTime; i++ {
            asgGroups = getGroups(*argGroup)
            _, _, desired, instances := getDetectedSize(asgGroups)
            fmt.Fprintf(writer, "Waiting...%d\n  Desired Capacity : %d\n  Instances        : %d\n", i, desired, instances)
            if int(desired) == instances {
                fmt.Fprintln(writer, "Launched the specified number of instances.")
                writer.Stop()
                os.Exit(0)
            }
            time.Sleep(time.Second * 1)
        }
        fmt.Println("Wait time out!")
        os.Exit(1)
...

ここで, ちょっとした工夫で gosuri/uilive を利用して待機中の出力をループごとに書き換えるようにしています. 実際に以下のように出力されてます. これは, CircleCI 等の環境で実行結果の出力で画面が一杯にならないようにしたいという意図があります.

f:id:inokara:20200627202714p:plain

ちなみに, gosuri/uilive は以下のようにプログレスバーも簡単に実装出来るので, 今後, コマンドラインツールを作る際には是非利用したいなあと考えています.

https://github.com/gosuri/uilive/blob/master/doc/example.gif?raw=true

以上

この記事を書きながら, もう少し待機系の処理をちゃんと実装した方が良さそうな気がしてきました.

以上, もし, よろしければ asg をお試し頂けると幸いです.