Table of Contents

Infraestrutura KVM com Terraform para Docker Swarm

Este tutorial explica como configurar uma infraestrutura utilizando KVM com Terraform para provisionar um cluster Docker Swarm. A infraestrutura inclui um manager e dois workers, além de um container para registro de imagens Docker.

Requisitos

  1. KVM instalado e configurado.
  2. Terraform para orquestração.
  3. Template de imagem Ubuntu 22.04 Cloud.
  4. Chave SSH pública para autenticação.

Arquivos principais

main.tf

Este arquivo define os recursos que serão provisionados no KVM usando o provider Libvirt.

main.tf
variable "vms" {
  type = list(map(any))
}
 
terraform {
  required_providers {
    libvirt = {
      source = "dmacvicar/libvirt"
    }
  }
}
 
provider "libvirt" {
  uri = "qemu:///system"
}
 
resource "libvirt_network" "swarm" {
  name      = "swarm"
  mode      = "nat"
  addresses = ["10.2.3.0/24"]
  autostart = true
  dhcp {
    enabled = false
  }
  dns {
    enabled = true
  }
}
 
resource "libvirt_volume" "os_image" {
  for_each = { for vm in var.vms : vm.name => vm }
 
  name   = each.value["os_image_name"]
  pool   = each.value["storage_pool"]
  source = each.value["os_image_url"]
  format = "qcow2"
}
 
resource "libvirt_volume" "os_datas" {
  for_each = { for vm in var.vms : vm.name => vm }
 
  name           = each.value["os_datas_name"]
  base_volume_id = libvirt_volume.os_image[each.key].id
  pool           = each.value["storage_pool"]
  size           = each.value["disksize"] * 1024 * 1024 * 1024
}
 
data "template_file" "user_data" {
  for_each = { for vm in var.vms : vm.name => vm }
 
  template = file("${path.module}/${each.value["user_data"]}")
 
  vars = {
    hostname = each.value["hostname"]
  }
}
 
data "template_file" "network_config" {
  for_each = { for vm in var.vms : vm.name => vm }
 
  template = file("${path.module}/${each.value["network_config"]}")
 
  vars = {
    network_ip = each.value["network_ip"]
  }
}
 
resource "libvirt_cloudinit_disk" "cloudinit" {
  for_each = { for vm in var.vms : vm.name => vm }
 
  name           = "${each.key}-cloudinit.iso"
  user_data      = data.template_file.user_data[each.key].rendered
  network_config = data.template_file.network_config[each.key].rendered
  pool           = each.value["storage_pool"]
}
 
resource "libvirt_domain" "domain" {
  for_each = { for vm in var.vms : vm.name => vm }
 
  name   = each.value["name"]
  memory = each.value["memory"]
  vcpu   = each.value["cpu"]
 
  cpu {
    mode = "host-passthrough"
  }
 
  cloudinit = libvirt_cloudinit_disk.cloudinit[each.key].id
 
  network_interface {
    network_name = each.value["network_name"]
  }
 
  console {
    type        = "pty"
    target_port = "0"
    target_type = "serial"
  }
 
  console {
    type        = "pty"
    target_type = "virtio"
    target_port = "1"
  }
 
  disk {
    volume_id = libvirt_volume.os_datas[each.key].id
  }
 
  graphics {
    type        = "spice"
    listen_type = "address"
    autoport    = true
  }
 
}

terraform.tfvars

Este arquivo define as variáveis usadas para configurar as VMs. Ajuste os valores conforme sua necessidade.

terraform.tfvars
vms = [
  {
    name          = "docker-manager"
    cpu           = 2
    memory        = 4096
    disksize      = 32
    storage_pool  = "default"
    hostname      = "docker-manager"
    os_image_name = "docker_manager_image.qcow2"
    os_datas_name = "docker_manager_datas.qcow2"
    network_name  = "swarm"
    user_data     = "cloud-init.yml"
    network_config = "network-config.yml"
    network_ip    = "10.2.3.10"
    os_image_url  = "/home/gean/kvm/templates/ubuntu-22.04-server-cloudimg-amd64.img"
  },
  {
    name          = "docker-worker1"
    cpu           = 2
    memory        = 2048
    disksize      = 32
    storage_pool  = "default"
    hostname      = "docker-worker1"
    os_image_name = "docker_worker1_image.qcow2"
    os_datas_name = "docker_worker1_datas.qcow2"
    network_name  = "swarm"
    user_data     = "cloud-init.yml"
    network_config = "network-config.yml"
    network_ip    = "10.2.3.11"
    os_image_url  = "/home/gean/kvm/templates/ubuntu-22.04-server-cloudimg-amd64.img"
  },
  {
    name          = "docker-worker2"
    cpu           = 2
    memory        = 2048
    disksize      = 32
    storage_pool  = "default"
    hostname      = "docker-worker2"
    os_image_name = "docker_worker2_image.qcow2"
    os_datas_name = "docker_worker2_datas.qcow2"
    network_name  = "swarm"
    user_data     = "cloud-init.yml"
    network_config = "network-config.yml"
    network_ip    = "10.2.3.12"
    os_image_url  = "/home/gean/kvm/templates/ubuntu-22.04-server-cloudimg-amd64.img"
  },
  {
    name          = "docker-registry"
    cpu           = 2
    memory        = 2048
    disksize      = 32
    storage_pool  = "default"
    hostname      = "docker-registry"
    os_image_name = "docker_registry_image.qcow2"
    os_datas_name = "docker_registry_datas.qcow2"
    network_name  = "swarm"
    user_data     = "cloud-init.yml"
    network_config = "network-config.yml"
    network_ip    = "10.2.3.13"
    os_image_url  = "/home/gean/kvm/templates/ubuntu-22.04-server-cloudimg-amd64.img"
  },
]

cloud-init.yml

Este arquivo define a configuração de inicialização da VM, como hostname, criação de usuários, e instalação de pacotes.

cloud-init.yml
#cloud-config
 
# Definindo o hostname dinamicamente
hostname: ${hostname}
 
# Criação de usuário e configuração de SSH
users:
  - name: gean
    sudo: ALL=(ALL) NOPASSWD:ALL
    groups: users, sudo
    shell: /bin/bash
    ssh_authorized_keys:
      - ${file("~/.ssh/tfvms.pub")} 
 
# Definir senha root 
chpasswd:
  list: |
    root:$6$R4tXC5apTx$f4WVAylB/SZ/0ppE7Zp4lurvzAhcm.BaU3xJKaoESu7cv13sR7RYVkjVQwxtvA9/vUggWu/a9N0L9EP1lg/Ez1
  expire: False
 
# Atualização de pacotes e instalação de utilitários
package_update: true
package_upgrade: true
 
# Lista de pacotes para instalar
packages:
  - qemu-guest-agent
  - bash-completion

network-config.yml

Arquivo que define as configurações de rede da VM, como IP e rota de gateway.

network-config.yml
#cloud-config
network:
  version: 2
  ethernets:
    ens3:
      addresses:
        - ${network_ip}/24
      nameservers:
        addresses: 
          - 10.2.3.1
      routes:
        - to: default
          via: 10.2.3.1

Passos para execução

1. Instale o Terraform e KVM em sua máquina. 2. Crie um diretório de trabalho e coloque os arquivos `main.tf`, `terraform.tfvars`, `cloud-init.yml` e `network-config.yml` nesse diretório. 3. Execute os comandos a seguir no terminal para iniciar a infraestrutura:

terraform init
terraform fmt
terraform validate
terraform apply

4. O Terraform criará o cluster Docker Swarm com as VMs definidas.

Considerações Finais

  1. Ajuste as variáveis no arquivo terraform.tfvars conforme sua infraestrutura.
  2. Verifique se o Terraform e o KVM estão corretamente configurados no ambiente.