Desplegar un sitio web con AWS CDK en S3 y CloudFront

En este post vamos a mostrar de manera práctica cómo desplegar un sitio web con AWS CDK en S3 y CloudFront, en este caso utilizaremos un proyecto en HTML que colocaremos en línea utilizando la siguiente infraestructura:

Antes de comenzar es importante que ya tengas configuradas tus credenciales y de preferencia el AWS CLI de Amazon en tu entorno de trabajo. Puedes hacerlo siguiendo este tutorial.

Configurando el proyecto

Nuestro proyecto constará de un archivo HTML, una hoja de estilos CSS, y un script que se visualizarán como una página web estática. Para desplegar nuestro proyecto utilizaremos AWS S3 para almacenar el sitio web y CloudFront para distribuir el contenido y generar una URL.

Para tener todo organizado tendremos una estructura principal de dos carpetas.

  • Public: Contendrá los archivos de nuestro sitio web
  • Infra: Contendrá todo el código y la lógica de nuestra infraestructura

Te dejo el código del sitio de ejemplo que estaremos utilizando aquí.

Agregando la Infraestructura con AWS CDK

1. Ingresamos a nuestra carpeta infra y ejecutamos el comando para iniciar un nuevo proyecto cdk.

cd infra
cdk init app --language=typescript

Este comando inicializa un nuevo proyecto de Amazon CDK utilizando typescript, una vez finalizado nuestro proyecto se verá de la siguiente manera.

Desplegar un sitio web con AWS CDK en S3 y CloudFront - CDK Proyecto

2. Ingresamos al archivo infra-stack.ts que se encuentra dentro de la carpeta lib, para agregar el código de nuestra infra:

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { Bucket, BlockPublicAccess, BucketEncryption } from 'aws-cdk-lib/aws-s3';
import { OriginAccessIdentity } from 'aws-cdk-lib/aws-cloudfront';
import { Distribution } from 'aws-cdk-lib/aws-cloudfront';
import { ViewerProtocolPolicy, AllowedMethods } from 'aws-cdk-lib/aws-cloudfront';
import * as s3deploy from "aws-cdk-lib/aws-s3-deployment";

// import * as sqs from 'aws-cdk-lib/aws-sqs';

export class InfraEstaticStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    //Definimos la configuración del bucket S3
    const s3Bucket = new Bucket(this, 'storage',{
      websiteIndexDocument: 'index.html',
      websiteErrorDocument: 'index.html',
      blockPublicAccess: BlockPublicAccess.BLOCK_ACLS,
      encryption: BucketEncryption.S3_MANAGED,
      enforceSSL: false,
      publicReadAccess: true,
      autoDeleteObjects: true,
      removalPolicy: cdk.RemovalPolicy.DESTROY
    });
  
    //Creamos una identidad de origen y se lo asignamos al bucket s3
    const oia = new OriginAccessIdentity(this, 'OIA', {
      comment: "OIA for Images infra"
    });
    s3Bucket.grantRead(oia);
    
    
    /* Definimos la configuració de nuestro bucket s3 */
    const cloudfrontDistrubution = new Distribution( this, 'spo-public-cf_', {
      defaultBehavior: {
        origin: new cdk.aws_cloudfront_origins.S3Origin(s3Bucket), //apuntamos nuestro cloud front a nuestro bucket
        viewerProtocolPolicy: ViewerProtocolPolicy.ALLOW_ALL,
        allowedMethods: AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
      },
      priceClass: cdk.aws_cloudfront.PriceClass.PRICE_CLASS_100,
      
    })
  
    //Iniciamos un despliegue de los archivos que están en la carpeta public a la raiz de nuestro bucket
    new s3deploy.BucketDeployment( this, 'DeployFiles', { 
      sources: [ s3deploy.Source.asset('../public/')],
      destinationBucket: s3Bucket,
    })
  
    //Imprimimos la url de nuestra distribución de cloud front
    new cdk.CfnOutput(this, "ulr", {
      value: `${cloudfrontDistrubution.distributionDomainName}`
    })
  }
}

3. Ya definida nuestra infraestructura, procederemos a agregar una instancia de nuestra infra dentro del archivo bin/infra.ts, quedaría de la siguiente manera.

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { InfraEstaticStack } from '../lib/infra-stack';

const app = new cdk.App();
new InfraEstaticStack(app, 'InfraEstaticStack', {
  env: {
    region: 'us-east-1', //Region en donde se va a desplegar tu proyecto
    account: '' //Tu número de cuenta de AWS
  }
});

Desplegando la infraestructura

1. Definida nuestra infra, procederemos a realizar un build de nuestro código.

npm run build
Desplegar un sitio web con AWS CDK en S3 y CloudFront - Build

2. Ahora ejecutamos el siguiente código para preparar el despliegue y comprobar errores.

cdk synth

Este comando generará nuestro template de cloud formation y si todo funciona bien, ya podremos lanzar el despliegue.

Desplegar un sitio web con AWS CDK en S3 y CloudFront - Synt

3. Ahora procedemos a lanzar el despliegue.

cdk deploy
Desplegar un sitio web con AWS CDK en S3 y CloudFront - Deploy CDK

La primera vez que lancemos el despliegue nos pedirá confirmar la creación de algunos permisos. Presionamos la tecla Y seguido de Enter

Desplegar un sitio web con AWS CDK en S3 y CloudFront - Preview cdk deploy

Ahora comenzará el despliegue, en la terminal podrás visualizar el avance de la creación de cada uno de los componentes.

Desplegar un sitio web con AWS CDK en S3 y CloudFront - Aprove deployment

Una vez que finalicé el despliegue, podrás ver la url del proyecto y ya podrás visualizar el resultado en tu navegador.

Desplegar un sitio web con AWS CDK en S3 y CloudFront - Finish deployment
Desplegar un sitio web con AWS CDK en S3 y CloudFront - Show result

Eliminando la infra creada

Una vez finalizada tu práctica vamos a eliminar todos los recursos creados, para evitar cargos no deseados en nuestra factura de AWS, la ventaja que tenemos al trabajar con CDK es que con solo ejecutar un comando podremos eliminar todo lo que desplegamos, sin tener que ingresar a la consola.

cdk destroy

Presionamos la tecla (y) seguida de Enter

Cdk destroy

CDK comenzará el proceso de eliminación

Aprove destroy

En cuanto finalicé veremos una salida en terminal similar a la siguiente.

Destroy success

Con esto hemos limpiado nuestra cuenta de AWS, y ahora ya podemos desplegar sitios web estáticos directamente en s3 sin tener que utilizar un servidor.