# Using The AWS CDK With LocalStack And aws-cdk-local

> Speed up your local AWS CDK development but using LocalStack and the AWS CDK Local wrapper package.

- Canonical: https://dennisokeeffe.com/blog/2021-08-07-using-the-aws-cdk-with-localstack-and-aws-cdk-local
- Published: 2021-08-07
- Updated: 2021-08-07
- Tags: aws, aws cdk, typescript, localstack

> This post is #2 of a multi-part series on the [AWS CDK with TypeScript](https://blog.dennisokeeffe.com/blog/series/working-with-the-type-script-aws-cdk) written during Melbourne lockdown #6.

We will explore how we can make use of [LocalStack](https://github.com/localstack/localstack) and LocalStack's wrapper package [aws-cdk-local](https://github.com/localstack/aws-cdk-local) to speed up our local development.

This post will build off the work that in my [AWS CDK With TypeScript Foundations](https://blog.dennisokeeffe.com/blog/2021-08-06-aws-cdk-with-typescript-foundations) blog post.

Source code can be found [here](https://github.com/okeeffed/using-the-aws-cdk-with-localstack-and-aws-cdk-local).

## Prerequisites

1. Basic familiarity with [AWS CDK for TypeScript](https://docs.aws.amazon.com/cdk/latest/guide/work-with-cdk-typescript.html).
2. Read [AWS CDK With TypeScript Foundations](https://blog.dennisokeeffe.com/blog/2021-08-06-aws-cdk-with-typescript-foundations)
3. [LocalStack installed](https://github.com/localstack/localstack)
4. [Docker installed](https://docs.docker.com/install/) and an understanding of `docker compose`.

This blog post will operate as if you have a pro LocalStack account, however it will also work on the free tier.

## Getting started

Clone the working repo from the previous blog post and add some files for our LocalStack config.

```s
# Clone and change into the working directory
$ git clone https://github.com/okeeffed/aws-cdk-with-typescript-foundations using-the-aws-cdk-with-localstack-and-aws-cdk-local
$ cd using-the-aws-cdk-with-localstack-and-aws-cdk-local

# Install the modules
$ npm install
# Add aws-cdk-local
$ npm i --save-dev aws-cdk-local

# Create docker-compose.yml file for LocalStack
$ touch docker-compose.yml
```

At this stage, we are ready to add our `docker-compose.yml` config and start up LocalStack.

## Starting up LocalStack

Add the following to your `docker-compose.yml` file:

```yaml
version: "2.1"
services:
  localstack:
    image: localstack/localstack
    ports:
      - "53:53"
      - "443:443"
      - "4510-4520:4510-4520"
      - "4566-4620:4566-4620"
      - "${PORT_WEB_UI-8080}:${PORT_WEB_UI-8080}"
    environment:
      - LOCALSTACK_API_KEY=${LOCALSTACK_API_KEY}
      - HOSTNAME_EXTERNAL=localstack
      - DEBUG=1
      - DATA_DIR=/tmp/localstack/data
      - DOCKER_HOST=unix:///var/run/docker.sock
      - LAMBDA_EXECUTOR=docker
      - LAMBDA_NETWORK=bridge
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock"
    tmpfs:
      - /tmp/localstack:exec,mode=600
```

Most of this config comes from the LocalStack documentation, but it is important to note that `LOCALSTACK_API_KEY` is an exported environment variable that I have available at runtime.

You can also add this to a local `.env` file.

To startup LocalStack, run `docker compose up` and let it does its things.

To check things are running, we can ping the port 4566:

```s
$ curl http://localhost:4566
# {"status": "running"}
```

## Updating our infrastructure to use AWS CDK Local

Once Docker is up and running, we need to amend our project code to allow for us to use `aws-cdk-local`.

To do so, we need to add the following to our `package.json` file under `scripts`:

```json
"scripts": {
	"local": "cdklocal"
},
```

That's it! The `cdklocal` command is a wrapper around `aws-cdk` that points the actions of the CDK to the local 4566 port used by LocalStack.

## Deploying our stack to LocalStack

Everything from our previous post has the code ready to deployed, so we can work through our lifecycle of `synth` and `deploy` but with the caveat that we use the local script:

```s
$ npm run local synth

> aws-cdk-with-typescript-foundations@0.1.0 local
> cdklocal "synth"

Resources:
  MyFirstBucketB8884501:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: hello-aws-cdk-my-first-bucket
    UpdateReplacePolicy: Delete
    DeletionPolicy: Delete
    Metadata:
      aws:cdk:path: AwsCdkWithTypescriptFoundationsStack/MyFirstBucket/Resource
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Analytics: v2:deflate64:H4sIAAAAAAAAEyWNSwrDMAxEz9K9o9SU0C5Lc4P0BEFWwTGVwJLThfHdm89qHswbxoP3d7henvNPOwypryiZoL5txuRGYbVc0Nz44YlUSkbaeStCtCjc3D7UG9RXwUSHeFJrjiUQLNqvfoDHdrJojF0ubPFLMJ35BzafENSBAAAA
    Metadata:
      aws:cdk:path: AwsCdkWithTypescriptFoundationsStack/CDKMetadata/Default
    Condition: CDKMetadataAvailable
Conditions:
  CDKMetadataAvailable:
    Fn::Or:
      - Fn::Or:
          - Fn::Equals:
              - Ref: AWS::Region
              - af-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-east-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-northeast-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-northeast-2
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-southeast-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-southeast-2
          - Fn::Equals:
              - Ref: AWS::Region
              - ca-central-1
          - Fn::Equals:
              - Ref: AWS::Region
              - cn-north-1
          - Fn::Equals:
              - Ref: AWS::Region
              - cn-northwest-1
      - Fn::Or:
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-central-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-north-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-west-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-west-2
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-west-3
          - Fn::Equals:
              - Ref: AWS::Region
              - me-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - sa-east-1
          - Fn::Equals:
              - Ref: AWS::Region
              - us-east-1
          - Fn::Equals:
              - Ref: AWS::Region
              - us-east-2
      - Fn::Or:
          - Fn::Equals:
              - Ref: AWS::Region
              - us-west-1
          - Fn::Equals:
              - Ref: AWS::Region
              - us-west-2
```

We are now ready to deploy:

```s
$ npm run local deploy

> aws-cdk-with-typescript-foundations@0.1.0 local
> cdklocal "deploy"

AwsCdkWithTypescriptFoundationsStack: deploying...
AwsCdkWithTypescriptFoundationsStack: creating CloudFormation changeset...


 ✅  AwsCdkWithTypescriptFoundationsStack

Stack ARN:
arn:aws:cloudformation:us-east-1:000000000000:stack/AwsCdkWithTypescriptFoundationsStack/ec2cbb64
```

## Seeing our new bucket locally

We can now check our bucket was deployed successfully through the AWS CLI. You have two choices:

1. Use the `--endpoint` argument with the AWS CLI to point to `localhost:4566`.
2. Use the [`awslocal package`](https://github.com/localstack/awscli-local) which will automatically point to `localhost:4566`.

I am going to use the latter in this demonstration as it is just a thin wrapper around the AWS CLI:

```s
$ awslocal s3 ls | grep hello-aws-cdk-my-first-bucket
2021-08-07 08:10:53 hello-aws-cdk-my-first-bucket
```

Awesome! We can see our bucket is available locally.

## Tearing down our local stack

As per usual, we can go through the process of tearing down the local stack (or simply stopping the Docker containers).

For now, let's get into the habit of a proper teardown via the CDK:

```s
$ npm run local destroy

> aws-cdk-with-typescript-foundations@0.1.0 local
> cdklocal "destroy"

Are you sure you want to delete: AwsCdkWithTypescriptFoundationsStack (y/n)? y
AwsCdkWithTypescriptFoundationsStack: destroying...

 ✅  AwsCdkWithTypescriptFoundationsStack: destroyed

$ awslocal s3 ls | grep hello-aws-cdk-my-first-bucket
# no grep output
```

## Summary

Today's post demonstrated how to use [LocalStack](https://github.com/localstack/localstack) to work on a local AWS environment.

LocalStack significantly improves development time for infrastructure (where supported) and is a great tool all around with an active community.

I highly recommend giving it a go. I will be using LocalStack behind the scenes where I can for the upcoming blog posts to test locally.

## Resources and further reading

1. [AWS CDK for TypeScript](https://docs.aws.amazon.com/cdk/latest/guide/work-with-cdk-typescript.html)
2. [LocalStack](https://github.com/localstack/localstack)
3. [`awslocal package`](https://github.com/localstack/awscli-local)
4. [AWS CDK With TypeScript Foundations](https://blog.dennisokeeffe.com/blog/2021-08-06-aws-cdk-with-typescript-foundations)
5. [LocalStack installed](https://github.com/localstack/localstack)
6. [Docker installed](https://docs.docker.com/install/)
7. [Working with the TypeScript AWS CDK blog series](https://blog.dennisokeeffe.com/blog/series/working-with-the-type-script-aws-cdk)

_Photo credit: [`rishabh`](https://unsplash.com/@rishabh)_
