Despliegue de Hugo con AWS CodeBuild en Lambda Compute

Hugo Amazon Web Services AWS CodeBuild

Introducción

Hugo ama AWS CodeBuild

En esta receta, revisaremos cómo desplegar un sitio estático de Hugo utilizando AWS CodeBuild en AWS Lambda compute. AWS Lambda compute ofrece tiempos de inicio optimizados y escalado automático para compilaciones más rápidas. Sin embargo, hay algunas limitaciones a tener en cuenta.

Utilizaremos AWS CodeBuild para compilar el sitio de Hugo, desplegarlo en un bucket de S3 e invalidar la caché de CloudFront. GitHub se utilizará como repositorio fuente para el sitio de Hugo.

Pre-requisitos

Antes de comenzar, asegúrate de tener lo siguiente:

Paso 1: Crear un nuevo rol IAM para el proyecto CodeBuild

Necesitamos crear un nuevo rol IAM que será utilizado por el proyecto CodeBuild para “sincronizar” el bucket de S3 e “invalidar” la distribución de CloudFront.

Crear una nueva política

  1. Ve a la consola de AWS IAM: Políticas.
  2. Haz clic en el botón Create policy (Crear política).
  3. Haz clic en la pestaña JSON y pega el siguiente documento de política:
⚠️
Reemplaza YOUR_BUCKET_NAME, YOUR_ACCOUNT_ID, y YOUR_DISTRIBUTION_ID con tus valores.
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject",
                "s3:GetBucketAcl",
                "s3:GetBucketLocation",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::YOUR_BUCKET_NAME",
                "arn:aws:s3:::YOUR_BUCKET_NAME/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "cloudfront:CreateInvalidation"
            ],
            "Resource": [
                "arn:aws:cloudfront::YOUR_ACCOUNT_ID:distribution/YOUR_DISTRIBUTION_ID" 
            ]
        }
    ]
}
  1. Haz clic en el botón Next (Siguiente).
  2. Ingresa el nombre y la descripción de la política.
  3. Haz clic en el botón Create policy (Crear política).

Crear un nuevo rol

  1. Regresa a la consola de AWS IAM: Roles.
  2. Haz clic en el botón Create Role (Crear rol).
  3. Selecciona AWS service como la entidad de confianza.
  4. Elige CodeBuild como el servicio que utilizará este rol.
  5. Haz clic en el botón Next: Add Permissions (Siguiente: Agregar permisos).
  6. Busca y marca la casilla junto a la política que creaste anteriormente.
  7. Haz clic en el botón Next: Name, review and create (Siguiente: Nombre, revisión y creación).
  8. Ingresa el nombre y la descripción del rol.
  9. Haz clic en el botón Create role (Crear rol).

Ahora tienes un nuevo rol IAM que puede ser utilizado por el proyecto de CodeBuild.

Paso 2: Crear un nuevo proyecto de CodeBuild

Vamos a crear un nuevo proyecto de CodeBuild que construirá e implementará nuestro sitio en cada envío al repositorio de GitHub.

Ve a la consola de AWS CodeBuild y haz clic en el botón Create build project (Crear proyecto de compilación).

Configuración del proyecto

  1. Ingresa el nombre y la descripción del proyecto.
  2. Restringe el número de compilaciones concurrentes que este proyecto puede iniciar a 1.

Origen

  1. Selecciona GitHub como proveedor de origen.
  2. Haz clic en el botón Connect to GitHub y autoriza a AWS para acceder a tus repositorios de GitHub.
  3. Selecciona tu repositorio y la rama.

Entorno

  1. Selecciona Managed Image como la imagen de entorno.
  2. Elige Lambda como tipo de cómputo.
  3. Sistema operativo: Amazon Linux (no tienes otras opciones aquí).
  4. Runtime: Golang.
  5. Imagen: aws/codebuild/amazonlinux-aarch64-lambda-standard:go1.21 o la más reciente disponible.
  6. Versión de imagen: Always use the latest image for this runtime version.
  7. Rol de servicio: Existing service role.
  8. ARN del rol: elige el rol que creaste en el paso anterior.
  9. Marca la casilla Allow AWS CodeBuild to modify this service role so it can be used with this build project (Permitir a AWS CodeBuild modificar este rol de servicio para que pueda ser utilizado con este proyecto de compilación).

Buildspec

Elige Insert build commands y pega el siguiente buildspec:

ℹ️
El entorno Lambda de CodeBuild está limitado y no permite el uso de gestores de paquetes como yum o rpm debido a que requieren acceso de root. Por lo tanto, necesitamos descargar y extraer manualmente Hugo. Para más información, consulta las Limitaciones del cómputo Lambda de AWS.
⚠️
Reemplaza YOUR_BUCKET_NAME, YOUR_REGION, y YOUR_DISTRIBUTION_ID con tus valores.
version: 0.2

phases:
  install:
    commands:
      # Download and extract Hugo
      - curl -Ls https://github.com/gohugoio/hugo/releases/download/v0.127.0/hugo_extended_0.127.0_linux-arm64.tar.gz -o /tmp/hugo.tar.gz
      - mkdir /tmp/hugo_0.127.0
      - tar xf /tmp/hugo.tar.gz -C /tmp/hugo_0.127.0
      - /tmp/hugo_0.127.0/hugo version
  build:
    commands:
      # Build the site using Hugo
      - /tmp/hugo_0.127.0/hugo --minify --gc
  post_build:
    commands:
      # Sync the Hugo build public folder with S3 bucket
      - aws s3 sync public/ s3://YOUR_BUCKET_NAME --region YOUR_REGION --delete
      # Invalidate CloudFront cache
      - aws cloudfront create-invalidation --distribution-id YOUR_DISTRIBUTION_ID --paths '/*'

Artefactos

Selecciona No artifacts como tipo de artefacto de salida, ya que estamos desplegando el sitio a S3 dentro del buildspec.

Registros

Opcionalmente, puedes configurar registros de CloudWatch para el proyecto de compilación. Esto te ayudará a depurar el proceso de compilación.

Paso 3: Activar la compilación

Ahora puedes activar la compilación al hacer un nuevo envío (commit) al repositorio de GitHub. El proyecto de CodeBuild iniciará automáticamente el proceso de compilación y desplegará el sitio en el bucket de S3. Alternativamente, puedes iniciar manualmente la compilación presionando el botón Start build en la consola de CodeBuild.

¡Eso es todo! Has desplegado exitosamente tu sitio Hugo utilizando AWS CodeBuild en un entorno Lambda.

Despliegue con CloudFormation

Si prefieres desplegar el proyecto de CodeBuild usando CloudFormation, puedes utilizar la plantilla siguiente. Está parametrizada con los valores requeridos.

⚠️
Considera configurar la conexión a GitHub manualmente en la consola de AWS CodeBuild antes de desplegar la pila de CloudFormation.
AWSTemplateFormatVersion: '2010-09-09'
Description: CodeBuild project for Hugo site deployment
Parameters:
  ProjectName:
    Type: String
    Description: CodeBuild project name
    Default: HugoSiteBuild
  SiteBucketName:
    Type: String
    Description: Site S3 bucket name
  DistributionId:
    Type: String
    Description: CloudFront distribution ID
  Region:
    Type: String
    Description: AWS region
  HugoVersion:
    Type: String
    Description: Hugo version
    Default: 0.127.0
  GitHubRepo:
    Type: String
    Description: GitHub repository URL
Resources:
  ServiceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: codebuild.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: CodeBuildServiceRolePolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource:
                  - !Sub arn:aws:logs:${Region}:${AWS::AccountId}:log-group:/aws/codebuild/${ProjectName}
                  - !Sub arn:aws:logs:${Region}:${AWS::AccountId}:log-group:/aws/codebuild/${ProjectName}:*
        - PolicyName: DeploySiteCodeBuildPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:PutObject
                  - s3:GetObject
                  - s3:DeleteObject
                  - s3:GetBucketAcl
                  - s3:GetBucketLocation
                  - s3:ListBucket
                Resource:
                  - !Sub arn:aws:s3:::${SiteBucketName}
                  - !Sub arn:aws:s3:::${SiteBucketName}/*
              - Effect: Allow
                Action:
                  - cloudfront:CreateInvalidation
                Resource:
                  - !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${DistributionId}
  CodeBuildProject:
    Type: AWS::CodeBuild::Project
    Properties:
      Name: !Ref ProjectName
      Description: Build and deploy Hugo site
      ConcurrentBuildLimit: 1
      Environment:
        Type: ARM_LAMBDA_CONTAINER
        ComputeType: BUILD_LAMBDA_1GB
        Image: aws/codebuild/amazonlinux-aarch64-lambda-standard:go1.21
      ServiceRole: !GetAtt ServiceRole.Arn
      Source:
        Type: GITHUB
        BuildSpec: !Sub |
          version: 0.2
          phases:
            install:
              commands:
                - curl -Ls https://github.com/gohugoio/hugo/releases/download/v${HugoVersion}/hugo_extended_${HugoVersion}_linux-arm64.tar.gz -o /tmp/hugo.tar.gz
                - mkdir /tmp/hugo_${HugoVersion}
                - tar xf /tmp/hugo.tar.gz -C /tmp/hugo_${HugoVersion}
                - /tmp/hugo_${HugoVersion}/hugo version
            build:
              commands:
                - /tmp/hugo_${HugoVersion}/hugo --minify --gc
            post_build:
              commands:
                - aws s3 sync public/ s3://${SiteBucketName} --region us-east-1 --delete
                - aws cloudfront create-invalidation --distribution-id ${DistributionId} --paths '/*'
        Location: !Ref GitHubRepo
      Artifacts:
        Type: NO_ARTIFACTS
      Triggers:
        Webhook: true
        BuildType: BUILD
        FilterGroups:
          - - Type: EVENT
              Pattern: PUSH
      LogsConfig:
        CloudWatchLogs:
          Status: ENABLED
          GroupName: !Sub /aws/codebuild/${ProjectName}

Conclusión

En esta receta, aprendimos cómo desplegar un sitio estático de Hugo utilizando AWS CodeBuild en un entorno Lambda, que es una forma más económica, fácil y rápida en comparación con el entorno tradicional de EC2. También escribimos todos los pasos en una plantilla de CloudFormation para facilitar el despliegue y la gestión.