Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ jobs:
basic_usage.py
command_stdin.py
custom_image.py
dockerfile_launch.py
named_sandbox.py
network_policy.py
port_forwarding.py
Expand Down
21 changes: 21 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ tunnels. The project overview and deployment quick start are in
- `sdk/python/` - AKernel Python SDK and CLI.
- `sdk/python/akernel_sdk/` - SDK implementation for `Sandbox`, commands,
filesystem, PTY support, instance plumbing, and CLI helpers.
- `sdk/python/akernel_sdk/_dockerfile_launch.py` - lightweight public
Dockerfile direct-launch configuration, independent of the parser and backend.
- `sdk/python/examples/` - maintained AKernel SDK examples.
- `sdk/python/tests/` - maintained AKernel SDK tests.
- `src/yuanrong/` - pinned openYuanRong mirror checkout, including its
Expand Down Expand Up @@ -347,6 +349,25 @@ Keep public `Sandbox`, `Commands`, `Filesystem`, and value types independent
of both native packages; all native conversions belong under
`akernel_sdk._backends`.

Dockerfile direct launch is a supported AKernel SDK capability through
`DockerContext` and
`Sandbox(dockerfile=DockerfileLaunch(context=..., auto_start_cmd=..., run_timeout=...))`.
The capability will remain available. Its documented strict subset evolves
incrementally with production experience, while unsupported inputs continue to
fail closed. The specific API surface may evolve; material changes require
documentation and migration guidance. Read
[`sdk/python/docs/launch-from-dockerfile.md`](./sdk/python/docs/launch-from-dockerfile.md)
before changing this path. `FROM` supplies only the root filesystem; inherited
OCI configuration is not applied. Runtime availability and compatibility remain
backend-owned. `DockerContext.walk()` exposes public structured file and
directory entries, including modes and empty directories; context transfer must
remain backend-neutral, reject unsafe manifests and unsupported syntax
fail-closed, and preserve documented Dockerfile-specific ignore-file
precedence. Dockerfiles and active or root ignore files remain ordinary context
entries unless the active matcher excludes them. Keep the public types, unit
tests, SDK README, Dockerfile launch guide, and
`examples/dockerfile_launch.py` in sync.

When changing a public SDK method, update its type annotations and docstring,
add or update unit coverage, and keep the SDK README and maintained examples in
sync. Benchmark programs under `sdk/python/benchmarks/` are manual tools and
Expand Down
6 changes: 3 additions & 3 deletions builder/node.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ ARG AKERNEL_RUNTIME_PROFILE=rrt
ARG AKERNEL_ENABLE_KATA=true
ARG SANDBOXD_BUILD_IMAGE=golang:1.25.5-bookworm
ARG DISTILL_FS_BUILD_IMAGE=rust:1.85.0-bookworm
ARG OPEN_YR_VERSION=0.9.7
ARG OPEN_YR_VERSION=0.9.8
ARG OPEN_YR_CORE_WHEEL_URL=
ARG OPEN_YR_CORE_WHEEL_SHA256=
ARG OPEN_YR_RELEASE_BASE_URL=https://github.com/openYuanrong-mirror/yuanrong/releases/download
ARG OPEN_YR_CORE_AMD64_SHA256=0a890db1785e349bfd625844a05059bdd494e32a429cea771cf969f09e3aba2c
ARG OPEN_YR_CORE_ARM64_SHA256=64e14233fcbbb3418311d2f242e164e7be6e7bee0315c7619b18d9c5ddd01a76
ARG OPEN_YR_CORE_AMD64_SHA256=733218f65ca1d46c468d699f4b24bac5a1f749b6328270c3b8c300442df36daa
ARG OPEN_YR_CORE_ARM64_SHA256=34556071bb0b31d6ef0086ec4ae9e6ccd144ddcec1404b39c6ff1c33861ac65b
ARG GVISOR_RELEASE=release-20260706.0
ARG GVISOR_RELEASE_BASE_URL=https://storage.googleapis.com/gvisor/releases
ARG LIBNVIDIA_CONTAINER_VERSION=1.19.1-1
Expand Down
4 changes: 2 additions & 2 deletions builder/runtime.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ ARG PYTHON_311_VERSION=3.11.13
ARG PYTHON_312_VERSION=3.12.11
ARG PYTHON_313_VERSION=3.13.5
ARG PYTHON_314_VERSION=3.14.6
ARG OPEN_YR_VERSION=0.9.7
ARG OPEN_YR_VERSION=0.9.8

FROM ${AKERNEL_RUNTIME_BASE_IMAGE} AS rrt-download

ARG OPEN_YR_VERSION
ARG RRT_RUNTIME_URL=https://github.com/openYuanrong-mirror/yuanrong/releases/download/${OPEN_YR_VERSION}/rrt-runtime-amd64
ARG RRT_RUNTIME_SHA256=c7f7441ed631de564f56c1878b84598a7364ffae040a0e51f6e14a82f6ae31d5
ARG RRT_RUNTIME_SHA256=dbb120370f18de6a9a0b50678f2d76d2a8fc7d40c1983d3ac735140a9cfe838c

RUN apt-get update && \
apt-get install -y --no-install-recommends ca-certificates curl && \
Expand Down
32 changes: 32 additions & 0 deletions sdk/python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ It supports two backends:
- [Port forwarding](#port-forwarding)
- [Reverse tunnels](#reverse-tunnels)
- [Rootfs and mounts](#rootfs-and-mounts)
- [Launch from a Dockerfile](#launch-from-a-dockerfile)
- [Resources and lifecycle](#resources-and-lifecycle)
- [CLI](#cli)
- [Examples and tests](#examples-and-tests)
Expand Down Expand Up @@ -101,6 +102,7 @@ Sandbox(
xpu: str | None = None,
storage_mb: int | None = None,
network_policy: NetworkPolicy | None = None,
dockerfile: DockerfileLaunch | None = None,
)
```

Expand Down Expand Up @@ -410,6 +412,31 @@ OCI images can also be mounted read-only:
mount = Mount(target="/opt/tools", image_url="ubuntu:24.04")
```

## Launch from a Dockerfile

Dockerfile direct launch is a supported AKernel SDK capability and will remain
available. Its documented strict subset evolves incrementally with production
experience; unsupported inputs continue to fail closed. The specific API surface
may evolve, with documentation and migration guidance for material changes. It
is not a general-purpose Docker build.

`FROM` supplies only the root filesystem; inherited OCI configuration is not
applied. Precheck the context, then pass its launch configuration to `Sandbox`:

```python
from akernel_sdk import DockerfileLaunch, LocalDockerContext, Sandbox, check_direct_launch
context = LocalDockerContext("Dockerfile", context_dir=".")
if check_direct_launch(context).direct_launchable:
with Sandbox(dockerfile=DockerfileLaunch(context, run_timeout=300)) as sandbox:
pass
```

`RUN`, `COPY`, and `ADD` run on every launch without a snapshot or cache;
unsupported Dockerfiles must be built externally. Read the complete contract,
security boundaries, and supported syntax in
[the Dockerfile launch guide](./docs/launch-from-dockerfile.md). See the
[runnable example](./examples/dockerfile_launch.py).

## Resources and lifecycle

`resources()` returns stable `NodeInfo` values rather than backend objects:
Expand Down Expand Up @@ -461,6 +488,7 @@ Maintained examples are under [`examples/`](./examples):
- `basic_usage.py`
- `command_stdin.py`
- `custom_image.py`
- `dockerfile_launch.py`
- `gpu_sandbox.py`
- `named_sandbox.py`
- `network_policy.py`
Expand Down Expand Up @@ -501,3 +529,7 @@ not part of the default test suite.
| `Mount` | `target`, one source, and `type` |
| `HttpReverseTunnel` | `target`, `reverse_port`, `listen_port`, `connect_timeout` |
| `NetworkPolicy` | `block_network`, `dns_blacklist` |
| `DockerfileLaunch` | `context`, `auto_start_cmd`, `run_timeout` |
| `DockerContext` | Abstract Dockerfile and build-context source |
| `DockerContextEntry` | `path`, `kind`, `mode` |
| `LocalDockerContext` | Local Dockerfile and context implementation |
26 changes: 26 additions & 0 deletions sdk/python/akernel_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,19 @@
"BackendNotInstalledError",
"UnsupportedBackendFeatureError",
"BackendOperationError",
"DockerContext",
"DockerfileLaunch",
"DockerContextEntry",
"LocalDockerContext",
"parse_dockerfile",
"check_direct_launch",
"apply_dockerfile",
"ParsedDockerfile",
"DockerfileApplyResult",
"DockerfileCheckResult",
"DockerfileBuildError",
"DockerfileParseError",
"BuildInstruction",
]

_LAZY_IMPORTS = {
Expand All @@ -65,6 +78,19 @@
"PtySession": (".pty", "PtySession"),
"PtyError": (".pty", "PtyError"),
"resources": ("._resources", "resources"),
"DockerContext": ("._dockercontext", "DockerContext"),
"DockerfileLaunch": ("._dockerfile_launch", "DockerfileLaunch"),
"DockerContextEntry": ("._dockercontext", "DockerContextEntry"),
"LocalDockerContext": ("._dockercontext", "LocalDockerContext"),
"parse_dockerfile": ("._dockerfile", "parse_dockerfile"),
"check_direct_launch": ("._dockerfile", "check_direct_launch"),
"ParsedDockerfile": ("._dockerfile", "ParsedDockerfile"),
"DockerfileCheckResult": ("._dockerfile", "DockerfileCheckResult"),
"DockerfileParseError": ("._dockerfile", "DockerfileParseError"),
"BuildInstruction": ("._dockerfile", "BuildInstruction"),
"apply_dockerfile": ("._dockerfile_runner", "apply_dockerfile"),
"DockerfileApplyResult": ("._dockerfile_runner", "DockerfileApplyResult"),
"DockerfileBuildError": ("._dockerfile", "DockerfileBuildError"),
}


Expand Down
26 changes: 16 additions & 10 deletions sdk/python/akernel_sdk/_backends/openyuanrong_sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

from __future__ import annotations

import os
from collections.abc import Mapping
from typing import Any

Expand Down Expand Up @@ -217,12 +216,14 @@ def __init__(
self,
sandbox: Any,
spec: SandboxSpec,
connection: Any,
) -> None:
self.id = str(sandbox.id)
self.commands = _CommandsDriver(sandbox.commands)
self.files = _FilesystemDriver(sandbox.files)
self._sandbox = sandbox
self._spec = spec
self._connection = connection
self._terminated = False
self._closed = False

Expand Down Expand Up @@ -255,7 +256,7 @@ def terminate(self) -> None:
# client, so a failed deletion remains retryable after local cleanup.
self.close()
try:
yr_sandbox.Sandbox.delete(self.id)
yr_sandbox.Sandbox.delete(self.id, connection=self._connection)
except Exception as error:
raise _convert_error("terminate sandbox", error) from error
self._terminated = True
Expand Down Expand Up @@ -284,13 +285,13 @@ class OpenYuanRongSandboxBackend:
)

def __init__(self, config: BackendConfig) -> None:
os.environ["YR_SERVER_ADDRESS"] = config.api_endpoint.authority()
os.environ["YR_TLS"] = "1" if config.api_endpoint.use_tls else "0"
os.environ["YR_GATEWAY_ADDRESS"] = config.gateway_endpoint.authority()
os.environ["YR_GATEWAY_TLS"] = (
"1" if config.gateway_endpoint.use_tls else "0"
self._connection = yr_sandbox.ConnectionConfig(
server_address=config.api_endpoint.authority(),
token=config.token,
use_tls=config.api_endpoint.use_tls,
gateway_address=config.gateway_endpoint.authority(),
gateway_use_tls=config.gateway_endpoint.use_tls,
)
os.environ["YR_TOKEN"] = config.token

def _validate(self, spec: SandboxSpec) -> None:
tunnel = spec.reverse_tunnel
Expand Down Expand Up @@ -372,17 +373,22 @@ def create(self, spec: SandboxSpec) -> BackendSession:
node_id=spec.node_id,
xpu=spec.xpu,
storage_mb=spec.storage_mb,
storage_limit_mb=spec.storage_mb or 0,
network=network,
create_timeout=create_timeout,
connection=self._connection,
)
except Exception as error:
raise _convert_error("create sandbox", error) from error
return _Session(sandbox, spec)
return _Session(sandbox, spec, self._connection)

def delete_named(self, name: str) -> None:
sandbox_id = f"{self.namespace}-{name}"
try:
yr_sandbox.Sandbox.delete(sandbox_id)
yr_sandbox.Sandbox.delete(
sandbox_id,
connection=self._connection,
)
except Exception as error:
raise _convert_error(f"delete sandbox {name!r}", error) from error

Expand Down
Loading