Skip to content

Commit d9607fd

Browse files
adding the python snapshot video tutorial (#2934)
1 parent 04cb953 commit d9607fd

File tree

2 files changed

+261
-0
lines changed

2 files changed

+261
-0
lines changed

examples/_data.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,11 @@ export const sidebar = [
393393
href: "/examples/snapshots_tutorial/",
394394
type: "example",
395395
},
396+
{
397+
title: "Boot a Python environment with snapshots",
398+
href: "/examples/snapshot_python_video/",
399+
type: "video",
400+
},
396401
{
397402
title: "Boot a Python environment with snapshots",
398403
href: "/examples/snapshot_python_tutorial/",

examples/videos/snapshot_python.md

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
---
2+
title: "Safe Cloud Code Execution with Snapshots"
3+
description: "Deno Sandbox lets you spin up isolated cloud VMs programmatically. With the snapshots feature, you can pre-install an entire environment once and boot it without waiting for installs every time after."
4+
url: /examples/snapshot_python_video/
5+
videoUrl: https://youtu.be/mASEjxpuDTM
6+
layout: video.tsx
7+
---
8+
9+
## Video description
10+
11+
Deno Sandbox lets you spin up isolated cloud VMs programmatically. With the
12+
snapshots feature, you can pre-install an entire environment once and boot it
13+
without waiting for installs every time after.
14+
15+
In this video we show you the snapshot workflow end to end:
16+
17+
- Create a cloud volume and boot a sandbox
18+
- Install Python, and required packages and build tools
19+
- Snapshot the volume — your environment is now frozen and reusable
20+
- Boot fresh sandboxes from that snapshot instantly, with everything
21+
pre-installed
22+
23+
As a demo we run a live interactive Mandelbrot fractal explorer. An HTTP server
24+
deployed entirely inside the sandbox, the code never touching the host machine.
25+
26+
This is the foundation for safe execution of AI-generated code, user-submitted
27+
scripts, or any workload you want fully isolated and reproducible.
28+
29+
## Transcript and code
30+
31+
Python is everywhere - data science, AI, scripting, web apps, it's the language
32+
everyone reaches for. But there's a problem that you tend to hit fast. Python
33+
environments can be a mess; you've got system Python fighting with virtual
34+
environments, packages that need native build tools. It can be a whole thing.
35+
36+
Now, imagine you want to run Python code that you didn't write yourself. Maybe
37+
it is AI generated. Maybe it's from a user. Maybe it's just experimental. You
38+
really don't want that touching your machine.
39+
40+
Today, I'm going to show you how to spin up a fully isolated cloud sandbox with
41+
Python pre-installed. We're going to run a Numpy powered Mandelbrot fractal
42+
explorer in it and serve it as a live web app, all with about 60 lines of
43+
TypeScript, and your machine will never run a single line of Python. Let's get
44+
into it.
45+
46+
### Initialize a basic Deno project
47+
48+
```sh
49+
deno init my-snapshot-project
50+
cd my-snapshot-project
51+
deno add jsr:@deno/sandbox
52+
```
53+
54+
This is a really basic Deno project. The only dependency that we're going to use
55+
is the Deno Sandbox SDK from JSR. That's the SDK for creating and managing cloud
56+
sandboxes programmatically. We're going to write two TypeScript files.
57+
58+
`setup_python.ts`: We're going to run this one time to create our sandbox,
59+
install Python, and a bunch of useful packages, and then snapshot.
60+
61+
`use_python.ts`: The script that we're going to run any time we want to actually
62+
use the Python environment inside our sandbox.
63+
64+
This two-step pattern is the whole point. We do the heavy lifting once, then we
65+
reuse that result forever. It's kind of the same idea as a Docker image or a VM
66+
snapshot. They can be expensive and slow to build, but they're cheap and quick
67+
to use.
68+
69+
### Setting up a Snapshot
70+
71+
So, let's take a look at Setting up a Snapshot our setup python.ts file. We
72+
create a client with the Deno Sandbox SDK.
73+
74+
```ts title="setup_python.ts"
75+
import { SandboxClient } from "@deno/sandbox";
76+
const client = new SandboxClient();
77+
78+
async function initSandbox() {
79+
// ... we'll fill this in next
80+
}
81+
```
82+
83+
Then we create a volume with 10 gigs of space. And I'm using the `ord` region,
84+
but you can pick any region. The region just determines where the sandbox runs.
85+
The closer to you, the lower the latency.
86+
87+
```ts title="setup_python.ts (cont.)"
88+
const volume = await client.volumes.create({
89+
region: "ord",
90+
slug: "fun-with-python",
91+
capacity: "10GB",
92+
});
93+
```
94+
95+
We're then going to boot a sandbox with that volume as its root file system.
96+
Notice the await using syntax here. That's JavaScript's explicit resource
97+
management. When this scope exits, the sandbox automatically tears itself down
98+
and we never have to think about the cleanup ourselves.
99+
100+
```ts title="setup_python.ts (cont.)"
101+
await using sandbox = await client.sandboxes.create({
102+
region: "ord",
103+
root: volume.slug,
104+
});
105+
```
106+
107+
Inside the sandbox, we're going to run our setup commands. Firstly, we've got
108+
apt-get update, followed by installing Python 3, Python 3 pip, Python 3 VMv,
109+
Python 3D dev, and build essential. That last one is important. It gives us the
110+
compiler that we're going to need for the packages that ship native extensions.
111+
112+
Then we're going to install our packages. We've got requests, httpx, numpy,
113+
pandas, python.m and we use the break system packages flag because inside this
114+
sandbox, we own the whole system. So there's no reason to fight pip's usual
115+
guard rails. Finally, we can verify that everything is in place by printing the
116+
Python and pip version.
117+
118+
```ts title="setup_python.ts (cont.)"
119+
await sandbox.sh`sudo apt-get update -qq`;
120+
await sandbox
121+
.sh`sudo apt-get install -y python3 python3-pip python3-venv python3-dev build-essential`;
122+
123+
await sandbox.sh`sudo pip3 install --break-system-packages \
124+
requests \
125+
httpx \
126+
numpy \
127+
pandas \
128+
python-dotenv`;
129+
130+
console.log("Verifying Python installation...");
131+
132+
await sandbox.sh`python3 --version`;
133+
await sandbox.sh`pip3 --version`;
134+
135+
return volume.id;
136+
```
137+
138+
Once that's all done, we snapshot the volume with `client.volumes.snapshot`,
139+
giving it the volume ID and the slug for our snapshot.
140+
141+
```ts title="setup_python.ts (cont.)"
142+
const volumeId = await initSandbox();
143+
144+
console.log("Snapshotting the volume...");
145+
146+
const snapshot = await client.volumes.snapshot(volumeId, {
147+
slug: "fun-with-python-snapshot",
148+
});
149+
150+
console.log("Created Python snapshot " + snapshot.id);
151+
```
152+
153+
To run this script, we're going to use the dino run command with the allow net
154+
and allow env permissions set. And then we're done. We never need to run that
155+
again.
156+
157+
```sh
158+
deno run -N -E setup_python.ts
159+
```
160+
161+
### Booting from a Snapshot
162+
163+
Now, let's take a look at our `use_python.ts`. First of all, we're going to
164+
create a sandbox from the snapshot that we just set up. We don't need any
165+
installation step here. The snapshot already has everything. We're going to
166+
expose port 8000 and we'll give it a 30 minute timeout.
167+
168+
```ts title="use_python.ts (cont.)"
169+
await using sandbox = await client.sandboxes.create({
170+
region: "ord",
171+
root: "fun-with-python-snapshot",
172+
port: 8000,
173+
timeout: "30m",
174+
});
175+
```
176+
177+
Then we're going to use `sandbox.fs.writeTextFile` to drop our Python app
178+
directly into the sandbox file system at a temporary location. This is a nice
179+
clean way to get code into a sandbox without messing with shell escaping. We are
180+
just passing it a TypeScript string.
181+
182+
```ts title="use_python.ts (cont.)"
183+
const appCode = `# Python app code goes here`;
184+
185+
await sandbox.fs.writeTextFile("/tmp/app.py", appCode);
186+
```
187+
188+
The
189+
[Python app itself](https://github.com/denoland/tutorial-with-snapshot/blob/7b8e5331ab22968a7fc52dc84e1613072c7494d1/use_python.ts#L18-L131)
190+
is a self-contained HTTP server. You can take the code from the repo and paste
191+
it into the `appCode` string.
192+
193+
```ts title="use_python.ts (cont.)"
194+
const p = await sandbox.sh`python3 /tmp/app.py`.spawn();
195+
196+
console.log("\nMandelbrot Explorer running at", sandbox.url);
197+
198+
await p.output();
199+
```
200+
201+
`sandbox.url` gives us a public URL where port 8000 is reachable. `p.output()`
202+
keeps the script alive for the duration.
203+
204+
Now, let's take a look at what we're actually running inside the sandbox. The
205+
Python app uses NumPy to compute the Mandelbrot set. That's just a classic
206+
fractal where you interactively apply z= z^ 2 + c across a grid of complex
207+
numbers and then you count how many steps it takes each point to escape to
208+
infinity. NumPy can do this really fast and the result is rendered as colored
209+
block characters based on their escape time ranging from electric blue through
210+
to green through to deep red. And points that never escape are colored in solid
211+
black.
212+
213+
Run the `use_python.ts` script with
214+
215+
```sh
216+
deno run -A use_python.ts
217+
```
218+
219+
and open the URL in your browser.
220+
221+
If we take a look at what's actually rendered in the browser, we can see we've
222+
got a nice interactive app here. Each nav button is just a link with query
223+
parameters that shift the viewpoint. When we click zoom in, the server
224+
recomputes the fractal for the new region and returns a new page. No JavaScript,
225+
no websockets, just HTTP. And the whole time we're running this whole thing on a
226+
throwaway Linux VM in the cloud. We're using Python, NumPy, and a web server,
227+
and none of it is running on our own machine.
228+
229+
This pattern is useful well beyond fractals.
230+
231+
- If you're building a tool where Claude or another model is writing Python for
232+
you, you can execute that code in a sandbox and it won't be able to touch your
233+
system or read your files and it won't be able to exfiltrate your secret API
234+
keys.
235+
236+
- If you're building a data analysis tool where users are able to upload their
237+
own Python, same idea. Each user gets an isolated environment with the
238+
packages that they need pre-baked into a snapshot.
239+
240+
- The snapshot is a fixed point in time. Every sandbox that you boot from it is
241+
identical. So we're not going to have to worry about any it works on my
242+
machine or any drift.
243+
244+
- And finally, because NumPy and all the other packages are already in the
245+
snapshot, the snapshot is ready to run in under 200 milliseconds, that's fast
246+
enough to use on demand per request.
247+
248+
All of the code used in this demo is also available as a
249+
[walk through tutorial](/examples/snapshot_python_tutorial/). You'll need a Dino
250+
deploy account to use the sandbox SDK.
251+
252+
If you want to go further, you could of course swap out the fractal for your own
253+
Python script or try adding different packages to the setup.
254+
255+
🦕 The snapshot approach means that you can build up exactly the environment you
256+
want and reuse it as many times as you like.

0 commit comments

Comments
 (0)