# How to debug AWS ECS Tasks locally using LocalStack and VS Code

LocalStack offers some important features that can improve the developer experience of building applications on ECS, including hot-reloading and debugging for compute infrastructure like [Lambda](https://docs.localstack.cloud/user-guide/aws/lambda/) and [ECS](https://docs.localstack.cloud/user-guide/aws/ecs/).

LocalStack allows you to debug your application code in ECS tasks by setting breakpoints and improving your development and testing process without the requirement to deploy to the real cloud. This post will show you how to set up a local ECS cluster and task, open a remote debugging port on the LocalStack container, configure VS Code for debugging, and run the debugger.

## Prerequisites

* [`localstack` CLI](https://docs.localstack.cloud/getting-started/installation/#localstack-cli) with the [`LOCALSTACK_AUTH_TOKEN`](https://docs.localstack.cloud/getting-started/auth-token/)
    
* [Docker](https://docs.docker.com/get-docker/)
    
* [Visual Studio Code](https://code.visualstudio.com/download)
    
* [AWS CDK](https://docs.aws.amazon.com/cdk/latest/guide/work-with-cdk-typescript.html) with [`cdklocal`](https://docs.localstack.cloud/user-guide/integrations/aws-cdk)
    
* [Node.js](https://nodejs.org/en/download/prebuilt-binaries) & `npm`
    
* [AWS CLI](https://docs.aws.amazon.com/cli/v1/userguide/cli-chap-install.html) with [`awslocal` wrapper](https://docs.localstack.cloud/user-guide/integrations/aws-cli/#localstack-aws-cli-awslocal) (optional)
    
* [`curl`](https://curl.se/)
    

## Node.js app on ECS with Elastic Load Balancer

The sample application uses [AWS CDK](https://github.com/aws/aws-cdk) to deploy a Node.js containerized app on [AWS Fargate](https://aws.amazon.com/fargate/) within an [ECS cluster](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/clusters.html). The CDK stack:

* Creates a local VPC and an ECS Cluster.
    
* Builds and pushes the Docker image to a local ECR repository.
    
* Adds task and container Definition for the local ECS tasks.
    
* Runs containers on Fargate, distributing traffic using ELB.
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723015645943/a97b2b4a-d539-4d68-b398-9effa224b954.png align="center")

After deploying the CDK stack, you will create a VS Code task & launch configuration and attach the debugger to the ECS task.

### Start your LocalStack container

Launch the LocalStack container on your local machine using the specified command:

```bash
export LOCALSTACK_AUTH_TOKEN=<your-auth-token>
ECS_DOCKER_FLAGS="-e NODE_OPTIONS=--inspect-brk=0.0.0.0:9229 -p 9229:9229" \
localstack start
```

The configuration variable `ECS_DOCKER_FLAGS` in the command mentioned above is used to pass additional flags to Docker when creating ECS task containers. The option is used to enable a remote debugging port for your ECS tasks. This exposes the debugger on a random port on the host machine, allowing you to remotely attach your debugger to the ECS tasks.

> Alternatively, you can utilize the [Docker Compose configuration](https://github.com/localstack-samples/sample-cdk-ecs-elb/blob/main/devops-tooling/docker-compose.yml) provided in the repository to start the LocalStack container with the following command:
> 
> ```bash
> cd devops-tooling && docker compose -p ecslb up
> ```

### Install the dependencies

To begin, fork the [LocalStack sample repository on GitHub](https://github.com/localstack-samples/sample-cdk-ecs-elb) using this command:

```bash
git clone git@github.com:localstack-samples/sample-cdk-ecs-elb.git
```

After cloning the repository, navigate to the `iac/awscdk` directory and install all the required dependencies with the following command:

```bash
cd iac/awscdk
npm install
```

### Deploy the application locally

To deploy the application, you should use [`cdklocal`](https://github.com/localstack/aws-cdk-local), which is a wrapper script for utilizing the AWS Cloud Development Kit (CDK) with local APIs provided by LocalStack.

Start by ensuring that each AWS environment you plan to deploy resources to is bootstrapped. Run the following command in the `iac/awscdk` directory:

```bash
cdklocal bootstrap
```

Next, you can deploy the CDK stack using this command in the `iac/awscdk` directory:

```bash
cdklocal deploy
```

After a successful deployment, you should see output similar to the following:

```bash
✅  RepoStack

✨  Deployment time: 20.15s

Outputs:
RepoStack.MyFargateServiceLoadBalancerDNS704F6391 = lb-bf1b158e.elb.localhost.localstack.cloud
RepoStack.MyFargateServiceServiceURL4CF8398A = http://lb-bf1b158e.elb.localhost.localstack.cloud
RepoStack.localstackserviceslb = lb-bf1b158e.elb.localhost.localstack.cloud:4566
RepoStack.serviceslb = lb-bf1b158e.elb.localhost.localstack.cloud
Stack ARN:
arn:aws:cloudformation:us-east-1:000000000000:stack/RepoStack/77d40ed8

✨  Total time: 22.55s
```

You can now use the URLs provided to send requests to the Node.js application running in the ECS task locally. To inspect the ELB endpoint further, if you have `awslocal` installed, run the following command:

```bash
awslocal elbv2 describe-load-balancers --query 'LoadBalancers[0].DNSName' --output text
```

The output should be:

```bash
lb-bf1b158e.elb.localhost.localstack.cloud
```

### Configure VS Code for remote debugging

While starting LocalStack, you configured `ECS_DOCKER_FLAGS` to enable the required configuration for remote debugging. You can now add a [VS Code task](https://code.visualstudio.com/docs/editor/tasks) to wait for the remote debugging server. Create a `tasks.json` file in the `.vscode` directory of the project and add the following:

```json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Wait Remote Debugger Server",
            "type": "shell",
            "command": "while [[ -z $(docker ps | grep :9229) ]]; do sleep 1; done; sleep 1;"
        }
    ]
}
```

Next, you can define how VS Code should connect to the remote Node.js application. Create a new `launch.json` file in the `.vscode` directory of the project and add the following:

```json
{
    "version": "0.2.0",
    "configurations": [
        {
            "address": "127.0.0.1",
            "localRoot": "${workspaceFolder}",
            "name": "Attach to Remote Node.js",
            "port": 9229,
            "remoteRoot": "/app",
            "request": "attach",
            "type": "node",
            "preLaunchTask": "Wait Remote Debugger Server"
        }
    ]
}
```

### Run the debugging process

For the debugging process, you can set [breakpoints](https://code.visualstudio.com/docs/editor/debugging#_breakpoints) in the Node.js application code. Breakpoints allow you to pause the code execution on a specific line to inspect it. To run the debugger:

* Click on **Run and Debug** in your VS Code session.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723008324621/e16740f9-38ae-4390-a88a-beef46d968c8.png align="center")
    
* Select the **Attach to Remote Node.js** configuration and click **Start Debugging**.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723008472995/17e89a32-b723-4cea-acc6-67eb7908ec0d.png align="center")
    
* Navigate to `src/app/server.js` in your VS Code and set breakpoints (for example, on line 5).
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723008574888/5ec6bfdd-c32b-4dc6-99b0-39d75d13bf6a.png align="center")
    
* Open your terminal and execute the following command to trigger the code where you set the breakpoint:
    
    ```bash
    curl "lb-bf1b158e.elb.localhost.localstack.cloud:4566"
    ```
    
    Replace the endpoint URL with the appropriate URL in your setup.
    

You will now see the remote debugging in action on your VS Code:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723196567473/40c511ad-9a2f-4dae-a1c9-3e96f441a866.png align="center")

You can now inspect the values of any identifiers within the current scope using the **Variables** and **Watch** pane in VS Code. Additionally, use the debug toolbar at the top of the editor to step through the code, continue execution, or manage breakpoints during debugging.

After the debugging process is completed, the command you ran previously will produce the following output:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1723017502912/338145c7-3d86-48f2-9755-27c53817aca4.png align="center")

## Conclusion

That brings us to the end of our tour of how you can debug ECS tasks locally with LocalStack. You can mount code from the host filesystem into the ECS container for hot reloading, enabling quick debugging and testing without needing to rebuild and redeploy the Docker image each time. LocalStack not only lets you deploy and test your infrastructure but also offers various developer experience (**DevEx**) features, allowing you to develop your application without interacting with the actual cloud throughout your software development lifecycle.
