Cargando...

Crear AMI en AWS con Packer

En este artículo te mostraremos como construir una AMI personalizada en AWS usando Packer. Se trata de una plantilla completa de Packer para crear una AMI de AWS con Ubuntu 20.04, Apache, PHP, y el código de una aplicación ubicada en un repositorio público en GitHub. Finalmente quedará la imagen empaquetada con las configuraciones necesarias, que perfectamente puede ser usada para lanzar una instancia Amazon EC2.

Requisitos previos

Lo que aprenderás

  • Qué es Packer
  • Por qué usar Packer
  • Crear imágenes personalizadas para AWS con Packer

Packer es una herramienta de código abierto para automatizar la creación de imágenes de máquinas idénticas para diferentes plataformas, se configuran con un sistema operativo y el software requerido para el caso de uso. En AWS estas imágenes se denominan AMI (Amazon Machine Image). Una AMI proporciona la información necesaria para lanzar una instancia. ¿Por qué automatizar la construcción de imágenes? Hay varios escenarios, por ejemplo, cuando tenemos un Auto Scaling y hacemos actualizaciones en el código de la aplicación, es necesario volver a generar la imagen para que el Auto Scaling inicie nuevamente las instancias con la versión más reciente de la aplicación.

Por qué usar Packer

La agilidad y portabilidad de Packer son puntos clave. Packer es ligero, se ejecuta en todos los sistemas operativos principales como Windows, GNU/Linux y macOS. Es importante mencionar que Packer no reemplaza las herramientas de gestión de configuración como Ansible, Chef o Puppet. De hecho, al crear imágenes, Packer puede apoyarse de estas herramientas para instalar software en la imagen y realizar las configuraciones necesarias.

Además, se pueden usar otras herramientas como Terraform para automatizar el aprovisionamiento de infraestructura y lanzar instancias de máquina totalmente configuradas con imágenes de Packer en cuestión de segundos.

Crear una AMI personalizada para AWS con Packer

Con Packer instalado, pasamos a definir la plantilla en HCL (lenguaje de configuración de Hashicorp). El archivo debe tener la extensión .pkr.hcl, en este ejemplo lo he nombrado aws-ubuntu-apache.pkr.hcl

packer {
  required_plugins {
    amazon = {
      version = ">= 0.0.2"
      source  = "github.com/hashicorp/amazon"
    }
  }
}

source "amazon-ebs" "ubuntu" {
  ami_name        = "crashell-ami-ubuntu-{{timestamp}}"
  ami_description = "Crashell Web Server"
  instance_type   = "t2.micro"
  region          = "us-east-2"
  subnet_id       = "subnet-0bf9bf5ffdaa3fc63"
  source_ami      = "ami-00399ec92321828f5"
  ssh_username    = "ubuntu"
  tags = {
    Name = "Crashell"
    Os   = "Ubuntu 20.04"
  }
}

build {
  name = "crashell-ami"
  sources = [
    "source.amazon-ebs.ubuntu"
  ]

  provisioner "file" {
    source      = "config/webapp.conf"
    destination = "/tmp/webapp.conf"
  }

  provisioner "shell" {
    inline = [
      "sleep 30",
      "sudo apt-get update",
      "sudo apt-get install -y apache2 php7.4",
      "sudo git clone https://github.com/frankroot/WebApp.git /var/www/WebApp",
      "sudo cp /tmp/webapp.conf /etc/apache2/sites-available/webapp.conf",
      "sudo a2ensite webapp.conf",
      "sudo a2dissite 000-default.conf"
    ]
  }
}

Adicionalmente, he creado un archivo nombrado como webapp.conf, contiene la configuración básica para un sitio virtual en Apache, que se copia (provisioner "file") en la instancia para que la AMI final lleve configuración en mención.

<VirtualHost *:80>
   DocumentRoot /var/www/WebApp
   ErrorLog ${APACHE_LOG_DIR}/webapp_error.log
   CustomLog ${APACHE_LOG_DIR}/webapp_access.log combined
</VirtualHost>

Tenemos la plantilla completa, ahora la vamos separar en partes para explicar un poco cual es la función de cada bloque.

En el primer bloque se especifica el plugin requerido para construir la AMI. En este caso es el plugin de Amazon.

packer {
  required_plugins {
    amazon = {
      version = ">= 0.0.2"
      source  = "github.com/hashicorp/amazon"
    }
  }
}

Con el bloque source se lanza una instancia t2.micro en la región us-east-2, utilizando una AMI de Ubuntu como imagen base, y partir de esa, crea una nueva AMI nombrada como crashell-ami-ubuntu- más un numero de versión, generado con la función timestamp. También, le agrega un par de etiquetas al recurso: Name y Os. El constructor definido se encarga de crear todos los recursos de forma temporal, por ejemplo, par de claves, grupos de seguridad, etc., los cuales son necesarios para acceder a la instancia mientras se crea la AMI. Un detalle importante, en este ejemplo le especifico la subnet, esto porque la estoy lanzando en una VPC diferente a la que se crea por defecto en una cuenta. En caso de no especificar la subnet, Packer buscará una VPC por defecto.

source "amazon-ebs" "ubuntu" {
  ami_name        = "crashell-ami-ubuntu-{{timestamp}}"
  ami_description = "Crashell Web Server"
  instance_type   = "t2.micro"
  region          = "us-east-2"
  subnet_id       = "subnet-0bf9bf5ffdaa3fc63"
  source_ami      = "ami-00399ec92321828f5"
  ssh_username    = "ubuntu"
  tags = {
    Name = "Crashell"
    Os   = "Ubuntu 20.04"
  }
}

El bloque build especifica lo que Packer debe hacer con la instancia EC2 después del lanzamiento. Para ello, se hace referencia a la AMI definida en el bloque source.

Seguidamente se realiza el aprovisionamiento, hay varias alternativas. En este ejemplo, usamos dos métodos en específico. Con file, copiamos un fichero que contiene la configuración básica del sitio virtual, se sebe indicar una ubicación donde el usuario tenga permisos de escritura, y posteriormente con shell, moverlo a la ubicación correspondiente. Por otra parte, también, con shell, se ejecuta la instalación del software y la configuración que haga falta. Recuerda, que hay más opciones para realizar las tareas de aprovisionamiento, Ansible es una gran herramienta, PorwerShell para Windows, etc.

build {
  name = "crashell-ami"
  sources = [
    "source.amazon-ebs.ubuntu"
  ]

  provisioner "file" {
    source      = "config/webapp.conf"
    destination = "/tmp/webapp.conf"
  }

  provisioner "shell" {
    inline = [
      "sleep 30",
      "sudo apt-get update",
      "sudo apt-get install -y apache2 php7.4",
      "sudo git clone https://github.com/frankroot/WebApp.git /var/www/WebApp",
      "sudo cp /tmp/webapp.conf /etc/apache2/sites-available/webapp.conf",
      "sudo a2ensite webapp.conf",
      "sudo a2dissite 000-default.conf"
    ]
  }
}

¡Está todo preparado!

Para validar la plantilla y detectar errores en la sintaxis del código ejecuta:

packer validate aws-ubuntu-apache.pkr.hcl

Compilar y generar AMI

packer build aws-ubuntu-apache.pkr.hcl

Tardará unos minutos en finalizar el proceso, cuando termina devuelve el id de la AMI que puedes usar para lanzar las instancias con Terraform u otra herramienta para aprovisionar infraestructura.

Puedes descargar la plantilla de ejemplo desde el repositorio packer-ami-aws en GitHub, hacer un git clone o fork.

  • John Doe
    43 Sales$156,24 Totals
    62%
  • Rosy O'Dowell
    12 Leads$56,24 Totals
    32%

With supporting text below as a natural lead-in to additional content.

Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled.