LocalStack LogoLocalStack Icon

Running LocalStack on Kubernetes for Local AWS Development & Testing

Learn how to run LocalStack on a local Kubernetes cluster using the LocalStack Operator, and deploy a Lambda function that queries an RDS MySQL database, with both running as pods in your cluster.

Running LocalStack on Kubernetes for Local AWS Development & Testing

Introduction

Kubernetes has become a popular solution for running containerized applications, and many development teams want their local environments to match what runs in production. Instead of maintaining a separate container setup for local development, these teams run Kubernetes locally and deploy their services there from the start.

LocalStack emulates AWS cloud services on your local machine. It runs as a container and replicates services like Lambda, S3, RDS, SQS, and many more, so you can develop and test AWS-dependent applications without connecting to the real cloud. Since LocalStack runs in a container, it can deploy directly into a Kubernetes cluster, fitting into existing workflows without requiring a different runtime.

In this tutorial, we’ll deploy LocalStack into a local Kubernetes cluster and use it to run a Lambda function that queries an RDS MySQL database. Both the database and the Lambda function run as separate pods in the cluster, managed by LocalStack’s Kubernetes executor. We’ll provision the AWS resources on LocalStack using Terraform, then invoke the function to verify the setup.

Architecture Diagram

Key Concepts

The Kubernetes Executor

LocalStack runs many AWS services (S3, SQS, DynamoDB, and others) inside its own container. Some services need their own isolated containers: Lambda functions, ECS tasks, EC2 instances, DocumentDB, MWAA, and several RDS engines (MySQL, MSSQL) fall into this category. By default, LocalStack launches these using a Docker backend.

When you set the CONTAINER_RUNTIME environment variable to kubernetes, LocalStack switches to its Kubernetes executor. Instead of creating Docker containers, it launches these services as pods in your Kubernetes cluster. A Lambda function becomes a pod. An RDS MySQL database becomes a MySQL pod.

They all share the cluster’s networking and can communicate with LocalStack through standard Kubernetes service discovery. This is transparent to your application code: AWS API calls work the same way regardless of which executor handles the containers behind the scenes.

The LocalStack Operator

The LocalStack operator is a Kubernetes controller that manages LocalStack deployments. You define a LocalStack custom resource in YAML, and the operator handles creating the LocalStack pod, configuring cluster DNS so that AWS-style hostnames resolve to the LocalStack service, and managing the deployment lifecycle. This removes the need to manually configure DNS entries or run custom setup scripts.

Prerequisites

Before starting, make sure you have the following:

Step 1: Clone the repository

Clone the demo repository that contains the Terraform configuration and Lambda function source code:

Terminal window
git clone https://github.com/localstack-samples/localstack-k8s-demo.git
cd localstack-k8s-demo

The repository has the following files:

  • main.tf: Terraform configuration that provisions an RDS MySQL database and a Lambda function on LocalStack
  • lambda-src/: Python code for the Lambda function, with pymysql as a dependency
  • localstack-instance.yml: Custom resource definition for the LocalStack deployment
  • scripts/: Helper scripts for managing the auth token secret and port forwarding
  • Makefile: Convenience targets for the full workflow

Step 2: Create the Kubernetes cluster

If you want to monitor the cluster visually, open a separate terminal and run k9s. The interface starts empty but populates as pods come up.

Create a local Kubernetes cluster using kind:

Terminal window
kind create cluster --name ls-k8s-demo

Verify the cluster is running:

Terminal window
kubectl cluster-info

Step 3: Deploy the LocalStack operator

Deploy the LocalStack operator to manage the cluster DNS. This step installs the operator controller and sets the LocalStack service as the cluster DNS resolver, so that AWS-style hostnames (like RDS endpoints) resolve correctly inside the cluster:

Terminal window
kubectl apply -f https://github.com/localstack/localstack-operator/releases/latest/download/controller.yaml

Wait for the operator pod to reach a Running state:

Terminal window
kubectl get pods -n localstack-operator-system

You should see the controller manager pod ready:

Terminal window
NAME READY STATUS RESTARTS AGE
localstack-operator-controller-manager-78dcf78855-xxxxx 1/1 Running 0 30s

Step 4: Deploy LocalStack into the cluster

Create a Kubernetes namespace and a secret containing your Auth Token. The LocalStack deployment references this secret to activate licensed features like the Kubernetes executor:

Terminal window
kubectl create namespace workspace
kubectl create secret -n workspace generic localstack-auth-token \
--from-literal=LOCALSTACK_AUTH_TOKEN=$LOCALSTACK_AUTH_TOKEN

Deploy the LocalStack instance using the custom resource definition:

Terminal window
kubectl apply --server-side -f ./localstack-instance.yml

The localstack-instance.yml defines a LocalStack custom resource that the operator picks up:

apiVersion: api.localstack.cloud/v1alpha1
kind: LocalStack
metadata:
name: env-1
namespace: workspace
spec:
image: localstack/localstack-pro
dnsProvider: coredns
dnsConfigName: coredns
dnsConfigNamespace: kube-system
debug: "trace"
envFrom:
- secretRef:
name: localstack-auth-token

The operator reads this resource, creates a pod running the LocalStack Pro image, and configures CoreDNS to forward AWS-style DNS queries to LocalStack.

Wait for the LocalStack pod to be ready before continuing. This may take a minute or two while the image is pulled:

Terminal window
kubectl get pods -n workspace -w

Once the pod shows 1/1 Running, proceed to the next step.

Step 5:Set up port forwarding

To run AWS commands against LocalStack from your host machine, forward port 4566:

Terminal window
kubectl port-forward -n workspace svc/localstack-env-1 4566

This runs in the foreground, so open a new terminal for the remaining steps. Verify that LocalStack is accessible:

Terminal window
awslocal sts get-caller-identity

The awslocal command sends AWS API calls to port 4566 on your machine. The port forwarding then routes these requests to the LocalStack pod, so you can create and manage AWS resources from your host.

Step 6: Deploy the AWS infrastructure with Terraform

The Terraform configuration in main.tf provisions the following resources on LocalStack:

  • A VPC (required by the RDS module)
  • An RDS MySQL database (k8sdb)
  • A Lambda function (myfunction) that connects to and queries the database

Both the database and the Lambda function are managed by LocalStack but run as separate pods in the cluster. The RDS instance starts a MySQL pod, and the Lambda function gets its own pod when invoked.

Initialize Terraform and apply the configuration:

Terminal window
tflocal init -upgrade
tflocal apply -auto-approve

The deployment takes a few minutes as the MySQL pod needs to start up. Monitor progress with k9s or:

Terminal window
kubectl get pods -A -w

Step 7: Invoke the Lambda function

The Lambda function connects to the RDS MySQL database and runs the following operations:

  1. Creates a temporary table:
    CREATE TEMPORARY TABLE foo (
    id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    value VARCHAR(255) NOT NULL
    );
  2. Inserts two rows:
    INSERT INTO foo (value) VALUES ('test'), ('another')
  3. Queries all rows:
    SELECT * FROM foo

Invoke the function:

Terminal window
awslocal lambda invoke \
--function-name myfunction \
--payload '{}' /dev/stdout | jq .

The first invocation takes about 30 seconds as the Lambda pod needs to start. You should see output like:

{
"results": [
[
1,
"test"
],
[
2,
"another"
]
]
}
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}

Check the k9s interface or run kubectl get pods -n workspace to see all running pods:

Terminal window
NAME READY STATUS AGE
lambda-myfunction-xxxxx 1/1 Running 36s
localstack-env-1-xxxxx 1/1 Running 11m
ls-mysql-xxxxx 1/1 Running 4m

You’ll find the LocalStack pod (localstack-*), the MySQL database pod (ls-mysql-*), and the Lambda function pod (lambda-myfunction-*), all running in the workspace namespace.

Step 8: Cleanup

To tear down the setup:

Terminal window
tflocal apply -destroy -auto-approve
kubectl delete -f ./localstack-instance.yml
kubectl delete secret -n workspace localstack-auth-token
kind delete cluster --name ls-k8s-demo

Conclusion

This tutorial walked through deploying LocalStack into a local Kubernetes cluster using the LocalStack operator, then provisioning an RDS MySQL database and a Lambda function with Terraform. The Kubernetes executor placed both services into separate pods, and we invoked the Lambda function to query the database, all running locally in the cluster.

This setup fits teams that already use Kubernetes and want their local AWS development to run in the same environment. The LocalStack operator handles DNS and deployment management, and the Kubernetes executor routes services that need their own containers into dedicated pods.

Find the sample repository at localstack-samples/localstack-k8s-demo. For more on LocalStack’s Kubernetes integration, see the LocalStack documentation.


Harsh Mishra
Harsh Mishra
Engineer at LocalStack
Harsh Mishra is an Engineer at LocalStack and AWS Community Builder. Harsh has previously worked at HackerRank, Red Hat, and Quansight, and specialized in DevOps, Platform Engineering, and CI/CD pipelines.