ようへいの日々精進XP

よかろうもん

EC2 イメージ (AMI) を操作するツール (amiCtrl) を作って公開していましたが, 最近, 大幅にバージョンアップしたので自慢させてください

tl;dr

EC2 インスタンスのマシンイメージ (以後, AMI) を操作するツール (https://github.com/oreno-tools/amiCtrl, 以後 amiCtrl) を前職で作って利用していたのですが, 色々と AMI を弄ることが多くなったので amiCtrl を大幅にバージョンアップして利用していますので紹介させて頂きます.

github.com

そして, この記事は YAMAP エンジニア Advent Calendar 2019 の六日目の記事になる予定です.

qiita.com

amiCtrl に出来ること

amiCtrl は以下のような AMI に纏わる作業を 1 コマンドで実行出来るようになっています.

  • 指定した EC2 インスタンスの AMI を作成
  • 指定した AMI の情報を取得
  • 指定した AMI の削除
  • 指定したリージョンの AMI 一覧を取得

実際に動かしてみると, 以下のような感じになります.

# AMI 作成
$ ./amiCtrl -instance=i-18173987 -name=suzuki-ami-desu -create
+-----------------+--------------+-----------+-------------+
|    AMI NAME     |    AMI ID    |   STATE   | SNAPSHOT ID |
+-----------------+--------------+-----------+-------------+
| suzuki-ami-desu | ami-00385acd | available | snap-0c1cf6 |
+-----------------+--------------+-----------+-------------+

# AMI 情報取得
$ ./amiCtrl -ami=ami-00385acd # -ami オプションを指定しない場合, 所有している AMI の一覧が表示されます
+-----------------+--------------+-----------+-------------+
|    AMI NAME     |    AMI ID    |   STATE   | SNAPSHOT ID |
+-----------------+--------------+-----------+-------------+
| suzuki-ami-desu | ami-00385acd | available | snap-0c1cf6 |
+-----------------+--------------+-----------+-------------+

# AMI 削除
$ ./amiCtrl -ami=ami-00385acd -delete
+-----------------+--------------+-----------+-------------+
|    AMI NAME     |    AMI ID    |   STATE   | SNAPSHOT ID |
+-----------------+--------------+-----------+-------------+
| suzuki-ami-desu | ami-00385acd | available | snap-0c1cf6 |
+-----------------+--------------+-----------+-------------+
上記の AMI を削除しますか?(y/n): y
AMI を削除します...
AMI を削除しました.

シンプルにこれだけのことしか出来ないコマンドラインツールです.

今回, amiCtrl に追加した機能

今回 AMI の作成を自動化するにあたり, 自動的に作成した AMI のから古い AMI を自動的に削除する必要がありましたので, 以下のような機能追加 (オプション追加) 及び機能改善 (速度改善) を行いました.

  1. AMI 名の一部を指定して AMI 情報を取得出来る --prefix オプションを追加
  2. 作成日 (CreationDate) をチェックして古い AMI を検出する --days オプションを追加 (--prefix オプションと併用)
  3. 作成日 (CreationDate) をチェックして最新の AMI を検出する --latest オプションを追加 (--prefix オプションと併用)
  4. AMI に紐づく Snapshot ID 取得の高速化
  5. AMI 一覧の取得において, CreationDate が古い順に一覧を取得する --sort-by-creation オプションを追加

今回, 特に自慢したいのは, AMI に紐付いている Snapshot ID 取得の高速化です. 過去のバージョンでは AMI ID をキーにして describe-snapshots を実行して Snapshot ID を取得していましたが, 今回のバージョンからは describe-images 内に含まれている Snapshot ID を取得する実装に変更しています. これにより, AWSAPI を叩く回数を大幅に減らすことで Snapshot ID 取得が高速化され, 全体的な処理速度向上につながっています.

amiCtrl の様子

以下は amiCtrl を動かしている様子です.

f:id:inokara:20191205231918g:plain

AMI の一覧を取得, AMI の一覧を AMI が作成された順番で出力, AMI を AMI ID を指定して削除しようとしている様子です.

落ち穂拾い

Go で作ったコマンドラインツールのテスト

amiCtrl は一応 Golang で実装されています. また, 自分の Golang 力が無いのでユニットテストはありませんが, 一応, インテグレーションテスト的なものは用意しています.

インテグレーションテストは moto_server という AWS のモックサーバーを起動してモックサーバーに対して amiCtrl を実行して結果をパースするテストを行っています.

テストの実行自体は Docker コンテナをガチャガチャして docker-compose を介して, 以下のようにテストを実行します.

$ docker-compose exec -T amictrl_local make test
=== RUN   TestVersionFlag
--- PASS: TestVersionFlag (2.38s)
=== RUN   TestStdoutList
--- PASS: TestStdoutList (3.65s)
=== RUN   TestStdoutCreate
--- PASS: TestStdoutCreate (2.96s)
=== RUN   TestStdoutCreateError
--- PASS: TestStdoutCreateError (2.79s)
=== RUN   TestStdoutDelete
--- PASS: TestStdoutDelete (3.34s)
=== RUN   TestStdoutDeleteError
--- PASS: TestStdoutDeleteError (3.33s)
=== RUN   TestStdoutDeleteNo
--- PASS: TestStdoutDeleteNo (3.27s)
=== RUN   TestStdoutState
--- PASS: TestStdoutState (5.34s)
=== RUN   TestStdoutJson
--- PASS: TestStdoutJson (5.01s)
PASS
ok      amiCtrl 32.076s

docker-compose.yml は以下のような感じです.

version: '3'
services:
  moto_server:
    build:
      context: ./tests
      dockerfile: Dockerfile.moto_server
    container_name: moto-server
    command: ["moto_server", "ec2", "-H", "0.0.0.0", "-p", "5000"]
    ports:
      - "5000:5000"
    networks:
      amictrl_test_net:
        ipv4_address: 192.168.0.100
  amictrl_local:
    build:
      context: ./
      dockerfile: ./tests/Dockerfile.golang
    container_name: amictrl-local
    volumes:
      - .:/go/src/amiCtrl
    working_dir: /go/src/amiCtrl
    command: tail -f /dev/null
    networks:
      amictrl_test_net:
        ipv4_address: 192.168.0.2
  amictrl_circleci:
    build:
      context: ./
      dockerfile: ./tests/Dockerfile.golang
    container_name: amictrl-circleci
    working_dir: /go/src/amiCtrl
    command: tail -f /dev/null
    networks:
      amictrl_test_net:
        ipv4_address: 192.168.0.3

networks:
  amictrl_test_net:
    driver: bridge
    ipam:
     driver: default
     config:
       - subnet: 192.168.0.0/24

amictrl_localamictrl_circleci の 2 のサービスが用意されている理由は後述いたします.

CircleCI でテスト

CircleCI でテストを実行する場合にはひと手間必要でした. .circleci/config.yml 内で setup_remote_docker を利用した場合, Docker の --volume オプションが利用出来ないという制約があります.

docker-compose.yml だと volumes キーでローカルのパスを Docker コンテナにマウントする以下の部分になります.

    volumes:
      - .:/go/src/amiCtrl

マウント出来ないのであれば, 無視してくれれば良いのですが, CircleCI では空のディレクトリがマウントされた状態となる為, ローカル端末でテストを実行する場合と CircleCI でテストを実行する場合とで docker-compose の Service を分けている為, 先述の通り, docker-compose.yml 内に 2 つのサービスを用意しています.

ローカルの端末上でテストを実行する場合, 以下のように実行します.

$ docker-compose exec amictrl_local make test

CircleCI 上でテストを実行する場合, 以下のように実行します.

$ docker-compose exec amictrl_circleci make test

ということで

AMI を操作する際には是非, amiCtrl をご用命くださいませ.

(完)