ちょっと話題の記事

Jenkinsやcronを使ったEC2の定期的な起動停止

2014.09.16

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

渡辺です。

AWS最大の特徴のひとつは時間課金であるということです。 したがって、利用しない時間帯にインスタンスを停止しておけば、それだけ運用コストを減らすことができます。 手動でやっても良いのですが、自動化しまうほうが良いでしょう。

今回は、定期的にEC2インスタンスの起動・停止を行う方法として、昔ながらのcronを使う方法と、Jenkinsを使う方法を紹介します。

インスタンスの起動・停止をコマンドで実行する

インスタンスの起動・停止は様々な方法で行うことができますが、最も簡単に行う方法はaws-cliを利用することです。

# インスタンスの起動
aws ec2 start-instances --region=ap-northeast-1 --instance-ids=i-XXXXXXXX 
# インスタンスの起動
aws ec2 stop-instances --region=ap-northeast-1 --instance-ids=i-XXXXXXXX

aws-cliは、Amazon Linuxであればデフォルトでインストールされています。 インスタンスのidはマネジメントコンソール等で確認してください。

これらのコマンドをコマンド実行用のインスタンス(microインスタンスで充分でしょう)からcron等で実行すれば、簡単に定期的なインスタンスの起動停止が実現出来ます。 ただし、これらのコマンドを実行するには、実行権限を持つIAMユーザのアクセスキー/シークレットキーか、Roleが必要です。

EC2の起動停止を行うRoleを割り当てる

可能であればアクセスキーとシークレットキーの管理はやりたくありません。 ここではRoleを割り当てておきます。

専用のRole(例: mainte)を作成し、EC2インスタンスの起動・停止に関する権限を付与しましょう。 テンプレートにある、EC2のPower Userプロファイルでも構いません。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
         // 略
        "ec2:Describe*",
        "ec2:StopInstances",
        "ec2:StartInstances",
         // 略
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

後はこのRoleを使ってEC2インスタンスを起動しておきます。

cronジョブの追加

Roleを作成し、ジョブ実行用のインスタンスを起動したならば、例えば、次のようにcronにコマンドを登録します。

0 0 * * * aws ec2 stop-instances  --region=ap-northeast-1 --instance-ids=i-XXXXXXXX
8 0 * * * aws ec2 start-instances  --region=ap-northeast-1 --instance-ids=i-XXXXXXXX

これで深夜0時にインスタンスを停止し、翌朝8時にインスタンスを起動することができます。 これだけでインスタンスの利用費は約2/3(8/24)になりますね!

なお、登録する時はインスタンスのタイムゾーン設定に注意してください。 EC2のデフォルトタイムゾーンはUTCです。

Jenkinsによる定期実行

cronは手軽に導入可能でコマンドさえ登録すれば簡単にスケジュール実行することができます。 しかし、実行ログなどの管理は自分で行わなければなりません。 SSHでログインする必要もあります。

ならば、Jenkinsを導入してみるのも良い選択です。 Jenkinsは継続的インテグレーションのためのツールとして有名ですが、ジョブスケジューラとしても便利に使うことができます。そして導入もラクチンです。

Jenkinsの準備

Jenkins用のインスタンスを立ち上げます。 cronの時と同様に他のインスタンスを操作可能なRoleを適用してください。

Jenkinsはyumでインストールできます。 リポジトリを登録してインストールすれば簡単に実行可能となるでしょう。

$ sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
$ sudo rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key
$ sudo yum install jenkins
$ sudo yum -y install jenkins
$ sudo service jenkins start
$ sudo chkconfig jenkins on

Jenkinsはデフォルトで8080ポートで起動します。 セキュリティグループの設定で、8080ポートにアクセスできるように設定してください。 また、デフォルトではパスワード等のセキュリティが有効になっていません。 IPアドレスで制限を行うか、パスワード等の設定をする必要があります。

なお、EC2の定期起動・停止程度のジョブを実行するだけであれば、microインスタンスでも問題なく動作します。

ジョブの登録

Jenkinsにアクセスしたならば、ジョブを登録します。

jenkins-1

ジョブで設定が必要なのは2個所です。

ビルド・トリガセクションでは「定期的に実行」を選択し、スケジュールを登録します。 基本的にはcronと同じ書式で設定可能です。

ビルドセクションでは、「シェルの実行」を選択し、実行するコマンドを入力します。

jenkins-2

ジョブが登録されると、ダッシュボードに表示されます。 最新の実行結果や実行時間なども確認できるので便利です。

jenkins-3

また、ジョブは実行されるとログが記録されます。 コンソールへの標準出力も確認できるため、失敗した場合のエラーメッセージも簡単に確認できます。

jenkins-4

なお、「ビルド」と表示されているのは、JenkinsがJava系のプロジェクトのビルド支援ツールとして開発された経緯があるからです。 シェルの実行しかしていないので「ビルド」と書かれると、少し違和感も感じますが、細かい所は気にしないでください。

その他の機能

Jenkinsには他にも多くの機能があります。

バージョン管理システムとの連携

GitやSubversionなど、各種バージョン管理システムと簡単に連携させることができます。 このため、実行するスクリプト自体をバージョン管理することも容易です。

通知

ジョブの実行に失敗した場合にメールやその他の手段で失敗を通知する機能があります。 この機能を使えば、インスタンスの起動(停止)失敗時に対応しやすいでしょう。

ジョブの連携

インスタンスを停止後にスナップショットを作成するなど、あるジョブを実行した後に別のジョブを実行したい場合があります。 このような場合でも、Jenkinsではジョブの発火タイミングを細かく制御できます。

まとめ

aws cliを定期的に実行出来れば、簡単にインスタンスの起動・停止やスナップショットの作成を行うことができます。 cronを利用するのが定番ですが、Jenkinsを使えば運用も楽になり小回りも効くようになります。 導入も非常に簡単です。 定期的なコマンドの実行は、cronだけではなくJenkinsを使ってみてはどうでしょうか?