Garbage Collector


The little space of a writer, tinkerer, and a coffee addict

Terraformer son serveur Proxmox

Terraformer son serveur Proxmox

A la suite du malheureux incident vécu par OVH et ayant perdu mon serveur dédié durant celui-ci, j’ai du tout reconstruire. Le bon côté de cette mésaventure est que cela me permet de repartir sur une nouvelle base et de développer de nouvelles compétences. Ici, mon objectif a été d’automatiser le plus possible les actions me permettant de créer les différents composants que j’auto-héberge sur ma machine. Le premier était : reconstruire mes VM en peu de temps.

Qu’est-ce que Terraform

logo terraform Logo Terraform de Hashicorp, licence MPL-2.0

Terraform est un logiciel développé par la société Hashicorp, qui est aujourd’hui l’un des grands acteurs de solutions Infrastructure as Code et outils orientés service Cloud. L’entreprise possède un business model intéressant car ses logiciels sont tous Open Source et disponibles gratuitement. Des versions commerciales disposant de plus de fonctionnalités sont proposées contre achat de licence. Parmi leurs autres logiciels dont on entend souvent parler : Consul, un logiciel de découverte de services en réseau, Vagrant qui permet de provisionner des environnements de développement facilement, Vault qui est un gestionnaire de secrets, etc.

Terraform est un outil dont on entend assez souvent parler dans le domaine du Cloud Computing car il est rapidement devenu un standard de fait. Son but est simple : à partir d’un fichier de déclarations (le langage HCL, HashiCorp Configuration Language, mais aussi du JSON), Terraform va exécuter les instructions demandées en se connectant au fournisseur de service Cloud. Il supporte nativement la majorité des services (AWS, Azure, GCP, IBM cloud, DigitalOcean….) et peut être étendu avec des plugins communautaires. Dans mon cas, utilisant Proxmox, j’ai du utiliser un connecteur communautaire. Le concept d’Infrasturcture as Codene se limite pas aux machines virtuelles, il peut aussi servir à déployer des composants réseau ou des espaces de stockage.

L’outil est capable d’établir un plan des actions qui seront réalisées (ajout, suppression, modification d’élément) puis d’appliquer celui-ci. Cette automatisation permet de créer ou de modifier un grand nombre de ressources d’une traite. Dans la première version de mon serveur perso, j’avais installé les VM à la main progressivement… Pour la reconstruction, je n’ai clairement pas eu envie de le refaire. Grâce à lui, j’ai pu reconstruire 5 VM en 5 minutes.

Pour utiliser Terraform avec Proxmox, nous allons avoir besoin de différentes choses :

Créer son image de base

Terraform n’est pas magique, pour créer les VM il se base en fait sur une image système au format “cloud-init”. Ces images sont proposées par les éditeurs des différents systèmes sous plusieurs formats permettant de les importer chez les Cloud Providers.

Exemples :

Dans le cas de Proxmox, nous avons besoin de récupérer l’image au format qcow2qui est de type “disque virtuel”. Dans cet exemple, je partirai de l’image CentOS 8 Stream. A noter que je considère ici que vous connaissez déjà Proxmox.

Tout d’abord, récupérons l’image qcow2 qu’on souhaite utiliser.

wget https://cloud.centos.org/centos/8-stream/x86_64/images/CentOS-Stream-GenericCloud-8-20210210.0.x86_64.qcow2

On crée une VM qui deviendra le template. Je lui donne l’ID 9000 et une configuration minimaliste. Adaptez les paramètres selon votre installation de Proxmox ! (notamment les internes réseau ou le nom du stockage)

qm create 9000 -name centos-8-stream-template -memory 1024 -net0 virtio,bridge=vmbr1 -cores 1 -sockets 1 -cpu cputype=kvm64 -description "Centos 8 Stream Cloud Image" -kvm 1 -numa 1

A cette VM, on rajoute le disque précédemment téléchargé. (Ici, “local” est le nom de mon stockage)

qm importdisk 9000 CentOS-Stream-GenericCloud-8-20210210.0.x86_64.qcow2 local

J’applique ensuite différentes commandes pour modifier la VM.

# On rattache le disque à la VM
qm set 9000 -scsihw virtio-scsi-pci -virtio0 local:9000/vm-9000-disk-0.raw
qm set 9000 -serial0 socket
# restreint le boot au disque cloud-init
qm set 9000 -boot c -bootdisk virtio0
qm set 9000 -agent 1
# activation du hotplug
qm set 9000 -hotplug disk,network,usb,memory,cpu
# 1 vcpu et 1 socket
qm set 9000 -vcpus 1
qm set 9000 -vga qxl
# nommage de la VM
qm set 9000 -name centos-8-stream-template
# Ajout du lecteur CD pour cloudinit
qm set 9000 -ide2 local:cloudinit

Notez que je n’ai pas passé ma VM en mode template, je voulais pouvoir la démarrer pour modifier ou préinstaller dessus des éléments.

Vous vous retrouvez ainsi avec une VM préconfigurée avec une image de base. Attention, ces images sont généralement fournies sans mot de passe root, l’intérêt de Cloudinit est de définir lors du déploiement l’utilisateur administrateur par défaut.

VM template

Dans l’onglet “Cloud Init” vous pouvez définir des options génériques telles que le user par défaut (et lui fournir une clé SSH) ou encore les DNS ou l’IP de la machine. Mais ces params peuvent aussi être initiés par Terraform.

VM template

Si vous modifiez la machine de base, cliquez sur “Regenerate image” pour mettre à jour pour vos prochaines VM.

On a la base, passons à la suite.

Installer Terraform et écrire le template de VM

Récupérez le binaire de Terraform depuis son site officiel et installez-le avec la méthode de votre choix. Ceci fait, on attaque dans le vif du sujet en créant trois fichiers templates pour Terraform (on peut tout mettre dans le même, mais ça permet d’être plus lisible) :

Un premier fichier qu’on appellera provider.tf contiendra la définition du fournisseur. En l’occurrence, le fournisseur est ici notre serveur Proxmox.

terraform {
    required_providers {
        proxmox =  {
        source = "Telmate/proxmox"
        version = "2.6.7"
        }
    }
}

provider  "proxmox" {
    pm_parallel =  1
    pm_tls_insecure =  true
    pm_api_url =  var.pm_api_url
    pm_password =  var.pm_password
    pm_user =  var.pm_user
}

Le premier bloc d’instruction indique à Terraform d’utiliser le provider Proxmox qui est hébergé dans le registre d’extensions communautaire hébergé par HashiCorp.

Le second permet de configurer la connexion au provider. Comme vous pouvez le constater, il fait mention de variables. Nous allons justement les définir dans un fichier variables.tf :

variable  "pm_api_url" {
    default =  "https://mon_serveur_proxmox/api2/json"
}

  

variable  "pm_user" {
    default =  "votre_login_proxmox"
}

  

variable  "pm_password" {
    default =  "le_password_proxmox"
}


variable  "ssh_key" {
    default =  "ssh-rsa ....................."
}

Les trois premières variables sont assez parlantes : la première concerne l’API Proxmox et les deux autres les codes d’accès. La dernière est une clé ssh publique qui sera déployée sur l’utilisateur créé lors de la fabrication des VM. Nous allons voir son usage dans un dernier fichier qu’on appellera judicieusement : vm.tf.

J’ai commenté les endroits intéressants pour plus de lisibilité.

# définit le groupe de ressources "my_servers"
resource  "proxmox_vm_qemu"  "my_servers" {
    # la variable count permet de dire le nom d'objets à créer
    count =  3
    desc =  "My terraformed server"
    name =  "server-${count.index}" # count.index correspond à la valeur en cours de count. Soit server-1, server-2, server-3
    target_node =  "<nom du noeud proxmox>" # renseigner ici le nom du noeud Proxmox sur lequel déployer
    clone =  "centos-8-stream-template" # le template de VM
    os_type =  "cloud-init"
    cores =  2
    sockets =  "1"
    cpu =  "host"
    memory =  2048
    scsihw =  "virtio-scsi-pci"
    bootdisk =  "scsi0"
        # le premier disque est celui de l'image cloud-init. On peut l'agrandir si besoin.
        disk {
            size =  "10G"
            type =  "scsi"
            storage =  "local" # mettre ici le nom du storage Proxmox
            iothread =  1
        }
        # On peut spécifier un second disque à rattacher à la VM
        disk {
            size =  "100G"
            type =  "scsi"
            storage =  "local" # mettre ici le nom du storage Proxmox
            iothread =  1
        }
    network {
        model =  "virtio"
        bridge =  "vmbr0" # adapter le bridge réseau à votre infra
    }

    # Cloud Init Settings
    ## ici, on incrémente l'IP avec l'index
    ipconfig0 =  "ip=192.168.1.1${count.index}/24,gw=192.168.1.1"
    ## la clé SSH précédemment définie dans les variables sera insérée dans le profil de l'utilisateur
    ## qui a été créé lors de la mise en place de l'image cloud-init
    sshkeys =  <<EOF
        ${var.ssh_key}
    EOF

}

D’abord, on lance la commande terraform init qui va initialiser l’espace de travail et télécharger le provider Proxmox.

$ terraform init

Initializing the backend...

Initializing provider plugins...
- Finding telmate/proxmox versions matching "2.6.7"...
- Installing telmate/proxmox v2.6.7...
- Installed telmate/proxmox v2.6.7 (self-signed, key ID A9EBBE091B35AFCE)

Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

Ok, l’espace de travail est initialisé, on va pouvoir…

Tester et appliquer le déploiement

Pour tester le déploiement, il suffit d’exécuter la commande terraform plan. Celle-ci va retourner le plan d’exécution que TF va estimer faire.

$ terraform plan

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # proxmox_vm_qemu.my_servers[0] will be created
  + resource "proxmox_vm_qemu" "my_servers" {
(...............)
         + tag       = -1
        }
    }

Plan: 3 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.

Dans ce plan d’exécution, on peut voir l’effet des variables ${count.index} par exemple : + ipconfig0 = "ip=192.168.1.12/24,gw=192.168.1.1"

La ligne “Plan: " résume les actions. Ici, Terraform nous dit qu’il va ajouter 3 ressources, en l’occurrence 3 VMs. Nous pouvons alors lancer le déploiement avec la commande : terraform apply. TF vous affichera de nouveau le plan d’exécution puis demandera de valider en répondant “yes”. Au bout de quelques minutes, il vous informera du résultat du déploiement et de la création des ressources.

$ terraform apply
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

proxmox_vm_qemu.my_servers[1]: Creating...
proxmox_vm_qemu.my_servers[2]: Creating...
proxmox_vm_qemu.my_servers[0]: Creating...
...
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.

Mais ce n’est pas tout, Terraform permet de modifier un déploiement existant, voire de le détruire aussi aisément. Ce que nous allons voir après.

Juste avant, sachez qu’il est possible d’aller plus loin en exécutant des scripts post qui peuvent permettre d’installer des logiciels par exemple. Personnellement je n’ai pas voulu utiliser ces fonctions préférant Ansible pour ce rôle. Terraform me créé mes VM prêtes à l’emploi, et Ansible la contextualise en formatant les différents volumes du LVM. Si j’ai besoin de rajouter du disque, TF pourra me le faire et derrière Ansible se chargera de les ajouter au volume group.

Modifier le déploiement

Admettons que vous souhaitiez rajouter du disque sur les 3 VMs que nous avons précédemment créées. La méthode de base voudrait que vous alliez sur Proxmox et demandiez l’ajout de disque pour chacune d’elle… Fastidieux !

Il faut cependant avoir en tête que Terraform considère que l’espace de travail est ce qui doit se trouver sur le serveur. J’entends par là que si vous utilisiez un autre template de déploiement dans le même espace de travail, il supprimerait les ressources qui ne sont pas présentes dans le-dit template. Je vous conseille donc de bien séparer les espaces de travail en fonction de la cohérence des ressources que vous voulez déployer. Si jamais vous êtes dans ce cas de figure, il est possible de cibler uniquement les ressources voulues avec l’argument -target=resource.

Exemple : terraform apply -target=my_servers

Ouvrez donc le fichier vm.tf et ajoutez un nouveau disque dedans.

(....)
bootdisk =  "scsi0"
# le premier disque est celui de l'image cloud-init. On peut l'agrandir si besoin.
disk {
    size =  "10G"
    type =  "scsi"
    storage =  "local"  # mettre ici le nom du storage Proxmox
    iothread =  1
}

# On peut spécifier un second disque à rattacher à la VM
disk {
    size =  "1G"
    type =  "scsi"
    storage =  "local"  # mettre ici le nom du storage Proxmox
    iothread =  1
}

# On ajoute un troisième disque
disk {
    size =  "1G"
    type =  "scsi"
    storage =  "local"  # mettre ici le nom du storage Proxmox
    iothread =  1
}
(....)

On lance le plan :

$ terraform plan
proxmox_vm_qemu.my_servers[0]: Refreshing state... [id=ns303122/qemu/106]
proxmox_vm_qemu.my_servers[2]: Refreshing state... [id=ns303122/qemu/105]
proxmox_vm_qemu.my_servers[1]: Refreshing state... [id=ns303122/qemu/102]
(...)
      + disk {
          + backup      = 0
          + cache       = "none"
          + iothread    = 1
          + mbps        = 0
          + mbps_rd     = 0
          + mbps_rd_max = 0
          + mbps_wr     = 0
          + mbps_wr_max = 0
          + replicate   = 0
          + size        = "1G"
          + ssd         = 0
          + storage     = "local"
          + type        = "scsi"
        }

(...)

Il a vu qu’il faut ajouter des disques.

Et on applique. Attention, Terraform est susceptible de redémarrer les VM.

$ terraform apply
Plan: 0 to add, 3 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

(...)
Apply complete! Resources: 0 added, 3 changed, 0 destroyed.

Si on va sur Proxmox, on constate que les 3 VM ont désormais un disque de plus.

Détruire le déploiement

Pour détruire un déploiement c’est aussi simple, il suffit d’appeler terraform destroy.

Attention, une fois lancé c’est sans appel !

$ terraform destroy

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  - destroy
 # proxmox_vm_qemu.my_servers[0] will be destroyed
  - resource "proxmox_vm_qemu" "my_servers" {
...
  # proxmox_vm_qemu.my_servers[1] will be destroyed
  - resource "proxmox_vm_qemu" "my_servers" {
...
  # proxmox_vm_qemu.my_servers[2] will be destroyed
  - resource "proxmox_vm_qemu" "my_servers" {

Plan: 0 to add, 0 to change, 3 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: 
yes

Et voilà.

Sources documentaires


📑 Table of Contents

📚 Read my latest book

Follow me on Mastodon

🏷️ All Tags 📄 All Posts 🗺 Sitemap RSS Feed