エンジニアレポート

【Azure】仮想マシンの起動・停止をスポーツイベントスケジュールに沿って自動化する

2018年12月17日

はじめまして。DataStadiumでエンジニア兼マネージャーをやっています、菅です。

弊社では各種スポーツに関するビジネスを展開させて頂いていますが、ビジネスオペレーションはスポーツイベント、すなわち試合がある日、時間帯に集中しています。
つまり、対応するシステムもこの時間帯に稼働がピークを迎えることになります。

逆に言えば、この時間帯以外は稼働する必要がないシステムが大半なので、そういう意味ではクラウドの「利用した分だけコストを支払う」という特徴とすごく相性がいいビジネスと言えます。

つい最近まではオンプレのサーバに適当なスクリプトを書いてcronで定期実行、クラウドサービスの提供するAPIを叩いて試合開始前にサーバを起動する、みたいなことをやってましたが、最近はAWS LambdaやAzure Functionsなどのサーバレスアーキテクチャが隆盛・・・ということで、上記の仕組みをAzure Functionsに置き換えてみました。

Agenda

  • やりたいこと
  • Azure Automationの作成
  • Azure Functionsの作成
  • MS Teamsへ実行結果をPost
  • まとめ

やりたいこと

Azure上に建てた仮想マシンにMySQLを構築。関連するスポーツイベントのスケジュール情報をあらかじめ登録しておき、Azure Functionsがこのデータを定期的に参照。
イベント時間が近づいたら関連する運用サーバを起動、イベント終了時刻を過ぎたら停止。。。みたいな感じです。
できれば、サーバ起動、停止時にMS Teamsに稼働状況をPostして確認できるようになるとGood。

Azure Automationの作成

サーバの起動、停止のアクションはあらかじめAzure Automationで作成しておきます。

1.Automationアカウントの追加

Azureコンソールから「すべてのサービス」→「Automation アカウント」を選択 → 「追加」

005_001

必要事項を記入し「作成」

2.Runbookのインポート

仮想マシンの起動・停止であれば、すでにテンプレ的なRunbookが用意されていますので、ギャラリーからインポートします。
1で作成したAutomationアカウントを選択し、「Runbookギャラリー」を選択

005_002

ずらずらとテンプレが表示されますので・・・

005_003

「Start Azure V2 VMs」「Stop Azure V2 VMs」を選択し、それぞれ「インポート」します。

005_004

インポートが完了すると「Runbook」に追加されているのが分かります。

005_005

こんな感じ。

3.Runbookの編集

インポートしたRunbookを編集します。

005_006

テンプレートのグラフィックRunbookを編集して、特定の仮想マシンだけをスタート、ストップするように変更します。

005_007

今回はGet Single VM以外を削除しました。

005_008

こんな感じで不要な条件をDeleteします。
後は、実行時のパラメータに特定の仮想マシン名及びリソースグループを指定すればOKなはず。
テストウィンドウを利用してテストもできますよ。
編集、テストが終わったら「公開」でそのRunbookを利用できる状態にします。

005_009

4.ログとトレースの設定

Runbookの実行結果を測定できるように、ログとトレースの設定をしておきます。
該当のRunbookを選択し、「ログとトレース」を選択

005_010

それぞれオンにして、保存します。

5.Webhookの設定

HTTPトリガでRunbookを実行できるようにWebhookを作成します。
該当のRunbookを選択し、「Webhook」を選択

005_011

「Webhookの追加」を選択して

005_012

「名前」と「有効期限」を設定します。
この時、WebhookのURLが表示されますが、以降表示されませんので必ずコピーしておいてください。
最後に、パラメータとして起動or停止させたい仮想マシン名、リソースグループを設定しておきます。

005_013

以上でAutomationの準備は完了です。

Azure Functionsの作成

Automationが準備できたところでいよいよAzure Functionsを作成していきます。
利用できる言語はNode.js,C#,F#などあるようですが、今回はNode.jsを利用します。

1.Function Appの作成

Azureコンソールから「リソースの作成」→「Serveres Function App」を選択

005_014

アプリ名など、必須事項を記入して作成を押下します。
※今回、Node.jsなのでランタイムはJavaScriptを選択しました。

005_015

作成すると、デプロイが走ってしばらく待ちます。
デプロイ完了後、「すべてのサービス」→「Function App」を選択すると、作成したFunction Appが一覧上に表示されます。

005_016

2.関数の作成

1で作成したFunction Appを一覧から選択します。

005_017

「関数」の「+」ボタンから関数を新規に作成します。

005_018

今回はポータル画面上のエディタでソースを編集しますので、環境はポータル内を選択します。

次に作成する関数の性格からテンプレートを選択します。

005_019

今回はタイマーで定期実行させますので、「タイマー」を選択します。

005_020

関数が作成されて、ソースコードのテンプレが作成されました。
このコードを改変していきます。

3.外部ライブラリのインポート

さて、実際にソースコードに手を入れる前に、必要な外部ライブラリをFunction Appの環境にインポートします。
今回作成する関数は、自前のMySQLデータベースからスポーツイベントの日程データを取得しますので、MySQL関連のnode.jsライブラリ(npmモジュール)と、Webhookを実行するためのHTTPリクエスト実行のライブラリをインポートします。

まずは、Function Appのプラットフォーム機能の画面に遷移します。

005_021

プラットフォーム機能から、「コンソール(CMD/Powershell)」を選択します。

005_022

すると、該当Function Appの環境のコンソールが起動します。
ここで、npmのmysql,requestモジュールをそれぞれインストールします。

D:\home\site\wwwroot> npm install mysql
D:\home\site\wwwroot> npm install request

005_023

これでコード上で該当ライブラリを参照できるようになります。

4.ソースコードの編集

さて、ようやくソースコードの編集です。

まず、mysqlモジュールを利用してデータベースからスケジュールデータを参照します。

const mysql = require('mysql');

//connect mysql database
var conn = mysql.createConnection({
    host: 'データベースホスト',
    user: 'データベースユーザー',
    password: 'パスワード',
    database: 'データベース名'
});

conn.connect(
    function(err){
        if(err){
            context.log("!! Cannot connect !! ERROR!");
            throw err;
        }
        else
        {
            context.log("Connection Established.");
        }
    }
);
conn.query("SELECT * FROM テーブル名 WHERE 日付 =?", [今日の日付], (err, rows,fields) => {
    if(err) throw err;

    context.log('SELECT RESULTS: ', rows.length);
    context.log(rows);


});

conn.end();

こんな感じですね。
context.log()でログを吐くことができます。

SELECTした結果、サーバを起動させたい・・・となったら、事前に準備していたAzure Automation関数のWebhookを実行します。
これはrequestモジュールを利用します。

var request = require('request');
var options = {
    uri: "automationでWebhook作成時にコピーしたURL",
    headers: {
        "Content-Type" : "application/x-www-form-urlencoded"
    }
}
request.post(options, function(error, response, body){
});

こんな感じです。

関数ができたら実行してみます。
「保存」→「実行」でうまくいけば、DBからデータ参照し、スケジュールが登録されていれば特定の仮想マシンを起動・・・となるハズです。

(参考).Azure Functionsからのリクエスト元IPアドレス

今回、Azure FunctionsからMySQLデータベースにSQLで情報取得しに接続しましたが、データベース側で接続元を限定したいことが多々あるかと思います。
そもそもAzure Functionsからの通信って、IPアドレスはどうなるんでしょうか?
実はこれもプラットフォーム機能から確認することができます。

005_024

プロパティを選択すると

005_025

005_026

送信元IPが記載されています。
これらすべてから通信される可能性がありますので、接続先ではすべてからのアクセスを受け付ける必要があります。

実行結果をMS TeamsにPOST

ここまでで、当初の目的はほぼ達成されましたが、最後に「(起動・停止)された」ことをMS TeamsにPOSTして関係者が把握できるようにしてみました。

弊社では社内のコミュニケーションツールにMS Teamsを利用していますが、ここはSlackやLINEなどでも応用が利くかと思います。

まずはMS Teams側の準備です。

1.MS Teamsの特定チャンネルでWebhookを準備する

まずPOSTしたい特定のチャンネルを選んで、コネクタの設定をします。

005_027

Incoming Webhookのコネクタを追加します。

005_028

005_029

インストールして・・・

005_030

適当に名前を入力し、作成します。

005_031

ここでWebhookのURLが表示されますが、1度しか表示されないので必ずコピーします。

以上でTeams側の設定は完了です。

2.Function App側の実装

Function App側のコードを編集してWebhookリクエストでPOSTするようにします。
AutomationのWebhookを実行したときと同様、以下のような感じです。

 var request = require('request');
 var optionsTeams = {
    uri: "MS TeamsのWebhook URL",
    headers: {
        "Content-Type" : "application/json"
    },
    json: {
        "text" : "サーバ起動しました!"
    }
}
request.post(optionsTeams, function(error, response, body){
});

これでTeamsにAzure FunctionsからPOSTできるようになりました。

まとめ

今回初めてAzure Functionsを触りましたが、スムーズに導入まで行けました。
今後もこういった仕組みを利用して、運用の自動化を進めていきたいですね。

エンジニア募集中!

データスタジアムでは一緒に働いていただけるエンジニアを募集しています。野球、サッカー、バスケなどスポーツが好きな方であれば、とても面白い仕事ができる会社です。興味を持たれた方はぜひこちらをご覧ください。

エンジニアトップ エンジニアインタビュー エンジニアレポート

  • 採用情報
  • おしらせ
  • 掲載事例

ページトップヘ