Introduction
Recently, I've been increasingly using LocalStack to set up local development environments at work, so I'd like to explain the reasons behind this.
What is LocalStack?
LocalStack is a tool that can emulate AWS services on your local machine.
https://www.localstack.cloud/
An emulator is software that mimics the behavior of other software or systems and can be used as an alternative. By using LocalStack, you can reproduce AWS services like S3 and Lambda in your local environment.
The main use cases are individual learning and testing in local environments.
The free version supports around 30 services, which is sufficient for individual learning purposes. However, for commercial services or web services of a certain scale, I believe you would need to use the Base plan.
Motivation for Adoption
In our usual backend development, we follow the flow of developing in a local environment → deploying to the cloud for functional verification.
When developing in a local environment, we set up AWS profiles and SSH tunneling to resolve authentication and network issues.
This is sufficient for regular development, but we decided to use LocalStack due to the following requirements:
- We want members from other departments to run the applications we operate, but for various reasons, we don't want to grant them AWS account permissions.
- We want to use AI agents like Devin for development, but it's difficult to resolve network and authentication issues.
- Even if we could resolve these issues, we want to avoid excessive usage of pay-per-use services due to AI agent malfunctions.
Environment Setup
Environment setup is done using Docker and Docker Compose. Here is the image of the difference between AWS Cloud and Localstack.
// AWS Cloud ┌─────────────────┐ ┌─────────────────────────────────┐ │ Local env │ │ AWS Cloud │ │ │ │ │ │ ┌───────────┐ │ HTTPS │ ┌─────────┐ ┌─────────┐ │ │ │Backend │ │ ────────► │ │ S3 │ │ Lambda │ │ │ │Code │ │ Request │ │ │ │ │ │ │ └───────────┘ │ │ └─────────┘ └─────────┘ │ │ │ │ │ │ ┌───────────┐ │ │ ┌─────────┐ ┌─────────┐ │ │ │Terraform │ │ ────────► │ │DynamoDB │ │ SQS │ │ │ │ │ │ │ │ │ │ │ │ │ └───────────┘ │ │ └─────────┘ └─────────┘ │ └─────────────────┘ └─────────────────────────────────┘ // Localstack ┌───────────────────────────────────────────────────────────────┐ │ Local env │ │ │ │ ┌───────────┐ ┌─────────────────────────────────┐ │ │ │Backend │ HTTP │ Docker Container │ │ │ │Code │ ────────► │ │ │ │ └───────────┘ :4566 │ ┌──────────┐ ┌──────────┐ │ │ │ │ │ S3 │ │ Lambda │ │ │ │ ┌───────────┐ │ │(emulated)│ │(emulated)│ │ │ │ │Terraform │ ────────► │ └──────────┘ └──────────┘ │ │ │ │ │ │ │ │ │ └───────────┘ │ ┌──────────┐ ┌──────────┐ │ │ │ │ │DynamoDB │ │ SQS │ │ │ │ │ │(emulated)│ │(emulated)│ │ │ │ │ └──────────┘ └──────────┘ │ │ │ │ │ │ │ │ LocalStack Process │ │ │ └─────────────────────────────────┘ │ └───────────────────────────────────────────────────────────────┘
The official documentation provides installation instructions, and you can follow these to set it up.
Prepare a YAML file like the following:
version: "3.8" services: localstack: container_name: localstack image: localstack/localstack-pro:latest ports: - "4566:4566" environment: - LOCALSTACK_AUTH_TOKEN="${LOCALSTACK_AUTH_TOKEN}" # required for base, pro... - SERVICES=<AWS services> # comma delimited AWS services list like s3, lambda, batch... - DEFAULT_REGION=<aws-region> - DOCKER_HOST=unix:///var/run/docker.sock volumes: - "./:/tmp/app" - "/var/run/docker.sock:/var/run/docker.sock"
Start the Docker process with docker-compose up -d
. This process creates emulated AWS endpoints, and you can create AWS services by sending requests to these endpoints.
There's an AWS CLI called awslocal that can be used with LocalStack, which allows you to easily create resources. To create an S3 bucket, execute the following command:
awslocal s3 mb s3://${S3_BUCKET_NAME}
You can also use Terraform with LocalStack.
In the provider configuration, change the endpoint to LocalStack's endpoint as follows. The default endpoint is http://localhost:4566
, so use that:
provider "aws" { region = "<region>" endpoints { // specify localstack endpoint to the services you use. dynamodb = "http://localhost:4566" s3 = "http://localhost:4566" lambda = "http://localhost:4566" ... } s3_use_path_style = true skip_credentials_validation = true skip_metadata_api_check = true skip_requesting_account_id = true access_key = "test" secret_key = "test" }
After configuring the above settings, execute terraform apply
to create emulated resources using Terraform with LocalStack's endpoint.
That covers how to create AWS resources.
To use AWS services created with LocalStack from backend code, change the AWS service endpoint to LocalStack's endpoint, similar to Terraform. Here's sample code for initializing an S3 client in Go:
var configOptions []func(*config.LoadOptions) error cfg, err := config.LoadDefaultConfig(context.TODO(), configOptions...) if err != nil { return nil, err } localstackEndpoint := "http://localhost:4566" cfg.BaseEndpoint = aws.String(localstackEndpoint) client := s3.NewFromConfig(cfg) ...
Conclusion
That's all there is to it. It can be used with relatively simple changes. The use of AI agents, as mentioned in the motivation section, will likely increase in the future, so using LocalStack as a measure to prevent excessive service usage seems like a good strategy.
I hope this article will be helpful to everyone.
Top comments (0)