Skip to main content
Kubernetes is a common choice for running Restate services in production environments. This page explains how to deploy Restate applications on Kubernetes with Restate Operator.

What is the Restate Operator?

The Restate Operator is the recommended way to deploy Restate services on Kubernetes. You can find its source code, releases, and complete resource specifications on GitHub.
restatedev/restate-operator
Loading repository data...
The operator extends Kubernetes with resources for running Restate and deploying your service applications: For service deployments, the operator:
  • Deploys your application with ReplicaSets or Knative Serving
  • Registers its SDK endpoint with Restate Cloud, BYOC, or a self-hosted Restate environment
  • Creates a new service revision when your pod template changes
  • Keeps old revisions available until their invocations have drained
  • Establishes a secure outbound tunnel when connecting private services to Restate Cloud
In ReplicaSet mode, the operator keeps old ReplicaSets and their Service objects available while in-flight invocations drain. In Knative mode, it manages Configurations and Routes for each service version. Learn more.
Operator 3 introduced Helm-managed CRD upgrades. The first upgrade to version 3 requires a one-time CRD ownership handoff. Follow the operator 3 upgrade instructions before upgrading an existing installation.

Deploy a service to Restate Cloud or BYOC

Restate Cloud must be able to send invocations to your SDK endpoint. Services in a private Kubernetes cluster connect through an outbound tunnel, so you do not need to expose a public ingress. TypeScript and Go services can run the tunnel client in the application process. Other SDKs use the standalone tunnel client managed by the RestateCloudEnvironment.

Prerequisites

Before you start, you need:
  • A Restate Cloud or BYOC environment
  • A Kubernetes cluster with a current kubectl context
  • Permission to create namespaces and Custom Resource Definitions
  • Helm
  • A container registry that your cluster can pull images from
If you don’t have a Kubernetes cluster, you can run it locally with kind.
Set kubectl context to kind-kind:

Deploy the Restate Operator and connect to Restate Cloud

You perform these steps once for each Kubernetes cluster and Restate Cloud environment.
1

Install the Restate Operator

Install the Restate Operator via Helm:
To install the operator, you need permission to create namespaces and CRDs.Wait for the operator to become available:
2

Create the service namespace and Restate Cloud Secrets

Create an API key in Restate Cloud at Developers > API Keys > Create API Key. Save the key_ value in a file named token. Create the secret in the operator namespace:
3

Configure the Restate Cloud environment

Create a file named restate-cloud-environment.yaml:
restate-cloud-environment.yaml
Set the environment-specific fields:
  • environmentId: the env_... value in the top left corner of the Restate Cloud UI
  • signingPublicKey: the publickeyv1_... under Developers > Security > HTTP endpoints
  • region: the identifier shown next to the environment ID, such as us or eu. A BYOC region can contain multiple labels, such as <environment>.byoc
The RestateCloudEnvironment also manages a standalone tunnel client. Services that use tunnelMode: in-process connect directly from their application pods and do not use that client in the invocation path.

Deploy a service

Choose your SDK and follow the steps to deploy the example service.
1

Download the TypeScript template

If you use an existing service, replace its HTTP listener with an in-process tunnel before building the image. Otherwise, download the TypeScript Kubernetes template, which already starts the tunnel:
The template contains a sample Greeter service, a Dockerfile, and k8s/deployment.yaml.Then, build the image and push it to a registry that your cluster can access:
2

Configure the Restate API key

Create the namespace where your services will run:
Your service needs the Restate API key in its namespace for the in-process tunnel. Use the same token as for the Restate Cloud environment or create an API key in Restate Cloud at Developers > API Keys > Create API Key and save it in a file named token.
3

Deploy and verify the service

In k8s/deployment.yaml, replace the example image with the image you pushed:
k8s/deployment.yaml
Apply the manifest:
Inspect the deployment and its pods:
When the deployment is ready, the operator registers it with Restate Cloud and handles service versioning.
Inspect the deployment status and application logs:
TypeScript and Go use an in-process tunnel. Each application pod opens an outbound connection directly to Restate Cloud. The operator injects the Cloud environment, region, signing key, and versioned tunnel name. Your deployment mounts the tunnel authentication Secret.Java, Kotlin, Python, and Rust use the standalone tunnel managed by the RestateCloudEnvironment. The application keeps its normal HTTP listener. The operator creates a Kubernetes Service for that endpoint, and the standalone tunnel forwards invocations to it. This mode also supports Knative deployments.The tunnel client opens an outbound connection to Restate Cloud, so your service needs no public ingress and no inbound ports.
  1. Connect. The tunnel client resolves the tunnel servers for your region and dials out to them, authenticating with your API key. It holds one connection per tunnel server and redials on its own if a connection drops.
  2. Register. Each connection is keyed by your environment and tunnel name. The deployment URL you register encodes both, plus the address the tunnel client should forward to.
  3. Invoke. Restate Cloud sends discovery and invocation requests for that deployment to the tunnel server, which streams them down one of the connections registered under that tunnel name.
  4. Forward. The tunnel client forwards each request to your service’s endpoint inside your network, and responses stream back over the same connection.
Requests are signed with your environment’s request identity key, so your service only accepts requests that genuinely came from your environment.Run several tunnel clients with the same tunnel name for redundancy. The tunnel server load balances invocations across every connection registered under that name, so a client going away does not take the deployment offline.
Restate Cloud reaching a private service through a tunnel client that holds an outbound connection

Deploy a service to self-hosted Restate

Register your service with a self-hosted Restate environment. This example uses a RestateCluster resource named restate in the same Kubernetes cluster, so no Restate Cloud tunnel or Cloud API key is required.
To deploy a self-hosted Restate cluster with the operator, see Deploy Restate on Kubernetes.
1

Install the Restate Operator

Install the Restate Operator via Helm:
To install the operator, you need permission to create namespaces and CRDs.
2

Create the RestateDeployment

Create a RestateDeployment that references your RestateCluster named restate:
service-deployment.yaml
Once applied, the Restate Operator registers your service and handles versioning.
Read the RestateDeployment documentation, or view the full specification as Pkl or YAML.
3

Invoke your service

Go to the Restate UI’s Playground and send a request to your service.

Knative Deployment

The RestateDeployment CRD can use Knative Serving instead of ReplicaSets. The operator then manages the Knative Configurations, Routes, Restate registration, and service versions while Knative provides request-based autoscaling and scale-to-zero. Install Knative Serving before applying a Knative-mode RestateDeployment:
The example registers with a RestateCluster named restate. To register with Restate Cloud or BYOC, use cloud: my-cloud-env instead. The optional knative.tag controls deployment identity:
  • Omit the tag to use the pod template hash and create a new version for every template change.
  • Change the tag to create and register a new version while the previous version drains.
  • Not recommended / dangerous: Keep the same tag for an in-place update to the existing Restate deployment. Only do this when the change is compatible with invocations already assigned to that deployment.
The container port must be named h2c for HTTP/2 or http1 for HTTP/1.1. In-process Restate Cloud tunnels are not supported in Knative mode.

Horizontal scaling and load balancing

You can scale your services horizontally by running multiple pod replicas. With an in-process tunnel, the tunnel server balances invocations across replicas without an additional load balancer in the invocation path. For autoscaling configuration and examples, see the Restate Operator documentation:

Direct Kubernetes deployments

Use the Restate Operator when you want automatic registration, version management, and operator-managed scaling.
If you prefer not to use the Restate Operator, you can deploy your Restate services directly using standard Kubernetes Deployment and Service resources. A Kubernetes Deployment of more than one replica is generally appropriate, and a Kubernetes Service is used to provide a stable DNS name and IP for the pods. Here is an example manifest with a single pod in Kubernetes:
Once you have applied the manifest, register the service at http://<service>.<namespace>:9080. ⚠️ Note that this setup will not account for keeping around old code versions, so updating your code can break in-flight invocations. Check the versioning documentation for more information.
Restate services also run on a plain Knative Service, without the operator. There are no special container requirements beyond naming the port h2c:
Or as a manifest:
The service is reachable at http://<service-name>.<namespace>, but to handle versioning it is preferable to register the revision URL, such as http://<service-name>-0001.<namespace>, as part of your deployment workflow.Knative exposes the service through the Ingress by default. Restate does not require this, so you can pass --cluster-local to the creation command to disable it.
Learn more in this blog post and the Go example.