AWS CLI で EC2 を操作するときの基本は、aws ec2 describe-instances で一覧と状態を確認し、start-instances・stop-instances・reboot-instances・terminate-instances にインスタンス ID を渡す、という流れです。 describe-instances はそのままだと 1 台あたり 100 行を超える JSON を返すので、--query で必要な項目だけを取り出し、--filters で対象を絞るのがコツです。

この記事では、「ID・Name タグ・状態・種類・IP」を表で出すワンライナーを最初に示し、--filters の条件名の早見表、起動・停止・再起動・終了と wait の応答 JSON(PreviousState → CurrentState)、状態遷移の表、タグ指定で複数台をまとめて止めるスクリプト、--dry-run の出力、エラー文と原因までを、実行結果をそのまま載せて説明します。

確認環境:Ubuntu 24.04、AWS CLI 1.46.1、boto3 1.43.103、Python 3.11。AWS の API をローカルで再現するツール(moto 5.2.3)で実行しました。掲載するコマンドは、ローカル向けの接続先指定を外して AWS でそのまま使える形にしています。

AWS CLI の EC2 操作 早見表

まず、やりたいことからコマンドを引ける表です。 i-xxxx の部分はインスタンス ID で、スペース区切りで複数並べられます。

やりたいこと コマンド 応答
一覧を表で見る aws ec2 describe-instances --query '…' --output table(次の節) 表
実行中のものだけ見る --filters Name=instance-state-name,Values=running を足す 絞り込んだ結果
Name タグで探す --filters "Name=tag:Name,Values=web-*" を足す 絞り込んだ結果
1 台の状態だけ知る aws ec2 describe-instances --instance-ids i-xxxx --query 'Reservations[0].Instances[0].State.Name' --output text running など
起動する aws ec2 start-instances --instance-ids i-xxxx StartingInstances
停止する aws ec2 stop-instances --instance-ids i-xxxx StoppingInstances
再起動する aws ec2 reboot-instances --instance-ids i-xxxx 出力なし
終了(削除)する aws ec2 terminate-instances --instance-ids i-xxxx TerminatingInstances
起動が終わるまで待つ aws ec2 wait instance-running --instance-ids i-xxxx 出力なし
停止が終わるまで待つ aws ec2 wait instance-stopped --instance-ids i-xxxx 出力なし
実行せずに権限だけ確かめる 各コマンドに --dry-run を足す DryRunOperation

状態(State.Name)は 6 種類です。数字は State.Code の値です。

状態 コード 意味 インスタンスの利用料金
pending 0 起動の準備中 かからない
running 16 実行中 かかる
stopping 64 停止の準備中 かからない(休止の準備中はかかる)
stopped 80 停止中。いつでも起動できる かからない
shutting-down 32 終了の準備中 かからない
terminated 48 終了済み。起動できない かからない

料金の列は Amazon EC2 ユーザーガイド(Amazon EC2 instance state changes)の記載です。停止中もボリュームの利用料金はかかります(stop-instances のリファレンス)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「AWS CLIでEC2操作|describe-instancesと起動・停止」

インスタンス一覧を表で出すワンライナー

次の 1 行で、ID・Name タグ・状態・種類・IP が表になります。 今回は説明用に 4 台(web-01、web-02、batch-01、Name タグなしの 1 台)を用意しました。

aws ec2 describe-instances \
  --query 'Reservations[].Instances[].{ID:InstanceId,Name:Tags[?Key==`Name`]|[0].Value,State:State.Name,Type:InstanceType,PrivateIP:PrivateIpAddress,PublicIP:PublicIpAddress}' \
  --output table
------------------------------------------------------------------------------------------------
|                                       DescribeInstances                                      |
+---------------------+-----------+-----------------+-----------------+-----------+------------+
|         ID          |   Name    |    PrivateIP    |    PublicIP     |   State   |   Type     |
+---------------------+-----------+-----------------+-----------------+-----------+------------+
|  i-3df4a515b28813aa5|  web-01   |  10.176.8.189   |  54.214.62.204  |  running  |  t3.micro  |
|  i-46c6786516445a138|  web-02   |  10.104.219.140 |  54.214.105.171 |  running  |  t3.micro  |
|  i-279405888125529b9|  batch-01 |  10.151.197.48  |  None           |  stopped  |  t3.small  |
|  i-a82a1805e1d9668b3|  None     |  10.71.72.109   |  54.214.86.59   |  running  |  t3.micro  |
+---------------------+-----------+-----------------+-----------------+-----------+------------+

結果から読み取れることが 3 つあります。

  • {見出し:項目} の形で書くと、見出しつきの表になります。 列は見出しのアルファベット順に並びます(ID、Name、PrivateIP、PublicIP、State、Type)。
  • Name タグが無いインスタンスは None と表示されます。
  • 停止中のインスタンスはパブリック IP が None です。

列の順番を自分で決めたいときは、{ } の代わりに [ ] で並べます。見出しは付きませんが、書いた順に出ます。

aws ec2 describe-instances \
  --query 'Reservations[].Instances[].[InstanceId,Tags[?Key==`Name`]|[0].Value,State.Name,InstanceType,PrivateIpAddress,PublicIpAddress]' \
  --output table
------------------------------------------------------------------------------------------------
|                                       DescribeInstances                                      |
+---------------------+-----------+----------+-----------+------------------+------------------+
|  i-3df4a515b28813aa5|  web-01   |  running |  t3.micro |  10.176.8.189    |  54.214.62.204   |
|  i-46c6786516445a138|  web-02   |  running |  t3.micro |  10.104.219.140  |  54.214.105.171  |
|  i-279405888125529b9|  batch-01 |  stopped |  t3.small |  10.151.197.48   |  None            |
|  i-a82a1805e1d9668b3|  None     |  running |  t3.micro |  10.71.72.109    |  54.214.86.59    |
+---------------------+-----------+----------+-----------+------------------+------------------+

シェルスクリプトで加工するなら --output text(タブ区切り)が扱いやすい形です。

aws ec2 describe-instances \
  --query 'Reservations[].Instances[].[InstanceId,Tags[?Key==`Name`]|[0].Value,State.Name]' \
  --output text
i-3df4a515b28813aa5 web-01  running
i-46c6786516445a138 web-02  running
i-279405888125529b9 batch-01    stopped
i-a82a1805e1d9668b3 None    running

--query の式を分解して読む

ワンライナーの --query は JMESPath という JSON 用の問い合わせ言語で書かれています。部品ごとに意味を整理します。

部品 意味
Reservations[] 最上位の Reservations 配列を 1 つずつ取り出す
.Instances[] 各 Reservation の中の Instances 配列を取り出して 1 本の配列に平らにする
.{ID:InstanceId, …} 各インスタンスから、見出しつきで項目を選ぶ
.[InstanceId, …] 各インスタンスから、順番どおりに項目を選ぶ(見出しなし)
State.Name 入れ子の値はドットでたどる
Tags[?Key==`Name`] Tags 配列から Key が Name の要素だけに絞る
|[0].Value 絞った結果の 1 件目の Value を取る

式の中でバッククォートを使うので、全体はシングルクォートで囲みます。

元の JSON の形(どこに何があるか)

describe-instances をそのまま実行すると、今回の環境では 1 台で 129 行の JSON が返りました。主要なキーだけを抜き出すと、次の構造です。

{
    "Reservations": [
        {
            "ReservationId": "r-153e110eaf58d42c8",
            "OwnerId": "123456789012",
            "Instances": [
                {
                    "InstanceId": "i-3df4a515b28813aa5",
                    "InstanceType": "t3.micro",
                    "State": { "Code": 16, "Name": "running" },
                    "PrivateIpAddress": "10.176.8.189",
                    "PublicIpAddress": "54.214.62.204",
                    "Tags": [
                        { "Key": "Name", "Value": "web-01" },
                        { "Key": "Env", "Value": "dev" }
                    ],
                    "Placement": { "AvailabilityZone": "ap-northeast-1a" },
                    "VpcId": "vpc-c0dddd23e9a22bbe0",
                    "SubnetId": "subnet-cdc627277e29a834e",
                    "LaunchTime": "2026-10-03T09:44:24.000Z",
                    "StateTransitionReason": ""
                }
            ]
        }
    ]
}

インスタンスは Reservations → Instances の 2 段の配列の中にあります。 --query の先頭が Reservations[].Instances[] になるのはこのためです。

取り出したい項目 --query に書くキー
インスタンス ID InstanceId
状態 State.Name(数字は State.Code)
インスタンスタイプ InstanceType
プライベート IP / パブリック IP PrivateIpAddress / PublicIpAddress
アベイラビリティーゾーン Placement.AvailabilityZone
VPC / サブネット VpcId / SubnetId
起動日時 LaunchTime
状態が変わった理由 StateTransitionReason
AMI の ID ImageId

--filters の条件名 早見表

--filters は Name=条件名,Values=値 の形で書き、AWS 側で絞り込んでから結果を返します。 AWS CLI のリファレンス(describe-instances)に載っている条件名のうち、よく使うものを表にしました。

条件名 絞り込む対象 書き方の例
instance-state-name 状態 Name=instance-state-name,Values=running
tag:キー 指定したキーのタグの値 "Name=tag:Name,Values=web-*"
tag-key タグのキーがあるかどうか Name=tag-key,Values=Env
instance-type インスタンスタイプ Name=instance-type,Values=t3.small
vpc-id VPC Name=vpc-id,Values=vpc-xxxx
subnet-id サブネット Name=subnet-id,Values=subnet-xxxx
availability-zone アベイラビリティーゾーン Name=availability-zone,Values=ap-northeast-1a
private-ip-address プライベート IPv4 アドレス Name=private-ip-address,Values=10.0.1.15
ip-address パブリック IPv4 アドレス Name=ip-address,Values=203.0.113.10
image-id AMI の ID Name=image-id,Values=ami-xxxx
instance.group-id セキュリティグループの ID Name=instance.group-id,Values=sg-xxxx
key-name キーペアの名前 Name=key-name,Values=my-key
architecture アーキテクチャ(x86_64、arm64 など) Name=architecture,Values=arm64

4 つの条件を実行した結果

実行中のインスタンスの ID だけを取り出します。

aws ec2 describe-instances \
  --filters Name=instance-state-name,Values=running \
  --query 'Reservations[].Instances[].InstanceId' --output text
i-3df4a515b28813aa5 i-46c6786516445a138 i-a82a1805e1d9668b3

Name タグが web- で始まるものを探します。値には * のワイルドカードが使えました。

aws ec2 describe-instances \
  --filters "Name=tag:Name,Values=web-*" \
  --query 'Reservations[].Instances[].[InstanceId,Tags[?Key==`Name`]|[0].Value]' \
  --output text
i-3df4a515b28813aa5 web-01
i-46c6786516445a138 web-02

インスタンスタイプで絞ります。

aws ec2 describe-instances \
  --filters Name=instance-type,Values=t3.small \
  --query 'Reservations[].Instances[].[InstanceId,InstanceType]' --output text
i-279405888125529b9 t3.small

VPC で絞って台数を数えます。length() は配列の要素数を返す関数です。

aws ec2 describe-instances \
  --filters Name=vpc-id,Values=vpc-c0dddd23e9a22bbe0 \
  --query 'length(Reservations[].Instances[])'
4

条件を組み合わせる(AND と OR)

複数の Name=… を並べると「かつ(AND)」、1 つの Values= にカンマで並べると「または(OR)」になります。

# Env タグが dev、かつ 状態が running または stopped
aws ec2 describe-instances \
  --filters Name=tag:Env,Values=dev Name=instance-state-name,Values=running,stopped \
  --query 'Reservations[].Instances[].[InstanceId,State.Name]' --output text
i-3df4a515b28813aa5 running
i-46c6786516445a138 running
# Env タグが dev または prod、かつ 種類が t3.small
aws ec2 describe-instances \
  --filters Name=tag:Env,Values=dev,prod Name=instance-type,Values=t3.small \
  --query 'Reservations[].Instances[].InstanceId' --output text
i-279405888125529b9

条件に合うものが無いときは、エラーではなく空の配列が返ります。

aws ec2 describe-instances --filters Name=tag:Name,Values=nothing
{
    "Reservations": []
}

--filters と --query の使い分け

項目 --filters --query
絞り込む場所 AWS 側(サーバー側) 手元の CLI(クライアント側)
役割 どのインスタンスを返すか 返ってきた JSON のどの項目を表示するか
処理の順番 先 あと
台数が多いとき 返るデータが減るので有利 全件を受け取ってから処理する

AWS CLI ユーザーガイド(Filtering output)にも、サーバー側の絞り込みが先に処理され、その結果に --query が適用されると書かれています。「対象は --filters、表示項目は --query」と分けて書くのが基本です。

--query だけでも状態で絞れますが、全件を受け取ってからの処理になります。

aws ec2 describe-instances \
  --query 'Reservations[].Instances[?State.Name==`stopped`][].InstanceId' \
  --output text
i-279405888125529b9

起動・停止・再起動・終了の応答 JSON

start・stop・terminate の応答には、直前の状態(PreviousState)と現在の状態(CurrentState)が入っています。 順に実行します。

停止する(stop-instances)

aws ec2 stop-instances --instance-ids i-3df4a515b28813aa5
{
    "StoppingInstances": [
        {
            "InstanceId": "i-3df4a515b28813aa5",
            "CurrentState": {
                "Code": 64,
                "Name": "stopping"
            },
            "PreviousState": {
                "Code": 16,
                "Name": "running"
            }
        }
    ]
}

コマンドはすぐに返り、状態は running → stopping になりました。この時点ではまだ停止の途中です。 止まり切るまで待つには wait を使います。

aws ec2 wait instance-stopped --instance-ids i-3df4a515b28813aa5

wait は何も出力せず、条件を満たすと終了します。停止後の状態を確認します。

aws ec2 describe-instances --instance-ids i-3df4a515b28813aa5 \
  --query 'Reservations[].Instances[].[State.Name,PublicIpAddress,PrivateIpAddress,StateTransitionReason]'
[
    [
        "stopped",
        null,
        "10.176.8.189",
        "User initiated (2026-10-03 09:45:01 UTC)"
    ]
]

停止するとパブリック IP は null になり、プライベート IP は残ります。 StateTransitionReason には、利用者の操作で止まったことと時刻が記録されます。

起動する(start-instances)と wait instance-running

aws ec2 start-instances --instance-ids i-3df4a515b28813aa5
{
    "StartingInstances": [
        {
            "InstanceId": "i-3df4a515b28813aa5",
            "CurrentState": {
                "Code": 0,
                "Name": "pending"
            },
            "PreviousState": {
                "Code": 80,
                "Name": "stopped"
            }
        }
    ]
}

stopped → pending になりました。running になるまで待ちます。

aws ec2 wait instance-running --instance-ids i-3df4a515b28813aa5

aws ec2 describe-instances --instance-ids i-3df4a515b28813aa5 \
  --query 'Reservations[].Instances[].State'
[
    {
        "Code": 16,
        "Name": "running"
    }
]

起動し直したあとに一覧を出すと、web-01 のパブリック IP は 54.214.62.204 から 54.214.32.108 に変わっていました。停止と起動をはさむとパブリック IP は新しくなります(Elastic IP を付けている場合は変わりません。Amazon EC2 ユーザーガイド)。

wait のリファレンスによると、wait instance-running は describe-instances を 15 秒ごとに呼び、40 回確認しても条件を満たさなければ終了コード 255 で終わります。スクリプトでは次のように続けて書けます。

aws ec2 start-instances --instance-ids i-3df4a515b28813aa5
aws ec2 wait instance-running --instance-ids i-3df4a515b28813aa5 && echo "起動しました"
起動しました
wait のサブコマンド 待つ条件
instance-running 状態が running になる
instance-stopped 状態が stopped になる
instance-terminated 状態が terminated になる
instance-status-ok インスタンスのステータスチェックが ok になる
system-status-ok システムのステータスチェックが ok になる
instance-exists インスタンスが存在する

running になった直後は、OS の起動がまだ終わっていないことがあります。SSH 接続などを続けて行うスクリプトでは、instance-status-ok まで待つと安定します。ステータスチェックの結果は describe-instance-status で見られます。

aws ec2 describe-instance-status --instance-ids i-3df4a515b28813aa5 \
  --query 'InstanceStatuses[].[InstanceState.Name,InstanceStatus.Status,SystemStatus.Status]' \
  --output text
running ok  ok

左から、インスタンスの状態、インスタンスのステータスチェック、システムのステータスチェックです。

再起動する(reboot-instances)

aws ec2 reboot-instances --instance-ids i-3df4a515b28813aa5

reboot-instances は成功しても何も出力しません。 状態は running のままで、PreviousState・CurrentState の応答もありません。再起動では、同じホスト上にとどまり、パブリック IP も保たれます(Amazon EC2 ユーザーガイド)。

終了する(terminate-instances)

terminate-instances はインスタンスを削除する操作で、元に戻せません。 実行前に ID と Name タグを必ず確認します。

aws ec2 terminate-instances --instance-ids i-a82a1805e1d9668b3
{
    "TerminatingInstances": [
        {
            "InstanceId": "i-a82a1805e1d9668b3",
            "CurrentState": {
                "Code": 32,
                "Name": "shutting-down"
            },
            "PreviousState": {
                "Code": 16,
                "Name": "running"
            }
        }
    ]
}
aws ec2 wait instance-terminated --instance-ids i-a82a1805e1d9668b3

aws ec2 describe-instances --instance-ids i-a82a1805e1d9668b3 \
  --query 'Reservations[].Instances[].[InstanceId,State.Name,State.Code,StateTransitionReason]'
[
    [
        "i-a82a1805e1d9668b3",
        "terminated",
        48,
        "User initiated (2026-10-03 09:45:46 UTC)"
    ]
]

終了したインスタンスは、しばらくの間 terminated の状態で一覧に残ります(AWS CLI のリファレンスでは、通常 1 時間未満とされています)。一覧から外したいときは、--filters Name=instance-state-name,Values=running,stopped のように状態で絞ります。

終了保護を付けておく

うっかり終了させたくないインスタンスには、終了保護を付けられます。上の終了を行う前に、同じインスタンスで試した結果です。

aws ec2 modify-instance-attribute \
  --instance-id i-a82a1805e1d9668b3 --disable-api-termination

この状態で terminate-instances を実行すると、次のメッセージで止まります。

An error occurred (OperationNotPermitted) when calling the TerminateInstances operation: The instance 'i-a82a1805e1d9668b3' may not be terminated. Modify its 'disableApiTermination' instance attribute and try again.

保護を外すときは --no-disable-api-termination を指定します。

状態遷移の表(どの操作でどう変わるか)

4 つの操作による状態の移り変わりを、応答 JSON の PreviousState → CurrentState とあわせて整理します。

操作 実行できる状態 応答の PreviousState → CurrentState 最終的な状態 待つコマンド
start-instances stopped stopped → pending running wait instance-running
stop-instances running running → stopping stopped wait instance-stopped
reboot-instances running 応答なし running のまま —(状態は変わらない)
terminate-instances running、stopped running → shutting-down(停止中からは stopped → shutting-down) terminated wait instance-terminated
stateDiagram-v2
    [*] --> pending: run-instances
    pending --> running
    running --> stopping: stop-instances
    stopping --> stopped
    stopped --> pending: start-instances
    running --> running: reboot-instances
    running --> shutting_down: terminate-instances
    stopped --> shutting_down: terminate-instances
    shutting_down --> terminated
    terminated --> [*]

再起動・停止・終了で何が保たれるかは、Amazon EC2 ユーザーガイドの比較が参考になります。

項目 再起動 停止 → 起動 終了
ホスト 同じホストのまま 新しいホストに移る(同じ場合もある) —
プライベート IPv4 保たれる 保たれる —
パブリック IPv4 保たれる 新しくなる(Elastic IP は除く) —
Elastic IP 関連付けたまま 関連付けたまま 関連付けが外れる
インスタンスストアのデータ 保たれる 消える 消える
ルートボリューム 保たれる 保たれる 既定では削除される
メモリの内容 消える 消える 消える

stop-instances には、次のオプションもあります(stop-instances のリファレンス)。

オプション 動き
--hibernate 起動時に休止を有効にしたインスタンスを休止させる。休止できない場合は通常の停止になる
--force 強制的に停止する。まず通常のシャットダウンを試み、時間内に終わらなければ強制的に止める
--dry-run 実行せずに、必要な権限があるかだけを確かめる

タグ指定で複数台をまとめて止める

「タグで ID を集める → その ID を stop-instances に渡す」の 2 段構えにすると、台数が増えても同じコマンドで止められます。 Env タグが dev で実行中のものを止める例です。

IDS=$(aws ec2 describe-instances \
  --filters Name=tag:Env,Values=dev Name=instance-state-name,Values=running \
  --query 'Reservations[].Instances[].InstanceId' --output text)

aws ec2 stop-instances --instance-ids $IDS \
  --query 'StoppingInstances[].[InstanceId,PreviousState.Name,CurrentState.Name]' \
  --output table
------------------------------------------------
|                 StopInstances                |
+----------------------+----------+------------+
|  i-3df4a515b28813aa5 |  running |  stopping  |
|  i-46c6786516445a138 |  running |  stopping  |
+----------------------+----------+------------+

stop-instances の応答にも --query が使えるので、「どれが、どの状態からどの状態になったか」を表で残せます。$IDS はスペース(タブ)区切りの ID を複数の引数として渡したいので、ここではクォートで囲みません。

起動も同じ形です。

aws ec2 start-instances --instance-ids $IDS \
  --query 'StartingInstances[].[InstanceId,PreviousState.Name,CurrentState.Name]' \
  --output text
i-3df4a515b28813aa5 stopped pending
i-46c6786516445a138 stopped pending

スクリプトにまとめる(対象が 0 台のときの分岐つき)

対象が 1 台も無いときに空の ID で stop-instances を呼ばないよう、分岐を入れたスクリプトです。

#!/bin/bash
# 使い方: ./stop_by_tag.sh Env dev
KEY=$1; VALUE=$2

IDS=$(aws ec2 describe-instances \
  --filters "Name=tag:$KEY,Values=$VALUE" "Name=instance-state-name,Values=running" \
  --query 'Reservations[].Instances[].InstanceId' --output text)

if [ -z "$IDS" ]; then
  echo "対象のインスタンスはありません(tag:$KEY=$VALUE, running)"
  exit 0
fi

echo "停止対象: $IDS"
aws ec2 stop-instances --instance-ids $IDS \
  --query 'StoppingInstances[].[InstanceId,PreviousState.Name,CurrentState.Name]' --output text
aws ec2 wait instance-stopped --instance-ids $IDS
echo "停止を確認しました"
./stop_by_tag.sh Env dev
停止対象: i-3df4a515b28813aa5   i-46c6786516445a138
i-3df4a515b28813aa5 running stopping
i-46c6786516445a138 running stopping
停止を確認しました
./stop_by_tag.sh Env none
対象のインスタンスはありません(tag:Env=none, running)

停止後に、止まったものと理由を一覧で確認できます。

aws ec2 describe-instances \
  --filters Name=instance-state-name,Values=stopped \
  --query 'Reservations[].Instances[].[InstanceId,Tags[?Key==`Name`]|[0].Value,StateTransitionReason]' \
  --output table
-------------------------------------------------------------------------------
|                              DescribeInstances                              |
+----------------------+---------+--------------------------------------------+
|  i-3df4a515b28813aa5 |  web-01 |  User initiated (2026-10-03 09:53:46 UTC)  |
|  i-46c6786516445a138 |  web-02 |  User initiated (2026-10-03 09:53:46 UTC)  |
+----------------------+---------+--------------------------------------------+

boto3 で同じことをする

Python から行う場合の完成形です。一覧の取得は paginator で回し、停止の完了は waiter で待ちます。

import boto3
from botocore.exceptions import ClientError

ec2 = boto3.client("ec2", region_name="ap-northeast-1")

def list_instances(filters=None):
    rows = []
    paginator = ec2.get_paginator("describe_instances")
    for page in paginator.paginate(Filters=filters or []):
        for r in page["Reservations"]:
            for i in r["Instances"]:
                name = next((t["Value"] for t in i.get("Tags", []) if t["Key"] == "Name"), "-")
                rows.append((i["InstanceId"], name, i["State"]["Name"], i["InstanceType"]))
    return rows

for row in list_instances([{"Name": "tag:Env", "Values": ["dev"]}]):
    print(*row)

ids = [r[0] for r in list_instances([
    {"Name": "tag:Env", "Values": ["dev"]},
    {"Name": "instance-state-name", "Values": ["running"]},
])]
if ids:
    res = ec2.stop_instances(InstanceIds=ids)
    for s in res["StoppingInstances"]:
        print(s["InstanceId"], s["PreviousState"]["Name"], "->", s["CurrentState"]["Name"])
    ec2.get_waiter("instance_stopped").wait(InstanceIds=ids)
    print("停止を確認:", len(ids), "台")

try:
    ec2.stop_instances(InstanceIds=["i-0123456789abcdef0"])
except ClientError as e:
    print("エラー:", e.response["Error"]["Code"])

web-01 が停止中、web-02 が実行中の状態で実行した結果です。

i-3df4a515b28813aa5 web-01 stopped t3.small
i-46c6786516445a138 web-02 running t3.micro
i-46c6786516445a138 running -> stopping
停止を確認: 1 台
エラー: InvalidInstanceID.NotFound

--dry-run で実行前に確かめる

--dry-run を付けると、実際には操作せず、権限があるかどうかだけを確かめられます。

aws ec2 stop-instances --instance-ids i-3df4a515b28813aa5 --dry-run
An error occurred (DryRunOperation) when calling the StopInstances operation: Request would have succeeded, but DryRun flag is set.

「An error occurred」と表示されますが、DryRunOperation は「権限があり、実行すれば成功する」という意味です。 終了コードは 255 でした。terminate-instances や start-instances でも同じ形で返ります。

An error occurred (DryRunOperation) when calling the TerminateInstances operation: Request would have succeeded, but DryRun flag is set.
--dry-run の結果 意味 次にすること
DryRunOperation 必要な権限があり、実行すれば成功する --dry-run を外して実行
UnauthorizedOperation この操作を行う権限がない IAM ポリシーと、使っている認証情報を確認

エラーコードの意味は Amazon EC2 API リファレンス(Error codes)の記載です。終了コードが 0 にならないので、スクリプトで判定するときはメッセージに DryRunOperation が含まれるかどうかを見ます。

if aws ec2 terminate-instances --instance-ids i-a82a1805e1d9668b3 --dry-run 2>&1 \
     | grep -q DryRunOperation; then
  echo "権限あり。実行できます"
fi
権限あり。実行できます

エラー文と原因のまとめ

エラーは An error occurred (エラーコード) when calling the 操作名 operation: 説明 の形で返ります。 かっこの中のエラーコードで原因を切り分けます。

InvalidInstanceID.NotFound

存在しない ID を指定した例です。

aws ec2 stop-instances --instance-ids i-0123456789abcdef0
An error occurred (InvalidInstanceID.NotFound) when calling the StopInstances operation: The instance ID 'i-0123456789abcdef0' does not exist

describe-instances でも同じエラーコードになります。

An error occurred (InvalidInstanceID.NotFound) when calling the DescribeInstances operation: The instance ID 'i-0123456789abcdef0' does not exist

ID が合っているのにこのエラーが出るときは、リージョンが違うことがよくあります。インスタンスはリージョンごとに管理されているので、--region や設定ファイルのリージョンを確認します。API リファレンスには、作成した直後のインスタンスで、ID がまだ行き渡っていないときにも出ることがあると書かれています。

--instance-ids の付け忘れ

aws ec2 stop-instances
aws: error: the following arguments are required: --instance-ids

これは AWS に送る前に CLI が止めるエラーです。

エラーコードの一覧

エラーコード 意味・出る場面 確認すること
InvalidInstanceID.NotFound 指定したインスタンスが存在しない ID の打ち間違い、リージョン、終了済みで一覧から消えていないか
InvalidInstanceID.Malformed ID の形式が正しくない i- で始まる完全な ID を渡しているか(Name タグを渡していないか)
IncorrectInstanceState その操作ができない状態にある describe-instances で現在の状態を確認し、wait で遷移を待ってから実行
OperationNotPermitted 許可されていない操作(終了保護が有効なインスタンスの終了など) 終了保護(disableApiTermination)の設定
UnauthorizedOperation 操作する権限がない IAM ポリシー、使っているプロファイル
UnsupportedOperation 対応していない操作(インスタンスストアをルートにしたインスタンスの停止など) インスタンスの種類やルートデバイスの種類
InstanceLimitExceeded 同時に実行できるインスタンス数の上限に達した 上限の確認と、使っていないインスタンスの整理
DryRunOperation --dry-run を付けた。権限はあり、実行すれば成功する --dry-run を外す

意味の列は Amazon EC2 API リファレンス(Error codes)の説明をもとにしています。IncorrectInstanceState の例として、同リファレンスは「ユーザーデータなど一部の属性は、停止中でないと変更できない」ことを挙げています。停止や起動の直後に次の操作を続けるときは、wait をはさんで状態が落ち着いてから実行すると、このエラーを避けられます。

よくある質問

Q. describe-instances で Name タグを表示するにはどう書きますか? A. --query の中で Tags[?Key==`Name`]|[0].Value と書きます。Tags 配列から Key が Name の要素を選び、その 1 件目の Value を取り出す式です。Name タグが無いインスタンスは None と表示されます。

Q. stop-instances を実行したのに、状態が stopped になりません。 A. コマンドは停止を受け付けた時点で返るので、応答の CurrentState は stopping です。止まり切るまで待つには aws ec2 wait instance-stopped --instance-ids … を続けて実行します。

Q. インスタンス名(Name タグ)で起動・停止できますか? A. start-instances や stop-instances が受け取るのはインスタンス ID です。Name タグで操作したいときは、describe-instances --filters "Name=tag:Name,Values=名前" で ID を取り出し、その結果を --instance-ids に渡します。

Q. 停止(stop)と終了(terminate)の違いは何ですか? A. 停止は電源を切った状態で、あとから start-instances で起動できます。終了はインスタンスの削除で、起動し直すことはできず、ルートボリュームも既定では削除されます。

まとめ

  • 一覧は describe-instances に --query と --output table を付けると、ID・Name タグ・状態・種類・IP の表になります。
  • 対象は --filters(サーバー側)、表示項目は --query(手元側)で絞ります。複数の Name= は AND、Values= のカンマ区切りは OR です。
  • start・stop・terminate の応答には PreviousState と CurrentState が入り、reboot は何も出力しません。
  • コマンドは受け付けた時点で返るので、完了を待つときは aws ec2 wait instance-running / instance-stopped を使います。
  • 停止と起動をはさむとパブリック IP は新しくなり、プライベート IP は保たれます。
  • タグで ID を集めてから --instance-ids に渡すと、複数台をまとめて操作できます。対象 0 台の分岐を入れておくと安心です。
  • --dry-run の DryRunOperation は「実行すれば成功する」の意味。エラーは、かっこの中のエラーコードで切り分けます。

参考・出典

  • AWS CLI コマンドリファレンス「ec2 describe-instances」 https://docs.aws.amazon.com/cli/latest/reference/ec2/describe-instances.html
  • 同「ec2 stop-instances」 https://docs.aws.amazon.com/cli/latest/reference/ec2/stop-instances.html
  • 同「ec2 wait instance-running」 https://docs.aws.amazon.com/cli/latest/reference/ec2/wait/instance-running.html
  • AWS CLI ユーザーガイド「Filtering output in the AWS CLI」 https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-filter.html
  • Amazon EC2 ユーザーガイド「Amazon EC2 instance state changes」 https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-lifecycle.html
  • Amazon EC2 API リファレンス「Error codes for the Amazon EC2 API」 https://docs.aws.amazon.com/AWSEC2/latest/APIReference/errors-overview.html

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「AWS CLIでEC2操作|describe-instancesと起動・停止」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?