Deploy LocalStack Operator
The LocalStack Operator is our Kubernetes-native way to deploy and manage LocalStack instances. It abstracts Kubernetes-specific configuration and automates operational tasks, making LocalStack deployments more consistent and easier to maintain. It can manage multiple LocalStack instances within a cluster to provide isolated local clouds for multiple users.
The Operator manages the full lifecycle of LocalStack resources and enables advanced Kubernetes integrations that are difficult to configure manually.
Getting started
Section titled “Getting started”This guide explains how to deploy and manage LocalStack in a Kubernetes cluster using the LocalStack Operator.
Advanced features
Section titled “Advanced features”The Operator supports the following advanced capabilities:
- Opt-in DNS and endpoint injection for Kubernetes workloads
- Cluster DNS configuration to resolve AWS-style subdomains in the same namespace
- Automatic loading of Cloud Pods on startup
- Support for initialization hooks
- Simplified logging configuration
- Automatic mounting of a PersistentVolumeClaim (PVC) for the LocalStack data directory, enabling artifact caching and persistence
Prerequisites
Section titled “Prerequisites”Before installing the LocalStack Operator, ensure you have:
- A running Kubernetes cluster
- A LocalStack license that includes Kubernetes features
- An authentication token for that license
Deploy Operator
Section titled “Deploy Operator”The easiest way to install the Operator controller is to apply the published manifests directly from GitHub.
# Install the latest versionkubectl apply -f https://github.com/localstack/localstack-operator/releases/latest/download/controller.yamlTo install a specific version:
# Example: install v0.4.0kubectl apply -f https://github.com/localstack/localstack-operator/releases/v0.4.0/download/controller.yamlSee the Operator releases page for all available versions.
Deploy LocalStack instance
Section titled “Deploy LocalStack instance”Once the Operator is running, you can deploy a LocalStack instance by creating a LocalStack custom resource.
A minimal example looks like this:
apiVersion: api.localstack.cloud/v1alpha1kind: LocalStackmetadata: name: localstack namespace: my-namespacespec: image: localstack/localstack-pro:latest dnsProvider: coredns dnsConfigName: coredns dnsConfigNamespace: kube-system envFrom: - secretRef: name: localstack-auth-tokenIn this example, the LocalStack auth token is read from a Kubernetes Secret named localstack-auth-token.
You can create this Secret with:
kubectl create secret generic localstack-auth-token \ --from-literal=LOCALSTACK_AUTH_TOKEN="$LOCALSTACK_AUTH_TOKEN"With this example, the auth token must be available in the LOCALSTACK_AUTH_TOKEN environment variable when creating the Secret.
Accessing LocalStack
Section titled “Accessing LocalStack”By default, the Operator creates a ClusterIP Service named:
localstack-<crd-name>For the example above (name: localstack), the Service name is:
localstack-localstackThis Service exposes:
- The LocalStack gateway port (
4566) - AWS service ports
- Port
53for DNS
Using standard Kubernetes DNS resolution, the Service can be reached at:
localstack-localstack(same namespace)localstack-localstack.my-namespacelocalstack-localstack.my-namespace.svc.cluster.local
When dnsProvider: coredns is configured, LocalStack can also be reached through any subdomain of these service names.
Inject LocalStack endpoints into workloads
Section titled “Inject LocalStack endpoints into workloads”The Operator can configure individual workloads to use the LocalStack instance in their namespace without changing cluster-wide DNS. It uses an admission webhook to update opted-in Pods when Kubernetes creates them. Pods without the opt-in label are not affected.
Opt in a workload
Section titled “Opt in a workload”Add the localstack.cloud/inject-dns: "true" label to the Pod template of each Deployment, StatefulSet, Job, or other workload that needs to access LocalStack:
spec: template: metadata: labels: localstack.cloud/inject-dns: "true"Add the same label directly under metadata.labels when you create a standalone Pod.
Injected configuration
Section titled “Injected configuration”For an opted-in Pod, the Operator:
- Configures the Pod’s DNS to send requests to LocalStack first, before falling back to the cluster DNS resolver. LocalStack only responds to domain names it owns, that is, those ending in
localhost.localstack.cloudor your configured$LOCALSTACK_HOST, so requests such asmy-bucket.s3.localhost.localstack.cloudresolve to LocalStack while every other DNS request, including in-cluster Service names, is forwarded to the cluster resolver as normal. - Sets
AWS_ENDPOINT_URLtohttp://localstack-<localstack-name>.<namespace>:4566in every regular, init, and ephemeral container. AWS SDKs and tools that support this setting use the LocalStack endpoint without application-specific endpoint configuration.
If a container already defines AWS_ENDPOINT_URL, the Operator replaces its value with the LocalStack endpoint.
An endpoint configured directly in application code, with the AWS CLI --endpoint-url option, or with a service-specific endpoint environment variable takes precedence over AWS_ENDPOINT_URL.
Injection requirements and behavior
Section titled “Injection requirements and behavior”The namespace must contain exactly one LocalStack resource.
If the namespace contains no LocalStack resources or more than one, the Operator creates the Pod without injecting DNS or the endpoint.
The Operator also skips injection when the LocalStack Service does not have a usable ClusterIP.
Injection occurs only when Kubernetes creates a Pod. After adding the label to an existing workload, recreate its Pods to apply the configuration.
The webhook does not block Pod creation. If the Operator or LocalStack Service is unavailable, Kubernetes creates the Pod without the injected configuration.
Manage webhook certificates
Section titled “Manage webhook certificates”The endpoint injection webhook uses TLS. Choose how the Operator manages its serving certificate when you install the Operator.
Self-managed certificates
Section titled “Self-managed certificates”The default self-managed mode requires no additional cluster components.
The Operator creates and rotates the certificate and keeps the Kubernetes API server’s trust configuration up to date.
Existing installations continue to use this mode without configuration changes.
cert-manager certificates
Section titled “cert-manager certificates”Use cert-manager mode to delegate certificate issuance and rotation to cert-manager.
Install cert-manager and create an Issuer or ClusterIssuer before starting the Operator in this mode.
The Operator reports an error at startup if the cert-manager Certificate resource is unavailable.
Configure the Operator manager with the following flags or equivalent environment variables:
| Flag | Environment variable | Default | Description |
|---|---|---|---|
--certificate-mode |
CERTIFICATE_MODE |
self-managed |
Set to cert-manager to delegate certificate management. |
--certificate-issuer-name |
CERTIFICATE_ISSUER_NAME |
Unset | Name of the issuer. Required in cert-manager mode. |
--certificate-issuer-kind |
CERTIFICATE_ISSUER_KIND |
ClusterIssuer |
Set to Issuer or ClusterIssuer. |
When you install the Operator from the published controller.yaml, add the environment variables to the Operator’s ConfigMap and restart the manager:
kubectl patch configmap localstack-operator-controller-manager-config \ --namespace localstack-operator-system \ --type merge \ --patch '{"data":{"CERTIFICATE_MODE":"cert-manager","CERTIFICATE_ISSUER_NAME":"<issuer-name>","CERTIFICATE_ISSUER_KIND":"ClusterIssuer"}}'
kubectl rollout restart deployment/localstack-operator-controller-manager \ --namespace localstack-operator-systemReplace <issuer-name> with the name of your issuer.
Set CERTIFICATE_ISSUER_KIND to Issuer if you use a namespaced issuer.
Use a cert-manager CA issuer rather than a SelfSigned issuer.
The webhook does not block Pod creation while you switch certificate modes.
The LocalStack Operator introduces a LocalStack Custom Resource Definition (CRD) that controls how LocalStack instances are deployed and configured.
CRD documentation is currently maintained manually. For a full reference of available fields, see: https://github.com/localstack/localstack-operator/blob/main/api-docs.md
Permissions
Section titled “Permissions”The Operator manifest creates all required Roles, ClusterRoles, and bindings.
| Kind | Name | API Groups | Resources | Verbs |
|---|---|---|---|---|
| Role | localstack-operator-leader-election-role | configmaps | get, list, watch, create, update, patch, delete | |
coordination.k8s.io | leases | get, list, watch, create, update, patch, delete | ||
events | create, patch | |||
| ClusterRole | localstack-operator-manager-role | configmaps | delete, get, list, patch, update, watch | |
events | create, patch | |||
pods, pods/exec, pods/log | create, delete, deletecollection, get, list, patch, update, watch | |||
secrets | get, list, watch | |||
serviceaccounts | create, delete, get, list, update, watch | |||
services | create, delete, get, list, patch, update, watch | |||
api.localstack.cloud | localstacks | create, delete, get, list, patch, update, watch | ||
api.localstack.cloud | localstacks/finalizers | update | ||
api.localstack.cloud | localstacks/status | get, patch, update | ||
apps | deployments | create, delete, get, list, patch, update, watch | ||
apps | deployments/scale | create, delete, get, list, patch, update, watch | ||
rbac.authorization.k8s.io | rolebindings, roles | create, delete, list, update, watch | ||
| ClusterRole | localstack-operator-metrics-reader | (nonResourceURLs: /metrics) | get | |
| ClusterRole | localstack-operator-proxy-role | authentication.k8s.io | tokenreviews | create |
authorization.k8s.io | subjectaccessreviews | create |
Manager ClusterRole
Section titled “Manager ClusterRole”This ClusterRole allows the Operator to manage LocalStack resources and related Kubernetes objects.
Resources include:
- Pods (including exec and logs)
- Services
- Secrets
- Deployments
- ServiceAccounts
- LocalStack CRDs (
localstacks,status,finalizers) - RBAC roles and role bindings
Verbs include:
create, delete, get, list, watch, patch, updateMetrics and proxy ClusterRoles
Section titled “Metrics and proxy ClusterRoles”Additional ClusterRoles are created for:
- Reading metrics (
/metrics) - Authentication and authorization reviews (
tokenreviews,subjectaccessreviews)
DNS handling
Section titled “DNS handling”With dnsProvider: coredns, the LocalStack Operator configures cluster DNS to forward AWS-style subdomain requests to the LocalStack DNS server.
This enables features such as:
- S3 virtual-host–style addressing
- API Gateway domain name resolution
Example from another pod in the cluster:
aws apigatewayv2 create-api \ --name testGatewayProxy \ --protocol-type HTTP \ --target "https://httpbin.org"Example response:
{ "ApiEndpoint": "http://1d4b6907.execute-api.localstack-localstack.my-namespace:4566", "ApiId": "1d4b6907"}Calling the API:
curl http://1d4b6907.execute-api.localstack-localstack.my-namespace:4566/jsonThis works without additional DNS configuration in client applications.
EKS Auto Mode
Section titled “EKS Auto Mode”Amazon EKS Auto Mode does not expose the CoreDNS configuration for the Operator to modify.
Set dnsProvider: eksauto on the LocalStack resource to prevent the Operator from trying to update CoreDNS:
spec: # ... other fields dnsProvider: eksauto dnsConfigName: coredns dnsConfigNamespace: kube-systemThe dnsConfigName and dnsConfigNamespace fields remain required by the LocalStack resource schema, but the Operator does not use their values in eksauto mode.
Use opt-in endpoint injection to configure workloads that need to access LocalStack.
Storage
Section titled “Storage”To persist the LocalStack volume, use the spec.pvcName to specify the PVC you want to mount. This automatically mounts the PVC at /var/lib/localstack.
For example:
# pvc definitionapiVersion: v1kind: PersistentVolumeClaimmetadata: name: myPvcspec: # ...
# LocalStack instance definitionapiVersion: api.localstack.cloud/v1alpha1kind: LocalStackmetadata: name: localstack namespace: my-namespacespec: # ... pvcName: myPvcUpdate
Section titled “Update”The Operator can be upgraded by applying a newer controller manifest.
Example:
# Install an older versionkubectl apply -f https://github.com/localstack/localstack-operator/releases/download/v0.3.3/controller.yaml
# Upgrade to a newer versionkubectl apply -f https://github.com/localstack/localstack-operator/releases/download/v0.4.1/controller.yamlKubernetes will handle rolling updates of the Operator deployment.
Verify
Section titled “Verify”To verify that the Operator and LocalStack instance are running:
kubectl get pods -n my-namespacekubectl get localstacks -n my-namespaceEnsure that:
- The Operator controller pod is running
- The LocalStack resource reports a healthy status
- The LocalStack Service is created