はじめに
プロジェクトを進めていく中で、使用しているdev環境と同じ環境のコピーが欲しくなることがままあると思います。
少ない数のリソースで構成された環境であればポータルでポチポチとやっていくのもありですが、リソースの数が多い場合など、手作業でポチポチやるのはかなり手間な作業だし、また間違いも犯しやすくなるので、できれば、コード管理してやっていきたいところです。
AzureではARMテンプレートでリソースのコード管理ができるので、できるだけARMテンプレートを使って、仮想マシン等のdev環境のコピーを別のリソースグループに作成してみたいと思います。
やってみる
下準備
まずは、コピー元となるリソースが必要なので、今回は、オフィシャルのAzure Resource Manager テンプレートを使用して Linux 仮想マシンを作成する方法より「Deploy to Azure」ボタンを押してリソースを作成します。
リソースグループをCurrentGroup、Project NameをCurrentProjectとして作成しています。
正常にデプロイが完了すると、上記のように7つのリソースが作成されます。
SSHでアクセスできることを確認しておきます。
リソースグループの作成
今回、NewGroupという新しいリソースグループにCurrentGroupの環境をコピーしたいと思いますので、まずは下記コマンドでNewGroupというリソースグループを作成します。
az group create -l japaneast -n NewGroup
スナップショットの作成
CurrentGroupの仮想マシンをコピーするにあたり、コピー元の仮想マシンのスナップショットをとって、そちらから新しい仮想マシンを複製する方法をとるので、まずはコピー元の仮想マシンのススナップショットを作成します。
osDiskId=$(az vm show \
-g CurrentGroup \
-n CurrentProject-vm \
--query "storageProfile.osDisk.managedDisk.id" \
-o tsv)
az snapshot create \
-g NewGroup \
--source "$osDiskId" \
--name CurrentProject-vm-disk1-snapshot
NewGroupのリソースグループ内にCurrentProject-vm-disk1-snapshotというスナップショットが作成されます。
ARMテンプレートのエクスポート
CurrentGroupのリソースグループのオートメーション→テンプレートのエクスポートより、ARMテンプレートをエクスポートします。
CurrentGroup内のディスクのARMテンプレートは一緒にエクスポートされないので、別途ディスクのオートメーション→テンプレートのエクスポートより、ARMテンプレートをエクスポートします。
ARMテンプレートの編集
上記2つのテンプレートを編集・統合し、NewGroup用のARMテンプレートを作成します。
まずは、ディスクのテンプレートから編集していきます。
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"type": "Microsoft.Compute/disks",
"apiVersion": "2019-07-01",
"name": "NewProject-vm_disk",
"location": "japaneast",
"sku": {
"name": "Premium_LRS",
"tier": "Premium"
},
"properties": {
"osType": "Linux",
"creationData": {
"createOption": "Copy",
"sourceResourceId": "[resourceId('Microsoft.Compute/snapshots', 'CurrentProject-vm-disk1-snapshot')]"
},
"diskSizeGB": 30,
"diskIOPSReadWrite": 120,
"diskMBpsReadWrite": 25,
"encryption": {
"type": "EncryptionAtRestWithPlatformKey"
}
}
}
]
}
下記の変更を行いました。
- CurrentProjectとなっている箇所をNewProjectに変更
- properties.creationDataをイメージからではなくスナップショットから作成するように変更
続いて、リソースグループのテンプレートを編集します。先ほど編集したテンプレートについてもこちらに統合していきます。
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {},
"variables": {},
"resources": [
{
"type": "Microsoft.Compute/disks",
"apiVersion": "2019-07-01",
"name": "NewProject-vm_disk",
"location": "japaneast",
"sku": {
"name": "Premium_LRS",
"tier": "Premium"
},
"properties": {
"osType": "Linux",
"creationData": {
"createOption": "Copy",
"sourceResourceId": "[resourceId('Microsoft.Compute/snapshots', 'CurrentProject-vm-disk1-snapshot')]"
},
"diskSizeGB": 30,
"diskIOPSReadWrite": 120,
"diskMBpsReadWrite": 25,
"encryption": {
"type": "EncryptionAtRestWithPlatformKey"
}
}
},
{
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2020-05-01",
"name": "NewProject-nsg",
"location": "japaneast",
"properties": {
"securityRules": [
{
"name": "ssh_rule",
"properties": {
"description": "Locks inbound down to ssh default port 22.",
"protocol": "Tcp",
"sourcePortRange": "*",
"destinationPortRange": "22",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 123,
"direction": "Inbound",
"sourcePortRanges": [],
"destinationPortRanges": [],
"sourceAddressPrefixes": [],
"destinationAddressPrefixes": []
}
}
]
}
},
{
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2020-05-01",
"name": "default-nsg",
"location": "japaneast",
"properties": {
"securityRules": [
{
"name": "default-allow-22",
"properties": {
"protocol": "Tcp",
"sourcePortRange": "*",
"destinationPortRange": "22",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 1000,
"direction": "Inbound",
"sourcePortRanges": [],
"destinationPortRanges": [],
"sourceAddressPrefixes": [],
"destinationAddressPrefixes": []
}
}
]
}
},
{
"type": "Microsoft.Network/publicIPAddresses",
"apiVersion": "2020-05-01",
"name": "NewProject-ip",
"location": "japaneast",
"sku": {
"name": "Basic"
},
"properties": {
"publicIPAddressVersion": "IPv4",
"publicIPAllocationMethod": "Dynamic",
"idleTimeoutInMinutes": 4,
"ipTags": []
}
},
{
"type": "Microsoft.Compute/virtualMachines",
"apiVersion": "2019-07-01",
"name": "NewProject-vm",
"location": "japaneast",
"dependsOn": [
"[resourceId('Microsoft.Network/networkInterfaces', 'NewProject-nic')]",
"[resourceId('Microsoft.Compute/disks', 'NewProject-vm_disk')]"
],
"properties": {
"hardwareProfile": {
"vmSize": "Standard_D2s_v3"
},
"storageProfile": {
"osDisk": {
"osType": "Linux",
"name": "NewProject-vm_disk",
"createOption": "Attach",
"caching": "ReadWrite",
"managedDisk": {
"storageAccountType": "Premium_LRS",
"id": "[resourceId('Microsoft.Compute/disks', 'NewProject-vm_disk')]"
},
"diskSizeGB": 30
},
"dataDisks": []
},
"networkProfile": {
"networkInterfaces": [
{
"id": "[resourceId('Microsoft.Network/networkInterfaces', 'NewProject-nic')]"
}
]
}
}
},
{
"type": "Microsoft.Network/networkSecurityGroups/securityRules",
"apiVersion": "2020-05-01",
"name": "NewProject-nsg/ssh_rule",
"dependsOn": [
"[resourceId('Microsoft.Network/networkSecurityGroups', 'NewProject-nsg')]"
],
"properties": {
"description": "Locks inbound down to ssh default port 22.",
"protocol": "Tcp",
"sourcePortRange": "*",
"destinationPortRange": "22",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 123,
"direction": "Inbound",
"sourcePortRanges": [],
"destinationPortRanges": [],
"sourceAddressPrefixes": [],
"destinationAddressPrefixes": []
}
},
{
"type": "Microsoft.Network/networkSecurityGroups/securityRules",
"apiVersion": "2020-05-01",
"name": "default-nsg/default-allow-22",
"dependsOn": [
"[resourceId('Microsoft.Network/networkSecurityGroups', 'default-nsg')]"
],
"properties": {
"protocol": "Tcp",
"sourcePortRange": "*",
"destinationPortRange": "22",
"sourceAddressPrefix": "*",
"destinationAddressPrefix": "*",
"access": "Allow",
"priority": 1000,
"direction": "Inbound",
"sourcePortRanges": [],
"destinationPortRanges": [],
"sourceAddressPrefixes": [],
"destinationAddressPrefixes": []
}
},
{
"type": "Microsoft.Network/virtualNetworks",
"apiVersion": "2020-05-01",
"name": "NewProject-vnet",
"location": "japaneast",
"dependsOn": [
"[resourceId('Microsoft.Network/networkSecurityGroups', 'default-nsg')]"
],
"properties": {
"addressSpace": {
"addressPrefixes": [
"10.0.0.0/16"
]
},
"subnets": [
{
"name": "default",
"properties": {
"addressPrefix": "10.0.0.0/24",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', 'default-nsg')]"
},
"delegations": [],
"privateEndpointNetworkPolicies": "Enabled",
"privateLinkServiceNetworkPolicies": "Enabled"
}
}
],
"virtualNetworkPeerings": [],
"enableDdosProtection": false,
"enableVmProtection": false
}
},
{
"type": "Microsoft.Network/networkInterfaces",
"apiVersion": "2020-05-01",
"name": "NewProject-nic",
"location": "japaneast",
"dependsOn": [
"[resourceId('Microsoft.Network/publicIPAddresses', 'NewProject-ip')]",
"[resourceId('Microsoft.Network/virtualNetworks/subnets', 'NewProject-vnet', 'default')]"
],
"properties": {
"ipConfigurations": [
{
"name": "ipconfig1",
"properties": {
"privateIPAddress": "10.0.0.4",
"privateIPAllocationMethod": "Dynamic",
"publicIPAddress": {
"id": "[resourceId('Microsoft.Network/publicIPAddresses', 'NewProject-ip')]"
},
"subnet": {
"id": "[resourceId('Microsoft.Network/virtualNetworks/subnets', 'NewProject-vnet', 'default')]"
},
"primary": true,
"privateIPAddressVersion": "IPv4"
}
}
],
"dnsSettings": {
"dnsServers": []
},
"enableAcceleratedNetworking": false,
"enableIPForwarding": false
}
},
{
"type": "Microsoft.Network/virtualNetworks/subnets",
"apiVersion": "2020-05-01",
"name": "NewProject-vnet/default",
"dependsOn": [
"[resourceId('Microsoft.Network/virtualNetworks', 'NewProject-vnet')]",
"[resourceId('Microsoft.Network/networkSecurityGroups', 'default-nsg')]"
],
"properties": {
"addressPrefix": "10.0.0.0/24",
"networkSecurityGroup": {
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', 'default-nsg')]"
},
"delegations": [],
"privateEndpointNetworkPolicies": "Enabled",
"privateLinkServiceNetworkPolicies": "Enabled"
}
}
]
}
下記の変更を行いました。
- CurrentProjectとなっている箇所をNewProjectに変更
- Microsoft.Compute/disksをこちらに統合
- 仮想マシンの作成がdisksの作成の後になるようにMicrosoft.Compute/virtualMachinesのdependsOnに追加
- Microsoft.Compute/virtualMachinesのproperties.storageProfile.osDiskの名前を変更し、createOptionをAttachに変更
- Microsoft.Compute/virtualMachinesのproperties.storageProfile.imageReferenceと、properties.storageProfile.osProfileを削除
- Microsoft.Network/publicIPAddressesのproperties.ipAddressを削除
デプロイ
編集したテンプレートをNewGroupにデプロイします。
az deployment group create -g NewGroup --template-file template.json
正常にデプロイが完了すると、上記のように7つのリソースが作成されます。(スナップショット入れると8つ)
こちらも、SSHでアクセスできることを確認しておきます。
さいごに
デプロイ時にパラメータを渡すことで、一つのテンプレートで複数環境にデプロイできるようにしたりするなど、まだまだブラッシュアップできる点は多いかと思いますが、とりあえずはARMテンプレートで環境のコピーを作成することはできたと思います。
複数環境に対してコードで管理できるようになると、ステージング・本番の環境の整合性を管理できたり、複数の開発環境を同時に整備できたりなど、メリットはかなり大きいと思います。