Skip to content

Commit 20aca33

Browse files
committed
Improved Getting Started and general docs
1 parent d2321e2 commit 20aca33

File tree

6 files changed

+396
-65
lines changed

6 files changed

+396
-65
lines changed

src/content/docs/containers/get-started.mdx

Lines changed: 259 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,45 +5,284 @@ sidebar:
55
order: 2
66
---
77

8-
In this guide, you will get started with Cloudflare Images and make your first API request.
8+
In this guide, you will deploy a Worker that can make requests to one or more Containers in response to end-user requests.
9+
In this example, each container runs a small webserver written in Go.
10+
11+
Requests are initially handled by the Worker, then passed to container-enabled [Durable Objects](/durable-objects).
12+
Each Durable Object runs alongside a container, manages starting and stopping it, and
13+
can interact with the container through its ports.
14+
15+
In a simple app, the Durable Object may just boot the container and proxy requests to it.
16+
17+
In a more complex app, having container-enabled Durable Objects allows you to route requests to individual stateful container
18+
instances, manage the container lifecycle, pass in custom starting commands and environment variables to containers, run hooks
19+
on container status changes, and more.
20+
21+
This example Worker should give you a sense for simple Container use, and provide a starting point for more complex use cases.
922

1023
## Prerequisites
1124

12-
Before you make your first API request, ensure that you have a Cloudflare Account ID and an API token.
25+
### Get an API Token with the correct permissions
26+
27+
Ensure you have a Cloudflare Account ID and an API token.
28+
29+
Refer to [Find zone and account IDs](/fundamentals/setup/find-account-and-zone-ids/) for help locating
30+
your Account ID and [Create an API token](/fundamentals/api/get-started/create-token/) to learn how to create
31+
an access your API token.
32+
33+
When making your API token, make sure you supply the "Cloudchamber: Edit" and "Workers: Edit" permissions.
34+
35+
{/* NOTE: Change to "Containers: Edit" once this permission exists */}
36+
37+
### Ensure Docker is running locally
38+
39+
In this guide, we will build and push a container image alongside your Worker code. By default, this process uses
40+
Docker to do so. You must have Docker running locally when you run `wrangler deploy`.
41+
42+
If Docker is running properly, the `docker info` command will successfully run. If Docker is not running,
43+
the `docker info` command will hang or return an error including the message "Cannot connect to the Docker daemon".
1344

14-
Refer to [Find zone and account IDs](/fundamentals/setup/find-account-and-zone-ids/) for help locating your Account ID and [Create an API token](/fundamentals/api/get-started/create-token/) to learn how to create an access your API token.
45+
{/* FUTURE CHANGE: Add some image you can use if you don't have Docker running. */}
46+
{/* FUTURE CHANGE: Link to docs on alternative build/push options */}
1547

16-
## Make your first API request
48+
### Ensure Wrangler is Installed
1749

18-
```bash
19-
curl --request POST \
20-
--url https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/images/v1 \
21-
--header 'Authorization: Bearer <API_TOKEN>' \
22-
--header 'Content-Type: multipart/form-data' \
23-
--form file=@./<YOUR_IMAGE.IMG>
50+
You must have the `wrangler` CLI tool installed. See [documentation on installing and updating wrangler](/workers/wrangler/install-and-update/)
51+
for more details.
52+
53+
Currently, you will have to use a custom wrangler build to run `wrangler deploy`. Install it with the following command"
54+
55+
```sh
56+
npm install -g https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/prs/8482/npm-package-wrangler-8482
2457
```
2558

26-
## Enable transformations on your zone
59+
:::note
60+
After running this command, your global `wrangler` command will be overridden.
61+
:::
62+
63+
## Deploy a Container to Workers
64+
65+
Now that your environment is set up, you can write your Worker.
66+
67+
### Get a Template
68+
69+
First, clone the starter template and move into the folder:
70+
71+
{/* FUTURE CHANGE: THIS WILL BE C3 */}
72+
73+
```sh
74+
git clone https://github.com/mikenomitch/containers-starter-go.git
75+
cd containers-starter-go
76+
```
77+
78+
### Deploy with Wrangler
79+
80+
Now, deploy your Worker:
81+
82+
```sh
83+
wrangler deploy
84+
```
85+
86+
When you run this command, several things happen:
87+
88+
- Wrangler builds your image using Docker.
89+
- Wrangler pushes you image to the Cloudchamber Image Registry, which is automatically
90+
integrated with your Cloudflare account.
91+
- Wrangler deploys your Worker, which includes setting up a "Container" for it to interact with.
92+
93+
:::note
94+
The build and push usually take the longest on the first deploy. Future deploys
95+
will go faster by [reusing cached image layers](https://docs.docker.com/build/cache/).
96+
:::
97+
98+
After you deploy your Worker for the first time, you will need to wait several minutes until
99+
it is ready to receive requests. Unlike Workers, Containers take a few minutes to be provisioned.
100+
During this time, requests are sent to the Worker, but calls to the Container will error.
101+
102+
{/* FUTURE CHANGE: Add a command to check status from the CLI */}
103+
104+
### Make requests to Containers
105+
106+
Now, open the URL for your worker. It should look something like `https://container-starter.YOUR_ACCOUNT_NAME.workers.dev`.
107+
108+
If you make requests to the paths `/specific/1` or `/specific/2`, these requests are routed to specific containers.
109+
Each different path after "/specific/" routes to a unique container.
110+
111+
If you make requests to `/lb`, you will load balanace requests to one of 3 containers chosen at random.
112+
113+
You can confirm this behavior by reading the output of each request.
114+
115+
## Understanding the Code
116+
117+
### Worker Config
118+
119+
First, wrangler config sets up a container and a Durable Object that will run alongside it.
27120

28-
You can dynamically optimize images that are stored outside of Cloudflare Images and deliver them using [transformation URLs](/images/transform-images/transform-via-url/).
121+
```toml
122+
[[containers]]
123+
instances = 10
124+
name = "hello-containers"
125+
class_name = "MyContainer"
126+
image = "./Dockerfile"
29127

30-
Cloudflare will automatically cache every transformed image on our global network so that you store only the original image at your origin.
128+
[[durable_objects.bindings]]
129+
name = "MY_CONTAINER"
130+
class_name = "MyContainer"
31131

32-
To enable transformations on your zone:
132+
[[migrations]]
133+
tag = "v1"
134+
new_sqlite_classes = ["MyContainer"]
135+
```
136+
137+
Important points about this config:
33138

34-
1. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/login) and select your account.
35-
2. Go to **Images** > **Transformations**.
36-
3. Go to the specific zone where you want to enable transformations.
37-
4. Select **Enable for zone**. This will allow you to optimize and deliver remote images.
139+
- `image` points to a Dockerfile or to a directory containing a Dockerfile.
140+
- `class_name` must be a Durable Object class name.
141+
- `instances` declares the maximum number of simultaneously running container instances
142+
that will run.
143+
- The Durable Object must use `new_sqlite_classes` not `new_classes`.
38144

145+
{/* FUTURE CHANGE: Change instances to max_instances */}
39146
:::note
147+
`instances` **does not** mean the number of instances that will automatically run, it means the maximum number.
148+
149+
We plan to make `instances` optional some time during the Closed Beta period.
150+
:::
151+
152+
### The Container Image
153+
154+
The container image itself has to run on the `linux/amd64` architecture, but aside from that has few limitations.
40155

41-
With **Resize images from any origin** unchecked, only the initial URL passed will be checked. Any redirect returned will be followed, including if it leaves the zone, and the resulting image will be transformed.
156+
In this case, it is a simple Golang server that responds to requests on port 8080:
157+
158+
{/* TODO: Add reference about env variables that are auto-inserted */}
159+
160+
```go
161+
func handler(w http.ResponseWriter, r *http.Request) {
162+
country := os.Getenv("CLOUDFLARE_COUNTRY_A2")
163+
location := os.Getenv("CLOUDFLARE_LOCATION")
164+
region := os.Getenv("CLOUDFLARE_REGION")
165+
166+
fmt.Fprintf(w, "Hi, I'm a container running in %s, %s, which is part of %s ", location, country, region)
167+
}
168+
169+
func main() {
170+
http.HandleFunc("/", handler)
171+
log.Fatal(http.ListenAndServe(":8080", nil))
172+
}
173+
```
42174

175+
For communication between the container and Workers, you will likely want to listen on
176+
a specific port.
177+
178+
:::note
179+
After deploying the example code, feel free to replace the provided image with one of your own.
43180
:::
44181

182+
### Worker code
183+
184+
First note the Durable Object `MyContainer`:
185+
186+
```js
187+
export class MyContainer extends DurableObject {
188+
constructor(ctx, env) {
189+
super(ctx, env);
190+
ctx.blockConcurrencyWhile(async () => {
191+
await startAndWaitForPort(ctx.container, OPEN_CONTAINER_PORT);
192+
});
193+
}
194+
195+
async fetch(request) {
196+
return await proxyFetch(this.ctx.container, request, OPEN_CONTAINER_PORT);
197+
}
198+
}
199+
```
200+
201+
When the Durable Object instance is created, it starts a new container
202+
using the `startAndWaitForPort` method, which calls `this.ctx.container.start`.
203+
204+
The `fetch` method calls the `proxyFetch` helper, which passes a request
205+
to the server running on the open port.
206+
207+
In this case, the Workers request will be proxied to the Golang server
208+
listeining on port 8080.
209+
210+
{/* FUTURE CHANGE: Document the API for this.ctx.container in reference! */}
211+
45212
:::note
213+
Currently, the container is stopped when the Durable Object is put to sleep.
214+
215+
We plan to add the ability to keep the container alive for a configurable amount of time
216+
after the most recent request. This will be added soon.
217+
:::
218+
219+
In the Worker's main `fetch` handler, Container-enabled Durable Objects are
220+
launched in one of two ways:
221+
222+
- Making requests to `/specific/` passes requests to a new container for
223+
each path. This is done by spinning up a new Durable Object and Container. You may note
224+
that the first request to a new path takes longer than subsequent requests, this is
225+
because a new container is booting.
226+
227+
```js
228+
if (pathname.startsWith("/specific/")) {
229+
// In this case, each unique pathname with spawn a new container
230+
let id = env.MY_CONTAINER.idFromName(pathname);
231+
let stub = env.MY_CONTAINER.get(id);
232+
return await stub.fetch(request);
233+
}
234+
```
235+
236+
- Making requests to `/lb` will load balance requests across several containers.
237+
This uses a simple `loadBalance` helper method currently, which picks an ID at random
238+
from a set number (defined with `LB_INSTANCES`), then routes to that Durable Object instance.
239+
240+
```js
241+
if (pathname.startsWith("/lb")) {
242+
let container = await loadBalance(env.MY_CONTAINER, LB_INSTANCES);
243+
return await container.fetch(request);
244+
}
245+
```
246+
247+
This allows for multiple ways of using Containers:
248+
249+
- If you simply want to send requests to many stateless and interchangeable containers,
250+
you should load balance.
251+
- If you have stateful services or need individually addressable
252+
containers, you should request specific Durable Objects.
253+
- If you are running short-lived jobs, want fine-grained control over the container
254+
lifecycle, want to parameterize container entrypoint or env vars, or
255+
want to chain together multiple container calls, you should request specific
256+
Durable Objects.
46257

47-
If you are using transformations in a Worker, you need to include the appropriate logic in your Worker code to prevent resizing images from any origin. Unchecking this option in the dash does not apply to transformation requests coming from Cloudflare Workers.
258+
:::note
259+
Currently, routing requests to one of many interchangeable Container instances is accomplished
260+
with a function like `loadBalance`, written in the user's code.
48261

262+
We will add official first-party mechanisms for scaling and load-balanced routing soon.
49263
:::
264+
265+
## View Containers in your Dashboard
266+
267+
The Containers Dashboard shows you helpful information about your Containers, including:
268+
269+
- Status and Health
270+
- Metrics
271+
- Logs
272+
273+
After launching your Worker, navigate to the Containers Dashboard
274+
by clicking on "Containers" under "Workers & Pages" in your sidebar.
275+
276+
{/* TODO: Add note about navigation via the Worker once this is done */}
277+
278+
## Next Steps
279+
280+
To do more:
281+
282+
- Modify the image by changing the Dockerfile and calling `wrangler deploy`
283+
- Review our [Examples](/containers/examples) for more inspiration
284+
- Get [more information on the Containers Closed Beta](/containers/reference/closed-beta-info)
285+
286+
{/* Point to other examples */}
287+
{/* Reference Materials and more docs */}
288+
{/* Private beta information */}

0 commit comments

Comments
 (0)