itB!HatenaPocketLINELINEプラットフォーム技術部の小林正彦です。何と無しにマネジメントコンソールをさわっていたら、先月まで実現できなかったことがいつのまにかできるようになっている。最近話題に上ったことがすでに実装されている。いう驚きに、AWSの最新情報には常にアンテナを張っていなければと改めて思いました。CLIコマンドによる簡単な起動停止スクリプトのご紹介をしていきます。記事をご覧になった方の日々の運用を改善するヒントになれば幸いです。最後までお付き合いよろしくお願いします。まとめRDSインスタンスの停止についてRDSインスタンスを停止させる機能は2017年1月から利用可能となりました。この機能が提供されるまではインスタンスを単純に停止することができず、「インスタンスのスナップショットを作成してからインスタンスを削除する」という作業をしなければなりませんでした。そんな折、2017年1月以降にRDSインスタンスの停止が正式にサポートされたことによりRDSインスタンスを一時的な停止状態に置くことが簡単にできるようになりました。Auroraは対象外とされていたのですが、そのAuroraも他のエンジンに遅れること20ヶ月、ついに停止機能が実装されました。これによりRDSが提供するすべてのDBエンジンでインスタンスを一時的に停止させておくことができる。下表に、2018年11月時点での各DBエンジンにおける停止操作の可否についてまとめました。DBエンジン、シングル/マルチ構成、リードレプリカの有無等々で停止できるか否かが変わってくるので、(”すべての”と上では書いていますが)何でも停止できるわけではないということを覚えておきましょう。リードレプリカが存在する場合にインスタンスを停止しようとすると下記のエラーが表示され、停止させることができません。クラスターの停止のみ可能。クラスター内の各インスタンス単位での停止はできない。説明の中で「一時的な停止状態」と記載していますが、そのとおり、RDSインスタンスの停止状態とは一時的なものでしかありません。EC2インスタンスのように停止したらしっぱなしというわけにはいきません。RDSインスタンスの停止期間は最大7日間となっています。7日をすぎるとRDSインスタンスは自動的に起動してくるということです。停止したからもう安心、ではありません。停止における細かな制約についてはこちらも参照してください。インスタンスを停止するhttps://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide...停止する目的なぜRDSインスタンスを停めたいのか。それはずばりコスト削減です。使った分だけ課金されるクラウドシステムにおいて、無駄となってしまうような利用時間は極力減らしたいところです。本番環境においてはRDSの可用性と耐久性のおかげで常に稼動し続けてくれるというのは非常にありがたいものですが、こと開発環境で24/365で常時稼動させておく必要性があるかというと、おそらくないでしょう(このテスト期間中は停めないで、という要望はでてきます)。開発環境でのRDSインスタンスの利用最適化がコスト最適化に直結するのです。そのためにRDSインスタンスの停止について検討していきます。停止方法RDSインスタンス停止方法としては例えば下記のようなものがあげられます。EC2,RDS起動停止システムをデプロイできるソリューション。まとめて起動し、各処理をコーディングすることなくスケジューリング可能なサービス。これらに限らず多様なツールがありますので工夫次第で様々な仕組みを構築することができると思いますが、本記事では網羅的な停止方法の検討・検証は実施しないので、後日機会がありましたら書かせていただきます。マネジメントコンソール単純に停止するだけであればマネジメントコンソールで事足ります。運用担当者が手動でRDSを管理していけばコスト最適化も実現できるでしょう。手作業であるが故の面倒さは解消できません。起動/停止する時間帯に担当者がいなければならない。開発ツール各種開発ツールでAPIを利用するアプリケーションを開発するというのも1つの方法です。CLIコマンドを実行する簡単なスクリプトを作成し、そのスクリプトを定期的に実行する仕組み(タスクスケジューラ、cron、ジョブスケジュール製品など)と環境を用意すれば、それだけで自動化されたシステムの完成です。実行環境であるサーバー(EC2)の準備・管理や、アプリケーションの実行制御方式については検討が必要ですが、開発環境のRDS管理用であると割り切れば、それほど大掛かりなシステムを構築しなくても良いでしょうし比較的導入はしやすいと思います。API利用のための基盤が用意されているといった環境であれば難しいことを考えずに導入できるでしょう。Eventを組み合わせてサーバーレス環境を用意するのもいいでしょう。仕組みを考える必要も無く、AWSの自前のサービスを組み合わせるだけで実現できます。インターネットに接続されていないクローズドな環境でLambdaを利用してRDSのAPIを実行する、ということもできます。VPC内にLambdaを配置することの注意点についてこちらにまとめていますのでご参考に。...https://devlog.arksystems.co.jp/2018/04/04/4807/さてここまで以下のような流れで停止方法について書いてきました。サーバーレス化ですが、最終的にはサーバーレスな仕組みを実現しよう!ということをお伝えしたいわけではありません。要するに、どの方法が優れている、劣っているという問題ではなく、今の現場の運用にどの方法ならフィットするか、ベターであるかを検討する必要があるということです。自社のAWS利用環境が充実していて、サーバーレス構成を実現するためのナレッジがたまっている、共通化された仕組みがあるといった場合はサーバーレスを採用することになるでしょうし、場合によっては「コスト削減」という命題に対して「手運用」というのが最適解となる可能性もあります。AWSを利用するのだからサーバーレスな構成がベストである。決め付けてしまうのではなく、今の運用業務の延長線上にはまりそうか、という点をしっかり検討していきましょう。自動化する意義RDSインスタンスは停止後7日を過ぎると自動的に起動してきます。起動タイミングにあわせて週次で停止作業をしていけばよいのですが、仮に手運用で日々インスタンスの状態を確認していたとしても、タイミング悪く休日に起動し始めて翌営業日に担当者が確認するまで休日の間ずっと起動しっぱなしだった。なんてことが起こってしまうかもしれません。そんなもったいない事態を避けるためにもRDSの起動停止を自動化しよう!というわけです。「コスト削減が目的である」とはいったものの、実際にどれくらいコスト最適化が見込めるのでしょうか。下表は同じインスタンスタイプでのEC2とRDSのコスト比較表です。Multi-AZ構成は同じインスタンスタイプのEC2と比べて実に3倍近い料金が課金されます。RDSインスタンスの方が時間単価が高いのですから、RDSインスタンスの稼動時間を適切にコントロールする方がコスト最適化にインパクトがあるのはお分かりいただけると思います。RDSインスタンスの課金体系は1時間単位となります。1時間未満の稼動であっても1時間分の料金として課金されてしまうので、適切に利用時間をコントロールすることで、無駄な稼働時間を減らすことができます。(ちなみにEC2インスタンスは秒単位で料金計算。)開発環境上にEC2インスタンスとRDSインスタンスが1セットのみしか存在しないなんてことはないでしょう。開発の段階や用途に応じてセット数は増え、稼働時間の調整もばらばらだったりすると、それだけ管理が煩雑になっていきます。開発Aインスタンスは短時間の性能テスト用なので数時間だけ起動させる。開発Bインスタンスは9-18時の業務時間中は起動する。利用用途に応じて柔軟に起動停止時間を管理できることが望ましいです。→77%の稼働時間削減!!ということになります。CLIを使ったRDS管理方法について書いていきます。環境EC2、RDSインスタンス内のOS,MWなどはこちら。Single-AZ構成図はこちら。このように、クローズドな環境に配置されたEC2とRDS、インターネットへ接続するためのプロキシサーバが存在しています。直接アクセスして各サービスとやりとりします。CLIを利用するための大前提となります。CLIを利用する端末がインターネットに接続している端末であれば、難しいことを考えずにパブリックAPIを利用することができます。CLIによるAPI利用を検討する場合、下記のような構成が考えられます。Lambdaを利用するPrivateLinkの利用する場合の注意点などについてはこちらに詳細をまとめていますのでご参考までに。...https://devlog.arksystems.co.jp/2018/05/11/4896/IAMロールAPIリクエストを作成する際の認証情報は、IAMロールによって生成されたものを使用します。CLI環境設定にアクセスキー、シークレットアクセスキーの設定はしません。AWS認証情報についてはスクリプト解説欄に詳細を記載したのでそちらを参照ください。スクリプト実行環境となるEC2に、以下の3つのアクションを許可するロールをアタッチします。describe-db-instance停止するだけであれば停止アクションのみを、起動だけであれば起動アクションのみをアタッチすればオッケーです。起動停止だけであればDescribeDBInstancesのアクションは不要です。今回は1つの実行環境で3つのアクションを実行するのですべてのアクション許可ロールをアタッチしています。今回作成したポリシーのjson出力は下記のとおり。]}スクリプト作成の方針コスト最適化のための自動化用スクリプトであり、基本的に開発環境のみの利用を前提にしている運用スクリプトですので、細かい障害を想定したエラーハンドリングなどは実装していません。スクリプトの実行と制御はJP1で実現するため、「起動/停止/状態確認」といった各処理を1つのスクリプト上に実装するのではなく、1処理1スクリプトで分割して作成します。それらスクリプトをJP1の先行後続関係で順番に実行させていきます。今回作成したスクリプトは下記の4つです。起動スクリプト停止スクリプトステータスチェックスクリプトステータスチェックスクリプト(指定時間継続して状態監視)各スクリプトの内容を掲載していますのでご参考までに。見ていただければ分かると思いますが非常に簡単です。最後にスクリプトの簡単な解説をのせています。$INSTANCENAME停止スクリプト起動スクリプトと全く同じ構造です。CLIコマンドが異なるだけ。$INSTANCENAMEステータスチェックスクリプトインスタンスの状態確認用のスクリプトです。describe-db-instanceコマンドで出力した結果から、DBInstancesStatusの情報を抽出・整形して出力しています。15分の間、インスタンスのステータスを確認します。このスクリプトを先ほどの起動スクリプト、停止スクリプトの後続に配置して、インスタンスの状態が確実に[available/stopped]になるのを確認します。RDSインスタンスの起動・停止処理の開始から状態が落ち着くまでに5~10分ほどの時間がかかるので、余裕を持って、確認時間のデフォルトを15分間としています。アドレスを使用して設定しています。proxy.https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-h...プロキシ利用しない設定さきほどのプロキシ利用設定の次の行で、「169.254.169.254」のアドレス向けのHTTPアクセスはプロキシを利用しないよ、という設定をしています。169.254.169.254今回の操作に限らずにAPIリクエストを作成する処理を実装する場合は、その処理を実行するアプリケーション(というと大げさですが、今回のような非常に簡単なスクリプトもその一つ)がAWS認証情報(アクセスキー/シークレットアクセスキー)でAPIリクエストに署名をする必要があります。CLIコマンドのオプションとしてkeyを引き渡す。要するにAWS認証情報を実行環境となるインスタンス内部で保持し、適切に管理していかなければならないということになります。場合によっては非常に煩雑な運用をしていかないといけなくなる可能性もあります。そのような運用をしないために、AWS認証情報の配布を自身で管理せず、アプリケーションが使用するアクションとリソースを定義したロールを、実行環境となるEC2インスタンスにアタッチする構成をとっています。IAMロールによって提供される認証情報を取得するには、該当のインスタンスのインスタンスメタデータを参照できなければなりません。インスタンスメタデータとは下記のパスに格納されている情報で、その時点で有効なIAMロールが作成したセキュリティ情報が格納されています。CLIは、APIリクエストを作成する際に自動的にこのメタデータを参照することになっているので、さきほどのプロキシ除外設定をいれていないと下記のようなエラーが出力され、APIリクエストを作成することができません。表示される場合は、ワーニングの出力を回避するために下記のタイムゾーン設定をします。jst引数判定この辺は作成者の好みですが、引数に対象のRDSインスタンス名を指定できるようにしたので、引数判定処理を入れています。スクリプトの実行ログを出力するというような処理も実装していないので非常にシンプルです。}スクリプトの組み合わせ起動/停止コマンドを実行したあとに、想定どおりにインスタンスの状態が変わったかを確認するのにマネージドコンソールを開いていたのでは自動化する意味が全くありません。そこで、起動停止後の一定時間の状態変化を確認し、想定どおりの状態の落ち着いたところで処理が終了するという一連の流れを実装する必要があります。上記の流れを1つのスクリプトに実装することももちろんできますが、今回はジョブ実行環境としてJP1を利用したので、各スクリプトの処理は必要最低限にし、実行タイミングの制御や、先行後続関係の設定、処理のハンドリング等はJP1の機能を利用して実現しています。実際のジョブ構成はこのような感じです。処理が処理だけに非常にシンプルでおもしろみは無いですね。真ん中のCheckInstanceInterval処理で指定時間(15分)経過してもインスタンスの状態が[aveirable|stopped]になっていない場合は異常終了し、後続のリカバリジョブでもう一度起動処理を実施させています。masahiko-kobaこのサイトの掲載内容は投稿者自身の見解であり、必ずしも当社の立場、戦略ならびに意見を代表するものではありません。本サイトに掲載されている商品またはサービス等の名称は、各社の商標または登録商標です。アークシステムのSNSをいいね!&フォローしよう。@arksystemsJp最新情報をお届けします。この記事が気に入ったらいいね!&シェアお願いします。弊社でも社内業務システムをForce.com上に構築することになりました。CodeでRDS停止のLambda関数作ってみるLambda関数で「動いているRDSインスタンス一覧を取得して全て止める。