はじめに
こんにちは!AWSインフラエンジニアをやりながら、プライベートでRustを使ったOSS開発に取り組んでいます。
普段の業務でCloudFormationテンプレートやAWS CLIのレスポンス、Kubernetesマニフェストなど、様々な構造化データを扱う中で「もっと手軽にデータ構造を把握できるツールがあればいいのに...」と感じることが多々ありました。
そんな課題を解決するために開発したのが hawk というCLIツールです。本記事では、なぜ新しいツールを作ることにしたのか、その背景と設計思想をお話しします。
日常業務での「あるある」な困りごと
AWS CLIレスポンスの「構造把握地獄」
インフラエンジニアなら誰もが経験する光景です:
aws ec2 describe-instances --instance-ids i-1234567890abcdef0 > instance.json
cat instance.json
画面に流れる100行を超えるJSON。ネストの深いオブジェクト構造。「インスタンスの状態を確認したいだけなのに、どこにあるんだ?」
このJSONファイルから「インスタンスが起動中かどうか」を確認するために:
- lessでスクロールしながら構造を把握
- 目的のフィールドまでのパスを推測
- jqで試行錯誤しながらクエリを組み立て
たった一つの情報を取得するのに、なぜこんなに時間がかかるのでしょうか?
データ構造を「俯瞰」で見たい切実な願い
日常的に扱うファイルで困る場面:
- CloudFormationテンプレート: リソースの依存関係を把握したい
- docker-compose.yaml: サービス構成の全体像を理解したい
- Kubernetesマニフェスト: どんなフィールドが設定可能か知りたい
- 設定ファイル: スキーマや構造の理解に時間がかかる
特に、YAMLファイルの構造確認に使えるツールがなかなか見つからないのが悩みでした。
既存ツールの限界:なぜ満足できなかったのか
awkの高い学習コスト
# CSVの2列目を抽出したいだけなのに...
awk -F',' '{print $2}' data.csv
- 構文が難しすぎる:毎回ググって、毎回忘れる
- 長いワンライナーは覚えられない
- 構造化データ(JSON/YAML)には全く対応できない
jqの「JSON専用」という壁
# JSON は得意だが...
jq '.Reservations[0].Instances[0].State.Name' instance.json
# YAMLファイルは事前変換が必要
yq -o json config.yaml | jq '.some.field'
- YAMLファイルには直接対応していない
- 複雑なクエリは結局覚えられない
- 単純な構造確認すら冗長な記述が必要
pandasという「重厚長大」な解決策
import pandas as pd
import json
# ちょっとした確認のためにPythonスクリプト...
with open('data.json') as f:
data = json.load(f)
- 手軽な確認のためにPython環境を起動
- スクリプトファイルを作らないと使いづらい
- CLIでの手軽さとは対極
理想の解決策:「pandas風の操作感をCLIで」
目指したかった体験
- 統一されたクエリ言語で全形式(JSON/YAML/CSV)を扱う
- 直感的で覚えやすい操作感
- データフレームのような構造化データの統一的な扱い
- ワンライナーで完結する手軽さ
なぜ「新しいツール」を作ったのか
既存ツールの組み合わせでは根本解決にならないと感じました。インフラエンジニアの現場ニーズに最適化した、学習コストの低い、覚えやすいツールが欲しかったのです。
hawkの誕生:コンセプトと設計思想
実例で見る「Before/After」
以下は、AWS CLIで取得したEC2インスタンス情報の分析例です:
Before(従来の方法):
# EC2インスタンス情報の構造確認
aws ec2 describe-instances --instance-ids i-1234567890abcdef0 > instance.json
cat instance.json | less # 100行以上をスクロールして構造を把握
# 特定の情報を取得したいが、パスが分からない
jq '. | keys' instance.json
# → ["Reservations"] しか分からない
jq '.Reservations[0] | keys' instance.json
# さらに深く探る必要が...
# 結局、長いjqクエリを書くことに
jq '.Reservations[0].Instances[0].State.Name' instance.json
After(hawkを使用):
# 一発で全体構造を把握
hawk '. | info' instance.json
# === Data Information ===
# Total records: 1
# Type: Object Array
# Fields: 1
#
# Field Details:
# Reservations Array (e.g., [1 items])
#
# Array Fields:
# Reservations [1 items]
# └─ Groups, Instances, OwnerId, ReservationId
# さらに詳しく見たい場合
hawk '.Reservations[0].Instances[0] | info' instance.json
# === Data Information ===
# Total records: 1
# Type: Object Array
# Fields: 41
#
# Field Details:
# InstanceId String (e.g., "i-1234567890abcdef0")
# State Object (e.g., {Code...})
# PublicIpAddress String (e.g., "34.253.223.13")
# PrivateIpAddress String (e.g., "10-0-0-157")
# SecurityGroups Array (e.g., [1 items])
# Tags Array (e.g., [1 items])
# ... (41個のフィールド情報が一覧表示)
# 必要なデータに直感的にアクセス
hawk '.Reservations[0].Instances[0].State' instance.json
# Code Name
# 16 running
# 特定の値だけが欲しい場合
hawk '.Reservations[0].Instances[0].State.Name' instance.json
# → "running"
「構造を俯瞰する」info機能
hawkの最大の特徴は、データ構造を一発で把握できるinfo
機能です:
- データ構造の即座の把握: ネストの深さや型情報が一目瞭然
- アクセス可能なフィールド名の確認: どのフィールドにアクセスできるかすぐ分かる
- 段階的な探索: 気になる部分をさらに深く調べられる
hawkによる実践的な活用例
よくある業務シーンでの活用
# 1. インスタンスの状態確認(テーブル形式で表示)
hawk '.Reservations[0].Instances[0].State' instance.json
# Code Name
# 16 running
# 2. セキュリティグループの情報
hawk '.Reservations[0].Instances[0].SecurityGroups[0]' instance.json
# GroupName GroupId
# launch-wizard-146 sg-1234567890abcdefg
# 3. タグ情報の確認
hawk '.Reservations[0].Instances[0].Tags' instance.json
# Key Value
# Name my-instance
# 4. ネットワーク情報の表示
hawk '.Reservations[0].Instances[0] | select_fields(InstanceId, PublicIpAddress, PrivateIpAddress)' instance.json
# InstanceId PublicIpAddress PrivateIpAddress
# i-1234567890abcdef0 34.253.223.13 10-0-0-157
hawkの設計思想:シンプルさを重視
hawkでは「覚えやすく、間違えにくい」構文を重視しています:
# 段階的にデータを絞り込む、分かりやすいアプローチ
hawk '.Reservations[].Instances[]' instance.json # まずインスタンス一覧
hawk '.Reservations[].Instances[].State' instance.json # 次に状態を確認
hawk '.Reservations[].Instances[].State | select(.Name == "running")' instance.json # 条件で絞込
# ネストしたフィールドも段階的にアクセス
hawk '.Reservations[].Instances[].Placement' instance.json # Placementオブジェクト取得
hawk '.Reservations[].Instances[].Placement | group_by(.AvailabilityZone) | count' instance.json # AZ別集計
この設計により:
- 構文エラーが起きにくい - 深いネストでの複雑な指定を避けられる
- デバッグしやすい - 段階的に実行して結果を確認できる
- 学習コストが低い - 基本パターンを覚えれば応用が利く
複数インスタンスの分析例
# 全インスタンスの状態を一覧表示
hawk '.Reservations[].Instances[].State.Name' multi-instances.json
# 起動中のインスタンスを探す
hawk '.Reservations[].Instances[].State | select(.Name == "running")' multi-instances.json
# 全インスタンス数をカウント
hawk '.Reservations[].Instances[] | count' multi-instances.json
# インスタンスタイプごとの集計
hawk '.Reservations[].Instances[] | group_by(.InstanceType) | count' multi-instances.json
# アベイラビリティゾーンごとの分析
hawk '.Reservations[].Instances[].Placement | group_by(.AvailabilityZone) | count' multi-instances.json
技術選択:なぜRustとCLIなのか
Rustを選んだ理由
- 高速で軽量なバイナリ: シングルバイナリでの配布が容易
- 型安全性による信頼性: 実行時エラーを最小限に抑制
- 個人的な学習目標: 今後のキャリアのための土壌づくり
CLIツールとしての設計
- 既存ワークフローへの組み込み: パイプラインでの組み合わせが容易
- 軽量性: GUIツールにはない手軽さ
- 自動化対応: スクリプトでの利用も簡単
まとめ:日々の業務をもっと楽に
hawkが解決する課題
-
データ構造の即座の把握:
info
機能による一発理解 - 統一された操作感: JSON/YAML/CSV同じ書き方
- 学習コストの削減: シンプルで覚えやすい構文
- 形式を意識しない: 柔軟なデータ処理
試してみませんか?
同じような課題を感じているインフラエンジニアの方がいらっしゃいましたら、ぜひhawkを試してみてください。日々の業務が少しでも楽になれば嬉しいです。
フィードバックや改善提案も大歓迎です!
リンク
次回予告
次回は「Rustで学ぶCLIツール設計 - hawkの内部アーキテクチャを解説」として、hawkの実装について詳しく解説予定です。
この記事が参考になりましたら、いいね👍やストック📚をお願いします!