Azure Functions で AzureのVM を起動する

2024年6月30日

少し宣伝させてください!Azureの試験対策本を執筆しました。

概要

Azure Functions を使用して Azure 仮想マシン (VM) を起動する方法について、手順とコード実装を紹介します。この記事では、Azure Functions アプリに Managed Identity を設定し、必要な権限を付与して、プログラムから安全に Azure リソースを操作する方法を解説します。 Azure Functions と Managed Identity を組み合わせることで、セキュアかつ効率的に Azure リソースを管理できます。ここでは、環境設定から具体的なコード実装まで、段階的に説明していきます。

前提条件

Azure サブスクリションがあること

Azure Functions アプリがあること(リソースだけでOK)

起動対象の Azure VMがあること

環境設定

Azure Functions アプリに Managed Identity を設定します。

Azure ポータルで Functions アプリに移動

「ID」 → 「システム割り当て済み」を「オン」に設定

Object IDがコピペできるようになります。

Managed Identity にリソースグループの読み取り権限を付与します。

こちらは後から気づいた内容になります。以下のようなエラーが出て気づきました。後でコードを見ればわかりますが、FunctionsはVMへの操作をする時に、リソースグループの中からVMを見つけるようになっているからかなと推測しています。

Error starting VM: The client ‘xxx’ does not have authorization to perform action ‘Microsoft.Resources/subscriptions/resourcegroups/read’ over scope ‘/subscriptions/xxx/resourcegroups/rg-vm-start-sample’ or the scope is invalid. If access was recently granted, please refresh your credentials. Status: 403 (Forbidden)

上記のエラーからResourcesへのアクセスも必要というのがわかりました。

リソースグループに移動

アクセス制御(IAM)」 → 「ロールの割り当ての追加」

ロール:「Reader」

メンバー:Functions アプリの Managed Identity を選択して登録する

Managed Identity に VM の起動権限を付与します。

VM が存在するリソースグループに移動

「アクセス制御(IAM)」 → 「ロールの割り当ての追加」

ロール:「仮想マシン共同作成者」

メンバー:Functions アプリの Managed Identity を選択

環境変数を設定します。

Functions アプリの「構成」に移動

以下の環境変数を追加:

実装したコードと内容の確認

こちらが実装したコードになります。

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Azure.Identity;
using Azure.ResourceManager;
using Azure.ResourceManager.Compute;
using Azure.Core;

namespace func_xiao_dev_001
{
    public static class StartVm
    {
        [FunctionName("StartVm")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation($"C# HTTP trigger function executed at: {DateTime.Now}");

            try
            {
                // Azure認証情報を取得
                var credential = new DefaultAzureCredential();

                // ARMクライアントを作成
                var armClient = new ArmClient(credential);

                // サブスクリプションIDを指定
                string subscriptionId = Environment.GetEnvironmentVariable("AZURE_SUBSCRIPTION_ID");

                // リソースグループ名とVM名を指定
                string resourceGroupName = Environment.GetEnvironmentVariable("RESOURCE_GROUP_NAME");
                string vmName = Environment.GetEnvironmentVariable("VM_NAME");

                // VMリソースを取得
                var subscription = armClient.GetSubscriptionResource(new ResourceIdentifier($"/subscriptions/{subscriptionId}"));
                var resourceGroup = subscription.GetResourceGroup(resourceGroupName);
                var vm = await resourceGroup.Value.GetVirtualMachineAsync(vmName);

                // VMを起動
                await vm.Value.PowerOnAsync(Azure.WaitUntil.Completed);
                log.LogInformation($"VM {vmName} started successfully.");

                return new OkObjectResult($"VM {vmName} started successfully.");
            }
            catch (Exception ex)
            {
                log.LogError($"Error starting VM: {ex.Message}");
                return new StatusCodeResult(StatusCodes.Status500InternalServerError);
            }
        }
    }
}

ここからは備忘録も兼ねて、丁寧に見ていきます。

まず、NuGetで必要となるパッケージはusingしている部分でわかりますが、特に今回VMを起動するという観点から言ったときに必要となるのがこれらです。

using Azure.Identity;
using Azure.ResourceManager;
using Azure.ResourceManager.Compute;
using Azure.Core;

一つづつみていきます。

Azure.Identity

Azureサービスへの認証を行うために必要です。この名前空間には、Azureリソースにアクセスするための様々な認証方法とクライアントが含まれています。例えば、DefaultAzureCredential クラスは、開発環境と本番環境の両方で使用できる柔軟な認証方法を提供します。

コードでは以下部分で使用されています。

// Azure認証情報を取得
var credential = new DefaultAzureCredential();

より深掘りした内容は別で書きます。

Azure.ResourceManager

Azureリソースマネージャーを通じてAzureリソースの作成、読み取り、更新、削除(CRUD操作)を行うために必要です。この名前空間を使用することで、プログラムから直接Azureリソースを管理することができます。

この部分と対応しています。

                // ARMクライアントを作成
                var armClient = new ArmClient(credential);

Azure.ResourceManager.Compute

特に、Azureの仮想マシン(VM)やその他のコンピューティングリソースを管理するために必要です。この名前空間には、仮想マシンの作成、起動、停止などの操作を行うためのクラスが含まれています。

GetVirtualMachineAsyncを使う際に必要となります。

var vm = await resourceGroup.Value.GetVirtualMachineAsync(vmName);

少々脱線しますが、これ以外のリソースも操作できます。例えばStorageAccountの場合は以下のような感じになるはず。(ここはちょっと検証していない・・・)

// Nugetでインストールが必要
//dotnet add package Azure.ResourceManager.Storage

using Azure.ResourceManager.Storage;
var storageAccount = await resourceGroup.GetStorageAccounts().GetAsync(storageAccountName);

Azure.Core

Azure SDKの基本的な機能と共通のパターンを提供します。HTTPリクエストの送信、応答の処理、エラーのハンドリング、認証の流れなど、Azure SDKを使用する際に共通して必要となる機能が含まれています。

new ResourceIdentifier($”/subscriptions/{subscriptionId}”)で必要となります。

var subscription = armClient.GetSubscriptionResource(new ResourceIdentifier($"/subscriptions/{subscriptionId}"));

VMの起動

await vm.Value.PowerOnAsync(Azure.WaitUntil.Completed);

このメソッドは、仮想マシンを起動するためのもので、Azure.WaitUntil.Completed引数を使用しています。この引数は、仮想マシンの起動プロセスが完了するまで待機するようにメソッドに指示します。

PowerOnAsyncメソッドの実装を見ると、AzureのREST APIを呼び出して仮想マシンの起動をリクエストしています。このプロセスは、内部的にStartAsyncメソッドを使用しており、仮想マシンのID情報をパラメータとして渡しています。起動プロセスが開始されると、ComputeArmOperationオブジェクトが生成され、このオブジェクトを使用して操作の状態を追跡します。WaitUntil.Completedが指定されている場合、WaitForCompletionResponseAsyncメソッドが呼び出され、操作が完了するまで待機します。

WaitUntilには、CompletedStartedの2つの値が定義されています。Completedは、サーバー上の操作が完全に完了するまでメソッドが待機するべきことを示します。これは、操作の結果が必要で、その完了を確認してから次のステップに進みたい場合に使用されます。一方、Startedは、サーバー上の操作が開始された時点でメソッドが戻るべきことを示します。これは、操作の完了を待つ必要がなく、開始されたことだけを確認してから他の処理に移りたい場合に便利です。

まとめ

本記事では、Azure Functions を使用して Azure VM を起動する方法について、以下のポイントを解説しました:

  • Azure Functions アプリへの Managed Identity の設定
  • 必要な権限の付与(リソースグループの読み取りと VM の起動権限)
  • 環境変数の設定
  • C#コードの実装と詳細な解説
  • 使用する Azure SDK パッケージの説明

これらの手順とコード例を参考にすることで、Azure Functions から安全かつ効率的に Azure VM を制御することができます。Managed Identity を使用することで、認証情報を直接コードに埋め込む必要がなくなり、セキュリティが向上します。また、Azure Resource Manager (ARM) クライアントを使用することで、VM 以外の Azure リソースも同様の方法で管理できることを示しました。Azure Functions と Managed Identity の組み合わせは、リソースの自動化と管理以外でもよく利用されます。