1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Pulumi de Cloud】 Ubuntu の VM を作成し SSH してみました

Posted at

概要

Pulumiは Indrastracture as Code を実現するソフトウェア。 Azure Resource Manager(Template) や Terraform で出来ることと同じですが、一般的なプログラム言語(Node.js,JavaScript,TypeScript,Python,GO)で記述できるのが強みでしょうか、、、

この記事 は terraform を利用しましたが、今回は Pulumi を用いて Azure環境上に Ubuntu のVMを作成し、SSH接続してみました。

実行環境

macOS Sonoma 14.0
python 3.8.12
Azure CLI 2.53.0
pulumi v3.91.1


Pulumi IaC

作業環境の準備

Pulumiの状態管理をローカルで行います

## Azureへのログイン
az login

## 作業場所の定義
$ mkdir ~/MyDevelops/Pulumi/vm_azure_python
$ cd ~/MyDevelops/Pulumi/vm_azure_python

プロジェクトの作成

## 「vm-azure-python」からのプロジェクト作成
$ pulumi new vm-azure-python
This command will walk you through creating a new Pulumi project.

Enter a value or leave blank to accept the (default), and press <ENTER>.
Press ^C at any time to quit.

project name (vm_azure_python):  
project description (A Python program to deploy a virtual machine on Azure):  
Created project 'vm_azure_python'

stack name (dev):  
Created stack 'dev'
Enter your passphrase to protect config/secrets:  
Re-enter your passphrase to confirm:  

azure-native:location: The Azure location to deploy into (WestUS2): japaneast 
adminUsername: The user account to create on the VM (pulumiuser):  
osImage: The Azure URN of the base image to use for the VM (Debian:debian-11:11:latest): Canonical:UbuntuServer:18.04-LTS:latest 
servicePort: The HTTP service port to expose on the VM (80): 8080 
sshPublicKey: The public key data to use for SSH authentication:  
vmName: The DNS hostname prefix to use for the VM (my-server): vm-ituru-ubuntu 
vmSize: The machine size to use for the VM (Standard_A1_v2): Standard_B2s 
Saved config

Installing dependencies...

Creating virtual environment...
Finished creating virtual environment
Updating pip, setuptools, and wheel in virtual environment...
    :
   中略
    :
Your new project is ready to go! ✨
To perform an initial deployment, run `pulumi up`

プロジェクト作成後のフォルダ構成

## フォルダ・ファイルの確認
$ ls -l
total 80
drwxr-xr-x  13 ituru  staff   416 10 30 22:51 ./
drwxr-xr-x  10 ituru  staff   320 10 30 21:45 ../
-rw-r--r--   1 ituru  staff    12 10 30 21:46 .gitignore
drwxr-xr-x   8 ituru  staff   256 10 30 23:15 .pulumi/
-rw-r--r--   1 ituru  staff   974 10 30 23:27 Pulumi.dev.yaml
-rw-r--r--   1 ituru  staff   145 10 30 21:46 Pulumi.yaml
-rw-r--r--   1 ituru  staff  5505 10 30 23:42 __main__.py
drwxr-xr-x   3 ituru  staff    96 10 30 23:51 __pycache__/
-rw-r--r--   1 ituru  staff    82 10 30 21:46 requirements.txt
drwxr-xr-x   6 ituru  staff   192 10 30 21:52 venv/

設定情報の確認

Pulumi.dev.yaml
encryptionsalt: v1:LGF1nzVAmSs=:v1:rcevXbWYrtXUqi88...............
config:
  azure-native:location: japaneast
  vm_azure_python:adminUsername: pulumiuser
  vm_azure_python:osImage: Canonical:UbuntuServer:18.04-LTS:latest
  vm_azure_python:servicePort: "8080"
  vm_azure_python:vmName: vm-ituru-ubuntu
  vm_azure_python:vmSize: Standard_B2s

sshキー(秘密鍵・公開鍵)の作成

## カレントディレクトリに鍵保存ディレクトリの作成
$ mkdir .ssh
$ cd .ssh


## sshキーの作成
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/ituru/.ssh/id_rsa): /Users/ituru/MyDevelops/Pulumi/vm_azure_python/.ssh/id_rsa
Enter passphrase (empty for no passphrase): <-- パスフレーズの入力(任意)
Enter same passphrase again: <-- もう一度、パスフレーズの入力(任意)
Your identification has been saved in /Users/ituru/MyDevelops/Pulumi/vm_azure_python/.ssh/id_rsa
Your public key has been saved in /Users/ituru/MyDevelops/Pulumi/vm_azure_python/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:0j4NAXLGmq86AUj/k9wMqOIK3aP7777777777777777 ituru@IsseinoMacBook-Pro.local
The key's randomart image is:
+---[RSA 3072]----+
|  +.ooOo.+       |
| o + =.ooo.      |
|o + Eo  + .      |
|o. ooo . + .     |
| .. o.* S .      |
|.o.. =.* o       |
|+ ..o.o o .      |
|.....o   .       |
|o +=.            |
+----[SHA256]-----+


## 生成された鍵の確認
$ ls -l
total 16
drwxr-xr-x   4 ituru  staff   128 10 30 22:51 ./
drwxr-xr-x  13 ituru  staff   416 10 30 22:51 ../
-rw-------   1 ituru  staff  2622 10 30 22:51 id_rsa
-rw-r--r--   1 ituru  staff   584 10 30 22:51 id_rsa.pub
$ cd ..

作成するリソース(仮想マシン)への公開鍵の設定

必要な構成変数 'vm_azure_python:sshPublicKey' の作成(公開鍵の設定)

$ pulumi config set vm_azure_python:sshPublicKey "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQ............"

設定情報の確認、sshのPublicKeyの設定を確認できます。

Pulumi.dev.yaml
encryptionsalt: v1:LGF1nzVAmSs=:v1:rcevXbWYrtXUqi88...............
config:
  azure-native:location: japaneast
  vm_azure_python:adminUsername: pulumiuser
  vm_azure_python:osImage: Canonical:UbuntuServer:18.04-LTS:latest
  vm_azure_python:servicePort: "8080"
  vm_azure_python:sshPublicKey: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQ...........
  vm_azure_python:vmName: vm-ituru-ubuntu
  vm_azure_python:vmSize: Standard_B2s

構築コードの編集

作成したプロジェクト内の __main__.py ファイルの編集

__main__.py(編集)
import pulumi
from pulumi_azure_native import resources, network, compute
from pulumi_random import random_string
import base64

# Import the program's configuration settings.
config = pulumi.Config()
vm_name = config.get("vmName")
vm_size = config.get("vmSize")
os_image = config.get("osImage")
admin_username = config.get("adminUsername")
service_port = config.get("servicePort")
ssh_public_key = config.require("sshPublicKey")
os_image_publisher, os_image_offer, os_image_sku, os_image_version = os_image.split(":")

# Create a resource group.
resource_group = resources.ResourceGroup("rg_ituru_linuxvm_")

# Create a virtual network.
virtual_network = network.VirtualNetwork(
    "network",
    resource_group_name=resource_group.name,
    address_space=network.AddressSpaceArgs(
        address_prefixes=[
            "10.0.0.0/16",
        ],
    ),
    subnets=[
        network.SubnetArgs(
            name=f"{vm_name}-subnet",
            address_prefix="10.0.1.0/24",
        ),
    ],
)
# Use a random string to give the VM a unique DNS name.
domain_name_label = random_string.RandomString(
    "domain-label",
    length=8,
    upper=False,
    special=False,
).result.apply(lambda result: f"{vm_name}-{result}")

# Create a public IP address for the VM.
public_ip = network.PublicIPAddress(
    "public-ip",
    resource_group_name=resource_group.name,
    public_ip_allocation_method=network.IpAllocationMethod.DYNAMIC,
    dns_settings=network.PublicIPAddressDnsSettingsArgs(
        domain_name_label=domain_name_label,
    ),
)

# Create a security group allowing inbound access over ports 8080 (for HTTP) and 22 (for SSH).
security_group = network.NetworkSecurityGroup(
    "security-group",
    resource_group_name=resource_group.name,
    security_rules=[
        network.SecurityRuleArgs(
            name=f"{vm_name}-securityrule",
            priority=1000,
            direction=network.AccessRuleDirection.INBOUND,
            access="Allow",
            protocol="Tcp",
            source_port_range="*",
            source_address_prefix="123.123.123.123",
            destination_address_prefix="*",
            destination_port_ranges=[
                service_port,
                "22",
            ],
        ),
    ],
)

# Create a network interface with the virtual network, IP address, and security group.
network_interface = network.NetworkInterface(
    "network-interface",
    resource_group_name=resource_group.name,
    network_security_group=network.NetworkSecurityGroupArgs(
        id=security_group.id,
    ),
    ip_configurations=[
        network.NetworkInterfaceIPConfigurationArgs(
            name=f"{vm_name}-ipconfiguration",
            private_ip_allocation_method=network.IpAllocationMethod.DYNAMIC,
            subnet=network.SubnetArgs(
                id=virtual_network.subnets.apply(lambda subnets: subnets[0].id),
            ),
            public_ip_address=network.PublicIPAddressArgs(
                id=public_ip.id,
            ),
        ),
    ],
)

# Define a script to be run when the VM starts up.
init_script = f"""#!/bin/bash
    echo '<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Hello, world!</title>
    </head>
    <body>
        <h1>Hello, world! 👋</h1>
        <p>Deployed with 💜 by <a href="https://pulumi.com/">Pulumi</a>.</p>
    </body>
    </html>' > index.html
    sudo python3 -m http.server {service_port} &
    """

# Create the virtual machine.
vm = compute.VirtualMachine(
    "vm",
    resource_group_name=resource_group.name,
    network_profile=compute.NetworkProfileArgs(
        network_interfaces=[
            compute.NetworkInterfaceReferenceArgs(
                id=network_interface.id,
                primary=True,
            )
        ]
    ),
    hardware_profile=compute.HardwareProfileArgs(
        vm_size=vm_size,
    ),
    os_profile=compute.OSProfileArgs(
        computer_name=vm_name,
        admin_username=admin_username,
        custom_data=base64.b64encode(bytes(init_script, "utf-8")).decode("utf-8"),
        linux_configuration=compute.LinuxConfigurationArgs(
            disable_password_authentication=True,
            ssh=compute.SshConfigurationArgs(
                public_keys=[
                    compute.SshPublicKeyArgs(
                        key_data=ssh_public_key,
                        path=f"/home/{admin_username}/.ssh/authorized_keys",
                    ),
                ],
            ),
        ),
    ),
    storage_profile=compute.StorageProfileArgs(
        os_disk=compute.OSDiskArgs(
            name=f"{vm_name}-osdisk",
            create_option=compute.DiskCreateOption.FROM_IMAGE,
        ),
        image_reference=compute.ImageReferenceArgs(
            publisher=os_image_publisher,
            offer=os_image_offer,
            sku=os_image_sku,
            version=os_image_version,
        ),
    ),
)

# Once the machine is created, fetch its IP address and DNS hostname.
vm_address = vm.id.apply(
    lambda id: network.get_public_ip_address_output(
        resource_group_name=resource_group.name,
        public_ip_address_name=public_ip.name,
    )
)

# Export the VM's hostname, public IP address, and HTTP URL.
pulumi.export("ip", vm_address.ip_address)
pulumi.export("hostname", vm_address.dns_settings.apply(lambda settings: settings.fqdn))
pulumi.export(
    "url",
    vm_address.dns_settings.apply(
        lambda settings: f"http://{settings.fqdn}:{service_port}"
    ),
)

構築とテスト

Linux仮想マシンの構築

## Deploy Stack
$ pulumi up                                    
Enter your passphrase to unlock config/secrets
    (set PULUMI_CONFIG_PASSPHRASE or PULUMI_CONFIG_PASSPHRASE_FILE to remember):  *************
Enter your passphrase to unlock config/secrets
Previewing update (dev):
     Type                                          Name                 Plan       
 +   pulumi:pulumi:Stack                           vm_azure_python-dev  create     
 +   ├─ random:index:RandomString                  domain-label         create     
 +   ├─ azure-native:resources:ResourceGroup       rg_ituru_linuxvm_    create     
 +   ├─ azure-native:network:VirtualNetwork        network              create     
 +   ├─ azure-native:network:NetworkSecurityGroup  security-group       create     
 +   ├─ azure-native:network:PublicIPAddress       public-ip            create     
 +   ├─ azure-native:network:NetworkInterface      network-interface    create     
 +   └─ azure-native:compute:VirtualMachine        vm                   create     

Outputs:
    hostname: output<string>
    ip      : output<string>
    url     : output<string>

Resources:
    + 8 to create

Do you want to perform this update? yes
Updating (dev):
     Type                                          Name                 Status              
 +   pulumi:pulumi:Stack                           vm_azure_python-dev  created (91s)       
 +   ├─ random:index:RandomString                  domain-label         created (0.00s)     
 +   ├─ azure-native:resources:ResourceGroup       rg_ituru_linuxvm_    created (0.45s)     
 +   ├─ azure-native:network:VirtualNetwork        network              created (13s)       
 +   ├─ azure-native:network:NetworkSecurityGroup  security-group       created (4s)        
 +   ├─ azure-native:network:PublicIPAddress       public-ip            created (7s)        
 +   ├─ azure-native:network:NetworkInterface      network-interface    created (0.56s)     
 +   └─ azure-native:compute:VirtualMachine        vm                   created (76s)       

Outputs:
    hostname: "vm-ituru-ubuntu-as6zrbef.japaneast.cloudapp.azure.com"
    ip      : "52.140.201.159"
    url     : "http://vm-ituru-ubuntu-as6zrbef.japaneast.cloudapp.azure.com:8080"

Resources:
    + 8 created

Duration: 1m34s

接続テスト

Webアクセス

$ curl http://vm-ituru-ubuntu-as6zrbef.japaneast.cloudapp.azure.com:8080
<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Hello, world!</title>
    </head>
    <body>
        <h1>Hello, world! 👋</h1>
        <p>Deployed with 💜 by <a href="https://pulumi.com/">Pulumi</a>.</p>
    </body>
    </html>

SSH接続

## 秘密鍵を指定して ssh接続
$ ssh -i ./.ssh/id_rsa pulumiuser@52.140.201.159
The authenticity of host '52.140.201.159 (52.140.201.159)' can't be established.
ED25519 key fingerprint is SHA256:s5fcGz4UslCjpbdXXSiP5wOILvldhhYStnmYvdcQC7o.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '52.140.201.159' (ED25519) to the list of known hosts.
Welcome to Ubuntu 18.04.6 LTS (GNU/Linux 5.4.0-1109-azure x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Mon Oct 30 14:53:56 UTC 2023

  System load:  0.44              Processes:           135
  Usage of /:   4.5% of 28.89GB   Users logged in:     0
  Memory usage: 5%                IP address for eth0: 10.0.1.4
  Swap usage:   0%

Expanded Security Maintenance for Infrastructure is not enabled.

0 updates can be applied immediately.

Enable ESM Infra to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

pulumiuser@vm-ituru-ubuntu:~$  <--- SSH接続完了


## OSの確認
pulumiuser@vm-ituru-ubuntu:~$ uname -a
Linux vm-ituru-ubuntu 5.4.0-1109-azure #115~18.04.1-Ubuntu SMP Mon May 22 20:06:37 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
pulumiuser@vm-ituru-ubuntu:~$ exit

後片付け

リソースの全削除

$ pulumi destroy

まとめ

Pulumiで構築(プログラミング言語でコードを記載)すると単体テスト(同じプログラミング言語を利用して)はやりやすいかもしれませんね。

参考記事

以下の記事を参考にさせていただきました。感謝申し上げます。

PulumiはIaCの革命児になれるか
Pulumi使い始めた所感

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?