GitHub Copilotを使ってBicepファイルからAzure仮想マシンを作成する

Azureに仮想マシンを作成する際に、繰り返し作成削除を繰り返す要件があったので、Bicepでコード化することを考えました。

以前は一から作っていたのですが、ちょうどGitHub Copilotが利用できる状態だったので、せっかくなのでGitHub Copilotを使ってBicepファイルから仮想マシンを作成してみました。

GitHub Copilot の概要

GitHub Copilot は AIによってコーディングをアシストしてくれるサービスです。

コードの生成自体はChatGPTなどでも出来ますが、GitHub CopilotはGitHub上の公開データを学習ソースに使っているので、よりコーディングに特化しています。

なお、GitHub Copilotには、コーディング以外の質問は出来ないようになっています。

GitHub Copilotを利用するためには

本記事では利用のための細かい手順などは割愛しますが、大まかな流れだけ紹介します。

  1. GitHubのアカウントを用意
  2. 試用版またはサブスクリプションを用意
  3. Visual Studio Codeを用意し、GitHub Copilot 拡張機能をインストールする

参考: GitHub Copilot の概要 - GitHub Docs

なお、本記事では上記手順を行い、かつ「suggestions matching public code」をBlockした状態で実施をしました。

Bicepファイルの作成

では、早速Bicepファイルを作成していきましょう。

新規作成

まず、GitHub Copilotに全体像を伝えます。

Azure上に仮想マシンを作成するためのBicepファイルを作成したいです

このように生成してくれました。

実際のコードです。(クリックで展開します)

param vmName string
param resourceGroupName string
param location string = resourceGroup().location
param vmSize string = 'Standard_D2s_v3'

resource vm 'Microsoft.Compute/virtualMachines@2021-04-01' = {
  name: vmName
  location: location
  properties: {
    hardwareProfile: {
      vmSize: vmSize
    }
    storageProfile: {
      imageReference: {
        publisher: 'MicrosoftWindowsServer'
        offer: 'WindowsServer'
        sku: '2016-Datacenter'
        version: 'latest'
      }
      osDisk: {
        createOption: 'FromImage'
      }
    }
    osProfile: {
      computerName: vmName
      adminUsername: '<username>'
      adminPassword: '<password>'
    }
    networkProfile: {
      networkInterfaces: [
        {
          id: nic.id
        }
      ]
    }
  }
}

resource nic 'Microsoft.Network/networkInterfaces@2021-02-01' = {
  name: '${vmName}-nic'
  location: location
  properties: {
    ipConfigurations: [
      {
        name: 'ipconfig1'
        properties: {
          privateIPAllocationMethod: 'Dynamic'
          subnet: {
            id: subnet.id
          }
        }
      }
    ]
  }
}

resource vnet 'Microsoft.Network/virtualNetworks@2021-02-01' = {
  name: '${vmName}-vnet'
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        '10.0.0.0/16'
      ]
    }
    subnets: [
      {
        name: 'default'
        properties: {
          addressPrefix: '10.0.0.0/24'
        }
      }
    ]
  }
}

resource subnet 'Microsoft.Network/virtualNetworks/subnets@2021-02-01' = {
  parent: vnet
  name: 'default'
  properties: {}
}

基本的な要素はそろっているように見えますが、今回は以下の2つを追加で要求します。

  • NSGを追加し、HTTPの通信を許可する
  • 仮想マシンをAzure Compute Galleryから作成する

NSGを追加し、HTTPの通信を許可する

では、GitHub Copilotに追加の要件を伝えます。

NSGを追加し、HTTPの通信を許可してください。

差分を教えてくれました。丁寧に、NICへ紐づけるところまで教えてくれました。

ただ、NSGはNICではなくサブネットに設定したいので、修正してもらいましょう。

NSGはサブネットに紐づけてください。

ちゃんと修正してくれました。

「カーソルに挿入」を使うと、そのままソース内に貼り付けが可能です。

ただ、このままだとサブネットの定義が重複してしまうので、古い方は削除しておきましょう。

コメントも削除し、NSGを追加したBicepファイルが出来ました。

実際のコードです。(クリックで展開します)

param vmName string
param resourceGroupName string
param location string = resourceGroup().location
param vmSize string = 'Standard_D2s_v3'

resource vm 'Microsoft.Compute/virtualMachines@2021-04-01' = {
  name: vmName
  location: location
  properties: {
    hardwareProfile: {
      vmSize: vmSize
    }
    storageProfile: {
      imageReference: {
        publisher: 'MicrosoftWindowsServer'
        offer: 'WindowsServer'
        sku: '2016-Datacenter'
        version: 'latest'
      }
      osDisk: {
        createOption: 'FromImage'
      }
    }
    osProfile: {
      computerName: vmName
      adminUsername: '<username>'
      adminPassword: '<password>'
    }
    networkProfile: {
      networkInterfaces: [
        {
          id: nic.id
        }
      ]
    }
  }
}

resource nic 'Microsoft.Network/networkInterfaces@2021-02-01' = {
  name: '${vmName}-nic'
  location: location
  properties: {
    ipConfigurations: [
      {
        name: 'ipconfig1'
        properties: {
          privateIPAllocationMethod: 'Dynamic'
          subnet: {
            id: subnet.id
          }
        }
      }
    ]
  }
}

resource vnet 'Microsoft.Network/virtualNetworks@2021-02-01' = {
  name: '${vmName}-vnet'
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        '10.0.0.0/16'
      ]
    }
    subnets: [
      {
        name: 'default'
        properties: {
          addressPrefix: '10.0.0.0/24'
        }
      }
    ]
  }
}

resource nsg 'Microsoft.Network/networkSecurityGroups@2020-11-01' = {
  name: '${vmName}-nsg'
  location: location
  properties: {
    securityRules: [
      {
        name: 'AllowHTTP'
        properties: {
          protocol: 'Tcp'
          sourcePortRange: '*'
          destinationPortRange: '80'
          sourceAddressPrefix: '*'
          destinationAddressPrefix: '*'
          access: 'Allow'
          priority: 100
          direction: 'Inbound'
        }
      }
    ]
  }
}

resource subnet 'Microsoft.Network/virtualNetworks/subnets@2021-02-01' = {
  parent: vnet
  name: 'default'
  properties: {
    networkSecurityGroup: {
      id: nsg.id
    }
  }
}

仮想マシンをAzure Compute Galleryから作成する

続いて、仮想マシンをAzure Compute Galleryから作成するように変更したいと思います。

GitHub Copilotに再度追加の要件を伝えます。

仮想マシンをAzure Compute Galleryから作成するように変更してください。

変更する場所をコメント付きで教えてくれました。

コメントに沿ってソースを編集します。

Azure Compute Galleryから仮想マシンを作成するBicepファイルが出来ました。

実際のコードです。(クリックで展開します)

param vmName string
param resourceGroupName string
param location string = resourceGroup().location
param vmSize string = 'Standard_D2s_v3'
param imageVersionId string

resource vm 'Microsoft.Compute/virtualMachines@2021-04-01' = {
  name: vmName
  location: location
  properties: {
    hardwareProfile: {
      vmSize: vmSize
    }
    storageProfile: {
      imageReference: {
        id: imageVersionId
      }
      osDisk: {
        createOption: 'FromImage'
      }
    }
    osProfile: {
      computerName: vmName
      adminUsername: '<username>'
      adminPassword: '<password>'
    }
    networkProfile: {
      networkInterfaces: [
        {
          id: nic.id
        }
      ]
    }
  }
}

resource nic 'Microsoft.Network/networkInterfaces@2021-02-01' = {
  name: '${vmName}-nic'
  location: location
  properties: {
    ipConfigurations: [
      {
        name: 'ipconfig1'
        properties: {
          privateIPAllocationMethod: 'Dynamic'
          subnet: {
            id: subnet.id
          }
        }
      }
    ]
  }
}

resource vnet 'Microsoft.Network/virtualNetworks@2021-02-01' = {
  name: '${vmName}-vnet'
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        '10.0.0.0/16'
      ]
    }
    subnets: [
      {
        name: 'default'
        properties: {
          addressPrefix: '10.0.0.0/24'
        }
      }
    ]
  }
}

resource nsg 'Microsoft.Network/networkSecurityGroups@2020-11-01' = {
  name: '${vmName}-nsg'
  location: location
  properties: {
    securityRules: [
      {
        name: 'AllowHTTP'
        properties: {
          protocol: 'Tcp'
          sourcePortRange: '*'
          destinationPortRange: '80'
          sourceAddressPrefix: '*'
          destinationAddressPrefix: '*'
          access: 'Allow'
          priority: 100
          direction: 'Inbound'
        }
      }
    ]
  }
}

resource subnet 'Microsoft.Network/virtualNetworks/subnets@2021-02-01' = {
  parent: vnet
  name: 'default'
  properties: {
    networkSecurityGroup: {
      id: nsg.id
    }
  }
}

仮想マシンの作成

PowerShellスクリプトの作成

実際に出来上がったBicepファイルを使って仮想マシンを作成していきたいと思いますが、Bicepファイルだけでは作成できません。

そこで、このBicepファイルを使って仮想マシンを作成するPowerShellのスクリプトも、GitHub Copilotに用意してもらいましょう。

今作成したBicepファイルを使ってAzureにデプロイするためのPowerShellスクリプトを作ってください。

コードを生成し、Visual Studio Codeのターミナルまで起動してくれました。

実際のコードです。(クリックで展開します)

# パラメータ
$resourceGroupName = "yourResourceGroupName"
$location = "yourLocation"
$bicepFile = "path\to\your\newVM.bicep"
$imageVersionId = "yourImageVersionId"

# リソースグループの作成
New-AzResourceGroup -Name $resourceGroupName -Location $location

# Bicepファイルのデプロイ
New-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile $bicepFile -vmName "myVM" -imageVersionId $imageVersionId

PowerShellスクリプトの修正

ただ、生成されたスクリプトはAzureに接続している前提となっており、サブスクリプションの指定も出来ません。

追加の要望をGitHub Copilotに伝え、修正してもらいましょう。

Azureに接続し、サブスクリプションを指定する処理も入れて下さい。

修正してくれましたので、この内容に差し替えます。

実際のコードです。(クリックで展開します)

# パラメータ
$subscriptionId = "yourSubscriptionId"
$resourceGroupName = "yourResourceGroupName"
$location = "yourLocation"
$bicepFile = "path\to\your\newVM.bicep"
$imageVersionId = "yourImageVersionId"

# Azureに接続
Connect-AzAccount

# サブスクリプションを指定
Select-AzSubscription -SubscriptionId $subscriptionId

# リソースグループの作成
New-AzResourceGroup -Name $resourceGroupName -Location $location

# Bicepファイルのデプロイ
New-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile $bicepFile -vmName "myVM" -imageVersionId $imageVersionId

仮想マシンの作成

では、実際にGitHub Copilotを使って作成したBicepファイルとPowerShellスクリプトを使って仮想マシンを作成してみましょう。

その前に、実行前に環境に合わせて変数を修正しておきます。

実行すると、エラーではないのですが、パラメーターを追加で求められてしまいました。

cmdlet New-AzResourceGroupDeployment at command pipeline position 1
Supply values for the following parameters:
(Type !? for Help.)
resourceGroupNameFromTemplate:

パラメーターは指定してるように見えるのですが、うまく渡せていないのでしょうか。一旦Ctrl+Cで中断し、これもGitHub Copilotに聞いてみましょう。

次のメッセージが表示されて処理が進みませんでした。
cmdlet New-AzResourceGroupDeployment at command pipeline position 1
Supply values for the following parameters:
(Type !? for Help.)
resourceGroupNameFromTemplate:

ここはちょっと苦戦しました。

追加の質問をしたり、Bicepファイルの中身を共有したところ、BicepファイルにresourceGroupNameというパラメータが定義されているが使われていない、という指摘がありました。

確かに、使われていませんでした。*1

Bicepファイルのパラメーター指定からresourceGroupNameを削って再実行したところ、今度はPowerShellスクリプトまではうまくいったのですが、デプロイでエラーが出てしまいました。

これもGitHub Copilotに聞いてみて、仮想ネットワークとサブネットの依存関係ではないか、という事でアドバイスしてくれました。

アドバイスを元にBicepファイルの仮想ネットワークとサブネット周りを見直してみると、依存関係というよりは、そもそもサブネットの設定場所が重複してしまっていたようでした。

今回は、仮想ネットワーク作成時にはサブネットを定義せず、サブネット定義にすべて情報を集約する形にしました。

修正後、仮想マシンを無事作成できました。

最終的に使用したファイルです。

Bicepファイル(クリックで展開します)

param vmName string

param location string = resourceGroup().location
param vmSize string = 'Standard_D2s_v3'
param imageVersionId string

resource vm 'Microsoft.Compute/virtualMachines@2021-04-01' = {
  name: vmName
  location: location
  properties: {
    hardwareProfile: {
      vmSize: vmSize
    }
    storageProfile: {
      imageReference: {
        id: imageVersionId
      }
      osDisk: {
        createOption: 'FromImage'
      }
    }
    osProfile: {
      computerName: vmName
      adminUsername: '<username>'
      adminPassword: '<password>'
    }
    networkProfile: {
      networkInterfaces: [
        {
          id: nic.id
        }
      ]
    }
  }
}

resource nic 'Microsoft.Network/networkInterfaces@2021-02-01' = {
  name: '${vmName}-nic'
  location: location
  properties: {
    ipConfigurations: [
      {
        name: 'ipconfig1'
        properties: {
          privateIPAllocationMethod: 'Dynamic'
          subnet: {
            id: subnet.id
          }
        }
      }
    ]
  }
}

resource vnet 'Microsoft.Network/virtualNetworks@2021-02-01' = {
  name: '${vmName}-vnet'
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        '10.0.0.0/16'
      ]
    }
  }
}

resource nsg 'Microsoft.Network/networkSecurityGroups@2020-11-01' = {
  name: '${vmName}-nsg'
  location: location
  properties: {
    securityRules: [
      {
        name: 'AllowHTTP'
        properties: {
          protocol: 'Tcp'
          sourcePortRange: '*'
          destinationPortRange: '80'
          sourceAddressPrefix: '*'
          destinationAddressPrefix: '*'
          access: 'Allow'
          priority: 100
          direction: 'Inbound'
        }
      }
    ]
  }
}

resource subnet 'Microsoft.Network/virtualNetworks/subnets@2021-02-01' = {
  parent: vnet
  name: 'default'
  properties: {
    addressPrefix: '10.0.0.0/24'
    networkSecurityGroup: {
      id: nsg.id
    }
  }
}

PowerShellスクリプト(クリックで展開します)

# パラメータ
$subscriptionId = "<subscriptionId >"
$resourceGroupName = "<resourceGroupName>"
$location = "<location>"
$bicepFile = "<bicepFileのパス>"
$imageVersionId = "<Azure Compute GallaryのID>"

# Azureに接続
Connect-AzAccount

# サブスクリプションを指定
Select-AzSubscription -SubscriptionId $subscriptionId

# リソースグループの作成
New-AzResourceGroup -Name $resourceGroupName -Location $location

# Bicepファイルのデプロイ
New-AzResourceGroupDeployment -ResourceGroupName $resourceGroupName -TemplateFile $bicepFile -vmName "myVM" -imageVersionId $imageVersionId

おわりに

はじめてGitHub Copilotを使ってコードを生成しましたが、公式のリファレンスや類似例を探して自分で書くよりはかなりスムーズに進めることが出来ました。

一方で、GitHub Copilotが生成したコードで不要な個所があり、その部分が原因でトラブルが発生ました。生成AIは必ずしも正しい答えを返すわけではない、ということも身をもって体験しました。

今回の場合、元々自分でBicepファイルやPowerShellのスクリプトを一から書いたことがあったので、コードの内容が的外れたものではないかや、エラーの原因がどこか、などはすぐに見当がつきました。

もしそういった経験なしで、例えば初学者がGitHub Copilotだけでコードを作成できるかというと難しいと感じました。

一方で、ある程度の知識を持っていればGitHub Copilotをアシスタントとして効率よくコードの作成が進められることを実感しました。

今後もコードやスクリプトの生成では積極的に活用していきたいです。

*1:推測ですが、パラメーターが使われていなかっただけでなく、resourceGroupNameというパラメーターはNew-AzResourceGroupDeploymentのオプションでも使われるものだったので、ここでバッティングしてしまったように思われます

執筆担当者プロフィール
舟越 匠

舟越 匠(日本ビジネスシステムズ株式会社)

人材開発部に所属。社内向けの技術研修をメインにしつつ、JBS Tech BlogやMS認定資格取得の推進役もやっています。資格としてはAzure Solutions Architect Expertを所持。好きなサービスはPower Automate / Logic Apps。好きなアーティストはZABADAK。

担当記事一覧