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 le 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 :

  • Une image de base pour l’OS des VM
  • Le fournisseur Proxmox

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Ă©Ă© 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 VM. 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 VM que nous avons prĂ©cĂ©demment crĂ©Ă©. 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 utilisez un autre template de dĂ©ploiement dans le mĂȘme espace de travail, il va supprimer les ressources qui ne sont pas prĂ©sentes dans le 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