Azure Linux VM の OS に Azure CLI でコマンドをリモート実行する３つの方法を試してみた

## 背景と目的

一般的に Windows や Linux の OS に WinRM や SSH でネットワーク接続できる環境であれば、リモートからコマンドを実行する事は容易です。エージェントレスで OS を管理する仕組みは大抵この方法です。Azure VM の場合でも同様の事は可能なのですが、加えて Azure ポータルや Azure CLI の実行者に適切な権限が付与されていれば、WinRM や SSH を使用しなくても OS のコマンドをリモート実行する事が可能です。これは、Azure VM に WindowsAzureGuestAgent や waagent というエージェントがインストール済みで、このエージェントを介して様々な管理や機能を提供しているからです。そこで今回は、Azure Linux VM の OS に Azure CLI でコマンドをリモート実行する３つの方法を試してみました。

## 検証用 Azure Linux VM を作成

```bash:bash
# 環境変数をセットします
region=japaneast
prefix=mnroscmd

# リソースグループを作成します
az group create \
  --name ${prefix}-rg \
  --location $region

# Azure Linux VM を作成します
az vm create \
  --resource-group ${prefix}-rg \
  --name ${prefix}-vm \
  --os-disk-name ${prefix}-vmOSDisk \
  --image UbuntuLTS \
  --admin-username azureuser \
  --generate-ssh-keys \
  --size Standard_B1s \
  --nsg-rule NONE \
  --storage-sku Standard_LRS
```

## アクション実行コマンド

https://learn.microsoft.com/ja-jp/azure/virtual-machines/linux/run-command

単発でコマンド実行する場合は、これが一番簡単です。

```bash:bash
az vm run-command invoke \
  --command-id RunShellScript \
  --resource-group ${prefix}-rg \
  --name ${prefix}-vm \
  --scripts "id && uname -a"
```

以下のような JSON が出力されます。コマンドは root で実行されている事がわかります。

```json:json
{
  "value": [
    {
      "code": "ProvisioningState/succeeded",
      "displayStatus": "Provisioning succeeded",
      "level": "Info",
      "message": "Enable succeeded: \n[stdout]\nuid=0(root) gid=0(root) groups=0(root)\nLinux mnroscmd-vm 5.4.0-1091-azure #96~18.04.1-Ubuntu SMP Tue Aug 30 19:15:32 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux\n\n[stderr]\n",
      "time": null
    }
  ]
}
```

## マネージド実行コマンド（プレビュー）

https://learn.microsoft.com/ja-jp/azure/virtual-machines/linux/run-command-managed

アクション実行コマンドには無い、並列実行や長時間実行などに対応した、きめ細かいコマンド実行がサポートされています。

```bash:bash
# RunCommandPreview プレビュー機能を登録します
az feature register \
  --name RunCommandPreview \
  --namespace Microsoft.Compute

# RunCommandPreview を伝達させます
az provider register \
  --name Microsoft.Compute

# RunCommandPreview が有効になった事を確認します（数分で Registered と表示されました）
az feature show \
  --name RunCommandPreview \
  --namespace Microsoft.Compute \
  --query properties.state \
  --output tsv

# コマンドを実行します
az vm run-command create \
  --name "uname" \
  --resource-group ${prefix}-rg \
  --vm-name ${prefix}-vm \
  --script "id && uname && date > /tmp/date.txt"

# アクション実行コマンドで出力したファイルの内容を確認します
az vm run-command invoke \
  --command-id RunShellScript \
  --resource-group ${prefix}-rg \
  --name ${prefix}-vm \
  --query "value[0].message" \
  --output tsv \
  --scripts "cat /tmp/date.txt"

# 以下のように出力したファイルの内容が確認できました
Enable succeeded: 
[stdout]
Sun Oct 16 00:15:55 UTC 2022

[stderr]

# 実行済みのコマンドを一覧表示します
az vm run-command list \
  --resource-group ${prefix}-rg \
  --vm-name ${prefix}-vm \
  --output table

# 実行済みのコマンドを表示します
az vm run-command show \
  --name "uname" \
  --resource-group ${prefix}-rg \
  --vm-name ${prefix}-vm

# 実行済みのコマンドを削除します
az vm run-command delete \
  --name "uname" \
  --resource-group ${prefix}-rg \
  --vm-name ${prefix}-vm \
  --yes
```

## カスタムスクリプト拡張機能 v2

https://learn.microsoft.com/ja-jp/azure/virtual-machines/extensions/custom-script-linux

VMSS でも同様ですが、VM をスケールアウトした時に自動実行させる事ができるカスタムスクリプト拡張機能のコマンド実行です。

```bash:bash
# fileUris 無しでコマンドのみを実行します
az vm extension set \
  --publisher Microsoft.Azure.Extensions \
  --version 2.0 \
  --name CustomScript \
  --resource-group ${prefix}-rg \
  --vm-name ${prefix}-vm \
  --settings '{"commandToExecute":"id && uname && date > /tmp/date.txt"}'

# アクション実行コマンドで出力したファイルの内容を確認します
az vm run-command invoke \
  --command-id RunShellScript \
  --resource-group ${prefix}-rg \
  --name ${prefix}-vm \
  --query "value[0].message" \
  --output tsv \
  --scripts "cat /tmp/date.txt"

# 以下のように出力したファイルの内容が確認できました
Enable succeeded: 
[stdout]
Sun Oct 16 00:36:39 UTC 2022

[stderr]

# カスタムスクリプト拡張機能を削除します
az vm extension delete \
  --name CustomScript \
  --resource-group ${prefix}-rg \
  --vm-name ${prefix}-vm
```

## 余談

### cloud-init

https://learn.microsoft.com/ja-jp/azure/virtual-machines/linux/using-cloud-init

VM 作成時に、custom-data パラメーターで cloud-init 構成ファイルであるシェルスクリプトを指定して実行する事が可能です。

### VM アプリケーション

https://learn.microsoft.com/ja-jp/azure/virtual-machines/vm-applications-how-to?tabs=cli

VM アプリケーションは、自前で VM 拡張機能を作るイメージです。Blob ストレージの指定とインストール＆アンインストールコマンドが必須です。

## 検証環境を削除

```bash:bash
# リソースグループを削除します
az group delete \
  --name ${prefix}-rg \
  --yes
```

## 参考

https://learn.microsoft.com/ja-jp/cli/azure/vm/run-command?view=azure-cli-latest

https://learn.microsoft.com/ja-jp/cli/azure/vm/extension?view=azure-cli-latest

https://learn.microsoft.com/ja-jp/cli/azure/sig/gallery-application/version?view=azure-cli-latest

https://learn.microsoft.com/ja-jp/cli/azure/vm/application?view=azure-cli-latest