Skip to content

Latest commit

 

History

41 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

isuenv

ISUCON過去問とprivate-isuの練習環境を、 公開AMIからAWS EC2上にコマンド一発で構築・破棄するCLI。

インストール

Homebrew(macOSのみ。Cask配布なのでLinuxbrewからは入らない):

brew install kyosu-1/tap/isuenv

Go:

go install github.com/kyosu-1/isuenv@latest

Releases から macOS / Linux(amd64・arm64)のバイナリを直接落としてもよい。

前提

  • AWS認証情報(AWS_PROFILE などSDKの標準的な方法で解決される)
  • リージョンは ap-northeast-1 固定
  • EC2の vCPU クォータ(複数台構成を使う場合は6 vCPU以上)

使い方

isuenv problems               # 対応問題一覧
isuenv up isucon13            # 環境作成(1台, TTL 8h, c5.large)
isuenv up private-isu         # private-isu(1台, TTL 8h, c7a.large)
isuenv up isucon13 --nodes 3  # 本番同様の3台構成
isuenv up private-isu --bench # 競技1台 + ベンチマーカー専用1台(別のインスタンスタイプ)
isuenv list                   # 稼働中環境と概算コスト・残りTTL
isuenv ssh isucon13           # 1号機にSSH(isucon13-2 で2号機)
isuenv down isucon13          # 環境削除
isuenv nuke                   # isuenv管理の全リソース削除(VPC・キーペア含む)
isuenv version                # バージョン表示

コマンドリファレンス

isuenv up <問題名> [flags]

環境を作成し、全ノードがrunningかつパブリックIPが付くまで待ってから結果を表示する。

起動に使うAMIは問題ごとの名前パターンで毎回いちばん新しいものが選ばれる(AMI IDは固定していない)。 上流が同じパターンのままAMIを差し替えることがあるので、解決したAMIのIDと名前を起動前に表示する。

$ isuenv up isucon14
Resolving AMI for isucon14...
  -> ami-0fcf9e8e8675a9ee4 (isucon14-20260818100152)
Ensuring network...
フラグ 既定値 説明
--ttl 8h この時間が経過したら自動でterminateする(挙動
--nodes 1 起動台数。1以上
--instance-type 問題ごと EC2インスタンスタイプ。既定値は問題ごとに異なり、isuenv problems の TYPE 列で確認できる(ほとんどは c5.large、private-isuは推奨に合わせて c7a.large
--bench false ベンチマーカー専用ノードを1台追加する。タイプは isuenv problems の BENCH TYPE 列の値。推奨値の無い問題ではエラーになる
--bench-instance-type なし ベンチマーカー専用ノードのインスタンスタイプを明示する。指定すると --bench は省略できる

同名の環境が既にある場合は起動せずエラーになる。作り直すときは先に down する。

--ttl の書式は Go の duration 文字列で、単位は h / m / s。組み合わせもできる。

isuenv up isucon13 --ttl 90m      # 90分
isuenv up isucon13 --ttl 2h30m    # 2時間30分

日を表す d は使えない。 --ttl 1d はエラーになるので、24時間なら 24h と書く。

Error: invalid argument "1d" for "--ttl" flag: time: unknown unit "d" in duration "1d"

ベンチマーカー専用ノード

競技ノードと同じインスタンスタイプでベンチを回すと、アプリを最適化していった先で ベンチマーカー側が先にCPU飽和し、スコアがアプリではなく負荷生成側の性能で頭打ちになる (private-isuを競技1台+ベンチ1台のどちらも c7a.large で回したとき、ベンチ機のidleが1〜3%まで落ちても アプリ機には37%残っていた)。--bench はこれを避けるために、ベンチ用ノードだけ別タイプで追加する。

isuenv up private-isu --bench                                     # 競技1台(c7a.large) + ベンチ1台(c7a.xlarge)
isuenv up private-isu --nodes 3 --bench-instance-type c7a.2xlarge # 競技3台 + ベンチ1台(c7a.2xlarge)
isuenv up private-isu --nodes 4                                   # 従来どおりベンチノードなし

ベンチノードの番号は競技ノードの次になる(--nodes 3 --bench ならベンチは4号機)。 sshのホスト名は今までどおり <問題名>-<番号> なので isuenv ssh private-isu-4 で入れる。 ベンチノードがある構成では、up の結果にタイプとロールが並ぶ。

$ isuenv up private-isu --bench
...
  private-isu-1  public 1.2.3.4  private 10.100.0.1  c7a.large   app
  private-isu-2  public 5.6.7.8  private 10.100.0.2  c7a.xlarge  bench

isuenv list

稼働中の環境を一覧する。

内容
ENV 問題名
NODES 台数
TYPE インスタンスタイプ。ベンチノードがある場合は c7a.large +bench c7a.xlarge のように混在を表す
UPTIME 起動からの経過時間
EST COST 概算費用。ノードごとの単価で合算する。あくまで目安
TTL LEFT 自動terminateまでの残り時間
PUBLIC IPS 各ノードのパブリックIP

isuenv ssh <問題名>[-N]

ノードにSSHする。番号を省略すると1号機に繋ぐ(isucon13 = isucon13-1)。

実行のたびに次の2つを行うので、グローバルIPが変わったら打ち直せば復旧する

  • セキュリティグループのingressを、現在のグローバルIPで貼り直す
  • ~/.ssh/isuenv_config を稼働中の環境から再生成する

生成されたssh configは ~/.ssh/config からIncludeされるので、素の ssh isucon13-1 やVS Code Remoteからも使える。

isuenv down <問題名>

その環境のインスタンスをterminateする。VPC・サブネット・SG・キーペアは残るので、次の up で再利用される。対象が無い場合も成功扱い。

isuenv nuke

isuenv管理下の全リソースを削除する。yes の入力を求められる。インスタンスの終了を待ってから、キーペア・SG・サブネット・IGW・VPCの順に消す。

isuenv problems

対応している問題と、SSHユーザー、既定のインスタンスタイプ、ベンチマーカー専用ノードの推奨タイプ (BENCH TYPE。推奨値の無い問題は -)、ベンチ手順へのリンクを一覧する。

TTLの挙動

TTLの実体はインスタンス内の仕組みで、次の3段構えで動く。

  1. 起動時のuser-dataが絶対期限(UNIX時刻)を /var/lib/isuenv-expires-at に書く
  2. /etc/cron.d/isuenv-ttl が毎分その時刻を過ぎたか判定し、過ぎていれば shutdown -P now
  3. インスタンスは instance-initiated-shutdown-behavior=terminate で起動しているため、停止ではなくterminateされる(EBSごと消えるので課金が完全に止まる)

絶対時刻をディスクに持つので、リブートしても期限は維持される。判定が毎分なので、実際にterminateされるのは期限から1分程度あと。ノートPCを閉じてもCLIを終了しても効く。

作成されるリソース

AWS上のリソースはすべて isuenv:managed=true タグが付き、nuke の対象はこのタグで判定される。

リソース 内容
VPC 10.100.0.0/16
サブネット 10.100.0.0/24(パブリックIP自動割当ON)
インターネットゲートウェイ VPCにアタッチし、メインルートテーブルに 0.0.0.0/0 を向ける
セキュリティグループ 名前 isuenv実行時のグローバルIP/32からのtcp 22/80/443 と、自身のSGからの全プロトコル(ノード間通信用)
キーペア 名前 isuenv
EC2インスタンス --nodes の台数(--bench 指定時はベンチ用に+1台)

インスタンスには isuenv:env(問題名)、isuenv:node(何号機か)、isuenv:roleapp = 競技ノード / bench = ベンチマーカー専用ノード)、isuenv:expires-at(TTLの絶対期限)のタグが付く。 CLIはローカルに状態を持たず、すべてこれらのタグから復元する。

ローカルには次のファイルが作られる。

パス 内容
~/.ssh/isuenv.pem キーペアの秘密鍵(0600)。AWS側にキーペアが無いときに作成され、このファイルも上書きされるnuke 後の up など)
~/.ssh/isuenv_config ホスト定義。up / ssh / down のたびに再生成される
~/.ssh/config 先頭に Include 行を一度だけ追加(パスは絶対パスで書かれる)

VPC・サブネット・IGW・SG・キーペアは無料なので、down 後にこれらが残っていても費用は発生しない。

コストの目安

ap-northeast-1のオンデマンド概算で、c5.large(多くの問題の既定)が約$0.107/時、 c7a.large(private-isuの既定)が約$0.129/時、c7a.xlarge(private-isuのベンチ用)が約$0.258/時。 isuenv list の EST COST はノードごとの単価を合算した概算であり、実際の課金はAWSの請求を確認すること。

手動E2E検証手順

コードを変更したら以下を実施する:

  1. go test ./... && go build -o isuenv .
  2. ./isuenv up isucon14 --ttl 1h
  3. ./isuenv list — 環境が表示され、TTL LEFTが1h弱であること
  4. ./isuenv ssh isucon14 — ログインできること。sudo -i -u isucon でアプリを確認
  5. ブラウザで http://<public ip> にアクセスできること
  6. ./isuenv down isucon14 — 削除されること
  7. ./isuenv list — 空になること
  8. (まれに)./isuenv nuke でVPCまで消えることをAWSコンソールで確認
  9. 複数台構成の疎通確認: ./isuenv up isucon13 --nodes 2./isuenv ssh isucon13(1号機)でログイン → nc -zv <2号機のprivate ip> 22 が成功すること(SGの自己参照ルールでノード間通信が通ることの確認)→ ./isuenv down isucon13

private-isu

private-isuは提供元AMIがmatsuu/aws-isuconと別物なので、TTL(user-data)が効くかを個別に確認する。

  1. ./isuenv up private-isu --ttl 15mc7a.large で起動すること
  2. ./isuenv list — EST COST が - でなく金額で出ること(cost.go に c7a.large の単価があること)
  3. ./isuenv ssh private-isu — ログインでき、ブラウザで http://<public ip> が見えること
  4. TTLの実体確認(ここが効かないと課金が止まらない):
    cat /var/lib/isuenv-expires-at   # UNIX時刻が入っていること
    ls -l /etc/cron.d/isuenv-ttl     # 存在すること
  5. ベンチが通ること:
    sudo su - isucon
    /home/isucon/private_isu/benchmarker/bin/benchmarker \
      -u /home/isucon/private_isu/benchmarker/userdata -t http://localhost
  6. 15分後に実際にterminateされること(./isuenv list が空になる)
  7. ベンチ専用ノード構成: ./isuenv up private-isu --bench --ttl 1h./isuenv list の TYPE が c7a.large +bench c7a.xlarge、EST COST が2台の単価の合算になること → ./isuenv ssh private-isu-2 でベンチ機(c7a.xlarge)に入れること → ./isuenv down private-isu

リリース手順

main にタグを打つと GitHub Actions(.github/workflows/release.yml)が goreleaser を回し、 GitHub Releases へのバイナリ公開と kyosu-1/homebrew-tap の Formula 更新まで自動で行われる。

git switch main && git pull
git tag v0.1.0
git push origin v0.1.0
  • タグは vX.Y.Z 形式のみ発火する(v0.1.0-rc1 などは対象外)
  • tap への push には HOMEBREW_TAP_TOKEN シークレット(homebrew-tap への Contents: write を持つPAT)が必要
  • 設定を変更したらタグを打つ前に goreleaser checkgoreleaser release --snapshot --clean で確認する(CIでも自動で検証される)

注意

  • ベンチマーカーはAMIに同梱されている。実行方法は問題ごとに異なるので isuenv problems のNOTESのリンク先を参照
  • 消し忘れてもTTLで自己消滅するが、isuenv list での確認を習慣にすること

ライセンス

MIT License. 詳細は LICENSE を参照。

利用しているAMIは matsuu/aws-isucon(MIT)と catatsuy/private-isu(MIT)が公開しているもので、 本ツールはそれらのAMIを起動・破棄するだけであり、AMIそのものは配布していない。

About

ISUCON過去問の練習環境をAWS EC2にコマンド一発で構築・破棄するCLI

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages