|
| 1 | +--- |
| 2 | +title: "Deploy LocalStack on Kubernetes" |
| 3 | +description: Deploy LocalStack into a Kubernetes cluster and run a sample Lambda + RDS application in under 5 minutes. |
| 4 | +template: doc |
| 5 | +sidebar: |
| 6 | + order: 3 |
| 7 | +--- |
| 8 | + |
| 9 | +## Introduction |
| 10 | + |
| 11 | +This quickstart spins up LocalStack in a local Kubernetes cluster and deploys a sample application in 5 minutes. You'll run an AWS Lambda function that queries an RDS MySQL database, with both services executing as pods managed by LocalStack. |
| 12 | + |
| 13 | +LocalStack's Kubernetes integration is available as part of the [Enterprise plan](https://localstack.cloud/pricing). |
| 14 | + |
| 15 | +## Prerequisites |
| 16 | + |
| 17 | +Before starting, make sure you have the following: |
| 18 | + |
| 19 | +- A [LocalStack Auth Token](https://docs.localstack.cloud/getting-started/auth-token/) exported as `LOCALSTACK_AUTH_TOKEN` |
| 20 | +- [Docker](https://docs.docker.com/get-docker/) |
| 21 | +- [`kind`](https://kind.sigs.k8s.io/) |
| 22 | +- [Terraform](https://www.terraform.io/downloads) (v1.11.1 or later) with the [`tflocal`](https://docs.localstack.cloud/user-guide/integrations/terraform/) wrapper |
| 23 | +- [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) with the [`awslocal`](https://docs.localstack.cloud/user-guide/integrations/aws-cli/#localstack-aws-cli-awslocal) wrapper |
| 24 | +- [`kubectl`](https://kubernetes.io/docs/reference/kubectl/) |
| 25 | +- [`jq`](https://jqlang.github.io/jq/download/) |
| 26 | +- [`k9s`](https://k9scli.io/) (optional, for visual cluster monitoring) |
| 27 | + |
| 28 | +## Step by Step |
| 29 | + |
| 30 | +### Step 1: Clone the sample repository |
| 31 | + |
| 32 | +```bash |
| 33 | +git clone https://github.com/localstack-samples/localstack-k8s-demo.git |
| 34 | +cd localstack-k8s-demo |
| 35 | +``` |
| 36 | + |
| 37 | +The repository contains: |
| 38 | + |
| 39 | +- `main.tf`: Terraform configuration that provisions an RDS MySQL database and a Lambda function on LocalStack |
| 40 | +- `lambda-src/`: Python Lambda function source code with `pymysql` as a dependency |
| 41 | +- `localstack-instance.yml`: Custom resource definition for the LocalStack deployment |
| 42 | +- `scripts/`: Helper scripts for managing the auth token secret and port forwarding |
| 43 | +- `Makefile`: Convenience targets for the full workflow |
| 44 | + |
| 45 | +### Step 2: Create the Kubernetes cluster |
| 46 | + |
| 47 | +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. |
| 48 | + |
| 49 | +Create a local Kubernetes cluster using `kind`: |
| 50 | + |
| 51 | +```bash |
| 52 | +kind create cluster --name ls-k8s-demo |
| 53 | +``` |
| 54 | + |
| 55 | +Verify the cluster is running: |
| 56 | + |
| 57 | +```bash |
| 58 | +kubectl cluster-info |
| 59 | +``` |
| 60 | + |
| 61 | +### Step 3: Deploy the LocalStack Operator |
| 62 | + |
| 63 | +The [LocalStack Operator](https://github.com/localstack/localstack-operator) manages the LocalStack deployment and configures cluster DNS so that AWS-style hostnames resolve correctly inside the cluster. |
| 64 | + |
| 65 | +:::note |
| 66 | +The LocalStack Operator and Kubernetes executor are part of the [Enterprise plan](https://localstack.cloud/pricing) and are not enabled by default on a trial license. |
| 67 | +If your Auth Token doesn't have access, contact your LocalStack account team or [support](/aws/help-support/get-help/) to get the Kubernetes pack enabled on your trial. |
| 68 | +::: |
| 69 | + |
| 70 | +```bash |
| 71 | +kubectl apply -f https://github.com/localstack/localstack-operator/releases/latest/download/controller.yaml |
| 72 | +``` |
| 73 | + |
| 74 | +Wait for the operator pod to reach a `Running` state: |
| 75 | + |
| 76 | +```bash |
| 77 | +kubectl get pods -n localstack-operator-system |
| 78 | +``` |
| 79 | + |
| 80 | +``` |
| 81 | +NAME READY STATUS RESTARTS AGE |
| 82 | +localstack-operator-controller-manager-78dcf78855-xxxxx 1/1 Running 0 30s |
| 83 | +``` |
| 84 | + |
| 85 | +### Step 4: Deploy LocalStack into the cluster |
| 86 | + |
| 87 | +Create a namespace and a secret containing your Auth Token: |
| 88 | + |
| 89 | +```bash |
| 90 | +kubectl create namespace workspace |
| 91 | + |
| 92 | +kubectl create secret -n workspace generic localstack-auth-token \ |
| 93 | + --from-literal=LOCALSTACK_AUTH_TOKEN=$LOCALSTACK_AUTH_TOKEN |
| 94 | +``` |
| 95 | + |
| 96 | +Deploy the LocalStack instance: |
| 97 | + |
| 98 | +```bash |
| 99 | +kubectl apply --server-side -f ./localstack-instance.yml |
| 100 | +``` |
| 101 | + |
| 102 | +Wait for the LocalStack pod to be ready (this may take a minute or two while the image is pulled): |
| 103 | + |
| 104 | +```bash |
| 105 | +kubectl get pods -n workspace -w |
| 106 | +``` |
| 107 | + |
| 108 | +Proceed once the pod shows `1/1 Running`. |
| 109 | + |
| 110 | +### Step 5: Set up port forwarding |
| 111 | + |
| 112 | +Forward `port 4566` so you can run AWS commands against LocalStack from your local machine: |
| 113 | + |
| 114 | +```bash |
| 115 | +kubectl port-forward -n workspace svc/localstack-env-1 4566 |
| 116 | +``` |
| 117 | + |
| 118 | +This runs in the foreground. Open a new terminal for the remaining steps. Verify LocalStack is accessible: |
| 119 | + |
| 120 | +```bash |
| 121 | +awslocal sts get-caller-identity |
| 122 | +``` |
| 123 | + |
| 124 | +You can also confirm connectivity using the [LocalStack Web Application](https://app.localstack.cloud/inst/default/overview). |
| 125 | +With the port forward active, open the [Stack Overview](https://app.localstack.cloud/inst/default/overview) in your browser. |
| 126 | +It should load and show your LocalStack instance as connected, which is a quick way to confirm your cluster setup before deploying the sample application. |
| 127 | + |
| 128 | +### Step 6: Deploy the sample application with Terraform |
| 129 | + |
| 130 | +The Terraform configuration provisions the following resources on LocalStack: |
| 131 | + |
| 132 | +- A VPC |
| 133 | +- An RDS MySQL database (`k8sdb`) |
| 134 | +- A Lambda function (`myfunction`) that connects to and queries the database |
| 135 | + |
| 136 | +Both the database and Lambda function run as separate pods in the cluster, managed by LocalStack's Kubernetes executor. |
| 137 | + |
| 138 | +```bash |
| 139 | +tflocal init -upgrade |
| 140 | +tflocal apply -auto-approve |
| 141 | +``` |
| 142 | + |
| 143 | +The deployment takes a few minutes as the MySQL pod needs to start up. Monitor progress with `k9s` or: |
| 144 | + |
| 145 | +```bash |
| 146 | +kubectl get pods -A -w |
| 147 | +``` |
| 148 | + |
| 149 | +:::note |
| 150 | +The Lambda module is configured for ARM64 by default. If you are on an Intel/AMD machine, update `main.tf` to remove the `docker_additional_options` block and change `architectures` to `["x86_64"]`. |
| 151 | +::: |
| 152 | + |
| 153 | +### Step 7: Invoke the Lambda function |
| 154 | + |
| 155 | +```bash |
| 156 | +awslocal lambda invoke \ |
| 157 | + --function-name myfunction \ |
| 158 | + --payload '{}' /dev/stdout | jq . |
| 159 | +``` |
| 160 | + |
| 161 | +The first invocation takes about 30 seconds as the Lambda pod starts up. You should see output like: |
| 162 | + |
| 163 | +```json |
| 164 | +{ |
| 165 | + "results": [ |
| 166 | + [1, "test"], |
| 167 | + [2, "another"] |
| 168 | + ] |
| 169 | +} |
| 170 | +``` |
| 171 | + |
| 172 | +## Validation |
| 173 | + |
| 174 | +Confirm that all three pods are running in the `workspace` namespace: |
| 175 | + |
| 176 | +```bash |
| 177 | +kubectl get pods -n workspace |
| 178 | +``` |
| 179 | + |
| 180 | +``` |
| 181 | +NAME READY STATUS AGE |
| 182 | +lambda-myfunction-xxxxx 1/1 Running 36s |
| 183 | +localstack-env-1-xxxxx 1/1 Running 11m |
| 184 | +ls-mysql-xxxxx 1/1 Running 4m |
| 185 | +``` |
| 186 | + |
| 187 | +You should see the LocalStack pod (`localstack-*`), the MySQL database pod (`ls-mysql-*`), and the Lambda function pod (`lambda-myfunction-*`) all running. |
| 188 | + |
| 189 | +## Cleanup |
| 190 | + |
| 191 | +To tear down all resources: |
| 192 | + |
| 193 | +```bash |
| 194 | +tflocal apply -destroy -auto-approve |
| 195 | +kubectl delete -f ./localstack-instance.yml |
| 196 | +kubectl delete secret -n workspace localstack-auth-token |
| 197 | +``` |
| 198 | + |
| 199 | +## Troubleshooting |
| 200 | + |
| 201 | +### LocalStack pod is stuck in `Pending` or `ImagePullBackOff` |
| 202 | +Verify that your Auth Token secret was created correctly and that your cluster nodes can pull from the LocalStack registry. Check pod events with `kubectl describe pod -n workspace <pod-name>`. |
| 203 | + |
| 204 | +### `awslocal sts get-caller-identity` times out |
| 205 | +Confirm that port forwarding is still running in a separate terminal. If it dropped, restart it with `kubectl port-forward -n workspace svc/localstack-env-1 4566`. |
| 206 | + |
| 207 | +### Lambda invocation returns an error after the first call |
| 208 | +The first invocation takes up to 30 seconds for the Lambda pod to start. Wait and retry. |
| 209 | + |
| 210 | +### Terraform apply fails with a connection error |
| 211 | +Ensure port forwarding is active before running `tflocal apply`. LocalStack must be accessible on `localhost:4566`. |
| 212 | + |
| 213 | +### MySQL pod does not start |
| 214 | +Check cluster resource availability. The MySQL pod requires sufficient CPU and memory. Run `kubectl describe pod -n workspace <ls-mysql-pod-name>` to inspect scheduling events. |
| 215 | + |
| 216 | +## Next Steps |
| 217 | + |
| 218 | +This quickstart covers a minimal deployment. For production-ready configuration options (including persistent storage, advanced networking, scaling, and monitoring), see the full [Kubernetes Enterprise guide](https://docs.localstack.cloud/aws/enterprise/kubernetes/). |
0 commit comments