> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lazycloud.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Pods

> A container command, such as a model server, that you deploy under an app and scale by hand.

A pod fits when you already have a command or image to run. For Python you want
to call as a function or serve over HTTP, an [endpoint](/concepts/endpoints)
needs less setup.

## Define a pod

Save this as `tools.py`:

```python theme={null}
from lazycloud import App, Image

app = App("tools")

web = app.pod(
    name="web",
    image=Image(python_version="3.12"),
    command=["python", "-m", "http.server", "8080"],
    ports={"http": 8080},
    cpu=0.5,
    memory="256Mi",
    authorized=True,
)
```

Pods are public by default. `authorized=True` makes the URL take the same
bearer token as an [endpoint](/concepts/endpoints#authentication).

## Deploy it

`lazycloud deploy` runs the pod in the cloud and prints its URL. The
[vLLM example](/examples/openai-compatible-llm) deploys a model server this way.

```bash theme={null}
uv run lazycloud deploy tools:web
```

A deployed pod runs one container while it has connections and stops it after
`keep_warm` seconds idle, 600 by default. `keep_warm=-1` keeps one up at all
times, which suits a model server that can't wait for a cold start. Pods don't
autoscale, so more containers means a count:

```bash theme={null}
uv run lazycloud deployment scale web --containers 2
```

The count holds until the next `scale`, and `web.scale(n)` does the same from
Python.

## Create an instance on demand

A pod can also run once without a deployment. With an
[access token](/platform/auth#ci-and-scripts) in `LAZYCLOUD_TOKEN`, this starts
an instance, fetches the directory listing, and stops it:

```python theme={null}
import os
import urllib.request

from tools import web

instance = web.create()
try:
    request = urllib.request.Request(
        instance.url,
        headers={"Authorization": f"Bearer {os.environ['LAZYCLOUD_TOKEN']}"},
    )
    with urllib.request.urlopen(request, timeout=60) as response:
        print(response.read().decode())
finally:
    instance.terminate()
```

`web.run("python", "--version")` starts one with a different command. An
instance has a `url` and `terminate()`, and lives for `keep_warm` seconds unless
`timeout_seconds` says otherwise.

## Pod options

| Option                                   | What it does                                                            |
| ---------------------------------------- | ----------------------------------------------------------------------- |
| `command`, `ports`                       | What runs, and the named ports it listens on, such as `{"http": 8080}`. |
| `health_check_path`, `health_check_port` | An HTTP probe that must pass before traffic arrives.                    |
| `block_network`, `allow_list`            | Cut outbound access, or limit it to CIDR ranges.                        |
| `checkpoint_enabled`                     | Allow checkpoints, gated by `checkpoint_readiness_path` and `_port`.    |
| `docker_enabled`                         | Give the pod its own Docker daemon.                                     |

`env`, `secrets`, `volumes`, and `machine` work as on every workload, and
`web.shell()` opens a shell in a pod container.

### TCP connections

`tcp=True` exposes a raw TCP port at a `tls://hostname:port` address. Clients
connect with TLS and send that hostname as SNI. TCP pods are always public, so
the server authenticates its own clients.

```python theme={null}
import socket
import ssl
from urllib.parse import urlsplit

from lazycloud import App, Image

app = App("tcp_example")
tcp_server = app.pod(
    name="tcp-web",
    image=Image(python_version="3.12"),
    command=["python", "-m", "http.server", "8080"],
    ports={"http": 8080},
    tcp=True,
    authorized=False,
)

deployment = tcp_server.deploy()
address = urlsplit(deployment.invoke_url)
with socket.create_connection((address.hostname, address.port)) as connection:
    with ssl.create_default_context().wrap_socket(
        connection, server_hostname=address.hostname
    ) as stream:
        stream.sendall(b"GET / HTTP/1.0\r\n\r\n")
        print(stream.recv(1024))
```

## Stop and clean up

```bash theme={null}
uv run lazycloud deployment stop web
uv run lazycloud deployment delete web
```

`stop` keeps the definition and `delete` removes it, like `web.pause()` and
`web.delete()` in Python. A running deployment replaces any container you stop
by hand, so stopping the deployment is what keeps a pod down.

## Shared settings

[Images](/concepts/images), [resources](/concepts/resources), and
[scaling](/concepts/scaling).
