INTEGRITY Cloudflare Docs

Getting started

In this guide, you will deploy a Worker that can make requests to one or more Containers in response to end-user requests. In this example, each container runs a small webserver written in Go.

This example Worker should give you a sense for simple Container use, and provide a starting point for more complex use cases.

Prerequisites

Ensure Docker is running locally

In this guide, we will build and push a container image alongside your Worker code. By default, this process uses Docker to do so.

You must have Docker running locally when you run wrangler deploy. For most people, the best way to install Docker is to follow the docs for installing Docker Desktop. Other tools like Colima may also work.

You can check that Docker is running properly by running the docker info command in your terminal. If Docker is running, the command will succeed. If Docker is not running, the docker info command will hang or return an error including the message "Cannot connect to the Docker daemon".

Deploy your first Container

Run the following command to create and deploy a new Worker with a container, from the starter template:

npm create cloudflare@latest -- --template=cloudflare/templates/containers-template

When you want to deploy a code change to either the Worker or Container code, you can run the following command using Wrangler CLI:

npx wrangler deploy

On deploy, Wrangler uploads your Worker, builds and pushes the container image with Docker, and updates container instances on Cloudflare's network. The first build and push usually take the longest. Later deploys reuse cached image layers.

Check deployment status

After deploying, list containers in your account and their status:

npx wrangler containers list

List images in the Cloudflare Registry:

npx wrangler containers images list

Make requests to Containers

Open the URL for your Worker. It should look like https://hello-containers.<YOUR_WORKERS_SUBDOMAIN>.workers.dev.

Read the response body to confirm which instance handled the request. If the Worker responds but container routes still error, wait for provisioning, then check Containers logs in the dashboard.

Understanding the Code

Now that you've deployed your first container, let's explain what is happening in your Worker's code, in your configuration file, in your container's code, and how requests are routed.

Configuration

Your Wrangler configuration file defines the configuration for both your Worker and your container:

{
	"containers": [
		{
			"max_instances": 10,
			"class_name": "MyContainer",
			"image": "./Dockerfile",
		},
	],
	"durable_objects": {
		"bindings": [
			{
				"name": "MY_CONTAINER",
				"class_name": "MyContainer",
			},
		],
	},
	"migrations": [
		{
			"tag": "v1",
			"new_sqlite_classes": ["MyContainer"],
		},
	],
}
[[containers]]
max_instances = 10
class_name = "MyContainer"
image = "./Dockerfile"

[[durable_objects.bindings]]
name = "MY_CONTAINER"
class_name = "MyContainer"

[[migrations]]
tag = "v1"
new_sqlite_classes = [ "MyContainer" ]

Important points about this config:

The Container Image

Your container image must be able to run on the linux/amd64 architecture, but aside from that, has few limitations.

In the example you just deployed, it is a simple Golang server that responds to requests on port 8080 using the MESSAGE environment variable that will be set in the Worker and an auto-generated environment variable CLOUDFLARE_DEPLOYMENT_ID.

func handler(w http.ResponseWriter, r *http.Request) {
	message := os.Getenv("MESSAGE")
	instanceId := os.Getenv("CLOUDFLARE_DEPLOYMENT_ID")

	fmt.Fprintf(w, "Hi, I'm a container and this is my message: %s, and my instance ID is: %s", message, instanceId)
}

Worker code

Container Configuration

First note MyContainer which extends the Container class:

export class MyContainer extends Container {
  defaultPort = 8080;
  sleepAfter = '10s';
  envVars = {
    MESSAGE: 'I was passed in via the container class!',
  };

  override onStart() {
    console.log('Container successfully started');
  }

  override onStop() {
    console.log('Container successfully shut down');
  }

  override onError(error: unknown) {
    console.log('Container error:', error);
  }
}

This defines basic configuration for the container:

The Container class itself extends DurableObject, so your subclass has access to the full Durable Object API. The Durable Object handles routing, lifecycle, and persistent state, while the container process runs your image inside a Linux VM. This means you can use this.ctx.storage to persist data that survives container restarts and resides close to the container itself.

Refer to the Container class reference and the low-level Durable Object container API for more details.

Routing to Containers

When a request enters Cloudflare, your Worker's fetch handler is invoked. This is the code that handles the incoming request. The fetch handler in the example code, launches containers in two ways, on different routes:

This allows for multiple ways of using Containers:

View Containers in your Dashboard

The Containers Dashboard shows you helpful information about your Containers, including:

After launching your Worker, go to the Containers Dashboard by selecting Workers & Pages > Containers in the dashboard sidebar.

Next Steps

To do more: