Microsoft Azure

クロスプラットフォーム クラウドの JavaScript による自動化

Steven Edouard

あまり知られていませんが、Microsoft Azure には、Microsoft Azure の IaaS サービスや PaaS サービスを管理するためのクロスプラットフォーム コマンド ライン インターフェイス (xplat-cli) が備わっています。マイクロソフトは長年スクリプト言語として Windows PowerShell の使用を提唱してきました。Windows PowerShell は、クラウドベースのリソースのプロビジョニングに威力を発揮します。しかし、クラウドへのアプリの配置や移行に関与する開発者が増え、JavaScript の使用が望まれるようになりました。このようなクロスプラットフォーム実装は、Microsoft Azure のサービス管理 REST API を使用すると容易になります。Microsoft Azure 正規の xplat-cli は Node.js を基盤として実装されています。JavaScript を使ってパフォーマンスの高い Web サイトや API をビルドする際は、多くの場合、Node.js と同じランタイムを使用します。

Node.js を基盤にビルドすると、スクリプトの作成は真の意味でクロスプラットフォームになります。つまり、仮想マシン (VM)、SQL Databases、Web サイト、仮想ネットワークを管理するために、任意のコンピューターからスクリプトを実行できます。これにより、多種多様なコンピュータを対象にさまざまな言語を使用して、自動化スクリプトを実行できるようになります (図 1 参照)。

サポート対象のスクリプティング環境
図 1 サポート対象のスクリプティング環境

クラウド リソースのプロビジョニングにスクリプトを使用することには多くのメリットがあります。たとえば、Web ポータルを使うと、人手による入力が必要になり、繰り返し利用することはできません。環境固有のさまざまな構成値を使用してサービスをプロビジョニングおよび配置する手順を示したソースのソース管理が行えるようになることもメリットの 1 つです。今回は、スクリプト自動化環境として Node.js を使用し、アフィニティ グループや仮想ネットワークに関連付けられる VM を作成するプロセスをスクリプトにする手順を説明します。

クロスプラットフォーム CLI

Microsoft Azure の PowerShell CLI と同様、このクロスプラットフォーム バージョンの CLI は、IaaS サービスや PaaS サービスを管理するための強力なスクリプト機能を提供します。この CLI を使って、コードによるインフラストラクチャの記述、ソース管理によるチームでのコードの共有、および開発、テスト、運用アプリ配置の作成の自動化が可能になります。

xplat-cli を使用するには、まず、Nodejs.org (英語) にアクセスして、使用しているシステムに適切な Node.js パッケージをインストールします。インストールしたら、npmjs.org/package/azure-cli (英語) で azure-cli パッケージを表示できます。

パッケージ リストには、CLI の全関連ドキュメントや、パッケージをインストールする簡単なコマンドラインが含まれています。このパッケージが CLI です。そのため、このパッケージは以下のように –g を指定してグローバル Node.js パッケージ ストアにインストールします。その結果、特定のディレクトリから CLI を明示的に呼び出すのではなく、すべてのディレクトリから Microsoft Azure のコマンドラインを呼び出すことができるようになります。

npm install azure-cli -g

Node Package Manager は数行出力した後、azure-cli パッケージのインストールを完了します。完了後はすぐに使い始めることができます。

ドキュメントを完備した CLI

この CLI が優れている点は、操作方法を記載したドキュメントを表示できることです。詳細を知りたいコマンドを入力するだけで、簡単に使い始めることができます。図 2 は、基本 CLI コマンドの "azure" を呼び出した場合の出力です。

xplat-cli の "azure" コマンド
図 2 xplat-cli の "azure" コマンド

基本の "azure" コマンドを呼び出すと、利用可能な多くのコマンドが表示されます。たとえば、図 2 の help 出力行に "vm"コマンドがあります。"vm" コマンドの使用方法を詳しく知りたければ、"azure vm" コマンドを入力するだけで、コマンドの詳細が表示されます (図 3 参照)。

仮想マシンを作成する CLI コマンド
図 3 仮想マシンを作成する CLI コマンド

同じパターンが、CLI のすべてのコマンドに当てはまります。これにより、コマンド ラインについて調べる際に直感的なインターフェイスを利用できます。

CLI からサブスクリプションにアクセスする

当然、Microsoft Azure サブスクリプションにサインアップして、コマンドライン ツールで使用するサブスクリプションを指示するまでは、大半の Azure コマンドが機能しません。Windows PowerShell のツールと同様、CLI からサブスクリプションにアクセスできるようにする必要があります。これを行う方法は 2 とおりあります。1 つは "login" コマンドと共に Microsoft 組織アカウントを使用して Active Directory アカウントを経由する方法、もう 1 つは "account import" コマンドを使用して移植可能な .publishsettings ファイルを使用する方法です。後者の方法は組織アカウントをセットアップする必要がないため、移植性が高くなります。以下のコマンドを使用して、.publishsettings ファイルを簡単にダウンロードできます。

azure account download

これにより、Microsoft Azure アカウントにサインインして .publishsettings ファイルをダウンロードするためのリンクが、既定のブラウザーで開かれます。.このファイルをダウンロードしたら、以下のように "account import" コマンドを使用してファイルを読み込みます。

azure account import <PATH TO .publishsettings>

これにより、CLI で呼び出されるすべての Microsoft Azure コマンドに、.publishsettings で指定された Microsoft Azure サブスクリプションを使用するようコマンドラインがセットアップされます。CLI が機能するかどうかを確認するには、"site list" コマンドを呼び出して、現在のサブスクリプションで実行されているすべての Web サイトを出力します。

CLI から開発用 VM を作成する

VM は特に DevOps のシナリオに役立ちます。VM は xplat-cli を使って簡単にプロビジョニングできます。

最終的には、Nodejs で JavaScript を使用して VM をプロビジョニングするタスクのスクリプトを作成することで、CLI を使ってタスクを自動化します。たとえば、新しい Ubuntu VM を作成するとします。そのためには VM イメージを見つける必要があります。以下のコマンドにより、利用可能な VM の一覧を取得できます。

azure vm image list

このコマンドの出力として、VM のプロビジョニングに利用できるパブリック イメージとプライベート イメージの一覧が表示されます。パブリック イメージはマイクロソフトが監修したイメージですが、独自のイメージをアップロードして使用することもできます。

VM を作成するには、データセンターの場所が必要です。VM を配置できる有効な場所の一覧を取得するには、以下のコマンドを実行します。

azure vm location list

この場所を "vm create" コマンドの入力に使用して、以下のように新しい VM を作成します。

azure vm create <yourdomainname> <imagename> <username> <password> --location '<selected datacenter region>'

コマンド ラインから VM を作成できたので、今度はスクリプトを使用して簡単に VM を作成する方法を見ていきます。

JavaScript で Microsoft Azure のリソース利用するスクリプトを作成する

多くの開発者が、あらゆることに JavaScript を使おうと試みています。クラウドでリソースをプロビジョニングすることも例外ではありません。クラウドでのリソースのプロビジョニングについては、Bash、Batch、Windows PowerShell などのスクリプト言語でもサポートされます。どのスクリプト言語を選択するかは、スクリプト言語を実行するプラットフォームや好みによって決まります。

マイクロソフトは、プログラミング モデルではなく、宣言型のモデルを使用する Microsoft Azure Resource Manager をまもなくリリースする予定です。Microsoft Azure Resource Manager が利用可能になるまでは、いずれかのプログラミング型の手法をして、クラウドへのプロビジョニングを自動化します。

azure-cli に関する npm のドキュメント (npmjs.org/package/azure-cli、英語) を詳しく見てみると、azure-cli を利用する azure-scripty というライブラリがあるのがわかります。このことから、オープン ソース Node.js コミュニティのメンバーが、JavaScript 向けに azure-cli 用のコマンドライン アダプターを作成することを既に決めていたことがわかります。このライブラリはコマンドラインのラッパーなので、JavaScript のコマンドラインでまったく同じコマンドを使用できます。以下はすべての VM を一覧する例です。

// Get the list of existing VMs on this subscription
scripty.invoke('vm list', function (err, result) {
  if (err) {
    return cb(err);
  }
  for (var i in result) {
    console.log(result[i].VMName);
  }
});

手始めに、一群の VM を作成する方法を見てみましょう。まず、以下のように必要なパッケージをインストールします。

# a command-line wrapper for the azure-cli
npm install azure-scripty
# a small library that helps manage asynchronous tasks
npm install async
# a library that makes using JSON configuration files easy
npm install nconf

ステージング、テスト、運用の構成設定をハードコードするのを避けるため、構成ファイルを使用して、スクリプトが異なる環境 (開発環境、テスト環境、運用環境) で十分な柔軟性を保てるようにします。この構成ファイルを config.json とします (図 4 参照)。

図 4 柔軟な設定を維持する Config.json ファイル

{
  "vnet_name":"azuretedvnet2",
  "vm_count": "3",
  "vm_image_name":
    "b39f27a8b8c64d52b05eac6a62ebad85__Ubuntu-14_04-LTS-amd64-server-20140416.1-en-us-30GB",
  "vm_base_name":"sedouardmachine",
  "vm_username":"sedouard",
  "vm_password":"p@assW0rd",
  "affinity_group":{
    "name":"azureteddemoaffinitygroup",
    "label":"sedouard",
    "location":"West US"
  }
}

この構成ファイルを使用して、アフィニティ グループ (azureteddemoaffinitygroup) に属する 3 つの Ubuntu VM と対応する仮想ネットワーク (azuretedvnet2) を完備する開発環境をセットアップします。このアプローチは宣言型です。つまり、この構成ファイルを変更するだけで、開発環境のセットアップ方法を変更できます。ステージング、テスト、運用に対して別のバージョンを用意して、それぞれのバージョンをソース管理することもできます。

適切な名前と値を指定してアフィニティ グループなどの依存関係をプロビジョニングするように、カスタム JavaScript コードによってこの構成ファイルを解析します。config.json ファイルの内部のスクリプトによって、アフィニティ グループ (azureteddemoaffinitygroup) の目的の名前が読み取られます。このスクリプトでは、データセンターに既に存在するプロビジョニング済みのアフィニティ グループの一覧をループ処理することで、アフィニティ グループが既に作成されたかどうかをチェックするクエリを実行できます (図 5 参照)。

図 5 アフィニティ グループの作成

//////////////////////////////////////////////////////////////////////////////
//Creates an affinity group if the specified one doesn't exist
//////////////////////////////////////////////////////////////////////////////
function createAffinityGroup(cb) {
  console.log('Getting affinity groups...');
  scripty.invoke('account affinity-group list', function (err, result) {
    // Check for errors.
    if (err) {
      return cb(err);
    }
    console.log('Current affinity groups');
    // For debugging purposes, list out names of existing affinity groups.
    for (var i in result) {
      console.log(result[i].name);
    }
    // Get the name of the desired affinity group from the config.json file.
    var affinityGroup = nconf.get('affinity_group').name;
    var label = nconf.get('affinity_group').label;
    // Verify that affinity group hasn't already been created.
    for (var i in result) {
      if (result[i].name === affinityGroup && result[i].label === label) {
        // The affinty group to use in the config already exists.
        return cb();
      }
    }
    // Create affinity group because it doesn't exist.
    console.log('Specified affinity group ' + affinityGroup +
      ' does not exist, creating new one...');
    var cmd = {
      command: 'account affinity-group create',
      positional: [affinityGroup],
      location: '\"West US\"',
      label: label
    };
    scripty.invoke(cmd, function (err) {
      if (err) {
        cb(err);
      }
      return cb();
    });
  });
}

azure-scripty ライブラリにより、コールバック関数の result 引数を使って azure-cli の出力を簡単に解析できるようになるのがわかります。command パラメーター、positional パラメーター、および名前付きのパラメーターを宣言的に指定して、CLI コマンドを作成することもできます。

図 6 は、先ほどと同じパターンを使用し、azure-scripty ライブラリを同じ方法で使用してと仮想ネットワークを作成しています。

図 6 仮想ネットワークの作成

//////////////////////////////////////////////////////////////////////////////
//Creates the config specified vnet, if it doesn't already exist
//////////////////////////////////////////////////////////////////////////////
function createVirtualNetwork(cb) {
  console.log('Getting networks...');
  scripty.invoke('network vnet list', function (err, result) {
    if (err) {
      return cb(err);
    }
    var networkName = nconf.get('vnet_name');
    for (var i in result) {
      console.log(result[i].name);
    }
    // Check if VNet name listed in config.json exists.
    // If it doesn't, create the VNet.
  });
}

説明を簡単にするために、図 6 のコードは一部省略していますが、パターンは同じです。必要なリソースは構成ファイルで指定します。必要なリソースが存在しない場合は、プロビジョニングする必要があります。

依存関係 (アフィニティ グループとネットワーク) を作成したら、一群の VM を作成します。作成する VM の数は、config.json 構成ファイルの vm_count フィールドで指定します。同じパターンに従い、まず、サブスクリプションにある現在の VM を一覧し、作成する VM が既に存在しているかどうかチェックして、存在しない VM だけを作成します。

図 7 はシンプルなアルゴリズムに従い、config.json の vm_base_name フィールドを使用して VM に名前を付け、0 ~ (vm_count - 1) の番号を VM 名の末尾に付けます。現在の config.json の場合は、サブスクリプションに VM が 1 つも存在しないため、sedouardmachine0、sedouardmachine1、および sedouardmachine2 が作成されます。

図 7 プロビジョニングする仮想マシンの一覧の作成

scripty.invoke('vm list', function (err, result) {
  if (err) {
    return cb(err);
  }
  // Read the desired VM name from config.json.
  var baseName = nconf.get('vm_base_name');
  var vmNames = [];
  // Create the array of the computed VM names.
  for (var z = 0; z < count; z++) {
    vmNames.push(baseName + z.toString());
  }
  // Go through the list of existing VMs.
  for (var i in result) {
    for (var k in vmNames) {
      if (result[i].VMName === vmNames[k]) {
        // A VM we intend on creating already exists on this sub.
        // Remove it on the list of VMs to create.
        delete vmNames[k];
      }
    }
  }
  // vmNames now only contains the name of VMs that do not exist.
  // Create them.

図 7 では、vmNames 配列に格納される存在しない VM の一覧を確認します。図 8 では、async ライブラリを使用して、実際に VM を作成する非同期タスクを管理します。

図 8 仮想マシンのプロビジョニングの完了

var domainName = nconf.get('dns_name');
var userName = nconf.get('vm_username');
var password = nconf.get('vm_password');
var imageName = nconf.get('vm_image_name');
var vmCreationTasks = [];
var taskArguments = [];
for (var m in vmNames) {
  if (vmNames[m]) {
    var cmd = {
      command: 'vm create',
      positional: [vmNames[m], imageName, userName, password],
      'affinity-group': nconf.get('affinity_group').name,
      'virtual-network-name': nconf.get('vnet_name')
    }
    // Define the async task function that will create each VM.
    var task = function (args, cb) {
      console.log('Creating vm ' + vmNames[args[0]]);
      scripty.invoke(args[1], function (err) {
        if (err) {
          console.log('Vm creation failed: ' + vmNames[args[0]]);
          return cb(err);
        }
        console.log('vm creation of ' + vmNames[args[0]] + ' successful');
        cb();
    });
  }
  // Bind this function to this context and pass the index and VM create command.
  task = task.bind(this, [m, cmd]);
  vmCreationTasks.push(task);
}
}
// Execute each VM creation task using the async libray.
async.series(vmCreationTasks, function (err) {
  if (err) {
    return cb(err);
  }
  console.log('All VMs created successfully!');
  cb();
})

図 8 では、作成する必要がある VM ごとにタスクを作成します。次に、これらのタスクを vmCreationTasks 配列に追加する必要があります。正しい VM 名を指定して azure-cli を呼び出すために、各タスクの関数に必要な引数をバインドします。その後、async ライブラリを使用して一連の各タスクを実行し、VM の作成に成功したかどうかを示す null パラメーターまたは error パラメーターを指定してコールバックを実行します。図 9 はスクリプトの出力を示しており、作成されたすべての VM が一覧されます。

仮想マシンの最終一覧
図 9 仮想マシンの最終一覧

各 VM が正しく作成されています。ポータルに戻ると、VM が作成されたことと、VM が指定された仮想ネットワークに含まれていることを確認できます。bit.ly/azure-xplat-cli (英語) の GitHub リポジトリを使用することで、Node.js を使用して Microsoft Azure のセットアップ スクリプトの作成に着手できます。

まとめ

Microsoft Azure の xplat-cli により、事実上、すべての OS で利用できる移植可能なスクリプトを使って、Microsoft Azure のリソース配置を完全に自動化できるようになります。また、ソース管理や構成ファイルを利用して共有を簡単にすることも可能です。テスト、ステージング、運用の配置モデルをそれぞれ表す config.json を複数バージョン用意することもできます。

また、配置プロセスを迅速かつ効率的に作り直すこともできます。マイクロソフトが 2015 年にリリースする予定の Microsoft Azure Resource Manager では今回説明した以上のことを実行できます。ただし、ここで説明したアプローチは、Microsoft Azure Resource Manager によって行われること (つまり、Microsoft Azure のデータセンターでリソースをプロビジョニングする方法を宣言的に指定すること) と実質的に同じです。


Steven Edouard は、マイクロソフトの開発者エバンジェリストです。以前は、Microsoft .NET Framework 4.5 および .NET Native Compilation のような製品を提供する、.NET Runtime チームのソフトウェア テスト エンジニアを務めていました。現在は、技術デモ、オンライン コンテンツ、プレゼンテーションに用意することで、開発者にクラウド コンピューティング サービスの無限の可能性に挑戦してもらうことに情熱を注いでいます。

この記事のレビューに協力してくれたマイクロソフト技術スタッフの Bruno Terkaly に心より感謝いたします。