AWSのLambdaでEC2自動起動・停止の関数を作成する手順を紹介します。業務時間内だけEC2を起動させるため、平日(土日祝と振り替え休日を除く)だけ処理が実行されるよう設定していきます。
Lambda関数の作成
・コンソール画面のLambdaにて、リージョンが「東京」であることを確認し「関数の作成」を選択
・ロールの項目にて「カスタムロールの作成」を選択
・ロールの作成画面が起動するので、ポリシードキュメントを表示し「編集」を選択 ※ロール名はそのままで大丈夫です。
・以下を参考にポリシードキュメントを編集 ※EC2インスタンスへの権限を追記
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
[js] { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": "arn:aws:logs:*:*:*" }, { "Effect": "Allow", "Action": [ "ec2:Start*", "ec2:Stop*" ], "Resource": "*" } ] } [/js] |
・ポリシードキュメントの編集が完了したら「許可」を選択
・関数の作成画面に戻り、各項目を入力したら「関数の作成」を選択 ※まずは自動起動の関数を作成します。
「名前」:任意(今回はStartFunctionとしました)
「ランタイム」:休日判定のプログラムを記述する言語(今回はNode.jsにしました)
「既存ロール」:先ほど作成したlambda_basic_executionを選択
休日判定の設定
・関数コード(index.js)を編集
・既存コードを削除し、以下コードをindex.jsに貼り付け ※【インスタンスID】を対象のIDに書き換えてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
[js] //引用開始部 function getNationalHoliday(dateobj) { //祝日を判定する関数。 //祝日ならばその名称、祝日でなければ空文字を返す。 var nen, tsuki, hi, yobi; if(dateobj.getFullYear() < 2007) { throw new Error("2007年以上にしてください。"); } nen = dateobj.getFullYear(); tsuki = dateobj.getMonth() + 1; hi = dateobj.getDate(); yobi = dateobj.getDay(); if(tsuki == 1 && hi == 1) { return "元日"; } if(tsuki == 2 && hi == 11) { return "建国記念の日"; } if(tsuki == 4 && hi == 29) { return "昭和の日"; } if(tsuki == 5 && hi == 3) { return "憲法記念日"; } if(tsuki == 5 && hi == 4) { return "みどりの日"; } if(tsuki == 5 && hi == 5) { return "こどもの日"; } if(nen >= 2016 && tsuki == 8 && hi == 11) { return "山の日"; //2016-8-11から実施。 } if(tsuki == 11 && hi == 3) { return "文化の日"; } if(tsuki == 11 && hi == 23) { return "勤労感謝の日"; } if(tsuki == 12 && hi == 23) { return "天皇誕生日"; } if(tsuki == 1 && yobi == 1 && 7 < hi && hi < 15) { return "成人の日"; //1月第2月曜日; } if(tsuki == 7 && yobi == 1 && 14 < hi && hi < 22) { return "海の日"; //7月第3月曜日 } if(tsuki == 9 && yobi == 1 && 14 < hi && hi < 22) { return "敬老の日"; //9月第3月曜日 } if(tsuki == 10 && yobi == 1 && 7 < hi && hi < 15) { return "体育の日"; //10月第2月曜日 } if(tsuki == 3 && hi == shunbun(nen)) { return "春分の日"; } if(tsuki == 9 && hi == shubun(nen)) { return "秋分の日"; } return ""; } function shunbun(nen) {//春分の日 if(nen < 1900 || nen > 2099) { return 0; } if(nen % 4 === 0) { return nen <= 1956 ? 21 : (nen <= 2088 ? 20 : 19); } else if(nen % 4 == 1) { return nen <= 1989 ? 21 : 20; } else if(nen % 4 == 2) { return nen <= 2022 ? 21 : 20; } else { return nen <= 1923 ? 22 : (nen <= 2055 ? 21 : 20); } } function shubun(nen) {//秋分の日 if(nen < 1900 || nen > 2099) { return 0; } if(nen % 4 === 0) { return nen <= 2008 ? 23 : 22; } else if(nen % 4 == 1) { return nen <= 1917 ? 24 : (nen <= 2041 ? 23 : 22); } else if(nen % 4 == 2) { return nen <= 1946 ? 24 : (nen <= 2074 ? 23 : 22); } else { return nen <= 1979 ? 24 : 23; } } function getHoliday(dateobj) { //休日(祝日と日曜日と振替休日)を判定する関数。 //休日ならばその名称、休日でなければ空文字を返す。 var kyujitsu = "休日"; var isNH = []; var isSun = []; var holidayname = []; var thisday, i; if(dateobj.getFullYear() < 2007) { throw new Error("2007年以上にしてください。"); } for(i = -3; i < 2; i++) { thisday = new Date( dateobj.getFullYear(), dateobj.getMonth(), dateobj.getDate() + i); holidayname[i] = getNationalHoliday(thisday); isNH[i] = (holidayname[i] != ""); isSun[i] = thisday.getDay() === 0 ? true : false; } //国民の祝日に関する法律第三条 //第1項 「国民の祝日」は、休日とする。 if(isNH[0]) { return holidayname[0]; } //第2項 「国民の祝日」が日曜日に当たるときは、 //その日後においてその日に最も近い「国民の祝日」でない日を //休日とする。 if(isSun[-1] && isNH[-1]) { return kyujitsu; } if(isSun[-2] && isNH[-2] && isNH[-1]) { return kyujitsu; } if(isSun[-3] && isNH[-3] && isNH[-2] && isNH[-1]) { return kyujitsu; } //第3項 その前日及び翌日が「国民の祝日」である日は、休日とする。 if(isNH[-1] && isNH[1]) { return kyujitsu; } //日曜日 if(isSun[0]) { return "日曜日"; } return ""; } //引用終了部 var AWS = require('aws-sdk'); var ec2 = new AWS.EC2(); AWS.config.update({region: 'ap-northeast-1'}); exports.handler = (event, context, callback) => { var params = { InstanceIds: ['【インスタンスID】'] }; var today = new Date(); today.setHours(today.getHours() + 9); var getHolidayName = getHoliday(today); if (getHolidayName == "" || null) { ec2.startInstances(params, function(err, data) { if (err) console.log(err, err.stack); // an error occurred else console.log(data); // successful response }); callback(null, 'done'); } }; [/js] |
【引用】
・コードを貼り付けたら「保存」を選択
関数実行トリガーの設定
・左側のトリガーリストから「CloudWatch Events」を選択
・トリガーの設定にて各項目を入力し「追加」を選択
「ルール」:新規ルールの作成を選択
「ルール名」:任意(今回はStartRuleとしました)
「ルールタイプ」:スケジュール式を選択
「スケジュール式」:月~金の8:00に起動する場合は以下となる
1 2 3 4 5 |
[js] cron(0 23 ? * SUN-THU *) [/js] |
※Lambdaにて日本時刻を指定する場合、実行時刻からマイナス9時間して設定(起動させたい8:00から9時間マイナスすると前日の23時となり、曜日もひとつずれるため日曜~木曜を指定する必要がある)
・「保存」を選択
以上で自動起動関数の作成は完了です。
自動停止関数の作成
自動起動関数と同様に自動停止関数を作成します。設定内容はほぼ同じなので、異なる設定箇所だけ記載します。
1)各名称 ※「Start」とつけたものは「Stop」に変える等
2)index.jsの151行目「ec2.startInstances(params, function(err, data) {」を以下に変更
1 2 3 4 5 |
[js] ec2.stopInstances(params, function(err, data) { [/js] |
3)トリガー設定のcronスケジュール式を変更 ※例)月~金の22:00に停止させる場合は以下
1 2 3 4 5 |
[js] cron(0 13 ? * MON-FRI *) [/js] |
まとめ
現状のLambdaでは処理実行の曜日は指定できても、祝日や振り替え休日を指定する機能はありません。なのでこういったプログラムを別途作成する必要があります。
今後、AWS環境や日本休日に変更があると、上記設定が正常に動作しない可能性があるため、使用する際は定期的に確認する必要があります。また設定については全て自己責任でお願いします。