JavaScriptを有効にしてください

Azure VM のユーザー データを Windows で使ってみ隊

 ·   4 分で読めます  ·   Kento

前回、仮想マシンの作成時にカスタムデータを使ってみましたが、今回はユーザー データを使ってみます
Azure VM のカスタム データを Windows で使ってみ隊 – クラウドを勉強し隊

image01
VM 作成時のパラメータ:

ユーザー データとは

Microsoft 公式から引用します

ユーザー データは、プロビジョニング時に Azure 仮想マシンに挿入されるスクリプトまたは他のメタデータのセットです。 仮想マシン上のどのアプリケーションも、プロビジョニング後に Azure Instance Metadata Service (IMDS) からユーザー データにアクセスできます。
ユーザー データは、カスタム データの新しいバージョンであり、次のようなさらなる利点があります。

  • ユーザー データは、プロビジョニング後に Azure Instance Metadata Service (IMDS) から取得できます。
  • ユーザー データは永続的です。 これは VM の有効期間中に使用できます。
  • VM を停止または再起動することなく、VM の外部からユーザー データを更新できます。
  • ユーザー データのクエリは、$expand オプション付きの GET VM/VMSS API を介して実行できます。

カスタムデータの新しいバージョンで利点が追加されたということなので、Base64 でエンコードする必要があると思いました
が、実際に試してみると Azure Portal でパラメータを指定する時は Base64 でユーザーがエンコードする必要はありませんでした

カスタムデータと比較してみます

項目 カスタムデータ ユーザー データ
設定タイミング VM 作成時 VM 作成時、作成後
データ取得タイミング VM 作成時 任意
データの取得場所 VM 内の特定のファイル IMDS

ざっくり手順

  1. ユーザー データを Base64 でエンコード
  2. VM 作成時にユーザー データを指定
  3. VM にログインし、ユーザー データを取得
  4. VM の再作成
  5. 改めて VM にログインし、ユーザー データを取得

1. ユーザー データを Base64 でエンコード

ユーザー データとして VM に渡す処理を Base64 にエンコードしたテキストを作成します
今回はファイルを作成するだけのシンプルな例を示します

エンコード前のスクリプトは下記になります

1
Out-File -FilePath "C:\Temp\output.txt" -InputObject "Hello, World!" -Encoding utf8

DevToys を使って Base64 にエンコードします
結果は下記のようになります

T3V0LUZpbGUgLUZpbGVQYXRoICJDOlxUZW1wXG91dHB1dC50eHQiIC1JbnB1dE9iamVjdCAiSGVsbG8sIFdvcmxkISIgLUVuY29kaW5nIHV0Zjg=
image02
Base64 エンコード:

2. VM 作成時にユーザー データを指定

Azure Portal で Windows 仮想マシンを作成します
作成時にユーザー データを指定します

image03
VM 作成時のパラメータ:

3. VM にログインし、ユーザー データを取得

作成した仮想マシンにログインします
公開情報をほぼ丸パクリして IMDS からデータを取得してみます

1
2
$userData = Invoke-RestMethod -Headers @{"Metadata"="true"} -Method GET -Uri "http://169.254.169.254/metadata/instance/compute/userData?api-version=2021-01-01&format=text"
[System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($userData))

仮想マシン用の Azure Instance Metadata Service - Azure Virtual Machines | Microsoft Learn

無事にカスタムデータが取得できました

image04
ユーザー データの取得:

しかし実行したスクリプトの2行目は Base64 でエンコードされたテキストをデコードする処理になっているにも関わらず、デコードされていないテキストが表示されています
詳細を見るために IMDS で取得したそのままのデータとデコードしたデータを比較してみます

  • 赤色:IMDS で取得したデータ
  • 緑色:デコードしたデータ
    です。これをみると IMDS で取得したデータは先の手順でエンコードしたものをさらにエンコードしているようです
image05
ユーザー データの取得:

Azure Portal でユーザーデータを入力する際は Base64 でエンコードする必要がないのかもしれないです

ちなみに Azure 仮想マシンのユーザー データ - Azure Virtual Machines | Microsoft Learn に記載のある ARM template のサンプルでは Base64 でエンコードされています

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "name": "testVM",
  "location": "West US",
  "properties": {
    "hardwareProfile": {
      "vmSize": "Standard_A1"
    },
    "storageProfile": {
      "osDisk": {
        "osType": "Windows",
        "name": "osDisk",
        "createOption": "Attach",
        "vhd": {
          "uri": "http://myaccount.blob.core.windows.net/container/directory/blob.vhd"
        }
      }
    },
    "userData": "c2FtcGxlIHVzZXJEYXRh",
    "networkProfile": { "networkInterfaces" : [ { "name" : "nic1" } ] },
  }
}

4. VM の再作成

REST API を使ってユーザーデータを更新することができるようですが、めんどくさいので VM を再作成します
今度はスクリプトをエンコードせずにそのまま貼り付けました

image06
VM 作成時のパラメータ:

5. 改めて VM にログインし、ユーザー データを取得

VM にログインし、ユーザー データを取得します
その結果、デコードしたテキストを見ると想定していたスクリプトを表示することができました

image07
ユーザー データの取得:

デコードしたテキストを実行してみます
IMDS からデータを取得、デコード、実行までのスクリプトは下記になります

1
2
3
4
5
6
7
$userData = Invoke-RestMethod -Headers @{"Metadata"="true"} -Method GET -Uri "http://169.254.169.254/metadata/instance/compute/userData?api-version=2021-01-01&format=text"
Write-Host $userData

$decodedData = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($userData))
Write-Host $decodedData

Invoke-Expression $decodedData

無事にスクリプトの実行をすることができました
実際にこれを自動化の運用で利用する際は Windows の起動時などに自動でこのスクリプトを実行する処理が必要になると思います

image08
スクリプトの実行:

まとめ

今回は Azure VM のユーザー データを使ってみました
めんどくさくて試しませんでしたが、VM 作成後にユーザー データを更新することもできるのがカスタムデータと比較すると大きな利点だと思います

参考

共有

Kento
著者
Kento
2020年に新卒で IT 企業に入社. インフラエンジニア(主にクラウド)として活動中