Skip to content

Commit

Permalink
Add jupyter notebook sandbox example (#938)
Browse files Browse the repository at this point in the history
* Add jupyter notebook sandbox example

* minor text fixes, πŸ–οΈ

* add headers

---------

Co-authored-by: Charles Frye <[email protected]>
  • Loading branch information
pawalt and charlesfrye authored Oct 21, 2024
1 parent d849a86 commit 7aafb61
Showing 1 changed file with 115 additions and 0 deletions.
115 changes: 115 additions & 0 deletions 13_sandboxes/jupyter_sandbox.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# ---
# cmd: ["python", "13_sandboxes/jupyter_sandbox.py"]
# tags: ["use-case-sandboxed-code-execution"]
# pytest: false
# ---

# # Run a Jupyter notebook in a Modal Sandbox

# This example demonstrates how to run a Jupyter notebook in a Modal
# [Sandbox](https://modal.com/docs/guide/sandbox).

# ## Setting up the Sandbox

import json
import secrets
import time
import urllib.request

import modal

# All Sandboxes are associated with an App. We look up our app by name, creating it if it doesn't exist.

app = modal.App.lookup("example-jupyter", create_if_missing=True)

# We define a custom Docker image that has Jupyter and some other dependencies installed.
# Using a pre-defined image allows us to avoid re-installing packages on every Sandbox startup.

image = (
modal.Image.debian_slim(python_version="3.12").pip_install("jupyter~=1.1.0")
# .pip_install("pandas", "numpy", "seaborn") # Any other deps
)

# ## Starting a Jupyter server in a Sandbox

# Since we'll be exposing a Jupyter server over the Internet, we need to create a password.
# We'll use `secrets` from the standard library to create a token
# and then store it in a Modal [Secret](https://modal.com/docs/guide/secrets).

token = secrets.token_urlsafe(13)
token_secret = modal.Secret.from_dict({"JUPYTER_TOKEN": token})

# Now, we can start our Sandbox. Note our use of the `encrypted_ports` argument, which
# allows us to securely expose the Jupyter server to the public Internet. We use
# `modal.enable_output()` to print the Sandbox's image build logs to the console.

JUPYTER_PORT = 8888

print("πŸ–οΈ Creating sandbox")

with modal.enable_output():
sandbox = modal.Sandbox.create(
"jupyter",
"notebook",
"--no-browser",
"--allow-root",
"--ip=0.0.0.0",
f"--port={JUPYTER_PORT}",
"--NotebookApp.allow_origin='*'",
"--NotebookApp.allow_remote_access=1",
encrypted_ports=[JUPYTER_PORT],
secrets=[token_secret],
timeout=5 * 60, # 5 minutes
image=image,
app=app,
)

print(f"πŸ–οΈ Sandbox ID: {sandbox.object_id}")

# ## Communicating with a Jupyter server

# Next, we print out a URL that we can use to connect to our Jupyter server.
# Note that we have to call [`Sandbox.tunnels`](/docs/reference/modal.Sandbox#tunnels)
# to get the URL. The Sandbox is not publicly accessible until we do so.

tunnel = sandbox.tunnels()[JUPYTER_PORT]
url = f"{tunnel.url}/?token={token}"
print(f"πŸ–οΈ Jupyter notebook is running at: {url}")

# Jupyter servers expose a [REST API](https://jupyter-server.readthedocs.io/en/latest/developers/rest-api.html)
# that you can use for programmatic manipulation.

# For example, we can check the server's status by
# sending a GET request to the `/api/status` endpoint.


def is_jupyter_up():
try:
response = urllib.request.urlopen(
f"{tunnel.url}/api/status?token={token}"
)
if response.getcode() == 200:
data = json.loads(response.read().decode())
return data.get("started", False)
except Exception:
return False
return False


# We'll now wait for the Jupyter server to be ready by hitting that endpoint.

timeout = 60 # seconds
start_time = time.time()
while time.time() - start_time < timeout:
if is_jupyter_up():
print("πŸ–οΈ Jupyter is up and running!")
break
time.sleep(1)
else:
print("πŸ–οΈ Timed out waiting for Jupyter to start.")


# You can now open this URL in your browser to access the Jupyter notebook!

# When you're done, terminate the sandbox using your [Modal dashboard](https://modal.com/sandboxes)
# or by running `Sandbox.from_id(sandbox.object_id).terminate()`.

0 comments on commit 7aafb61

Please sign in to comment.