Maison >développement back-end >Tutoriel Python >Automatisation du déploiement de Flask et PostgreSQL sur KVM avec Terraform et Ansible

Automatisation du déploiement de Flask et PostgreSQL sur KVM avec Terraform et Ansible

DDD
DDDoriginal
2025-01-02 14:49:42952parcourir

? Introduction

Bonjour, dans cet article, nous utiliserons Libvirt avec Terraform pour provisionner 2 KVM localement et après cela, nous déploierons Flask App et PostgreSQL à l'aide d'Ansible.

Contenu

  • Architecture du projet
  • Exigences
  • Créer KVM
  • Créer un manuel de jeu Ansible
    • Playbook pour installer Docker
    • Playbook pour installer et configurer postgresql
    • Playbook pour déployer Flask App
    • Exécuter Playbook et tester
  • Conclusion

? Architecture du projet

Nous allons donc créer 2 VM à l'aide de Terraform, puis déployer un projet Flask et la base de données à l'aide d'Ansible.

Automating Deployment of Flask and PostgreSQL on KVM with Terraform and Ansible

? Exigences

J'ai utilisé Ubuntu 22.04 LTS comme système d'exploitation pour ce projet. Si vous utilisez un autre système d'exploitation, veuillez effectuer les ajustements nécessaires lors de l'installation des dépendances requises.

Le pré-requis majeur pour cette configuration est l'hyperviseur KVM. Vous devez donc installer KVM sur votre système. Si vous utilisez Ubuntu, vous pouvez suivre cette étape :

sudo apt -y install bridge-utils cpu-checker libvirt-clients libvirt-daemon qemu qemu-kvm

Exécutez la commande suivante pour vous assurer que votre processeur prend en charge les capacités de virtualisation :

$ kvm-ok

INFO: /dev/kvm exists
KVM acceleration can be used

Installer Terraform

$ wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
$ echo "deb [arch=$(dpkg --print-architecture) 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 install terraform -y

Vérifier l'installation :

$ terraform version

Terraform v1.9.8
on linux_amd64

Installer Ansible

$ sudo apt update
$ sudo apt install software-properties-common
$ sudo add-apt-repository --yes --update ppa:ansible/ansible
$ sudo apt install ansible -y

Vérifier l'installation :

$ ansible --version

ansible [core 2.15.1]
...

Créer un KVM

nous utiliserons le fournisseur libvirt avec Terraform pour déployer une machine virtuelle KVM.

Créez main.tf, précisez simplement le fournisseur et la version que vous souhaitez utiliser :

terraform {
  required_providers {
    libvirt = {
      source = "dmacvicar/libvirt"
      version = "0.8.1"
    }
  }
}

provider "libvirt" {
  uri = "qemu:///system"
}

Ensuite, exécutez la commande terraform init pour initialiser l'environnement :

$ terraform init

Initializing the backend...
Initializing provider plugins...
- Reusing previous version of hashicorp/template from the dependency lock file
- Reusing previous version of dmacvicar/libvirt from the dependency lock file
- Reusing previous version of hashicorp/null from the dependency lock file
- Using previously-installed hashicorp/template v2.2.0
- Using previously-installed dmacvicar/libvirt v0.8.1
- Using previously-installed hashicorp/null v3.2.3

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.

Créez maintenant notre variables.tf. Ce fichier variables.tf définit les entrées pour le chemin du pool de disques libvirt, l'URL de l'image Ubuntu 20.04 en tant que système d'exploitation pour les machines virtuelles et une liste de noms d'hôtes de machines virtuelles.

variable "libvirt_disk_path" {
  description = "path for libvirt pool"
  default     = "default"
}

variable "ubuntu_20_img_url" {
  description = "ubuntu 20.04 image"
  default     = "https://cloud-images.ubuntu.com/releases/focal/release/ubuntu-20.04-server-cloudimg-amd64.img"
}

variable "vm_hostnames" {
  description = "List of VM hostnames"
  default     = ["vm1", "vm2"]
}

Mettons à jour notre main.tf :

resource "null_resource" "cache_image" {
  provisioner "local-exec" {
    command = "wget -O /tmp/ubuntu-20.04.qcow2 ${var.ubuntu_20_img_url}"
  }
}

resource "libvirt_volume" "base" {
  name   = "base.qcow2"
  source = "/tmp/ubuntu-20.04.qcow2"
  pool   = var.libvirt_disk_path
  format = "qcow2"
  depends_on = [null_resource.cache_image]
}
# Volume for VM with size 10GB
resource "libvirt_volume" "ubuntu20-qcow2" {
  count          = length(var.vm_hostnames)
  name           = "ubuntu20-${count.index}.qcow2"
  base_volume_id = libvirt_volume.base.id
  pool           = var.libvirt_disk_path
  size           = 10737418240  # 10GB
}

data "template_file" "user_data" {
  count    = length(var.vm_hostnames)
  template = file("${path.module}/config/cloud_init.yml")
}

data "template_file" "network_config" {
  count    = length(var.vm_hostnames)
  template = file("${path.module}/config/network_config.yml")
}

resource "libvirt_cloudinit_disk" "commoninit" {
  count          = length(var.vm_hostnames)
  name           = "commoninit-${count.index}.iso"
  user_data      = data.template_file.user_data[count.index].rendered
  network_config = data.template_file.network_config[count.index].rendered
  pool           = var.libvirt_disk_path
}

resource "libvirt_domain" "domain-ubuntu" {
  count  = length(var.vm_hostnames)
  name   = var.vm_hostnames[count.index]
  memory = "1024" # VM memory
  vcpu   = 1 # VM CPU

  cloudinit = libvirt_cloudinit_disk.commoninit[count.index].id

  network_interface {
    network_name   = "default"
    wait_for_lease = true
    hostname       = var.vm_hostnames[count.index]
  }

  console {
    type        = "pty"
    target_port = "0"
    target_type = "serial"
  }

  console {
    type        = "pty"
    target_type = "virtio"
    target_port = "1"
  }

  disk {
    volume_id = libvirt_volume.ubuntu20-qcow2[count.index].id
  }

  graphics {
    type        = "spice"
    listen_type = "address"
    autoport    = true
  }
}

le script provisionnera plusieurs machines virtuelles KVM à l'aide du fournisseur Libvirt. Il télécharge une image de base Ubuntu 20.04, la clone pour chaque VM, configure cloud-init pour les paramètres utilisateur et réseau et déploie des VM avec des noms d'hôte spécifiés, 1 Go de mémoire et des graphiques SPICE. La configuration s'adapte dynamiquement en fonction du nombre de noms d'hôte fournis dans var.vm_hostnames.

Comme je l'ai mentionné, j'utilise cloud-init, alors configurons la configuration réseau et cloud init dans le répertoire de configuration :

mkdir config/

Créez ensuite notre config/cloud_init.yml, assurez-vous simplement de configurer votre clé publique ssh pour l'accès ssh dans la configuration :

#cloud-config
runcmd:
  - sed -i '/PermitRootLogin/d' /etc/ssh/sshd_config
  - echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
  - systemctl restart sshd
ssh_pwauth: true
disable_root: false
chpasswd:
  list: |
    root:cloudy24
  expire: false
users:
  - name: ubuntu
    gecos: ubuntu
    groups:
      - sudo
    sudo:
      - ALL=(ALL) NOPASSWD:ALL
    home: /home/ubuntu
    shell: /bin/bash
    lock_passwd: false
    ssh_authorized_keys:
      - ssh-rsa AAAA...

Et puis config réseau, dans config/network_config.yml :

version: 2
ethernets:
  ens3:
    dhcp4: true

La structure de notre projet devrait ressembler à ceci :

sudo apt -y install bridge-utils cpu-checker libvirt-clients libvirt-daemon qemu qemu-kvm

Maintenant, exécutez un plan, pour voir ce qui sera fait :

$ kvm-ok

INFO: /dev/kvm exists
KVM acceleration can be used

Et exécutez terraform apply pour exécuter notre déploiement :

$ wget -O - https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
$ echo "deb [arch=$(dpkg --print-architecture) 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 install terraform -y

Vérifiez la création de la VM à l'aide de la commande virsh :

$ terraform version

Terraform v1.9.8
on linux_amd64

Obtenir l'adresse IP des instances :

$ sudo apt update
$ sudo apt install software-properties-common
$ sudo add-apt-repository --yes --update ppa:ansible/ansible
$ sudo apt install ansible -y

Essayez d'accéder à la machine virtuelle en utilisant l'utilisateur Ubuntu :

$ ansible --version

ansible [core 2.15.1]
...

Créer un manuel de jeu Ansible

Créons maintenant le Playbook Ansible pour déployer Flask et Postgresql sur Docker. Vous devez d'abord créer un répertoire ansible et un fichier ansible.cfg :

terraform {
  required_providers {
    libvirt = {
      source = "dmacvicar/libvirt"
      version = "0.8.1"
    }
  }
}

provider "libvirt" {
  uri = "qemu:///system"
}

$ terraform init

Initializing the backend...
Initializing provider plugins...
- Reusing previous version of hashicorp/template from the dependency lock file
- Reusing previous version of dmacvicar/libvirt from the dependency lock file
- Reusing previous version of hashicorp/null from the dependency lock file
- Using previously-installed hashicorp/template v2.2.0
- Using previously-installed dmacvicar/libvirt v0.8.1
- Using previously-installed hashicorp/null v3.2.3

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.

Créez ensuite un fichier d'inventaire appelé hosts :

variable "libvirt_disk_path" {
  description = "path for libvirt pool"
  default     = "default"
}

variable "ubuntu_20_img_url" {
  description = "ubuntu 20.04 image"
  default     = "https://cloud-images.ubuntu.com/releases/focal/release/ubuntu-20.04-server-cloudimg-amd64.img"
}

variable "vm_hostnames" {
  description = "List of VM hostnames"
  default     = ["vm1", "vm2"]
}

vérifier nos VM à l'aide de la commande ansible ping :

resource "null_resource" "cache_image" {
  provisioner "local-exec" {
    command = "wget -O /tmp/ubuntu-20.04.qcow2 ${var.ubuntu_20_img_url}"
  }
}

resource "libvirt_volume" "base" {
  name   = "base.qcow2"
  source = "/tmp/ubuntu-20.04.qcow2"
  pool   = var.libvirt_disk_path
  format = "qcow2"
  depends_on = [null_resource.cache_image]
}
# Volume for VM with size 10GB
resource "libvirt_volume" "ubuntu20-qcow2" {
  count          = length(var.vm_hostnames)
  name           = "ubuntu20-${count.index}.qcow2"
  base_volume_id = libvirt_volume.base.id
  pool           = var.libvirt_disk_path
  size           = 10737418240  # 10GB
}

data "template_file" "user_data" {
  count    = length(var.vm_hostnames)
  template = file("${path.module}/config/cloud_init.yml")
}

data "template_file" "network_config" {
  count    = length(var.vm_hostnames)
  template = file("${path.module}/config/network_config.yml")
}

resource "libvirt_cloudinit_disk" "commoninit" {
  count          = length(var.vm_hostnames)
  name           = "commoninit-${count.index}.iso"
  user_data      = data.template_file.user_data[count.index].rendered
  network_config = data.template_file.network_config[count.index].rendered
  pool           = var.libvirt_disk_path
}

resource "libvirt_domain" "domain-ubuntu" {
  count  = length(var.vm_hostnames)
  name   = var.vm_hostnames[count.index]
  memory = "1024" # VM memory
  vcpu   = 1 # VM CPU

  cloudinit = libvirt_cloudinit_disk.commoninit[count.index].id

  network_interface {
    network_name   = "default"
    wait_for_lease = true
    hostname       = var.vm_hostnames[count.index]
  }

  console {
    type        = "pty"
    target_port = "0"
    target_type = "serial"
  }

  console {
    type        = "pty"
    target_type = "virtio"
    target_port = "1"
  }

  disk {
    volume_id = libvirt_volume.ubuntu20-qcow2[count.index].id
  }

  graphics {
    type        = "spice"
    listen_type = "address"
    autoport    = true
  }
}

Créez maintenant playbook.yml et les rôles, ce playbook installera et configurera Docker, Flask et PostgreSQL :

mkdir config/

Playbook pour installer Docker

Créez maintenant un nouveau répertoire appelé rôles/docker :

#cloud-config
runcmd:
  - sed -i '/PermitRootLogin/d' /etc/ssh/sshd_config
  - echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
  - systemctl restart sshd
ssh_pwauth: true
disable_root: false
chpasswd:
  list: |
    root:cloudy24
  expire: false
users:
  - name: ubuntu
    gecos: ubuntu
    groups:
      - sudo
    sudo:
      - ALL=(ALL) NOPASSWD:ALL
    home: /home/ubuntu
    shell: /bin/bash
    lock_passwd: false
    ssh_authorized_keys:
      - ssh-rsa AAAA...

Créez un nouveau répertoire dans le docker appelé tâches, puis créez un nouveau fichier main.yml. Ce fichier installera Docker & Docker Compose :

version: 2
ethernets:
  ens3:
    dhcp4: true
$ tree
.
├── config
│   ├── cloud_init.yml
│   └── network_config.yml
├── main.tf
└── variables.tf

Playbook pour installer et configurer postgresql

Créez ensuite un nouveau répertoire appelé psql, créez un sous-répertoire appelé vars, tempalates & Tasks :

$  terraform plan

data.template_file.user_data[1]: Reading...
data.template_file.user_data[0]: Reading...
data.template_file.network_config[1]: Reading...
data.template_file.network_config[0]: Reading...
...

Plan: 8 to add, 0 to change, 0 to destroy

Après cela, dans vars, créez main.yml. Ce sont des variables utilisées pour définir le nom d'utilisateur, les mots de passe, etc :

$ terraform apply

...
null_resource.cache_image: Creation complete after 10m36s [id=4239391010009470471]
libvirt_volume.base: Creating...
libvirt_volume.base: Creation complete after 3s [id=/var/lib/libvirt/images/base.qcow2]
libvirt_volume.ubuntu20-qcow2[1]: Creating...
libvirt_volume.ubuntu20-qcow2[0]: Creating...
libvirt_volume.ubuntu20-qcow2[1]: Creation complete after 0s [id=/var/lib/libvirt/images/ubuntu20-1.qcow2]
libvirt_volume.ubuntu20-qcow2[0]: Creation complete after 0s [id=/var/lib/libvirt/images/ubuntu20-0.qcow2]
libvirt_domain.domain-ubuntu[1]: Creating...
...

libvirt_domain.domain-ubuntu[1]: Creation complete after 51s [id=6221f782-48b7-49a4-9eb9-fc92970f06a2]

Apply complete! Resources: 8 added, 0 changed, 0 destroyed

Ensuite, nous allons créer un fichier jinja appelé docker-compose.yml.j2. Avec ce fichier nous allons créer un conteneur postgresql :

$ virsh list

 Id   Name   State
----------------------
 1    vm1    running
 2    vm2    running

Ensuite, créez main.yml pour les tâches. Nous allons donc copier docker-compose.yml.j2 et exécuter en utilisant docker compose :

$ virsh net-dhcp-leases --network default

Expiry Time           MAC address         Protocol   IP address          Hostname   Client ID or DUID
-----------------------------------------------------------------------------------------------------------------------------------------------
2024-12-09 19:50:00   52:54:00:2e:0e:86   ipv4       192.168.122.19/24   vm1        ff:b5:5e:67:ff:00:02:00:00:ab:11:b0:43:6a:d8:bc:16:30:0d
2024-12-09 19:50:00   52:54:00:86:d4:ca   ipv4       192.168.122.15/24   vm2        ff:b5:5e:67:ff:00:02:00:00:ab:11:39:24:8c:4a:7e:6a:dd:78

Playbook pour déployer l'application Flask

Tout d'abord, vous devez créer un répertoire appelé flask, puis créer à nouveau un sous-répertoire :

$ ssh ubuntu@192.168.122.15

The authenticity of host '192.168.122.15 (192.168.122.15)' can't be established.
ED25519 key fingerprint is SHA256:Y20zaCcrlOZvPTP+/qLLHc7vJIOca7QjTinsz9Bj6sk.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '192.168.122.15' (ED25519) to the list of known hosts.
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-200-generic x86_64)
...

ubuntu@ubuntu:~$

Ensuite, ajoutez main.yml à vars. Ce fichier fait référence à la variable posgtresql auparavant, avec en plus l'adresse IP de la VM2 (base de données VM) :

$ mkdir ansible && cd ansible

Ensuite, créez config.py.j2 dans les modèles. Ce fichier remplacera l'ancien fichier de configuration du projet Flask :

[defaults]
inventory = hosts
host_key_checking = True
deprecation_warnings = False
collections = ansible.posix, community.general, community.postgresql

Ensuite, créez docker-compose.yml.j2 dans les modèles. Avec ce fichier nous allons créer un conteneur en utilisant docker compose :

[vm1]
192.168.122.19 ansible_user=ubuntu

[vm2]
192.168.122.15 ansible_user=ubuntu

Ensuite, créez main.yml dans les tâches. Avec ce fichier, nous allons cloner le projet flask, ajouter le fichier composer, remplacer config.py et créer un nouveau conteneur à l'aide de docker compose :

$ ansible -m ping all

192.168.122.15 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
192.168.122.19 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}

La structure de notre projet devrait ressembler à ceci :

---
- name: Deploy Flask
  hosts: vm1
  become: true
  remote_user: ubuntu
  roles:
    - flask
    - config

- name: Deploy Postgresql
  hosts: vm2
  become: true
  remote_user: ubuntu
  roles:
    - psql
    - config

Exécuter Playbook et tester

Enfin, exécutons ansible-playbook pour déployer PostgreSQL et Flask :

$ mkdir roles
$ mkdir docker

Une fois terminé, assurez-vous simplement qu'il n'y a pas d'erreur. Ensuite, vous voyez qu'il y en a deux créés. Dans VM1 se trouve Flask et VM2 est Postgresql :

sudo apt -y install bridge-utils cpu-checker libvirt-clients libvirt-daemon qemu qemu-kvm

Essayez d'accéder à l'application à l'aide des navigateurs, tapez simplement http://:

Automating Deployment of Flask and PostgreSQL on KVM with Terraform and Ansible

Essayez d'ajouter une nouvelle tâche et les données seront ensuite ajoutées à la base de données :

Automating Deployment of Flask and PostgreSQL on KVM with Terraform and Ansible

Conclusion

Enfin, merci d’avoir lu cet article. N'hésitez pas à laisser un commentaire si vous avez des questions, des suggestions ou des commentaires.

Nb : Project Repo : danielcristho/that-i-write

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn