LoginSignup
4
1

More than 3 years have passed since last update.

AWS CLIでEC2インスタンスを停止する

Last updated at Posted at 2019-12-13

こちらは、 “ゆるWeb勉強会@札幌 Advent Calendar 2019” の 14日目の記事です。

(本当は作成中の自分のサイトに載せたかったのですが、ヒジョーに見づらかったのでこちらに載せておきます...)

何を調べたか

今回は、「AWSでオペミスせずに(汗)想定のサーバーを停止する」方法を調べてみました。

背景

AWS マネジメントコンソールから検証サーバーを停止しようとして、間違えて本番サーバーを停止してしまいました。 (操作対象のチェックが複数入っているのに気づかず、停止してしまいました)

気づいたときには遅く、検証サーバーと本番サーバーが仲良く停止するのをボーゼンと見守るしかありませんでした…

できれば、停止前には「こちらのサーバーを停止しますが宜しいですか?」と確認するワンクッションが欲しい。 ということで探してみたくなりました。

結論

  • (2019/12/13現在では)AWS マネジメントコンソールの操作にワンクッション挟むことは出来ない
  • AWS コマンドラインインターフェイス(CLI)でバッチを作れば可能

※監視であれば「CloudWatch」、処理フローなら「Simple Workflow Service(SWF)」などが使えそうですが、イベントをトリガーにするため、イベント前に何かするのは難しいようです。

オペミスは想定されていないっ(ううう…)

作成したもの

WindowsのバッチファイルからAWS CLIのサーバー停止コマンドを呼び出すようにしました。

手順概要

AWS CLIは未使用で、インストールから行う場合です。

使用OS:Windows10
使用エディタ:Visual Studio Code

  1. IAMユーザーの作成
    • CLI用IAMユーザーを作成
    • IAMユーザーに権限付与
    • AWS CLI操作用アクセスキーの取得
  2. AWS EC2で各サーバにタグを付ける
  3. AWS CLIのインストール
  4. AWS CLIの初期設定
  5. AWS CLIの実行確認
    • AWSに接続
    • EC2(サーバー)一覧の取得
    • EC2停止コマンドの実行
    • EC2起動コマンドの実行
  6. バッチの作成

詳細手順

IAMユーザーの作成

※もし、EC2インスタンス停止などに使用するユーザーが作成済でしたら、新規作成しなくても良いと思います。 rootアカウントしか無い!という人は、操作用のIAMユーザーを作りましょう。

IAMユーザーの作り方は公式サイトを参照してください。

アクセス権限のポリシーは、「AmazonEC2FullAccess」を付けておきます。(今回だけならフルには不要なのですが)

IAMユーザーのアクセスキー、シークレットアクセスキーは後ほど設定で使用するため、メモしておきます。

AWS EC2で各サーバにタグを付ける

本番サーバー、検証サーバーが識別出来るようにタグを付けます。

詳しくは「Amazon EC2 リソースにタグを付ける」をご確認ください。

私は以下のようなタグを付けました。これで区別しようと思います。

対象 タグ名
本番サーバー Application Production
検証サーバー Application Staging

AWS CLIのインストール

AWS CLIにはバージョン1と2(評価版)があります。今回はバージョン1をインストールします。

Windowsの方はこちら

その他の方はAWS CLI バージョン 1 のインストールをどうぞ。

インストーラで実行した場合、パス設定がされる場合とされない場合があるようです。環境変数の設定方法はこちらを参照してください。

AWS CLIがインストールされたか確認します。コマンドプロンプトで以下を実行します。バージョンが表示されればインストールされています。

Visual Studio Codeの方は、ctrl+shift+@でターミナルが開き、そこでコマンドの実行が出来て便利です。



    > aws --version
    aws-cli/1.16.302 Python/3.6.0 Windows/10 botocore/1.13.38
  

AWS CLIの初期設定

先程メモしておいたアクセスキー、シークレットアクセスキーを用意します。

シャットダウンしたいEC2インスタンスが存在するリージョンが分からない方は、一旦マネジメントコンソールにログイン→EC2ダッシュボードに移動→右上のリージョンを確認してみてください。

リージョンが「東京」の場合は「ap-northeast-1」です。

その他のリージョンの確認はこちら


    
        > aws configure

        AWS Access Key ID [None]: ここにIAMユーザーのアクセスキー
        AWS Secret Access Key [None]: ここにシークレットアクセスキー
        Default region name [None]: (東京の場合ap-northeast-1)
        Default output format [None]:出力するデータフォーマット(json/text/tableから選択。デフォルトはjson)
    

設定されたか確認するには、aws configure listを入力します。


    
       > aws configure list
        Name                    Value             Type    Location
        ----                    -----             ----    --------
        profile                             None    None
        access_key     ****************PPUK shared-credentials-file
        secret_key     ****************h5n8 shared-credentials-file
        region           ap-northeast-1      config-file    ~/.aws/config
    

AWS CLIの実行確認

コマンド構造としては以下になっているようです。EC2の操作の場合は、aws ec2 操作 オプションのようになります。

<code>
    aws command subcommand [options and parameters]
</code>

ヘルプが見たい場合は、サービスやコマンド毎に確認できます。

aws ec2 help
aws ec2 describe-instances help

EC2(サーバー)一覧の取得

まずは設定した内容でAWSに接続できるか確認します。

aws ec2 describe-instances


    
    > aws ec2 describe-instances
{
    "Reservations": [
        {
            "Groups": [],
            "Instances": [
                {
                    "AmiLaunchIndex": 0,
                    "ImageId": "ami-3a5a415d",
                    "InstanceId": "i-09cc5014c75905b8f",
                    "InstanceType": "t2.micro",
                    "KeyName": "XXX",
                    "LaunchTime": "2019-12-10T13:54:36.000Z",
                    "Monitoring": {
                        "State": "disabled"
                    },
                    "Placement": {
                        "AvailabilityZone": "ap-northeast-1c",
                        "GroupName": "",
                        "Tenancy": "default"
                    },
                    "PrivateDnsName": "ip-XXX-XXX-XXX-XXX.ap-northeast-1.compute.internal",
                    "PrivateIpAddress": "XXX.XXX.XXX.XXX",
                    "ProductCodes": [
                        {
                            "ProductCodeId": "f18wc0igqjhsxwoxouogwqb8m",
                            "ProductCodeType": "marketplace"
                        }
                    ],
                    "PublicDnsName": "",
                    "PublicIpAddress": "XXX.XXX.XXX.XXX",
                    "State": {
                        "Code": 16,
                        "Name": "running"
                    },
                    "StateTransitionReason": "",
                    "SubnetId": "subnet-01db2ef783448de05",
                    "VpcId": "vpc-0e58a4cff354769c7",
                    "Architecture": "x86_64",
                    "BlockDeviceMappings": [
                        {
                            "DeviceName": "/dev/sda1",
                            "Ebs": {
                                "AttachTime": "2019-11-24T10:20:43.000Z",
                                "DeleteOnTermination": true,
                                "Status": "attached",
                                "VolumeId": "vol-0e8ea73e857cc1c26"
                            }
                        }
                    ],
                    "ClientToken": "157459081408640974",
                    "EbsOptimized": false,
                    "EnaSupport": false,
                    "Hypervisor": "xen",
                    "NetworkInterfaces": [
                        {
                            "Association": {
                                "IpOwnerId": "688747735680",
                                "PublicDnsName": "",
                                "PublicIp": "XXX.XXX.XXX.XXX"
                            },
                            "Attachment": {
                                "AttachTime": "2019-11-24T10:20:42.000Z",
                                "AttachmentId": "eni-attach-0e83f3e818c31d244",
                                "DeleteOnTermination": true,
                                "DeviceIndex": 0,
                                "Status": "attached"
                            },
                            "Description": "Primary network interface",
                            "Groups": [
                                {
                                    "GroupName": "wp-sg",
                                    "GroupId": "sg-0cab6793bf2ff78b9"
                                }
                            ],
                            "Ipv6Addresses": [],
                            "MacAddress": "0a:a3:df:b1:34:28",
                            "NetworkInterfaceId": "eni-01f4f73c21aab0a27",
                            "OwnerId": "688747735680",
                            "PrivateIpAddress": "XXX.XXX.XXX.XXX",
                            "PrivateIpAddresses": [
                                {
                                    "Association": {
                                        "IpOwnerId": "688747735680",
                                        "PublicDnsName": "",
                                        "PublicIp": "XXX.XXX.XXX.XXX"
                                    },
                                    "Primary": true,
                                    "PrivateIpAddress": "XXX.XXX.XXX.XXX"
                                }
                            ],
                            "SourceDestCheck": true,
                            "Status": "in-use",
                            "SubnetId": "subnet-01db2ef783448de05",
                            "VpcId": "vpc-0e58a4cff354769c7",
                            "InterfaceType": "interface"
                        }
                    ],
                    "RootDeviceName": "/dev/sda1",
                    "RootDeviceType": "ebs",
                    "SecurityGroups": [
                        {
                            "GroupName": "wp-sg",
                            "GroupId": "sg-0cab6793bf2ff78b9"
                        }
                    ],
                    "SourceDestCheck": true,
                    "Tags": [
                        {
                            "Key": "Application",
                            "Value": "Production"
                        },
                        {
                            "Key": "Name",
                            "Value": "wp-test"
                        }
                    ],
                    "VirtualizationType": "hvm",
                    "CpuOptions": {
                        "CoreCount": 1,
                        "ThreadsPerCore": 1
                    },
                    "CapacityReservationSpecification": {
                        "CapacityReservationPreference": "open"
                    },
                    "HibernationOptions": {
                        "Configured": false
                    },
                    "MetadataOptions": {
                        "State": "applied",
                        "HttpTokens": "optional",
                        "HttpPutResponseHopLimit": 1,
                        "HttpEndpoint": "enabled"
                    }
                }
            ],
            "OwnerId": "688747735680",
            "RequesterId": "086189789714",
            "ReservationId": "r-05b6d9b7554d0a378"
        },
        {
            "Groups": [],
            "Instances": [
                {
                 (2台目以降省略)
                }
  
        }
    ]
}
    


たくさん情報が出てきて見づらいです…必要な情報だけ表示したいので、絞り込みをします。


私はIPやNameタグで判断する事が多いので、後ほど使用するインスタンスID、IP、Nameタグを取得してみました。



    
        > aws ec2 describe-instances --filters 'Name=tag:Application,Values=Staging' --query 'Reservations[].Instances[].{PublicIp:PublicIpAddress,InstanceId:InstanceId,Name:Tags[?Key==Name].Value}'
        [
            {
                "PublicIp": "XXX.XXX.XXX.XXX",
                "InstanceId": "i-0c65cca2d2fbfb1db",
                "Name": [
                    "wp-site-stg"
                ]
            }
        ]
    

EC2停止コマンドの実行

停止する際のコマンドを試してみます。先程確認したインスタンスIDの情報が必要になります。

コマンドリファレンス:stop-instances

aws ec2 stop-instances --instance-ids インスタンスID

実行結果のイメージはこちらです。


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

画面上でも停止されていました。

result_img2-min.png

コマンドでも確認できるようです。以下コマンドでInstanceStatusesの値が空なら停止しています。

aws ec2 describe-instance-status --instance-ids インスタンスID


    
        //停止したインスタンス
        > aws ec2 describe-instance-status --instance-ids i-0c65cca2d2fbfb1db
        {
            "InstanceStatuses": []
        }

        //実行中のインスタンス
        > aws ec2 describe-instance-status --instance-ids i-09cc5014c75905b8f
        {
            "InstanceStatuses": [
                {
                    "AvailabilityZone": "ap-northeast-1c",
                    "InstanceId": "i-09cc5014c75905b8f",
                    "InstanceState": {
                        "Code": 16,
                        "Name": "running"
                    },
                    "InstanceStatus": {
                        "Details": [
                            {
                                "Name": "reachability",
                                "Status": "passed"
                            }
                        ],
                        "Status": "ok"
                    },
                    "SystemStatus": {
                        "Details": [
                            {
                                "Name": "reachability",
                                "Status": "passed"
                            }
                        ],
                        "Status": "ok"
                    }
                }
            ]
        }  
    

EC2起動コマンドの実行

ついでに起動コマンドも確認しておきます。こちらもインスタンスIDが必要です。

コマンドリファレンス:start-instances

aws ec2 start-instances --instance-ids インスタンスID


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

コマンド実行直後にステータスを確認してみました。


    
        > aws ec2 describe-instance-status --instance-ids i-0c65cca2d2fbfb1db
        {
            "InstanceStatuses": [
                {
                    "AvailabilityZone": "ap-northeast-1c",
                    "InstanceId": "i-0c65cca2d2fbfb1db",
                    "InstanceState": {
                        "Code": 16,
                        "Name": "running"
                    },
                    "InstanceStatus": {
                        "Details": [
                            {
                                "Name": "reachability",
                                "Status": "initializing"
                            }
                        ],
                        "Status": "initializing"
                    },
                    "SystemStatus": {
                        "Details": [
                            {
                                "Name": "reachability",
                                "Status": "initializing"
                            }
                        ],
                        "Status": "initializing"
                    }
                }
            ]
        }        
    

起動後のステータスはこちらです。


    
        > aws ec2 describe-instance-status --instance-ids i-0c65cca2d2fbfb1db
        {
            "InstanceStatuses": [
                {
                    "AvailabilityZone": "ap-northeast-1c",
                    "InstanceId": "i-0c65cca2d2fbfb1db",
                    "InstanceState": {
                        "Code": 16,
                        "Name": "running"
                    },
                    "InstanceStatus": {
                        "Details": [
                            {
                                "Name": "reachability",
                                "Status": "passed"
                            }
                        ],
                        "Status": "ok"
                    },
                    "SystemStatus": {
                        "Details": [
                            {
                                "Name": "reachability",
                                "Status": "passed"
                            }
                        ],
                        "Status": "ok"
                    }
                }
            ]
        }
    

バッチの作成

これで一通りコマンドの確認が出来たので、あとはバッチを作成していきます。
stop_stg.batなど適当な名前で、実行するPCに保存しておきます。

バッチでは、検証のインスタンス情報を表示し、停止するか確認メッセージを表示します。
はい、と答えたあと、コレジャナイ!!を予防するため、再確認もします(笑)。


    
        @echo off
        @SET AWS_ACCESS_KEY_ID=アクセスキー
        @SET AWS_SECRET_ACCESS_KEY=シークレットアクセスキー
        @SET AWS_DEFAULT_REGION=リージョン(東京はap-northeast-1)
        @SET TARGET_VM=画面に表示するサーバー名
        @SET TARGET_VM_ID=インスタンスID
        
        echo 停止するサーバ情報です。
        echo.
        aws ec2 describe-instances --filters Name=tag:Application,Values=Staging --query Reservations[].Instances[].{PublicIp:PublicIpAddress,InstanceId:InstanceId,Name:Tags[?Key==`Name`].Value}
        echo.
        echo %TARGET_VM% サーバを停止しますか?
        choice
        if %errorlevel% equ 1 goto okexe
        echo.
        echo 実行しません…。
        pause
        exit
        
        :okexe
        echo.
        echo 本当に実行しますか?
        choice /c yn /t 5 /d n
        if %errorlevel% equ 1 goto okok
        echo.
        echo 実行をキャンセルしました。
        pause
        exit
        
        :okok
        echo.
        echo 実行します!
        rem ここにサーバ停止コマンド
        echo aws ec2 stop-instances --instance-ids %TARGET_VM_ID%
        aws ec2 stop-instances --instance-ids %TARGET_VM_ID%
        echo.
        pause
        exit
        
    

作成中の失敗1:確認したコマンドがバッチでは動かない?

Visual Studio Codeではターミナルを「PowerShell」にしており、コマンドプロンプトで実行するとエラーになりました。

以下を修正すると動作するようになりました…


    
        #PowerShellで実行可能
        aws ec2 describe-instances --filters 'Name=tag:Application,Values=Staging' --query 'Reservations[].Instances[].{PublicIp:PublicIpAddress,InstanceId:InstanceId,Name:Tags[?Key==`Name`].Value}'

        #コマンドプロンプトで実行可能
        aws ec2 describe-instances --filters Name=tag:Application,Values=Staging --query Reservations[].Instances[].{PublicIp:PublicIpAddress,InstanceId:InstanceId,Name:Tags[?Key==`Name`].Value}
    

作成中の失敗2:認証エラーが出る

バッチを試す際、以下のエラーが出ました…

An error occurred (AuthFailure) when calling the DescribeInstances operation: AWS was not able to validate the provided access credentials

原因は、変数の値を""で囲っていたためでした。""を外すと動作しました。



    #NG
    @SET AWS_ACCESS_KEY_ID="アクセスキー"
    @SET AWS_SECRET_ACCESS_KEY="シークレットアクセスキー"    

    #OK
    @SET AWS_ACCESS_KEY_ID=アクセスキー
    @SET AWS_SECRET_ACCESS_KEY=o3ZvV3uAGi4WxDOs7kkYG2P45EfMgaH0nXMpRFyZ



実行結果

いろいろ試行錯誤しつつ、無事検証サーバーを停止することが出来ました!

result_img.png

ちゃんと停止しています…!

result_img2-min.png

次のステップ(野望)

次は以下も試してみたいです。

  • アクセスキーなどはベタ書きせず、ファイル読み込みにする(お恥ずかしい…)
  • バッチの中で、停止サーバーの指定が出来るようにしたい
  • AWSの別アカウントで管理されている場合の制御(AWS CLIに複数設定)も試したい

所感

いずれ使ってみたいと思っていたAWS CLI、オペミスにより使う機会が出来ました。(怪我の功名?)
色々操作が出来て良いですね。マウスなどを動かす手間が無くて便利です。

停止サーバーの選択が出来るようにすると、自由度は上がるものの、またオペミスするかもしれませんね…。どうしたらオペミスを無くせるのかしら。

もしオペミスを予防出来る素敵な案をお持ちの方はぜひ教えてください。お待ちしています !!!!!

P.S.明日はgishi_yamaさんの「ゆるくWeb開発環境(物理)について話します」です。楽しみで震えますね!(物理)

4
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1