Integración de Ansible, Terraform y KVM con Scripts Bash
Este manual cubre el uso avanzado de tres herramientas fundamentales en el mundo DevOps: Ansible para automatización de configuraciones, Terraform para infraestructura como código, y KVM para virtualización. Además, se incluyen scripts bash avanzados para integrar estas tecnologías.
Nota: Este manual asume que tienes conocimientos básicos de Linux, virtualización y conceptos de redes.
Ansible es una herramienta de automatización que simplifica la gestión de configuraciones, despliegue de aplicaciones y orquestración de tareas.
#!/bin/bash
# Instalación de Ansible en Ubuntu/Debian
sudo apt update
sudo apt install -y software-properties-common
sudo apt-add-repository --yes --update ppa:ansible/ansible
sudo apt install -y ansible
# Verificar instalación
ansible --version
# Configuración básica del archivo ansible.cfg
cat <<EOF > ~/ansible.cfg
[defaults]
inventory = ./inventory
host_key_checking = False
retry_files_enabled = False
EOF
Crear un inventario dinámico que se actualice automáticamente basado en instancias de AWS:
#!/bin/bash
# Script de inventario dinámico para AWS
#!/usr/bin/env python3
import boto3
import json
import argparse
def get_ec2_inventory():
ec2 = boto3.resource('ec2')
groups = {}
for instance in ec2.instances.all():
for tag in instance.tags or []:
if tag['Key'] == 'Group':
group_name = tag['Value']
if group_name not in groups:
groups[group_name] = []
groups[group_name].append(instance.public_ip_address)
return groups
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('--list', action='store_true')
args = parser.parse_args()
if args.list:
print(json.dumps(get_ec2_inventory()))
Ejemplo de playbook con roles, handlers y templates:
---
- name: Configurar servidor web
hosts: webservers
become: yes
vars:
http_port: 80
max_clients: 200
server_name: example.com
roles:
- common
- web
tasks:
- name: Instalar paquetes requeridos
apt:
name: "{{ item }}"
state: present
update_cache: yes
loop:
- nginx
- php-fpm
- mysql-client
- name: Configurar Nginx
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/sites-available/{{ server_name }}
owner: root
group: root
mode: '0644'
notify:
- restart nginx
handlers:
- name: restart nginx
service:
name: nginx
state: restarted
#!/bin/bash
# Crear archivo encriptado con Ansible Vault
ansible-vault create secrets.yml
# Editar archivo encriptado
ansible-vault edit secrets.yml
# Ejecutar playbook con archivo encriptado
ansible-playbook site.yml --ask-vault-pass
Terraform permite definir y provisionar infraestructura como código usando un lenguaje declarativo.
#!/bin/bash
# Instalar Terraform en Linux
wget https://releases.hashicorp.com/terraform/1.0.0/terraform_1.0.0_linux_amd64.zip
unzip terraform_1.0.0_linux_amd64.zip
sudo mv terraform /usr/local/bin/
terraform --version
mi-proyecto-terraform/
├── main.tf # Configuración principal
├── variables.tf # Variables de entrada
├── outputs.tf # Valores de salida
├── terraform.tfvars # Valores de variables
└── modules/ # Módulos reutilizables
└── vpc/ # Ejemplo de módulo VPC
├── main.tf
├── variables.tf
└── outputs.tf
# main.tf
provider "aws" {
region = var.region
}
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
tags = {
Name = "main-vpc"
}
}
resource "aws_subnet" "public" {
count = length(var.public_subnets_cidr)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnets_cidr[count.index]
availability_zone = var.azs[count.index]
tags = {
Name = "public-subnet-${count.index}"
}
}
module "ec2_instance" {
source = "terraform-aws-modules/ec2-instance/aws"
version = "~> 3.0"
name = "web-server"
instance_count = 3
ami = var.ami_id
instance_type = "t3.micro"
subnet_id = aws_subnet.public[0].id
tags = {
Terraform = "true"
Environment = "dev"
}
}
#!/bin/bash
# Crear y seleccionar workspace
terraform workspace new dev
terraform workspace select dev
# Configurar backend remoto en S3
cat <<EOF > backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state-bucket"
key = "global/s3/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
EOF
Kernel-based Virtual Machine (KVM) es una solución de virtualización completa para Linux.
#!/bin/bash
# Instalar KVM en Ubuntu/Debian
sudo apt update
sudo apt install -y qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virt-manager
# Agregar usuario a grupos necesarios
sudo usermod -aG libvirt $(whoami)
sudo usermod -aG kvm $(whoami)
# Verificar instalación
sudo systemctl status libvirtd
sudo virsh list --all
Script avanzado para crear VMs automáticamente:
#!/bin/bash
# Script para crear múltiples VMs en KVM
# Variables configurables
VM_COUNT=3
VM_NAME_PREFIX="vm"
VM_RAM="2048"
VM_CPUS=2
VM_DISK_SIZE="20G"
VM_OS_TYPE="linux"
VM_OS_VARIANT="ubuntu20.04"
NETWORK="default"
ISO_PATH="/var/lib/libvirt/images/ubuntu-20.04.3-live-server-amd64.iso"
# Verificar requisitos
if ! command -v virt-install > /dev/null; then
echo "virt-install no está instalado. Instale libvirt-clients."
exit 1
fi
# Crear VMs
for i in $(seq 1 $VM_COUNT); do
VM_NAME="${VM_NAME_PREFIX}${i}"
DISK_PATH="/var/lib/libvirt/images/${VM_NAME}.qcow2"
# Crear disco virtual
qemu-img create -f qcow2 $DISK_PATH $VM_DISK_SIZE
# Instalar VM
virt-install \
--name $VM_NAME \
--memory $VM_RAM \
--vcpus $VM_CPUS \
--disk path=$DISK_PATH,size=$VM_DISK_SIZE \
--os-type $VM_OS_TYPE \
--os-variant $VM_OS_VARIANT \
--network network=$NETWORK \
--graphics none \
--console pty,target_type=serial \
--location $ISO_PATH \
--extra-args "console=ttyS0,115200n8 serial" \
--noautoconsole \
--noreboot
echo "VM $VM_NAME creada. Puedes iniciarla con: virsh start $VM_NAME"
done
Crear una red puente (bridged network) para las VMs:
#!/bin/bash
# Crear red puente en KVM
# Detener el servicio de red
sudo systemctl stop NetworkManager
# Configurar interfaz de red
cat <<EOF | sudo tee /etc/sysconfig/network-scripts/ifcfg-br0
DEVICE=br0
TYPE=Bridge
BOOTPROTO=static
IPADDR=192.168.1.100
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
DNS1=8.8.8.8
DNS2=8.8.4.4
ONBOOT=yes
DELAY=0
EOF
# Modificar interfaz física para usar el puente
cat <<EOF | sudo tee /etc/sysconfig/network-scripts/ifcfg-enp3s0
DEVICE=enp3s0
TYPE=Ethernet
BOOTPROTO=none
ONBOOT=yes
BRIDGE=br0
EOF
# Reiniciar servicios de red
sudo systemctl restart NetworkManager
sudo systemctl restart libvirtd
# Verificar la red puente
ip addr show br0
brctl show
Combinar Ansible, Terraform y KVM para un flujo de trabajo completo de infraestructura como código.
#!/bin/bash
# Script para provisionar infraestructura y configurarla automáticamente
# Paso 1: Inicializar y aplicar Terraform
echo "Inicializando Terraform..."
terraform init
echo "Aplicando configuración de Terraform..."
terraform apply -auto-approve
# Paso 2: Obtener IPs de las instancias creadas
echo "Obteniendo IPs de las instancias..."
INSTANCE_IPS=$(terraform output -json instance_ips | jq -r '.[]')
# Paso 3: Crear inventario dinámico para Ansible
echo "Creando inventario de Ansible..."
cat <<EOF > inventory
[webservers]
$INSTANCE_IPS
[webservers:vars]
ansible_user=ubuntu
ansible_ssh_private_key_file=~/.ssh/terraform.pem
EOF
# Paso 4: Ejecutar playbook de Ansible
echo "Ejecutando playbook de Ansible..."
ansible-playbook -i inventory playbook.yml
#!/bin/bash
# Script para crear VMs en KVM y configurarlas con Ansible
# Paso 1: Crear VMs
echo "Creando VMs en KVM..."
./create_kvm_vms.sh
# Paso 2: Esperar a que las VMs obtengan IP
echo "Esperando a que las VMs arranquen..."
sleep 120
# Paso 3: Obtener IPs de las VMs
echo "Obteniendo IPs de las VMs..."
VM_IPS=$(virsh net-dhcp-leases default | grep ipv4 | awk '{print $5}' | cut -d'/' -f1)
# Paso 4: Crear inventario de Ansible
echo "Creando inventario de Ansible..."
cat <<EOF > inventory
[kvm_vms]
$VM_IPS
[kvm_vms:vars]
ansible_user=root
ansible_ssh_private_key_file=~/.ssh/id_rsa
EOF
# Paso 5: Ejecutar playbook de configuración
echo "Configurando VMs con Ansible..."
ansible-playbook -i inventory kvm_setup.yml
Colección de scripts bash útiles para automatizar tareas complejas.
#!/bin/bash
# Script para monitorear recursos del sistema y VMs
# Variables
THRESHOLD_CPU=80
THRESHOLD_MEM=80
THRESHOLD_DISK=85
LOG_FILE="/var/log/system_monitor.log"
# Función para loggear eventos
log_event() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE
}
# Monitorear CPU
check_cpu() {
local cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
if (( $(echo "$cpu_usage > $THRESHOLD_CPU" | bc -l) )); then
log_event "ALERTA: Uso de CPU alto - ${cpu_usage}%"
fi
}
# Monitorear memoria
check_memory() {
local mem_total=$(free -m | awk '/Mem:/ {print $2}')
local mem_used=$(free -m | awk '/Mem:/ {print $3}')
local mem_usage=$((mem_used * 100 / mem_total))
if [ $mem_usage -gt $THRESHOLD_MEM ]; then
log_event "ALERTA: Uso de memoria alto - ${mem_usage}%"
fi
}
# Monitorear disco
check_disk() {
local disk_usage=$(df -h / | awk '/\// {print $5}' | tr -d '%')
if [ $disk_usage -gt $THRESHOLD_DISK ]; then
log_event "ALERTA: Uso de disco alto - ${disk_usage}%"
fi
}
# Monitorear VMs KVM
check_vms() {
local running_vms=$(virsh list --state-running | grep -v "Id\|---" | wc -l)
local total_vms=$(virsh list --all | grep -v "Id\|---" | wc -l)
if [ $running_vms -lt $total_vms ]; then
log_event "ALERTA: No todas las VMs están corriendo ($running_vms/$total_vms)"
fi
}
# Ejecutar checks
check_cpu
check_memory
check_disk
check_vms
#!/bin/bash
# Script para hacer backup de configuraciones importantes
# Configuración
BACKUP_DIR="/backup/configs"
DATE=$(date +%Y%m%d)
RETENTION_DAYS=30
# Directorios a respaldar
DIRS_TO_BACKUP=(
"/etc/ansible"
"/etc/libvirt"
"/root/.terraform.d"
"/etc/ssh"
)
# Crear directorio de backup si no existe
mkdir -p "$BACKUP_DIR/$DATE"
# Función para comprimir directorios
compress_dir() {
local src=$1
local dest="$BACKUP_DIR/$DATE/$(basename $src).tar.gz"
tar -czf "$dest" "$src" >/dev/null 2>&1
echo "Backup de $src completado: $dest"
}
# Hacer backup de cada directorio
for dir in "${DIRS_TO_BACKUP[@]}"; do
if [ -d "$dir" ]; then
compress_dir "$dir"
else
echo "Advertencia: $dir no existe, omitiendo..."
fi
done
# Limpiar backups antiguos
find "$BACKUP_DIR" -type d -mtime +$RETENTION_DAYS -exec rm -rf {} \;
echo "Backups antiguos (más de $RETENTION_DAYS días) eliminados"