Gemini Advanced/Terraformを利用して、仮想マシンを構築してみる
皆さん、こんにちは。
前回のTerraformの投稿、準備編、チュートリアル編から大分時間がたってしまいましたが、改めてTerraformを利用してAzureリソースを作成したいと思います。
そろそろやらないとな、と思っていた矢先にGoogleのGemini Advanced / Utlra 1.0がリリースされました。折角なので、Gemini Advancedに協力をもらいながら、TerraformでAzure用リソースのコードを作成し、仮想マシンを構築してみたいと思います。
Terraformはインフラ環境のコード化:IaCツールとしてのデファクトスタンダードといっても過言ではないほどに定着しているツールになります。AIと組わせるとどうなるのか…
それではやっていきましょう!!!
1. 目指す先
以下が目指す環境になります。今回はとてもシンプルに、仮想マシンをAzureテナントにデプロイします。
もちろん、リソースグループを始めとした、仮想ネットワーク/サブネット、ネットワークセキュリティグループも含めて、同じタイミングで展開します。
余談ですが、もっと慣れてくれば、ハブ&スポーク環境も簡単にコードできそうになるなという実感がありますね。
2. コード生成
既にTerraformの準備は完了しているので、早速コードの作成に取り組みたいと思います。
Terraformのインストール等は過去の投稿からご確認ください。
さて、今回はGoogle Geminiを利用してコードを生成していくわけですが、今回使用するプロンプトは、
I want to set up a Virtual Machine that could run WordPress
としました。なるべく簡潔にすることで、どれほどの正確性で出力してくれるか把握するために敢えてそうしています。
日本語訳としては、ワードプレスを稼働できる仮想マシン環境を構築したい、となります。
※すみません、事前にTerraform/Azureを利用していることは指定しています。。。
出力結果はこちらになります。1回目の出力でパブリックIPアドレスについては、必要であれば作成してください、となっていたため、今回は2回出力しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# Provider Configuration provider "azurerm" { features {} # Add specific features if needed } # Resource Group resource "azurerm_resource_group" "wordpress_rg" { name = "my-wordpress-rg" location = "eastus" } # Virtual Network and Subnet resource "azurerm_virtual_network" "wordpress_vnet" { name = "my-wordpress-vnet" address_space = ["10.0.0.0/16"] location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name } resource "azurerm_subnet" "wordpress_subnet" { name = "my-wordpress-subnet" resource_group_name = azurerm_resource_group.wordpress_rg.name virtual_network_name = azurerm_virtual_network.wordpress_vnet.name address_prefixes = ["10.0.1.0/24"] } # Network Security Group resource "azurerm_network_security_group" "wordpress_nsg" { name = "my-wordpress-nsg" location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name security_rule { name = "web" priority = 100 direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = "80" source_address_prefix = "*" destination_address_prefix = "*" } # Add more rules as needed (SSH port 22 for access...) } # Network Interface resource "azurerm_network_interface" "wordpress_nic" { name = "my-wordpress-nic" location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name ip_configuration { name = "wordpressconfiguration" subnet_id = azurerm_subnet.wordpress_subnet.id private_ip_address_allocation = "Dynamic" public_ip_address_id = # ... (Create a public IP if needed) } } # Virtual Machine resource "azurerm_linux_virtual_machine" "wordpress_vm" { name = "my-wordpress-vm" resource_group_name = azurerm_resource_group.wordpress_rg.name location = azurerm_resource_group.wordpress_rg.location size = "Standard_B1s" admin_username = "adminuser" admin_password = "YourSecurePassword" network_interface_ids = [azurerm_network_interface.wordpress_nic.id] os_disk { caching = "ReadWrite" storage_account_type = "Standard_LRS" } source_image_reference { publisher = "Canonical" offer = "UbuntuServer" sku = "18.04-LTS" version = "latest" } } |
パブリックIPアドレスは必要になるため、パブリックIPアドレスを生成してほしいともう一度依頼しました。
I need public IP Address
その出力結果が…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# ... (Provider, Resource Group, VNet, Subnet, NSG remain the same) # Public IP Address resource "azurerm_public_ip" "wordpress_public_ip" { name = "my-wordpress-public-ip" location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name allocation_method = "Dynamic" sku = "Basic" } # Network Interface resource "azurerm_network_interface" "wordpress_nic" { name = "my-wordpress-nic" location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name ip_configuration { name = "wordpressconfiguration" subnet_id = azurerm_subnet.wordpress_subnet.id private_ip_address_allocation = "Dynamic" public_ip_address_id = azurerm_public_ip.wordpress_public_ip.id } } # ... (Virtual Machine remains the same) |
しっかりとネットワークインタフェースの項目にもパブリックIPアドレスの情報を追記してくれました。
このオリジナルを元に、必要に応じて変更したいと思います。
変更するものとして、
- Terraformのバージョン指定(お作法的にも)
- ローケションをjapaneastに変更
- 命名規則に基づいた名称変更
- ネットワークセキュリティグループにSSHを追加
- IPアドレスをBasicからStandardに変更
- Standard変更に伴い、IPアドレスのアロケーションをStatic(固定)に変更
- UbuntuOSのバージョンとして22.04-LTSを指定
22.04-LTSを指定するにあたり、イメージオファーとSKUの書き方が異なるため、そちらも合わせて修正したいと思います。
こちらが完成品になります。
「–」、はTerraformとしてはコメントアウトとして認識しないため、正式な「#」へ変更もしています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# Configure the Azure provider terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = "~> 3.0.2" } } required_version = ">= 1.1.0" } # Provider Configuration provider "azurerm" { features {} } # Resource Group resource "azurerm_resource_group" "wordpress_rg" { name = "rg-wordpress-env" location = "japaneast" } # Virtual Network and Subnet resource "azurerm_virtual_network" "wordpress_vnet" { name = "vnet-wordpress-env" address_space = ["10.0.0.0/16"] location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name } resource "azurerm_subnet" "wordpress_subnet" { name = "sb-wordpress-unit" resource_group_name = azurerm_resource_group.wordpress_rg.name virtual_network_name = azurerm_virtual_network.wordpress_vnet.name address_prefixes = ["10.0.1.0/24"] } # Network Security Group resource "azurerm_network_security_group" "wordpress_nsg" { name = "nsg-wordpress-env" location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name security_rule { name = "HTTPInbound" priority = 100 direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = "80" source_address_prefix = "*" destination_address_prefix = "*" } security_rule { name = "SSHInbound" priority = 110 direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = "22" source_address_prefix = "*" destination_address_prefix ="*" } } # Public IP Address resource "azurerm_public_ip" "wordpress_public_ip" { name = "ip-public-wordpress" location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name allocation_method = "Static" sku = "Standard" } # Network Interface resource "azurerm_network_interface" "wordpress_nic" { name = "nic-wordpress-env" location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name ip_configuration { name = "wordpressconfiguration" subnet_id = azurerm_subnet.wordpress_subnet.id private_ip_address_allocation = "Static" public_ip_address_id = azurerm_public_ip.wordpress_public_ip.id } } # Virtual Machine resource "azurerm_linux_virtual_machine" "wordpress_vm" { name = "vm-wordpress-env" resource_group_name = azurerm_resource_group.wordpress_rg.name location = azurerm_resource_group.wordpress_rg.location size = "Standard_B1s" admin_username = "adminuser" admin_password = "YourSecurePassword" #適切な値を入力ください network_interface_ids = [azurerm_network_interface.wordpress_nic.id] os_disk { caching = "ReadWrite" storage_account_type = "Standard_LRS" } source_image_reference { publisher = "Canonical" offer = "0001-com-ubuntu-server-jammy" sku = "22_04-lts-gen2" version = "latest" } } |
完成したので実行してみたいと思います。
3. 実行
PowerShellを実行します。Azureへのログイン、Terraformのファイルの初期化から、実際のファイルを実行して成功するか見てみましょう。
まずは、Terraformを利用してAzureリソースを展開するために必要な環境変数を指定します。
1 2 3 4 |
$env:ARM_CLIENT_ID="<service_principal_app_id>" $env:ARM_SUBSCRIPTION_ID="<azure_subscription_id>" $env:ARM_TENANT_ID="<azure_subscription_tenant_id>" $env:ARM_CLIENT_SECRET="<service_principal_password>" |
登録が完了しているかは下記のコマンドから確認できます。
1 |
gci env:ARM_* |
それではAzureにアクセスします。
1 |
az login |
無事ログインが完了しました。念のため、自分がデプロイしたいサブスクリプションが指定されていることを確認します。
1 |
az account show |
それでは、Terraformファイルの初期化から実行まで進めていきます。
1 2 3 4 5 6 |
--初期化 terraform init --terraform applyでも同じ確認はしくれますが丁寧に terraform plan --planの実行結果から、コードが認識されていることを確認できたらファイルを実行 terraform apply |
初期化が完了しました。
planでも、しっかりと7リソースが追加されることが確認できました。問題なさそうですので、
Applyを実行します。
残念ですが、エラーが出てしまいました。仮想マシンの作成時のエラーのようです。これもGeminiに聞いてみましょう。
How do I fix this error, At least one
admin_ssh_key
must be specified whendisable_password_authentication
is set totrue
丁寧にSSH Keyの生成方法について解説してくれました。
Terraformファイルに追加する場合は、public_key変数に、Keyファイルのパスを指定します。
1 2 3 4 5 6 7 8 9 10 |
resource "azurerm_linux_virtual_machine" "wordpress_vm" { # ... other configurations disable_password_authentication = true admin_ssh_key { username = "your_admin_username" public_key = file("~/.ssh/id_rsa.pub") # Path to your public key file } } |
デフォルトは’true’と判定されるようです。今回はシンプルに、disable_password_authentication = ‘false’を明記する形にしたいと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# Configure the Azure provider terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = "~> 3.0.2" } } required_version = ">= 1.1.0" } # Provider Configuration provider "azurerm" { features {} } # Resource Group resource "azurerm_resource_group" "wordpress_rg" { name = "rg-wordpress-env" location = "japaneast" } # Virtual Network and Subnet resource "azurerm_virtual_network" "wordpress_vnet" { name = "vnet-wordpress-env" address_space = ["10.0.0.0/16"] location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name } resource "azurerm_subnet" "wordpress_subnet" { name = "sb-wordpress-unit" resource_group_name = azurerm_resource_group.wordpress_rg.name virtual_network_name = azurerm_virtual_network.wordpress_vnet.name address_prefixes = ["10.0.1.0/24"] } # Network Security Group resource "azurerm_network_security_group" "wordpress_nsg" { name = "nsg-wordpress-env" location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name security_rule { name = "HTTPInbound" priority = 100 direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = "80" source_address_prefix = "*" destination_address_prefix = "*" } security_rule { name = "SSHInbound" priority = 110 direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = "22" source_address_prefix = "*" destination_address_prefix ="*" } } # Public IP Address resource "azurerm_public_ip" "wordpress_public_ip" { name = "ip-public-wordpress" location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name allocation_method = "Static" sku = "Standard" } # Network Interface resource "azurerm_network_interface" "wordpress_nic" { name = "nic-wordpress-env" location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name ip_configuration { name = "wordpressconfiguration" subnet_id = azurerm_subnet.wordpress_subnet.id private_ip_address_allocation = "Dynamic" public_ip_address_id = azurerm_public_ip.wordpress_public_ip.id } } # Virtual Machine resource "azurerm_linux_virtual_machine" "wordpress_vm" { name = "vm-wordpress-env" resource_group_name = azurerm_resource_group.wordpress_rg.name location = azurerm_resource_group.wordpress_rg.location size = "Standard_B1s" admin_username = "adminuser" admin_password = "YourSecurePassword" #適切な値を入力ください network_interface_ids = [azurerm_network_interface.wordpress_nic.id] disable_password_authentication = "false" os_disk { caching = "ReadWrite" storage_account_type = "Standard_LRS" } source_image_reference { publisher = "Canonical" offer = "0001-com-ubuntu-server-jammy" sku = "22_04-lts-gen2" version = "latest" } } |
では、再実行します。
無事作成されたことを確認しました。では、Azure Portal画面からも確認してみようと思います。
Azure Portal上からも作成を確認できました。ネットワークセキュリティグループも意図したように設定されています。
では、仮想マシンにアクセスができるのか…あーー、アクセスができません。
ふとコードを見直したら、Network Interface(NIC)とNetwork Security Group(NSG)が紐づいていないことに気が付きました。
Geminiにコードを分析してもらいましたが、問題ないと返事がきます。おかしいですね。。。
Microsoftに載っているTerraformコードを参考に修正します。折角なので聞いてみましょう。
In my opinion, I think you need to attach your network security group to network interface. Example code follows.
resource “azurerm_network_interface_security_group_association” “example” {
network_interface_id = azurerm_network_interface.my_terraform_nic.id
network_security_group_id = azurerm_network_security_group.my_terraform_nsg.id
}
すると、
You’re absolutely correct! That’s the missing piece. Currently, your Terraform code defines the network interface and network security group but doesn’t explicitly associate them with each other.
それが原因だ!と回答もらえました。正解だったようです。
そして、exampleだった箇所を適切な名称へ変更してもらえました。
1 2 3 4 5 6 |
# ... (Your other resources: Resource group, subnet, VM, NSG, NIC, etc.) resource "azurerm_network_interface_security_group_association" "wordpress_association" { network_interface_id = azurerm_network_interface.wordpress_nic.id network_security_group_id = azurerm_network_security_group.wordpress_nsg.id } |
これを追加して、今一度Terraform Applyを実施します。既にデプロイされているリソースは無視されるため、関連付けのみが実行される想定になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# Configure the Azure provider terraform { required_providers { azurerm = { source = "hashicorp/azurerm" version = "~> 3.0.2" } } required_version = ">= 1.1.0" } # Provider Configuration provider "azurerm" { features {} } # Resource Group resource "azurerm_resource_group" "wordpress_rg" { name = "rg-wordpress-env" location = "japaneast" } # Virtual Network and Subnet resource "azurerm_virtual_network" "wordpress_vnet" { name = "vnet-wordpress-env" address_space = ["10.0.0.0/16"] location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name } resource "azurerm_subnet" "wordpress_subnet" { name = "sb-wordpress-unit" resource_group_name = azurerm_resource_group.wordpress_rg.name virtual_network_name = azurerm_virtual_network.wordpress_vnet.name address_prefixes = ["10.0.1.0/24"] } # Network Security Group resource "azurerm_network_security_group" "wordpress_nsg" { name = "nsg-wordpress-env" location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name security_rule { name = "HTTPInbound" priority = 100 direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = "80" source_address_prefix = "*" destination_address_prefix = "*" } security_rule { name = "SSHInbound" priority = 110 direction = "Inbound" access = "Allow" protocol = "Tcp" source_port_range = "*" destination_port_range = "22" source_address_prefix = "*" destination_address_prefix ="*" } } # Public IP Address resource "azurerm_public_ip" "wordpress_public_ip" { name = "ip-public-wordpress" location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name allocation_method = "Static" sku = "Standard" } # Network Interface resource "azurerm_network_interface" "wordpress_nic" { name = "nic-wordpress-env" location = azurerm_resource_group.wordpress_rg.location resource_group_name = azurerm_resource_group.wordpress_rg.name ip_configuration { name = "wordpressconfiguration" subnet_id = azurerm_subnet.wordpress_subnet.id private_ip_address_allocation = "Dynamic" public_ip_address_id = azurerm_public_ip.wordpress_public_ip.id } } # Network Interface and Network Security Group Assosiation resource "azurerm_network_interface_security_group_association" "wordpress_association" { network_interface_id = azurerm_network_interface.wordpress_nic.id network_security_group_id = azurerm_network_security_group.wordpress_nsg.id } # Virtual Machine resource "azurerm_linux_virtual_machine" "wordpress_vm" { name = "vm-wordpress-env" resource_group_name = azurerm_resource_group.wordpress_rg.name location = azurerm_resource_group.wordpress_rg.location size = "Standard_B1s" admin_username = "adminuser" admin_password = "YourSecurePassword" network_interface_ids = [azurerm_network_interface.wordpress_nic.id] disable_password_authentication = "false" os_disk { caching = "ReadWrite" storage_account_type = "Standard_LRS" } source_image_reference { publisher = "Canonical" offer = "0001-com-ubuntu-server-jammy" sku = "22_04-lts-gen2" version = "latest" } } |
Terraformが差分部分のみ認識してくれました。問題ないため、yesとして続行します。
無事作成が完了しました。
Azure Portal画面からも確認します。
関連付けられたことが確認できました。今一度、アクセス確認したいと思います。
無事、Teratermからアクセス確認ができました。仮想マシンの構築完了です。
4. まとめ
Gemini単独でのコード生成ができませんでしたが、環境構築の時間を大幅に削減できるなという印象を持てたのではないでしょうか。
仮想マシンの管理者パスワード設定や、NICとNSGでの関連付け等、やはり人の目によるダブルチェックは必要となり、エンジニアは必要不可欠かと思います。
今回の検証を通じて感じたこととしてはAIを盲信しないことであり、AI×人の組み合わせによって最大限の効果を発揮するものであるといった点です。
少なくとも、AIは我々の業務効率化を助けてくれるツールであることは間違いはありませんので、今後もうまく付き合っていきましょう!
この記事を書いた人
- 森 信之介
- テクニカルマーケターとして、ブログ執筆、セミナー講師を行っております!
この投稿者の最新の記事
- 2024年3月26日ブログWindowsのメモ帳にスペルチェック機能が追加!
- 2024年3月25日ブログBCPの策定や見直しのhow to – ガートナー社が抑えておくべき3のポイントを発表
- 2024年3月22日ブログスポーツにもAIの力を~「TacticAI」が登場
- 2024年3月21日ブログChatGPTやGeminiに並ぶ「Claude3」のプロンプトライブラリをご紹介!