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
8 changes: 6 additions & 2 deletions docs/guide/tutorials/bring-your-own-image.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,12 @@ template**.

> Prefer to read a runnable end-to-end example? See
> [`examples/cubesandbox-base-nginx`](https://github.com/TencentCloud/CubeSandbox/tree/master/examples/cubesandbox-base-nginx)
> in the repo — a minimal demo that stacks nginx on top of
> `cubesandbox-base`.
> (nginx on `cubesandbox-base`),
> [`examples/cubesandbox-base-java`](https://github.com/TencentCloud/CubeSandbox/tree/master/examples/cubesandbox-base-java)
> (OpenJDK 17 + Maven on `cubesandbox-base`), or
> [`examples/cubesandbox-base-go`](https://github.com/TencentCloud/CubeSandbox/tree/master/examples/cubesandbox-base-go)
> (Go toolchain on `cubesandbox-base`) in the repo — all are minimal demos
> that add a real service on top of the base image.

### 2.1 Write a Dockerfile

Expand Down
2 changes: 2 additions & 0 deletions docs/guide/tutorials/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Hands-on examples demonstrating various Cube Sandbox use cases. Each example is
| [OpenAI Agents SDK Integration](https://github.com/tencentcloud/CubeSandbox/tree/master/examples/openai-agents-example) | Wire OpenAI Agents SDK's `E2BSandboxClient` to Cube Sandbox. Ships a minimal Shell Agent with Pause/Resume and a full SWE-bench Django debugging agent with streaming + tracing. |
| [OpenAI Agents + Code Interpreter](https://github.com/tencentcloud/CubeSandbox/tree/master/examples/openai-agents-code-interpreter) | Data-analysis Agent running pandas / matplotlib inside a Cube Sandbox. Provides two variants: generic E2B write+exec and Jupyter-kernel Code Interpreter with cross-turn state and auto image capture. |
| [cube-bench](https://github.com/tencentcloud/CubeSandbox/tree/master/examples/cube-bench) | CLI benchmark tool written in Go that measures sandbox creation/deletion latency at configurable concurrency levels. Features a real-time TUI dashboard (Bubbletea/Lipgloss), percentile report (P50/P95/P99), and JSON export. |
| [Java Runtime Template (cubesandbox-base-java)](https://github.com/tencentcloud/CubeSandbox/tree/master/examples/cubesandbox-base-java) | A Cube-ready image stacking OpenJDK 17 LTS + Maven and a tiny JDK-only HTTP server on `cubesandbox-base`. Use it as a starting point for Java code-execution or Java Web-service sandboxes. |
| [Go Runtime Template (cubesandbox-base-go)](https://github.com/tencentcloud/CubeSandbox/tree/master/examples/cubesandbox-base-go) | A Cube-ready image stacking the Go toolchain and a tiny standard-library HTTP server on `cubesandbox-base`. Use it as a starting point for Go code-execution or Go Web-service sandboxes. |

::: tip
All examples share the same environment variable conventions (`E2B_API_URL`, `E2B_API_KEY`, `CUBE_TEMPLATE_ID`). See the [Quick Start](../quickstart.md) guide to set up your Cube Sandbox deployment first.
Expand Down
7 changes: 4 additions & 3 deletions docs/zh/guide/tutorials/bring-your-own-image.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ Cube-Sandbox 与沙箱容器之间的所有通信都是通过容器内的 `envd`
了 `envd`,并附带一个通用入口脚本——后台拉起 `envd`、前台 `exec` 你
提供的 `CMD`。你只需要三步:**写 Dockerfile → 构建推送 → 创建模板**。

> 想看一个能直接跑通的完整示例?可以参考仓库里的
> [`examples/cubesandbox-base-nginx`](https://github.com/TencentCloud/CubeSandbox/tree/master/examples/cubesandbox-base-nginx),
> 里面是把 nginx 叠在 `cubesandbox-base` 上的最小 demo。
> 想看能直接跑通的完整示例?可以参考仓库里的
> [`examples/cubesandbox-base-nginx`](https://github.com/TencentCloud/CubeSandbox/tree/master/examples/cubesandbox-base-nginx)(nginx 叠在 `cubesandbox-base` 上)、
> [`examples/cubesandbox-base-java`](https://github.com/TencentCloud/CubeSandbox/tree/master/examples/cubesandbox-base-java)(OpenJDK 17 + Maven 叠在 `cubesandbox-base` 上)或
> [`examples/cubesandbox-base-go`](https://github.com/TencentCloud/CubeSandbox/tree/master/examples/cubesandbox-base-go)(Go 工具链叠在 `cubesandbox-base` 上),都是在基础镜像上加一个真实服务的最小 demo。

### 2.1 写 Dockerfile

Expand Down
2 changes: 2 additions & 0 deletions docs/zh/guide/tutorials/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
| [OpenAI Agents SDK 集成](https://github.com/tencentcloud/CubeSandbox/tree/master/examples/openai-agents-example) | 将 OpenAI Agents SDK 的 `E2BSandboxClient` 对接 Cube Sandbox。包含最小 Shell Agent(含 Pause/Resume 演示)以及完整的 SWE-bench Django 调试 Agent(流式输出 + 全链路追踪)。 |
| [OpenAI Agents + Code Interpreter](https://github.com/tencentcloud/CubeSandbox/tree/master/examples/openai-agents-code-interpreter) | 在 Cube Sandbox 中运行使用 pandas / matplotlib 的数据分析 Agent,提供通用 E2B(write+exec)与 Jupyter kernel(状态跨轮保留、图像自动捕获)两种执行形态。 |
| [cube-bench](https://github.com/tencentcloud/CubeSandbox/tree/master/examples/cube-bench) | Go 编写的 CLI 压测工具,可在可配置并发数下测量沙箱创建/删除延迟。具备实时 TUI 看板(Bubbletea/Lipgloss)、分位数报告(P50/P95/P99)和 JSON 导出功能。 |
| [Java 运行时模板(cubesandbox-base-java)](https://github.com/tencentcloud/CubeSandbox/tree/master/examples/cubesandbox-base-java) | 在 `cubesandbox-base` 上叠加 OpenJDK 17 LTS + Maven 与一个仅依赖 JDK 的极简 HTTP 服务器。可作为 Java 代码执行或 Java Web 服务沙箱的起点。 |
| [Go 运行时模板(cubesandbox-base-go)](https://github.com/tencentcloud/CubeSandbox/tree/master/examples/cubesandbox-base-go) | 在 `cubesandbox-base` 上叠加 Go 工具链与一个仅用标准库的极简 HTTP 服务器。可作为 Go 代码执行或 Go Web 服务沙箱的起点。 |

::: tip
所有示例共享相同的环境变量约定(`E2B_API_URL`、`E2B_API_KEY`、`CUBE_TEMPLATE_ID`)。请先参考[快速开始](../quickstart.md)指南搭建 Cube Sandbox 环境。
Expand Down
49 changes: 49 additions & 0 deletions examples/cubesandbox-base-go/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# syntax=docker/dockerfile:1.7
#
# Demo: a Cube-ready sandbox image that runs a tiny Go HTTP server on :8080
# while the cubesandbox-base entrypoint keeps envd running on :49983 in the
# background. A good starting point for Go workloads in CubeSandbox.
#
# Build:
# docker build -t cubesandbox-demo-go:latest examples/cubesandbox-base-go
#
# Run locally:
# docker run --rm -d -p 8080:8080 -p 49983:49983 \
# --name cube-demo-go cubesandbox-demo-go:latest
# curl http://127.0.0.1:8080/
# curl -o /dev/null -w "%{http_code}\n" http://127.0.0.1:49983/health # => 204

ARG CUBE_BASE_IMAGE=ghcr.io/tencentcloud/cubesandbox-base:2026.16
FROM ${CUBE_BASE_IMAGE}

ARG DEBIAN_FRONTEND=noninteractive
ARG GO_VERSION=1.23.4

# Install the Go toolchain from the official tarball — newer than Ubuntu
# 22.04's apt golang (1.18) and self-contained under /usr/local/go.
RUN curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" -o /tmp/go.tgz \
&& tar -C /usr/local -xzf /tmp/go.tgz \
&& rm /tmp/go.tgz \
&& /usr/local/go/bin/go version

ENV GOROOT=/usr/local/go \
GOPATH=/go \
PATH="/usr/local/go/bin:/go/bin:${PATH}"

WORKDIR /app
COPY main.go /app/main.go
COPY main_test.go /app/main_test.go

# Run unit tests (httptest-based, no network needed) before building.
RUN CGO_ENABLED=0 go test -v .

# Build a static-ish binary; CGO_ENABLED=0 avoids libc linkage surprises.
RUN CGO_ENABLED=0 go build -o /app/helloserver main.go

EXPOSE 8080 49983

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Critical: missing go.modgo test -v . will fail without a go.mod file because Go ≥1.16 defaults to module mode (GO111MODULE=on). Running go test . (package mode) requires a module context; only go build main.go (file-argument mode) works without one.

Add either:

  • A RUN go mod init cubesandbox-demo-go step before the test command, or
  • A go.mod file committed to the repository.

(The standalone go build -o /app/helloserver main.go on line 41 will work because it specifies a file argument, but the test will fail first.)


# cube-entrypoint.sh (inherited from the base image) will:
# 1. Launch envd on ${ENVD_PORT:-49983} in the background.
# 2. exec the CMD below as the foreground process, so the Go server owns
# PID 1's child and receives SIGTERM on `docker stop`.
CMD ["/app/helloserver"]
153 changes: 153 additions & 0 deletions examples/cubesandbox-base-go/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# cubesandbox-base-go demo

A minimal image that stacks a **Go toolchain** and a tiny HTTP server on top of
[`cubesandbox-base`](../../docker/Dockerfile.cube-base), so you can test the
"Bring Your Own Image" flow end-to-end with a real Go workload — and use it as
a ready-made starting point for Go-based sandboxes.

- envd listens on `:49983` (Cube readiness probe) — inherited from the base image.
- A Go HTTP server (standard library `net/http`) listens on `:8080` and serves a
tiny landing page that echoes the Go runtime version, so you can eyeball that
Go really served the request.

See [Bring Your Own Image (envd)](../../docs/guide/tutorials/bring-your-own-image.md)
for the full tutorial, and [`../cubesandbox-base-nginx/`](../cubesandbox-base-nginx/)
for a sibling example that follows the exact same pattern with nginx.

## What's inside

- **Go toolchain** — official tarball from `go.dev`, newer than Ubuntu 22.04's
apt `golang` (1.18). Installed under `/usr/local/go`, with `GOROOT`/`GOPATH`/`PATH`
wired up so `go` is on `$PATH`.
- **`main.go`** — a single-file HTTP server built on the standard library
`net/http` package, so the image needs **no third-party dependencies** and no
network access to build. Compiled to `/app/helloserver` at build time and
launched as the foreground process via `CMD ["/app/helloserver"]`.

## Build

```bash
docker build -t cubesandbox-demo-go:latest .
```

The Dockerfile runs `go test` during the build, so a failing unit test
will abort the image build.

> Pin a different Go version with `--build-arg GO_VERSION=1.22.0`.

## Run unit tests locally

```bash
go test -v .
```

Tests use only the standard library `net/http/httptest` — no external
dependencies or running server required.

## Run & verify locally

```bash
docker run --rm -d \
-p 8080:8080 \
-p 49983:49983 \
--name cube-demo-go \
cubesandbox-demo-go:latest

# Go server: should print the demo landing page (with the Go runtime version)
curl -s http://127.0.0.1:8080/

# envd readiness probe: should return 204
curl -s -o /dev/null -w "envd /health => %{http_code}\n" \
http://127.0.0.1:49983/health

# Sanity-check the toolchain inside the container
docker exec cube-demo-go go version
docker exec cube-demo-go go env GOROOT GOPATH

docker rm -f cube-demo-go
```

## Register as a Cube template

```bash
cubemastercli tpl create-from-image \
--image <your-registry>/cubesandbox-demo-go:latest \
--writable-layer-size 1G \
--expose-port 49983 \
--expose-port 8080 \
--probe 49983 \
--probe-path /health
```

`--probe 49983 --probe-path /health` points Cube at envd (guaranteed to
return `204` within ~1s); the Go server's `:8080` stays exposed for your
actual traffic. See
[Creating Templates from OCI Images](../../docs/guide/tutorials/template-from-image.md)
for monitoring (`tpl watch`) and troubleshooting.

## Try it with the E2B SDK

After registering the template, [`test_sandbox.py`](./test_sandbox.py) boots
a sandbox from it and verifies four things:

1. `go version` runs inside the sandbox (toolchain is on `$PATH`)
2. `go env GOROOT GOPATH` reports the expected paths
3. `/app/main.go` is readable via `sandbox.files.read(...)`
4. An HTTPS request to the sandbox's port `8080` returns the Go server's
landing page

```bash
pip install -r requirements.txt

cp env.example .env
# fill in E2B_API_URL and CUBE_TEMPLATE_ID

python3 test_sandbox.py
```

## Files

```
cubesandbox-base-go/
├── Dockerfile # FROM cubesandbox-base, installs Go toolchain, builds & runs the server
├── main.go # Standard-library HTTP server (net/http), no third-party deps
├── main_test.go # Unit tests for handleRoot / handleHealth (go test, no external deps)
├── test_sandbox.py # E2B SDK smoke test: go version/env, file read, HTTP GET :8080
├── env.example # E2B_API_URL / E2B_API_KEY / CUBE_TEMPLATE_ID
├── requirements.txt # e2b + python-dotenv
└── README.md # This file
```

## Use cases

- **Go code execution sandbox** — boot a sandbox and run `go build` / `go test`
via `sandbox.commands.run(...)` for isolated build or test jobs.
- **Go Web service base** — replace `main.go` with your own Gin / Echo / chi /
vanilla `net/http` app and expose its port with `--expose-port`.
- **CGo / multi-module build runner** — clone a repo into the sandbox and run
`go build ./...` against an isolated, disposable environment.

## Known limitations

- The image ships a **single Go version** (default `1.23.4`). Override with
`--build-arg GO_VERSION=<x.y.z>` for a different release.
- **`GOPATH` is `/go`** with no pre-created `src` tree. Go modules are the
default and recommended workflow; if you need legacy `GOPATH` mode, `mkdir -p
/go/src` in your downstream Dockerfile.
- `main.go` is a demo, not a production server — it has no TLS, no graceful
shutdown, no timeouts, and serves a single route. Swap it for your real
application's binary.
- The Go binary is built with `CGO_ENABLED=0` (pure Go). If your project needs
CGo (e.g. links a C library), drop that flag and ensure the toolchain image
has a C compiler (`apt-get install -y gcc`).

## Related

- [`../cubesandbox-base-nginx/`](../cubesandbox-base-nginx/) — the sibling
example this template is modelled on (nginx instead of Go).
- [`../cubesandbox-base-java/`](../cubesandbox-base-java/) — another sibling,
Java 17 + Maven on the same base image.
- [Bring Your Own Image (envd)](../../docs/guide/tutorials/bring-your-own-image.md)
— the entrypoint contract and `envd` requirements.
- [Creating Templates from OCI Images](../../docs/guide/tutorials/template-from-image.md)
— full `cubemastercli tpl create-from-image` reference.
11 changes: 11 additions & 0 deletions examples/cubesandbox-base-go/env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Required: Cube API server address
export E2B_API_URL="http://<your-node-ip>:3000"

# Required: any non-empty value satisfies the SDK check
export E2B_API_KEY="e2b_000000"

# Required: template ID from `cubemastercli tpl create-from-image ...`
export CUBE_TEMPLATE_ID="<your-template-id>"


export SSL_CERT_FILE="/etc/pki/tls/cert.pem"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/etc/pki/tls/cert.pem is a RHEL path — the base image is ubuntu:22.04, which stores the CA certificate bundle at /etc/ssl/certs/ca-certificates.crt. The path /etc/pki/tls/cert.pem will not exist on an Ubuntu host, causing TLS certificate verification failures when test_sandbox.py makes HTTPS requests. (This also applies to the Java env.example.)

50 changes: 50 additions & 0 deletions examples/cubesandbox-base-go/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Minimal HTTP server used by the cubesandbox-base-go demo template.
//
// Uses only the Go standard library (net/http) so the image needs no
// third-party dependencies. Listens on :8080 (override via APP_PORT) and
// serves a tiny landing page plus a /health endpoint. The Cube readiness
// probe is served by envd on :49983 — this server is the "real" application
// traffic endpoint, mirroring how nginx serves :80 in cubesandbox-base-nginx.
package main

import (
"fmt"
"net/http"
"os"
"runtime"
)

func main() {
port := os.Getenv("APP_PORT")
if port == "" {
port = "8080"
}

mux := http.NewServeMux()
mux.HandleFunc("/", handleRoot)
mux.HandleFunc("/health", handleHealth)

fmt.Printf("helloserver listening on :%s (Go %s)\n", port, runtime.Version())
if err := http.ListenAndServe(":"+port, mux); err != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing HTTP timeoutshttp.ListenAndServe uses the default http.Server with zero-valued ReadTimeout, WriteTimeout, and IdleTimeout. Slow or malicious clients can hold connections open indefinitely, exhausting goroutines and file descriptors. Consider setting explicit timeouts:

srv := &http.Server{
    Addr:         ":" + port,
    Handler:      mux,
    ReadTimeout:  10 * time.Second,
    WriteTimeout: 10 * time.Second,
    IdleTimeout:  30 * time.Second,
}
if err := srv.ListenAndServe(); err != nil { ... }

(This is a demo, so even 30s defaults are better than 0 = no timeout.)

fmt.Fprintln(os.Stderr, "server error:", err)
os.Exit(1)
}
}

func handleRoot(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
port := os.Getenv("APP_PORT")
if port == "" {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

os.Getenv("APP_PORT") is read on every request — this makes a syscall into the OS for each HTTP request. The port value is already captured in main() as the local variable port. Consider closing over it or storing it at the package level to avoid redundant lookups. Same pattern in the Java server.

port = "8080"
}
fmt.Fprintf(w, "<!doctype html>\n"+
"<title>cubesandbox-base-go</title>\n"+
"<h1>Hello from Go inside a CubeSandbox MicroVM</h1>\n"+
"<p>Go runtime: %s</p>\n"+
"<p>envd is running on :49983, this Go server on :%s.</p>\n",
runtime.Version(), port)
}

func handleHealth(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}
Loading
Loading