Un peu de DevOps avec de l’infratructure as code sur VMware VSphere

Lors de ce tuto, je vous propose de mettre en oeuvre 3 outils opensource sur une plateforme VMware VSphere :

  • Packer : permet de créer des images/templates pour différentes plateformes cibles, comme VMware, Linux KVM, AWS, AZURE, …
  • Terraform : va nous permettre de créer des VMs à partir des images/templates créés par Packer
  • Ansible : utilisé pour installer des packages, applications, configurer l’OS

Infrastructure as code packer terraform ansible vmware vsphere devops

HashiCorp Packer

Packer est un outil de construction automatique d'image de machine virtuelle. La création de templates, avec Packer va permettre de déployer dans le template des stratégies de sécurité, du hardening de l’OS, des créations d’utilisateurs, clés ssh, …

Astuce : si vous déclenchez plusieurs fois le script de création, ssh va créer une entrée dans le fichier ~/.ssh/known_hosts qui va générer une erreur de connexion ssh, afin de l’éviter je supprime systématiquement l’entrée avec la commande ssh-keygen.

ssh-keygen -f "/home/demo/.ssh/known_hosts" -R "192.168.1.2"

Définition de l’image pour Packer

Afin de définir notre image cible, nous allons fournir à Packer ce fichier de définition json. Ce fichier comporte 4 zones :

  • Informations sur le vcenter cible
  • Configuration du template (CPU, RAM, Disk, …)
  • Les informations concernant le fichier kickstart : ks.cfg
  • Enfin une zone provisioners qui permet d’appeler des scripts complémentaires comme des playbooks Ansible
{
  "builders" : [
    {
      "type" : "vsphere-iso",
      "vcenter_server" : "192.168.1.201",
      "username" : "administrator@phy-cluster.apps.local",
      "password" : "superpassword",
      "insecure_connection" : "true",
      "notes": "Build via Packer",
      "datacenter" : "APPS",
      "cluster":"Cluster-Apps",
      "datastore":"NFS",
      "network": "Net",
      "guest_os_type": "centos7_64Guest",
      "boot_wait":"10s",
      "boot_order":"disk,cdrom,floppy",
      "vm_name" : "CENTOS-8.x",
      "ssh_username": "demo",
      "ssh_password":"superpassword",
      "CPUs":"8",
      "RAM":"8192",
      "RAM_reserve_all": "false",
      "convert_to_template": "true",
      "folder": "Templates-VM",
      "disk_controller_type":  "pvscsi",
      "disk_size":"25000",
      "disk_thin_provisioned": "true",
      "network_card": "vmxnet3",
      "iso_paths": [
        "[NFS] ISO/CentOS8.iso"
      ],
      "floppy_files": [
        "ks.cfg"
      ],
      "boot_command": [
	"<esc><wait>",
	"linux ks=hd:fd0:/ks.cfg<enter>"
	] 
    }
],
"provisioners" : [
  {
    "type":"shell",
    "inline":[
	"touch done.txt"]
  },
  {
    "type":"ansible",
    "extra_arguments": ["--inventory-file=hosts.ini"],
    "playbook_file":"site.yml",
    "user":"demo"
  }
]
}

Fichier de démarrage de la distribution

En fonction de la distribution Linux, le fichier de démarrage sera spécifique à chaque distribution Linux. Dans mon cas il s’agit d’une distribution Linux Centos qui a besoin d’un fichier kickstart (ks.cfg dans mon fichier json ci-dessus) :

install
cdrom
lang fr_FR.UTF-8
keyboard fr
unsupported_hardware
network --bootproto=static --device=ens192 --gateway=192.168.1.254 --ip=192.168.1.2 --netmask=255.255.255.0 --nameserver=8.8.8.8 --hostname=Centos8Template 
rootpw superpassword
firewall --enable
selinux --permissive
timezone Europe/Paris
unsupported_hardware
bootloader --location=mbr
text
skipx
zerombr
clearpart --all --initlabel
autopart
auth --enableshadow --passalgo=sha512 --kickstart
firstboot --disabled
eula --agreed
services --enabled=NetworkManager,sshd
reboot
user --name=demo --plaintext --password superpassword --groups=demo,wheel
sshkey --username=demo "ssh-rsa ******** demo@"

%packages --ignoremissing --excludedocs
@Base
@Core
openssh-clients
sudo
net-tools
wget
curl
%end

%post
yum update -y

echo "demo        ALL=(ALL)       NOPASSWD: ALL" >> /etc/sudoers.d/demo
sed -i "s/^.*requiretty/#Defaults requiretty/" /etc/sudoers

%end

On y retrouve les paramètres de l’OS, la création de compte (ici demo), le passage de clé ssh. Dans la partie post, je fais une mise à jour complète et l’utilisateur demo est promu sudoer.

Build Packer

Maintenant que les 2 fichiers ont été créés, nous allons lancer le build avec la commande suivante :

Le build Packer peut prendre un certain temps a ce réaliser en fonction des actions à exécuter.

> packer build centos.json

La sortie d’écran suivante s’afficher alors :

> ssh-keygen -f ~/.ssh/known_hosts -R 192.168.1.2; packer build centos8.json
# Host 192.168.1.2 found: line 9
/home/demo/.ssh/known_hosts updated.
Original contents retained as /home/demo/.ssh/known_hosts.old
vsphere-iso: output will be in this color.

==> vsphere-iso: Creating VM...
==> vsphere-iso: Customizing hardware...
==> vsphere-iso: Mounting ISO images...
==> vsphere-iso: Creating floppy disk...
    vsphere-iso: Copying files flatly from floppy_files
    vsphere-iso: Copying file: ks.cfg
    vsphere-iso: Done copying files from floppy_files
    vsphere-iso: Collecting paths from floppy_dirs
    vsphere-iso: Resulting paths from floppy_dirs : []
    vsphere-iso: Done copying paths from floppy_dirs
==> vsphere-iso: Uploading created floppy image
==> vsphere-iso: Adding generated Floppy...
==> vsphere-iso: Set boot order...
==> vsphere-iso: Power on VM...
==> vsphere-iso: Waiting 10s for boot...
==> vsphere-iso: Typing boot command...
==> vsphere-iso: Waiting for IP...

Une fois l’opération de création de la VM terminée, elle est transformée en template. Dans le client VMware Vsphere on voit le template CentOS-8.x dans le répertoire Templates-VM :

Packer template vmware

HashiCorp Terraform

Terraform est un outil d'infra as code qui permet de provisionner et d’administrer des infrastructures on premise ou cloud de façon simple.

Définition du déploiement avec Terraform

Dans le fichier Terraform, on retrouve des zones équivalentes à celle de Packer

terraform {
  required_version = ">=0.12"
}

provider "vsphere" {
  user            = "administrator@phy-cluster.apps.local"
  password        = "superpassword"
  vsphere_server  = "192.168.1.201"
  allow_unverified_ssl = true
}

data "vsphere_datacenter" "dc" {
  name = "APPS" 
}

data "vsphere_datastore" "datastore" {
  name = "NFS"
  datacenter_id = data.vsphere_datacenter.dc.id
}

data "vsphere_resource_pool" "pool" {
  name = "Cluster-Apps/Resources"
  datacenter_id = data.vsphere_datacenter.dc.id
}

data "vsphere_network" "network" {
  name = "Net"
  datacenter_id = data.vsphere_datacenter.dc.id
}

data "vsphere_virtual_machine" "template" {
  name = "CENTOS-8.x"
  datacenter_id = data.vsphere_datacenter.dc.id
}

resource "vsphere_virtual_machine" "vm" {
  name = "terraform-test"
  resource_pool_id  = data.vsphere_resource_pool.pool.id
  datastore_id      = data.vsphere_datastore.datastore.id
  num_cpus = 2
  memory   = 2048
  guest_id = "centos7_64Guest"
  network_interface {
    network_id = data.vsphere_network.network.id
  }
  disk {
    label = "disk0"
    size  = 24
  }
  clone {
    template_uuid = data.vsphere_virtual_machine.template.id
    customize {
      linux_options {
        host_name = "vincent"
        domain    = "test.com"
      }
      network_interface {
        ipv4_address = "192.168.1.3"
        ipv4_netmask = "24"
      }
     ipv4_gateway = "192.168.1.254"
     dns_server_list = ["8.8.8.8"]
    }
  }
  provisioner "local-exec" {
    command = "ansible-playbook -i ../../new-roles/hosts.ini ../../new-roles/site.yml --tags linux"
  }
}

Déploiment Terraform sur VMware VSphere

IaC devops automatisation

Terraform propose plusieurs jeux de commandes, les plus utilisées sont les suivantes :

Pour initialiser l’environnement et downloader les plugins nécessaires au fichier de définition du déploiement Terraform :

> terraform init

Pour générer et visualiser le plan de déploiement :

> terraform plan

Pour construire ou modifier l’infrastructure :

> terraform apply

Voyons ce que ça donne quand on exécute la commande :

> terraform apply

Plan: 1 to add, 0 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

vsphere_virtual_machine.vm: Creating...
vsphere_virtual_machine.vm: Still creating... [10s elapsed]
vsphere_virtual_machine.vm: Still creating... [20s elapsed]
vsphere_virtual_machine.vm: Still creating... [30s elapsed]
vsphere_virtual_machine.vm: Still creating... [40s elapsed]
vsphere_virtual_machine.vm: Still creating... [50s elapsed]
vsphere_virtual_machine.vm: Still creating... [1m0s elapsed]
vsphere_virtual_machine.vm: Still creating... [1m10s elapsed]
vsphere_virtual_machine.vm: Still creating... [1m20s elapsed]
vsphere_virtual_machine.vm: Provisioning with 'local-exec'...
vsphere_virtual_machine.vm (local-exec): Executing: ["/bin/sh" "-c" "ansible-playbook -i ../../new-roles/hosts.ini ../../new-roles/site.yml --tags linux"]

vsphere_virtual_machine.vm (local-exec): PLAY [centos] ******************************************************************

Quand le provisonning de la VM Vmware est effectué, dans l’interface du VCenter, on voit la VM.

devops packer terraform ansible vsphere vmware

Et voilà tout fonctionne à merveille !

Dans un futur article, je présenterai comment faire la même chose avec le système de virtualisation natif de Linux : kvm.