Skip to content

AWS CDK - Cloud Developer Kit

En la plataforma de AWS (Amazon WebServices) es posible definir la infraesctructura usando código con un lenguaje de marcado como YAML, lo que se conoce como Infraestructura como Código (IaC - Infraestructure As Code). El componente tecnológico que permite esto se denomina CloudFormation. Es decir, con un archivo de estructura YAML se especifica un conjunto de servicios y como se aprovisionan en la plataforma de AWS de modo que puede ser replicable.

Luego, encontramos que también es posible usar un lenguaje de programación reconocido (tales como Javascript, Python, Java, C#, Go) para implementar IaC con un componente tecnológico que se denomina Cloud Developer Kit (CDK). Esto nos ofrece el uso de control de flujo con el lenguaje de programación y otras características para tener mayor control al definir nuestra IaC.

Como prerrequisitos de debe contar con un entorno Node.js instalado previamente, así como también contar con una cuenta configurada y la CLI (Command Line Interface) de AWS. A continuación veremos unos apuntes ágiles para iniciar con CDK.

Instalación de CDK

bash
npm install -g aws-cdk

Puede comprobarse la instalación con el comando npx cdk --version

Proyecto de inicio rápido

Para iniciar nuestro proyecto, nos ubicamos en una carpeta que se use como espacio de trabajo de proyectos y creamos nuestra subcarpeta para el proyecto. Luego inicializamos el proyecto, es decir, ejecutamos lo siguiente:

bash
mkdir cdk
cdk init app --language typescript

En algunos casos puede ser necesario anteponer npx al comando cdk

A continuación estableceremos un Construct, que es un componente de servicio base para crear recursos. En nuestro ejercicio incluiremos DynamoDB para crear una tabla, por lo que ejecutamos lo siguiente:

bash
npm install @aws-cdk/aws-dynamodb

Nos dirigimos a nuestro proyecto para modificar el archivo lib/cdk-stack.ts, de modo que quede con el siguiente contenido:

typescript
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';

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

    new dynamodb.Table(this, "user", {
      partitionKey: {
        name: "userId",
        type: dynamodb.AttributeType.STRING
      },
      sortKey: {
        name: "email",
        type: dynamodb.AttributeType.STRING
      }
    });
  }
}

Mediante el uso de dynamodb.Table se define nuestra tabla

CDK genera código de CloudFormation, así que para ver el resultado ejecutamos:

bash
cdk synth

En algunos casos puede ser necesario anteponer npx al comando cdk

Procedemos a establecer o asociar la cuenta de AWS que usaremos con CDK ejecutando un comando como el siguiente:

bash
cdk bootstrap aws://000000000000/us-east-1

dónde 000000000000 se refiere al número asignado a nuestra cuenta y us-east-1 a la región (la cual puede variar según corresponda).
es posible consultar la identidad de nuestra cuenta con el comando: aws sts get-caller-identity

Finalmente, para desplegar nuestra IaC ejecutamos:

bash
cdk deploy

cdk destroy elimina lo que desplegamos

Alternativa usando LocalStack con CDK

LocalStack provee un entorno local y simulado de AWS. Si se tiene LocalStack debidamente instalado y corriendo, es posible incorporar el uso del módulo cdklocal, el cual se instala ejecutando:

bash
npm install -g aws-cdk-local

Debe tenerse instalado aws-cdk como hicimos desde el principio.

En lugar de los comandos antes vistos, podríamos ejecutar entonces:

bash
npx cdklocal synth
npx cdk bootstrap
npx cdklocal deploy
npx cdklocal destroy

Completando nuestro ejercicio con una Lambda

Para acceder a la base de datos usaremos una Lambda, por lo que ejecutamos lo siguiente:

bash
npm install @aws-cdk/aws-lambda

El código de ejemplo a continuación sustituye el contenido anterior, siendo actualizado así:

typescript
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import { Runtime, FunctionUrlAuthType } from 'aws-cdk-lib/aws-lambda';
import * as lambda from 'aws-cdk-lib/aws-lambda-nodejs';
import * as path from 'path';

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

    // dynamo
    const table = new dynamodb.Table(this, "user", {
      partitionKey: {
        name: "userId",
        type: dynamodb.AttributeType.STRING
      },
      sortKey: {
        name: "email",
        type: dynamodb.AttributeType.STRING
      }
    });

    // lambda
    const handler = new lambda.NodejsFunction(this, "userHandler", {
      runtime: Runtime.NODEJS_18_X,
      entry: path.join(__dirname, `/../run/lambda.ts`),
      handler: "handler",
      environment: {
        USER_TABLE_NAME: table.tableName,
      },
    });

    // prvileges
    table.grantReadWriteData(handler);

    const userUrl = handler.addFunctionUrl({
      authType: FunctionUrlAuthType.NONE,
      cors: {
        allowedOrigins: ['*'],
      }
    });

    new cdk.CfnOutput(this, 'userUrl', {
      value: userUrl.url,
    });
  }
}

Nótese que se hace referencia a una lambda en el archivo run/lambda.ts (el cual contiene el código de la función y deberá implementarse)