---
title: "Packer i Terraform: generowanie obrazu Ubuntu 22.04-4 Server i automatyczne wdrażanie go na Proxmoxie"
url: https://michalasobczak.pl/pl/posts/use-packer-terraform-to-generate-ubuntu-22-04-4-server-image-and-deploy-it-automatically-to-proxmox.html
author: "Michał Sobczak"
description: "Jeśli zastanawiasz się, jak zautomatyzować tworzenie maszyn wirtualnych z Ubuntu, a następnie wdrażać je na Proxmoxie w wielu kopiach, to szukasz Packera i Terraforma. Na marginesie: maszyny wirtualne w Proxmoxie to właściwa droga."
published: 2024-09-06T12:12:26.000Z
updated: 2024-09-06T20:09:30.000Z
language: pl
categories: ["Technology"]
tags: ["DevOps & Automation", "Proxmox", "Ubuntu"]
license: CC BY-NC-ND 4.0 (https://creativecommons.org/licenses/by-nc-nd/4.0/)
---
# Packer i Terraform: generowanie obrazu Ubuntu 22.04-4 Server i automatyczne wdrażanie go na Proxmoxie

> Jeśli zastanawiasz się, jak zautomatyzować tworzenie maszyn wirtualnych z Ubuntu, a następnie wdrażać je na Proxmoxie w wielu kopiach, to szukasz Packera i Terraforma.

Na marginesie: *maszyny wirtualne w Proxmoxie to właściwa droga. Przez kilka dni próbowałem uruchomić kontenery LXC, jednak ostatecznie muszę powiedzieć, że nie jest to najlepsza opcja – wiele rzeczy się sypie, jak cgroups, AppArmor, zagnieżdżanie (nesting), FUSE, ruch przychodzący w sieci itd. Przy LXC jest po prostu za dużo do ogarnięcia, a przy VM takiego problemu nie ma, więc dyskusja kończy się tutaj na korzyść Proxmox Qemu. Kontenery LXC zostawcie do prostych rzeczy.*

## Po co automatyzować?

Bo możemy.

Bo to lepszy sposób wykorzystania naszego czasu.

Bo to lepiej się skaluje.

Bo zapewnia pewną formę samodokumentacji.

## Dlaczego Proxmox i VM z Ubuntu?

Ubuntu to wiodąca dystrybucja Linuksa bez problemów licencyjnych, z 34% udziałem w rynku Linuksa. Ma silną bazę użytkowników. To także moja osobista preferencja. Daje nam możliwość wykupienia subskrypcji Ubuntu Pro, która zawiera kilka narzędzi związanych z compliance.

Z kolei Proxmox/Qemu kilka lat temu stał się oprogramowaniem do wirtualizacji klasy enterprise i jest również wiodącym rozwiązaniem open source w swojej dziedzinie. Zawiera funkcje klastrowania (w tym failover), a także obsługę różnych typów storage'u. W zależności od źródła ma około 1% udziału w rynku oprogramowania do wirtualizacji.

## Instalacja Packera i Terraforma

Ważne jest, aby zarówno Packer, jak i Terraform były we właściwych wersjach, pochodzących z oficjalnych repozytoriów. Co więcej, istotne jest to, że dokładny sposób budowania konkretnej wersji systemu operacyjnego różni się między wersjami – dlatego tytuł tego artykułu mówi o 22.04-4, a nie 22.04-3, bo mogą występować pewne różnice.

Zainstaluj właściwą wersję Packera. Wersja z pakietów Ubuntu jest nieprawidłowa i nie ma możliwości zarządzania pluginami, więc koniecznie zainstaluj Packera z oficjalnego repozytorium.

```bash
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
sudo apt-get update &amp;&amp; sudo apt-get install packer
```

Zainstaluj właściwą wersję Terraforma. Mając problemy z dołączoną wersją Packera, postanowiłem od razu pójść oficjalną drogą instalacji:

```bash
sudo apt-get update &amp;&amp; sudo apt-get install -y gnupg software-properties-common

wget -O- https://apt.releases.hashicorp.com/gpg | \
gpg --dearmor | \
sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null

gpg --no-default-keyring \
--keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \
--fingerprint

echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/hashicorp.list

sudo apt update

sudo apt-get install terraform
```

## Terraform Telmate/Proxmox

Ważna uwaga dotycząca Terraforma i jego pluginu dla Proxmoxa. Ten plugin, podobnie jak API Proxmoxa w golangu, dostarcza jedna firma – Telmate LLC. Plugin ma pewne problemy z kompatybilnością i obecnie dla Proxmoxa 7 polecam używać Telmate/proxmox w wersji 2.9.0. Najnowsza wersja, czyli 2.9.14, ma pewne trudności z obsługą cloud-init, co daje 50% szans na VM wymagającą ręcznej rekonfiguracji dysków. Na dzień 2024/09/06 nie ma stabilnego wydania 3.0.1.

Jeśli masz najnowszą wersję i chcesz zrobić downgrade, usuń .terraform i .terraform.lock.hcl, a następnie zainicjalizuj ponownie poniższym poleceniem:

```bash
terraform init
```

## Generowanie szablonu Ubuntu 22.04-4 dla Proxmoxa za pomocą Packera

Kilka wersji temu projekt Ubuntu zmienił sposób automatyzacji instalacji. Zamiast seedowania masz teraz funkcję **autoinstall**. Struktura projektu Packera składa się z kilku plików, a zacznę od ubuntu-22-template/http/user-data zawierającego cloud-config:

```yaml
#cloud-config
autoinstall:
  version: 1
  locale: en_US
  ssh:
    install-server: true
    allow-pw: true
    disable_root: true
    ssh_quiet_keygen: true
    allow_public_ssh_keys: true
  packages:
    - qemu-guest-agent
    - sudo
  storage:
    layout:
      name: lvm
      sizing-policy: all
      # password: xxx
  user-data:
    package_upgrade: false
    timezone: Europe/Warsaw
    users:
      - name: temporary
        groups: [sudo]
        lock-passwd: false
        sudo: ALL=(ALL) NOPASSWD:ALL
        shell: /bin/bash
        passwd: "here you place SHA512 generated hash of a password"
```

**Aby włączyć LUKS**, odkomentuj pole storage.layout.password i ustaw wybrane hasło. **users.passwd można wygenerować** za pomocą mkpasswd z użyciem SHA-512. Dalej jest ubuntu-22-template/files/99-pve.cfg:

```text
datasource_list: [ConfigDrive, NoCloud]
```

**Dane uwierzytelniające** dostają własny plik (./credentials.pkr.hcl). Można je oczywiście umieścić bezpośrednio w swoim pliku, jednak jeśli trzymasz te pliki w SCM, zostaną tam na stałe i będą współdzielone z innymi – dlatego warto ten plik wydzielić, a nawet nie dołączać go do commitów:

```ini
proxmox_api_url = "https://192.168.2.10:8006/api2/json"
proxmox_api_token_id = "root@pam!root-token"
proxmox_api_token_secret = "your Proxmox token"
my_ssh_password = "your new VM SSH password"
```

Na koniec jest plik ubuntu-22-template/ubuntu-22-raw.pkr.hcl, w którym definiujesz zmienne, źródło i build. Wskazujemy obraz ISO i definiujemy parametry VM Proxmox VE Qemu. Najważniejszą i najbardziej zagadkową rzeczą jest podanie prawidłowego boot\_command. Sekcje http\* odnoszą się do Twojej maszyny serwującej pliki po HTTP, natomiast sekcja ssh\* dotyczy konfiguracji maszyny zdalnej (nowo utworzonej VM na Proxmoxie). Nasza lokalna maszyna dostarcza po HTTP polecenia powłoki, które po przekazaniu do maszyny zdalnej są wykonywane podczas instalacji systemu.

```hcl
variable "proxmox_api_url" {
    type = string
}
variable "proxmox_api_token_id" {
    type = string
}
variable "proxmox_api_token_secret" {
    type = string
    sensitive = true
}
variable "my_ssh_password" {
    type = string
    sensitive = true
}

source "proxmox-iso" "ubuntu-server-jammy" {
    proxmox_url = "${var.proxmox_api_url}"
    username =    "${var.proxmox_api_token_id}"
    token =       "${var.proxmox_api_token_secret}"
    insecure_skip_tls_verify = true
    node = "lab"
    vm_id = "141"
    vm_name = "z10-ubuntu-22-template-RAW"
    template_description = "Ubuntu Server Raw Encrypted"
    iso_file = "local:iso/ubuntu-22.04.4-live-server-amd64.iso"
    iso_storage_pool = "local"
    unmount_iso = true
    qemu_agent = true
    scsi_controller = "virtio-scsi-single"
    disks {
        disk_size = "10G"
        format = "raw"
        storage_pool = "vms1"
        storage_pool_type = "directory"
        type = "virtio"
    }
    cores = "2"    
    memory = "4096" 
    network_adapters {
        model = "virtio"
        bridge = "vmbr0"
        firewall = "false"
    } 
    cloud_init = true
    cloud_init_storage_pool = "local"
    boot_command = [
        "&lt;esc>&lt;wait>",
        "e&lt;wait>",
        "&lt;down>&lt;down>&lt;down>&lt;end>",
        "&lt;bs>&lt;bs>&lt;bs>&lt;bs>&lt;wait>",
        "ip=${cidrhost("192.168.2.0/24", 100)}::${cidrhost("192.168.1.0/24", 1)}:${cidrnetmask("192.168.0.0/22")}::::${cidrhost("1.1.1.0/24", 1)}:${cidrhost("9.9.9.0/24", 9)} ",
        "autoinstall ds=nocloud-net\\;s=http://{{ .HTTPIP }}:{{ .HTTPPort }}/ ---&lt;wait>",
        "&lt;f10>&lt;wait>"
    ]
    boot = "c"
    boot_wait = "5s"
    http_directory = "ubuntu-22-template/http" 
    http_bind_address = "IP of machine from which you will run Packer"
    http_port_min = 8802
    http_port_max = 8802
    ssh_host = "192.168.2.100" # new VM proposed IP address
    ssh_username = "temporary"
    ssh_password = "${var.my_ssh_password}"
    ssh_timeout = "20m"
}

build {
    name = "ubuntu-server-jammy"
    sources = ["proxmox-iso.ubuntu-server-jammy"]
    provisioner "shell" {
        inline = [
            "while [ ! -f /var/lib/cloud/instance/boot-finished ]; do echo 'Waiting for cloud-init...'; sleep 1; done",
            "sudo rm /etc/ssh/ssh_host_*",
            "sudo truncate -s 0 /etc/machine-id",
            "sudo apt -y autoremove --purge",
            "sudo apt -y clean",
            "sudo apt -y autoclean",
            "sudo cloud-init clean",
            "sudo rm -f /etc/cloud/cloud.cfg.d/subiquity-disable-cloudinit-networking.cfg",
            "sudo rm -f /etc/netplan/00-installer-config.yaml",
            "sudo sync"
        ]
    }
    provisioner "file" {
        source = "ubuntu-22-template/files/99-pve.cfg"
        destination = "/tmp/99-pve.cfg"
    }
    provisioner "shell" {
        inline = [ "sudo cp /tmp/99-pve.cfg /etc/cloud/cloud.cfg.d/99-pve.cfg" ]
    }
}
```

Aby to uruchomić:

```text
packer build -var-file=credentials.pkr.hcl ubuntu-22-template/ubuntu-22-raw.pkr.hcl
```

Proces instalacji jest zautomatyzowany i nie widzisz zwykłych ekranów konfiguracyjnych. Zamiast tego dostarczamy konfigurację autoinstall i zostawiamy kilka opcji do ustawienia później przez cloud-init, czyli dane użytkownika i szczegóły konfiguracji sieci. W ten sposób możemy zautomatyzować wdrożenia takiego systemu, co pokażę za chwilę w części tego artykułu poświęconej Terraformowi.

Pełny przegląd struktury projektu wygląda następująco:

```text
├── credentials.pkr.hcl
├── main.tf
├── packer_cache
│   └── port
├── terraform.tfstate
├── terraform.tfstate.backup
└── ubuntu-22-template
    ├── files
    │   └── 99-pve.cfg
    ├── http
    │   ├── meta-data
    │   └── user-data
    └── ubuntu-22-raw.pkr.hcl

5 directories, 8 files
```

Po udanej instalacji Ubuntu system zrestartuje się i **przekonwertuje się w szablon**, dzięki czemu będzie mógł później posłużyć jako baza dla kolejnych systemów, jako **linked clone albo full clone**. Jeśli zależy Ci na dużej elastyczności, wybierz full clone, bo nie będziesz mieć żadnych ograniczeń dotyczących użytkowania i migracji VM.

## Wdrażanie wielu VM z Ubuntu za pomocą Terraforma

Szablonu VM w Proxmoxie można użyć do utworzenia nowej VM ręcznie z poziomu UI Proxmoxa. Jednak w przypadku tworzenia 100 VM mogłoby to trochę potrwać. Jest więc narzędzie Terraform, które z pomocą pluginów potrafi połączyć się z Proxmoxem i **zautomatyzować ten proces** za Ciebie.

Zdefiniuj plik Terraforma (.tf) z sekcjami terraform, provider i resource. Sekcja terraform mówi Terraformowi, jakich pluginów będziesz używać. Sekcja provider określa, jak uzyskać dostęp do środowiska wirtualizacji Proxmox. Na koniec sekcja resource, w której umieszczasz całą konfigurację związaną z Twoim Ubuntu 22.04-4 wspartym przez cloud-init. Zaczynamy więc od terraform i wymaganych pluginów providera. W zależności od wersji Proxmoxa – 7 czy 8 – trzeba będzie podać inną konfigurację zasobu:

```hcl
terraform {
    required_providers {
        proxmox = {
            source  = "telmate/proxmox"
            version = "2.9.0" # this version has the greatest compatibility
        }
    }
}
```

Następnie umieszczasz providera Proxmox. Wszystkie wrażliwe dane można też zdefiniować jako zmienne:

```hcl
provider "proxmox" {
    pm_api_url      = "https://192.168.2.10:8006/api2/json"
    pm_user         = "root@pam"
    pm_password     = "xxx"
    pm_tls_insecure = true
}
```

Najpierw trzeba zainicjalizować „backend” Terraforma i zainstalować pluginy. Jeśli chcesz, możesz to zrobić mając tylko sekcje terraform i provider. Możesz to też zrobić po ukończeniu pełnej specyfikacji pliku tf.

```bash
terraform init
```

Na koniec sam zasób:

```hcl
resource "proxmox_vm_qemu" "ubuntu_vm" {
    name        = "z10-ubuntu-22-from-terraform-1-20"
    target_node = "lab" 
    clone       = "z10-ubuntu-22-template-RAW"
    memory      = 4000
    cores       = 2 

    network {
        bridge = "vmbr0"
        model = "virtio"
    }

    disk {
        slot = 0
        storage = "vms1"
        size = "10G"
        type = "virtio"
    }
  
    os_type = "cloud-init"
    ipconfig0 = "ip=192.168.2.20/22,gw=192.168.1.1"
    ciuser = "xxx"
    cipassword = "xxx"
}
```

Aby uruchomić ten skrypt Terraforma, najpierw sprawdzasz go poleceniem plan, a wykonujesz poleceniem apply:

```bash
terraform plan
terraform apply
```

Dzięki temu mechanizm ten wykona pełny klon szablonu jako nową maszynę wirtualną z podanymi definicjami cloud-init dotyczącymi użytkownika i konfiguracji sieci.

![](https://michalasobczak.pl/wp-content/uploads/2024/09/image-1.png)

Przygotowałem dwa przykładowe szablony – jeden z szyfrowaniem dysku LUKS, a drugi bez szyfrowania LUKS. Na potrzeby demo wystarczy niezaszyfrowany dysk, jednak w produkcji powinien to być Twój domyślny sposób instalowania systemów operacyjnych.

![](https://michalasobczak.pl/wp-content/uploads/2024/09/image.png)

**Checkpoint**: utworzyliśmy szablon Ubuntu za pomocą Packera i użyliśmy go do utworzenia nowej VM za pomocą Terraforma.

## Dalsza lektura

-   https://github.com/Telmate/terraform-provider-proxmox/tree/v2.9.0
-   https://registry.terraform.io/providers/Telmate/proxmox/2.9.0/docs/resources/vm\_qemu
