tl;dr
EC2 インスタンスのマシンイメージ (以後, AMI) を操作するツール (https://github.com/oreno-tools/amiCtrl, 以後 amiCtrl) を前職で作って利用していたのですが, 色々と AMI を弄ることが多くなったので amiCtrl を大幅にバージョンアップして利用していますので紹介させて頂きます.
そして, この記事は YAMAP エンジニア Advent Calendar 2019 の六日目の記事になる予定です.
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 を自動的に削除する必要がありましたので, 以下のような機能追加 (オプション追加) 及び機能改善 (速度改善) を行いました.
- AMI 名の一部を指定して AMI 情報を取得出来る
--prefix
オプションを追加 - 作成日 (CreationDate) をチェックして古い AMI を検出する
--days
オプションを追加 (--prefix
オプションと併用) - 作成日 (CreationDate) をチェックして最新の AMI を検出する
--latest
オプションを追加 (--prefix
オプションと併用) - AMI に紐づく Snapshot ID 取得の高速化
- AMI 一覧の取得において, CreationDate が古い順に一覧を取得する
--sort-by-creation
オプションを追加
今回, 特に自慢したいのは, AMI に紐付いている Snapshot ID 取得の高速化です. 過去のバージョンでは AMI ID をキーにして describe-snapshots
を実行して Snapshot ID を取得していましたが, 今回のバージョンからは describe-images
内に含まれている Snapshot ID を取得する実装に変更しています. これにより, AWS の API を叩く回数を大幅に減らすことで Snapshot ID 取得が高速化され, 全体的な処理速度向上につながっています.
amiCtrl の様子
以下は amiCtrl を動かしている様子です.
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_local
と amictrl_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 をご用命くださいませ.
(完)