FC Agent Sandbox templates can be created, queried, and deleted by calling Alibaba Cloud OpenAPI operations. CreateTemplate creates a template and starts its first build in a single call. The build runs asynchronously. Poll GetTemplate for the build status, and then create sandboxes from the ready template.
Prerequisites
-
Function Compute and FC Agent Sandbox are activated.
-
A Team is created in the FC Agent Sandbox console as described in Create a Team, and the Team ID is obtained.
-
An Alibaba Cloud account or a Resource Access Management (RAM) user is prepared, and the permissions on the template API operations are granted to the calling identity. For more information, see Permission configuration below.
-
The region in which the template resides is identified. Example: The China (Beijing) region is
cn-beijing. For the list of all supported regions, see Supported Regions. -
If you build templates on your on-premises machine by using the E2B SDK, obtain the E2B SDK connection parameters:
E2B_API_KEY,E2B_API_URL, andE2B_DOMAIN. The SDK automatically reads these environment variables.
Permission configuration
The RAM identity that calls the template API operations must have the following permissions:
{
"Version": "1",
"Statement": [
{
"Effect": "Allow",
"Action": [
"fcsandbox:CreateTemplate",
"fcsandbox:GetTemplate",
"fcsandbox:ListTemplates",
"fcsandbox:DeleteTemplate"
],
"Resource": "*"
}
]
}
Fine-grained, Team-level authorization is supported for Template resources:
acs:fcsandbox:<region>:<account-id>:teams/<team-id>/templates/*
For more information about how to configure permission policies, see Configure RAM User Permissions. Local builds that use the E2B SDK are authenticated by API key and do not require RAM permission configurations.
Install the SDK
The FC Agent Sandbox OpenAPI supports the Python, TypeScript, Go, and Java SDKs. For the supported scope, installation methods, and versions, see Alibaba Cloud SDK and API Guide:
Python
python3 -m venv .venv
source .venv/bin/activate
pip install "alibabacloud_fcsandbox20260509"
TypeScript
npm install @alicloud/fcsandbox20260509 @alicloud/openapi-client
Go
go mod init pop-template-demo
go get github.com/alibabacloud-go/fcsandbox-20260509
Java
Add the following Maven dependency to the pom.xml file of your project. For the version, see the SDK documentation:
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>fcsandbox20260509</artifactId>
<version>1.4.0</version>
</dependency>
If you create a new project, use the following minimal pom.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>demo</groupId>
<artifactId>pop-template-demo</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>fcsandbox20260509</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
</project>
Save the sample code as src/main/java/CreateTemplateDemo.java in the project.
Before you run the sample, set the following environment variables:
export ALIBABA_CLOUD_ACCESS_KEY_ID="<YOUR-ACCESS-KEY-ID>"
export ALIBABA_CLOUD_ACCESS_KEY_SECRET="<YOUR-ACCESS-KEY-SECRET>"
# To use STS temporary credentials, also set the following variables:
# export ALIBABA_CLOUD_SECURITY_TOKEN="<YOUR-SECURITY-TOKEN>"
export FCSANDBOX_REGION_ID="cn-beijing"
export FCSANDBOX_ENDPOINT="fcsandbox.cn-beijing.aliyuncs.com"
export FCSANDBOX_TEAM_ID="<team-id>"
FCSANDBOX_ENDPOINT does not contain https://. If the SDK has the endpoint of the destination region built in, leave this variable empty, and the SDK resolves the endpoint based on FCSANDBOX_REGION_ID.
Create and build a template
For more information about the request parameters, response parameters, and error codes, see CreateTemplate - Create a template in the OpenAPI Explorer.
The request body CreateTemplateInput contains the name, team_id, runtime_config, and build_config fields. The first build starts immediately after the template is created:
-
runtime_config: the specifications of the destination template. Setcpu(cores),memory_size(MB), anddisk_size(MB) as needed. If you leave the parameters empty, the default specifications are used.sandbox_config.imagespecifies the source image for the build and is required. -
build_config: the build method. If you leave the entire field empty, the value is automatically derived from the source image. Official FC Agent Sandbox images are used directly without a build. For other images, copy (processes and pushes the destination image) and envdInject (injects the dependencies required to run the sandbox) are automatically performed.
For more information about the image requirements and the limits and parameters of each image source, see Image requirements and Image sources below.
The following example creates a template in the China (Beijing) region by using an official FC Agent Sandbox image. You do not need to create a Container Registry Enterprise Edition (ACR EE) instance. The example polls the build status until the template is ready, and then deletes the template:
Python
import os
import time
from alibabacloud_fcsandbox20260509 import models
from alibabacloud_fcsandbox20260509.client import Client as FCSandboxClient
from alibabacloud_tea_openapi import models as open_api_models
def require_env(name: str) -> str:
value = os.environ.get(name, "").strip()
if not value:
raise RuntimeError(f"Missing environment variable: {name}")
return value
config = open_api_models.Config(
access_key_id=require_env("ALIBABA_CLOUD_ACCESS_KEY_ID"),
access_key_secret=require_env("ALIBABA_CLOUD_ACCESS_KEY_SECRET"),
security_token=os.environ.get("ALIBABA_CLOUD_SECURITY_TOKEN"),
region_id=require_env("FCSANDBOX_REGION_ID"),
)
if os.environ.get("FCSANDBOX_ENDPOINT"):
config.endpoint = os.environ["FCSANDBOX_ENDPOINT"]
pop_client = FCSandboxClient(config)
team_id = require_env("FCSANDBOX_TEAM_ID")
from_image = "fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49"
# 1. Create a template and submit the first build. templateID is returned.
response = pop_client.create_template(
models.CreateTemplateRequest(
body=models.CreateTemplateInput(
name=f"pop-demo-{int(time.time())}",
team_id=team_id,
runtime_config=models.CreateTemplateRuntimeConfig(
sandbox_config=models.CreateTemplateSandboxConfig(image=from_image),
),
)
)
)
template_id = response.body.template_id
print(f"created templateID: {template_id}, request_id: {response.body.request_id}")
# 2. Poll GetTemplate until the build enters a final state.
deadline = time.time() + 900
while True:
got = pop_client.get_template(template_id, models.GetTemplateRequest(team_id=team_id))
state = got.body.status.state
print(f"state: {state}")
if state in ("ready", "error"):
break
if time.time() > deadline:
raise SystemExit("Build timed out")
time.sleep(5)
if state == "error":
raise SystemExit(f"Build failed: {got.body.status.reason.message}")
# 3. After the template is ready, you can use the template to create sandboxes. Delete the template to release resources when it is no longer used.
pop_client.delete_template(template_id, models.DeleteTemplateRequest(team_id=team_id))
print(f"deleted templateID: {template_id}")
TypeScript
import * as process from 'process';
import FCSandbox20260509, * as $FCSandbox20260509 from '@alicloud/fcsandbox20260509';
import * as $OpenApi from '@alicloud/openapi-client';
function requireEnv(name: string): string {
const value = (process.env[name] ?? '').trim();
if (!value) {
throw new Error(`Missing environment variable: ${name}`);
}
return value;
}
async function main() {
const config = new $OpenApi.Config({
accessKeyId: requireEnv('ALIBABA_CLOUD_ACCESS_KEY_ID'),
accessKeySecret: requireEnv('ALIBABA_CLOUD_ACCESS_KEY_SECRET'),
securityToken: (process.env['ALIBABA_CLOUD_SECURITY_TOKEN'] ?? '').trim() || undefined,
regionId: requireEnv('FCSANDBOX_REGION_ID'),
endpoint: (process.env['FCSANDBOX_ENDPOINT'] ?? '').trim() || undefined,
});
const popClient = new FCSandbox20260509(config);
const teamID = requireEnv('FCSANDBOX_TEAM_ID');
const fromImage = 'fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49';
// 1. Create a template and submit the first build. templateID is returned.
const created = await popClient.createTemplate(new $FCSandbox20260509.CreateTemplateRequest({
body: new $FCSandbox20260509.CreateTemplateInput({
name: `pop-demo-${Math.floor(Date.now() / 1000)}`,
teamID,
runtimeConfig: new $FCSandbox20260509.CreateTemplateRuntimeConfig({
sandboxConfig: new $FCSandbox20260509.CreateTemplateSandboxConfig({ image: fromImage }),
}),
}),
}));
const templateID = created.body.templateID;
console.log(`created templateID: ${templateID}, request_id: ${created.body.requestId}`);
// 2. Poll GetTemplate until the build enters a final state.
const deadline = Date.now() + 900_000;
let state = '';
let reasonMessage = '';
while (true) {
const got = await popClient.getTemplate(templateID,
new $FCSandbox20260509.GetTemplateRequest({ teamID }));
state = got.body.status.state;
console.log(`state: ${state}`);
reasonMessage = got.body.status.reason?.message ?? '';
if (state === 'ready' || state === 'error') {
break;
}
if (Date.now() > deadline) {
throw new Error('Build timed out');
}
await new Promise(resolve => setTimeout(resolve, 5000));
}
if (state === 'error') {
throw new Error(`Build failed: ${reasonMessage}`);
}
// 3. After the template is ready, you can use the template to create sandboxes. Delete the template to release resources when it is no longer used.
await popClient.deleteTemplate(templateID,
new $FCSandbox20260509.DeleteTemplateRequest({ teamID }));
console.log(`deleted templateID: ${templateID}`);
}
main();
Go
package main
import (
"fmt"
"os"
"strings"
"time"
openapiutil "github.com/alibabacloud-go/darabonba-openapi/v2/utils"
fcsandbox20260509 "github.com/alibabacloud-go/fcsandbox-20260509/client"
"github.com/alibabacloud-go/tea/tea"
)
// requireEnv reads a required environment variable and panics if the variable is missing.
func requireEnv(name string) string {
value := strings.TrimSpace(os.Getenv(name))
if value == "" {
panic(fmt.Sprintf("Missing environment variable: %s", name))
}
return value
}
func main() {
config := &openapiutil.Config{
AccessKeyId: tea.String(requireEnv("ALIBABA_CLOUD_ACCESS_KEY_ID")),
AccessKeySecret: tea.String(requireEnv("ALIBABA_CLOUD_ACCESS_KEY_SECRET")),
RegionId: tea.String(requireEnv("FCSANDBOX_REGION_ID")),
}
if token := strings.TrimSpace(os.Getenv("ALIBABA_CLOUD_SECURITY_TOKEN")); token != "" {
config.SecurityToken = tea.String(token)
}
if endpoint := strings.TrimSpace(os.Getenv("FCSANDBOX_ENDPOINT")); endpoint != "" {
config.Endpoint = tea.String(endpoint)
}
popClient, err := fcsandbox20260509.NewClient(config)
if err != nil {
panic(err)
}
teamID := requireEnv("FCSANDBOX_TEAM_ID")
fromImage := "fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49"
// 1. Create a template and submit the first build. templateID is returned.
created, err := popClient.CreateTemplate(&fcsandbox20260509.CreateTemplateRequest{
Body: &fcsandbox20260509.CreateTemplateInput{
Name: tea.String(fmt.Sprintf("pop-demo-%d", time.Now().Unix())),
TeamID: tea.String(teamID),
RuntimeConfig: &fcsandbox20260509.CreateTemplateRuntimeConfig{
SandboxConfig: &fcsandbox20260509.CreateTemplateSandboxConfig{
Image: tea.String(fromImage),
},
},
},
})
if err != nil {
panic(err)
}
templateID := tea.StringValue(created.Body.TemplateID)
fmt.Printf("created templateID: %s, request_id: %s\n",
templateID, tea.StringValue(created.Body.RequestId))
// 2. Poll GetTemplate until the build enters a final state.
deadline := time.Now().Add(900 * time.Second)
state := ""
reasonMessage := ""
for {
got, err := popClient.GetTemplate(tea.String(templateID), &fcsandbox20260509.GetTemplateRequest{
TeamID: tea.String(teamID),
})
if err != nil {
panic(err)
}
state = tea.StringValue(got.Body.Status.State)
fmt.Printf("state: %s\n", state)
if got.Body.Status.Reason != nil {
reasonMessage = tea.StringValue(got.Body.Status.Reason.Message)
}
if state == "ready" || state == "error" {
break
}
if time.Now().After(deadline) {
panic("Build timed out")
}
time.Sleep(5 * time.Second)
}
if state == "error" {
panic(fmt.Sprintf("Build failed: %s", reasonMessage))
}
// 3. After the template is ready, you can use the template to create sandboxes. Delete the template to release resources when it is no longer used.
if _, err := popClient.DeleteTemplate(tea.String(templateID), &fcsandbox20260509.DeleteTemplateRequest{
TeamID: tea.String(teamID),
}); err != nil {
panic(err)
}
fmt.Printf("deleted templateID: %s\n", templateID)
}
Java
import com.aliyun.fcsandbox20260509.Client;
import com.aliyun.fcsandbox20260509.models.CreateTemplateBuildConfig;
import com.aliyun.fcsandbox20260509.models.CreateTemplateCopyAction;
import com.aliyun.fcsandbox20260509.models.CreateTemplateInput;
import com.aliyun.fcsandbox20260509.models.CreateTemplateLogConfig;
import com.aliyun.fcsandbox20260509.models.CreateTemplateRegistryAuthConfig;
import com.aliyun.fcsandbox20260509.models.CreateTemplateRegistryCertConfig;
import com.aliyun.fcsandbox20260509.models.CreateTemplateRegistryConfig;
import com.aliyun.fcsandbox20260509.models.CreateTemplateRegistryNetworkConfig;
import com.aliyun.fcsandbox20260509.models.CreateTemplateRequest;
import com.aliyun.fcsandbox20260509.models.CreateTemplateRuntimeConfig;
import com.aliyun.fcsandbox20260509.models.CreateTemplateSandboxConfig;
import com.aliyun.fcsandbox20260509.models.CreateTemplateVPCConfig;
import com.aliyun.fcsandbox20260509.models.DeleteTemplateRequest;
import com.aliyun.fcsandbox20260509.models.GetTemplateRequest;
import com.aliyun.fcsandbox20260509.models.GetTemplateResponse;
import com.aliyun.fcsandbox20260509.models.ListTemplatesRequest;
import com.aliyun.fcsandbox20260509.models.ListTemplatesResponse;
import com.aliyun.fcsandbox20260509.models.PublicTemplate;
import com.aliyun.teaopenapi.models.Config;
public class CreateTemplateDemo {
private static String requireEnv(String name) {
String value = System.getenv(name);
if (value == null || value.isBlank()) {
throw new RuntimeException("Missing environment variable: " + name);
}
return value.trim();
}
public static void main(String[] args) throws Exception {
Config config = new Config()
.setAccessKeyId(requireEnv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
.setAccessKeySecret(requireEnv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"))
.setRegionId(requireEnv("FCSANDBOX_REGION_ID"));
String securityToken = System.getenv("ALIBABA_CLOUD_SECURITY_TOKEN");
if (securityToken != null && !securityToken.isBlank()) {
config.setSecurityToken(securityToken.trim());
}
String endpoint = System.getenv("FCSANDBOX_ENDPOINT");
if (endpoint != null && !endpoint.isBlank()) {
config.setEndpoint(endpoint.trim());
}
Client popClient = new Client(config);
String teamID = requireEnv("FCSANDBOX_TEAM_ID");
String fromImage = "fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49";
// 1. Create a template and submit the first build. templateID is returned.
CreateTemplateInput body = new CreateTemplateInput()
.setName("pop-demo-" + System.currentTimeMillis() / 1000)
.setTeamID(teamID)
.setRuntimeConfig(new CreateTemplateRuntimeConfig()
.setSandboxConfig(new CreateTemplateSandboxConfig()
.setImage(fromImage)));
String templateID = popClient
.createTemplate(new CreateTemplateRequest().setBody(body))
.getBody().getTemplateID();
System.out.printf("created templateID: %s%n", templateID);
// 2. Poll GetTemplate until the build enters a final state.
long deadline = System.currentTimeMillis() + 900_000;
String state = "";
GetTemplateResponse got = null;
while (true) {
got = popClient.getTemplate(templateID,
new GetTemplateRequest().setTeamID(teamID));
state = got.getBody().getStatus().getState();
System.out.printf("state: %s%n", state);
if ("ready".equals(state) || "error".equals(state)) {
break;
}
if (System.currentTimeMillis() > deadline) {
throw new RuntimeException("Build timed out");
}
Thread.sleep(5000);
}
if ("error".equals(state)) {
throw new RuntimeException("Build failed: "
+ got.getBody().getStatus().getReason().getMessage());
}
// 3. After the template is ready, you can use the template to create sandboxes. Delete the template to release resources when it is no longer used.
popClient.deleteTemplate(templateID,
new DeleteTemplateRequest().setTeamID(teamID));
System.out.printf("deleted templateID: %s%n", templateID);
}
}
Run the sample:
Python
python create_template.py
TypeScript
npx tsx create_template.ts
Go
go mod tidy
go run main.go
Java
mvn compile exec:java -Dexec.mainClass="CreateTemplateDemo"
The build runs asynchronously. The time required for polling depends on the image size and typically ranges from tens of seconds to several minutes.
Image requirements
A custom image template can be built in two ways. The image requirements are the same, but the capabilities of credential and network configurations differ. To build an image by using OpenAPI, call CreateTemplate. The build runs on the server side, which suits automation scripts, infrastructure as code (IaC), and platform integration. To build an image by using the E2B SDK, run Template.build on your on-premises machine. Local builds suit initial verification and personal development.
Recommended base images: Ubuntu 20.04, Debian 12 (bookworm), or later. The Linux distribution is not mandatory. Custom images must meet the requirements described in the following table, which are classified into Required, Conditional, and Recommended:
|
Level |
Requirement |
Impact if not met |
|
Required |
The architecture is |
The template build fails immediately |
|
Required |
Image acceleration is not enabled for the ACR image |
The template build fails immediately |
|
Conditional |
The image contains |
|
|
Required |
|
The sandbox cannot initialize the default user, and the container fails to start |
|
Conditional |
|
Python |
|
Conditional |
|
JavaScript |
|
Conditional |
Provided as needed: |
The corresponding Git, SSH, HTTPS, and build-from-source operations are unavailable |
|
Recommended |
The system PATH contains at least |
Common commands may not be found in the login shell |
When you push images to your own image repository, do not push different image content to the same tag. Each distinct image must use a new and unique tag, such as a version number, date, or commit ID, and templates must reference the specific tag.
Image sources
Image sources are classified into four types: public images, ACR EE, public Open Container Initiative (OCI) registries, and private OCI registries in a virtual private cloud (VPC). The preparation, limits, and parameters of each type are described in the following sections. Each sample request is a complete CreateTemplate call. Replace Step 1 of the sample in the "Create and build a template" section with the corresponding sample, and keep the other steps (polling and deletion) unchanged.
Public images
You can use an official FC Agent Sandbox image without an ACR EE instance, credentials, or network configurations. Official images are provided in all supported regions. The image address is in the fc-e2b-registry.<region>.cr.aliyuncs.com/runtime/<image-name>:<tag> format. For the list of regions, see Supported Regions. The following example uses the China (Beijing) region:
fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/base:v0.0.49
fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49
Limits:
-
Only published official tags can be referenced, and images cannot be pushed to the official repository.
-
If
build_configis left empty, the official image is used directly and no build is triggered. -
Official images meet the requirements described in Image requirements above. The Create and build a template sample in this topic uses this method.
-
The region in the image address must be the same as the value of
FCSANDBOX_REGION_ID.
Sample request:
Python
response = pop_client.create_template(
models.CreateTemplateRequest(
body=models.CreateTemplateInput(
name=f"pop-demo-{int(time.time())}",
team_id=team_id,
runtime_config=models.CreateTemplateRuntimeConfig(
sandbox_config=models.CreateTemplateSandboxConfig(
image="fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49",
),
),
)
)
)
TypeScript
const created = await popClient.createTemplate(new $FCSandbox20260509.CreateTemplateRequest({
body: new $FCSandbox20260509.CreateTemplateInput({
name: `pop-demo-${Math.floor(Date.now() / 1000)}`,
teamID,
runtimeConfig: new $FCSandbox20260509.CreateTemplateRuntimeConfig({
sandboxConfig: new $FCSandbox20260509.CreateTemplateSandboxConfig({
image: 'fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49',
}),
}),
}),
}));
Go
created, err := popClient.CreateTemplate(&fcsandbox20260509.CreateTemplateRequest{
Body: &fcsandbox20260509.CreateTemplateInput{
Name: tea.String(fmt.Sprintf("pop-demo-%d", time.Now().Unix())),
TeamID: tea.String(teamID),
RuntimeConfig: &fcsandbox20260509.CreateTemplateRuntimeConfig{
SandboxConfig: &fcsandbox20260509.CreateTemplateSandboxConfig{
Image: tea.String("fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49"),
},
},
},
})
if err != nil {
panic(err)
}
Java
CreateTemplateInput body = new CreateTemplateInput()
.setName("pop-demo-" + System.currentTimeMillis() / 1000)
.setTeamID(teamID)
.setRuntimeConfig(new CreateTemplateRuntimeConfig()
.setSandboxConfig(new CreateTemplateSandboxConfig()
.setImage("fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49")));
String templateID = popClient
.createTemplate(new CreateTemplateRequest().setBody(body))
.getBody().getTemplateID();
ACR EE
Before you begin:
-
In the same Alibaba Cloud account and region as FC Agent Sandbox, create an ACR EE instance (the Economy Edition is not supported).
-
Add a VPC to the ACR EE instance to make sure that FC Agent Sandbox can pull images over the VPC.
-
Create a namespace and an image repository, push the image, and obtain an internal image address that supports VPC access. Example:
test-registry-vpc.cn-beijing.cr.aliyuncs.com/runtime/python:3.12-v1
Network limits:
-
The ACR EE instance is associated with at least one VPC.
-
The VPC contains at least one vSwitch in a zone supported by Function Compute.
-
The ACR EE image repository, VPC, vSwitch, and FC Agent Sandbox must reside in the same region. The samples in this topic use the China (Beijing) region by default.
-
The access control and VPC configurations of the ACR EE instance allow access over the corresponding network.
-
The CIDR block of the VPC must be a private CIDR block defined in RFC 1918:
10.0.0.0/8,172.16.0.0/12, or192.168.0.0/16. Public CIDR blocks cannot be used as private CIDR blocks. For more information, see VPC FAQ. -
At least one custom security group is configured for the VPC, and the outbound rules of the security group allow traffic on TCP port 443.
The zones supported by Function Compute vary based on regions and product capabilities. For the latest list, see Configure network.
Common failures:
-
Image pull failure: Check the image address, region, namespace, repository permissions, VPC association, and access control configurations in sequence. If you use a private ACR EE image, network configuration errors are more common than SDK parameter errors.
-
The zone of the vSwitch used for image pull is not supported
Pull method: The simplest option is to specify only image. The system obtains the ACR EE instance and repository type from the image address. It pulls the image by using the temporary authorization of the instance, and obtains the pull network from the VPC associated with the instance. If you want to specify the instance, credentials, or pull network, specify acr_instance_id, registry_config.auth_config, and registry_config.network_config. If the pull fails because the vSwitch resolved from the instance is located in an unsupported zone, you must use network_config to specify the VPC, vSwitch, and security group.
Sample request 1: Specify only image. The instance, credentials, and pull network are all resolved automatically:
Python
response = pop_client.create_template(
models.CreateTemplateRequest(
body=models.CreateTemplateInput(
name=f"pop-demo-{int(time.time())}",
team_id=team_id,
runtime_config=models.CreateTemplateRuntimeConfig(
sandbox_config=models.CreateTemplateSandboxConfig(
image="test-registry-vpc.cn-beijing.cr.aliyuncs.com/runtime/python:3.12-v1",
),
),
)
)
)
TypeScript
const created = await popClient.createTemplate(new $FCSandbox20260509.CreateTemplateRequest({
body: new $FCSandbox20260509.CreateTemplateInput({
name: `pop-demo-${Math.floor(Date.now() / 1000)}`,
teamID,
runtimeConfig: new $FCSandbox20260509.CreateTemplateRuntimeConfig({
sandboxConfig: new $FCSandbox20260509.CreateTemplateSandboxConfig({
image: 'test-registry-vpc.cn-beijing.cr.aliyuncs.com/runtime/python:3.12-v1',
}),
}),
}),
}));
Go
created, err := popClient.CreateTemplate(&fcsandbox20260509.CreateTemplateRequest{
Body: &fcsandbox20260509.CreateTemplateInput{
Name: tea.String(fmt.Sprintf("pop-demo-%d", time.Now().Unix())),
TeamID: tea.String(teamID),
RuntimeConfig: &fcsandbox20260509.CreateTemplateRuntimeConfig{
SandboxConfig: &fcsandbox20260509.CreateTemplateSandboxConfig{
Image: tea.String("test-registry-vpc.cn-beijing.cr.aliyuncs.com/runtime/python:3.12-v1"),
},
},
},
})
if err != nil {
panic(err)
}
Java
CreateTemplateInput body = new CreateTemplateInput()
.setName("pop-demo-" + System.currentTimeMillis() / 1000)
.setTeamID(teamID)
.setRuntimeConfig(new CreateTemplateRuntimeConfig()
.setSandboxConfig(new CreateTemplateSandboxConfig()
.setImage("test-registry-vpc.cn-beijing.cr.aliyuncs.com/runtime/python:3.12-v1")));
String templateID = popClient
.createTemplate(new CreateTemplateRequest().setBody(body))
.getBody().getTemplateID();
Sample request 2: Set acr_instance_id, auth_config, and network_config to explicitly specify the instance, credentials, and pull network:
Python
response = pop_client.create_template(
models.CreateTemplateRequest(
body=models.CreateTemplateInput(
name=f"pop-demo-{int(time.time())}",
team_id=team_id,
runtime_config=models.CreateTemplateRuntimeConfig(
sandbox_config=models.CreateTemplateSandboxConfig(
image="test-registry-vpc.cn-beijing.cr.aliyuncs.com/runtime/python:3.12-v1",
acr_instance_id="cri-xxxxxx",
registry_config=models.CreateTemplateRegistryConfig(
auth_config=models.CreateTemplateRegistryAuthConfig(
user_name="<username>",
password="<password>",
),
network_config=models.CreateTemplateRegistryNetworkConfig(
vpc_id="vpc-xxxxxx",
v_switch_id="vsw-xxxxxx",
security_group_id="sg-xxxxxx",
),
),
),
),
)
)
)
TypeScript
const created = await popClient.createTemplate(new $FCSandbox20260509.CreateTemplateRequest({
body: new $FCSandbox20260509.CreateTemplateInput({
name: `pop-demo-${Math.floor(Date.now() / 1000)}`,
teamID,
runtimeConfig: new $FCSandbox20260509.CreateTemplateRuntimeConfig({
sandboxConfig: new $FCSandbox20260509.CreateTemplateSandboxConfig({
image: 'test-registry-vpc.cn-beijing.cr.aliyuncs.com/runtime/python:3.12-v1',
acrInstanceId: 'cri-xxxxxx',
registryConfig: new $FCSandbox20260509.CreateTemplateRegistryConfig({
authConfig: new $FCSandbox20260509.CreateTemplateRegistryAuthConfig({
userName: '<username>',
password: '<password>',
}),
networkConfig: new $FCSandbox20260509.CreateTemplateRegistryNetworkConfig({
vpcId: 'vpc-xxxxxx',
vSwitchId: 'vsw-xxxxxx',
securityGroupId: 'sg-xxxxxx',
}),
}),
}),
}),
}),
}));
Go
created, err := popClient.CreateTemplate(&fcsandbox20260509.CreateTemplateRequest{
Body: &fcsandbox20260509.CreateTemplateInput{
Name: tea.String(fmt.Sprintf("pop-demo-%d", time.Now().Unix())),
TeamID: tea.String(teamID),
RuntimeConfig: &fcsandbox20260509.CreateTemplateRuntimeConfig{
SandboxConfig: &fcsandbox20260509.CreateTemplateSandboxConfig{
Image: tea.String("test-registry-vpc.cn-beijing.cr.aliyuncs.com/runtime/python:3.12-v1"),
AcrInstanceId: tea.String("cri-xxxxxx"),
RegistryConfig: &fcsandbox20260509.CreateTemplateRegistryConfig{
AuthConfig: &fcsandbox20260509.CreateTemplateRegistryAuthConfig{
UserName: tea.String("<username>"),
Password: tea.String("<password>"),
},
NetworkConfig: &fcsandbox20260509.CreateTemplateRegistryNetworkConfig{
VpcId: tea.String("vpc-xxxxxx"),
VSwitchId: tea.String("vsw-xxxxxx"),
SecurityGroupId: tea.String("sg-xxxxxx"),
},
},
},
},
},
})
if err != nil {
panic(err)
}
Java
CreateTemplateInput body = new CreateTemplateInput()
.setName("pop-demo-" + System.currentTimeMillis() / 1000)
.setTeamID(teamID)
.setRuntimeConfig(new CreateTemplateRuntimeConfig()
.setSandboxConfig(new CreateTemplateSandboxConfig()
.setImage("test-registry-vpc.cn-beijing.cr.aliyuncs.com/runtime/python:3.12-v1")
.setAcrInstanceId("cri-xxxxxx")
.setRegistryConfig(new CreateTemplateRegistryConfig()
.setAuthConfig(new CreateTemplateRegistryAuthConfig()
.setUserName("<username>")
.setPassword("<password>"))
.setNetworkConfig(new CreateTemplateRegistryNetworkConfig()
.setVpcId("vpc-xxxxxx")
.setVSwitchId("vsw-xxxxxx")
.setSecurityGroupId("sg-xxxxxx")))));
String templateID = popClient
.createTemplate(new CreateTemplateRequest().setBody(body))
.getBody().getTemplateID();
Public OCI registries
The OCI registry is accessible over the Internet and has a valid TLS certificate. You do not need to configure the VPC or the certificate. For public OCI registries, "accessible over the Internet" means that Function Compute can reach the registry from the corresponding region, not that the registry only exposes a public domain name.
Limits:
-
Only the username and password in
auth_configare required, andnetwork_configis not required. The credentials must have the pull permission on the repository. -
If
build_configis left empty, the build artifact is pushed to a new tag in the same repository. Therefore, the credentials must also have the push permission. -
network_configandcert_configare required only if certificate verification must be skipped for the repository or the repository has specific network requirements.
Sample request:
Python
response = pop_client.create_template(
models.CreateTemplateRequest(
body=models.CreateTemplateInput(
name=f"pop-demo-{int(time.time())}",
team_id=team_id,
runtime_config=models.CreateTemplateRuntimeConfig(
sandbox_config=models.CreateTemplateSandboxConfig(
image="registry.example.com/ns/repo:v1",
registry_config=models.CreateTemplateRegistryConfig(
auth_config=models.CreateTemplateRegistryAuthConfig(
user_name="<username>",
password="<password>",
),
),
),
),
)
)
)
TypeScript
const created = await popClient.createTemplate(new $FCSandbox20260509.CreateTemplateRequest({
body: new $FCSandbox20260509.CreateTemplateInput({
name: `pop-demo-${Math.floor(Date.now() / 1000)}`,
teamID,
runtimeConfig: new $FCSandbox20260509.CreateTemplateRuntimeConfig({
sandboxConfig: new $FCSandbox20260509.CreateTemplateSandboxConfig({
image: 'registry.example.com/ns/repo:v1',
registryConfig: new $FCSandbox20260509.CreateTemplateRegistryConfig({
authConfig: new $FCSandbox20260509.CreateTemplateRegistryAuthConfig({
userName: '<username>',
password: '<password>',
}),
}),
}),
}),
}),
}));
Go
created, err := popClient.CreateTemplate(&fcsandbox20260509.CreateTemplateRequest{
Body: &fcsandbox20260509.CreateTemplateInput{
Name: tea.String(fmt.Sprintf("pop-demo-%d", time.Now().Unix())),
TeamID: tea.String(teamID),
RuntimeConfig: &fcsandbox20260509.CreateTemplateRuntimeConfig{
SandboxConfig: &fcsandbox20260509.CreateTemplateSandboxConfig{
Image: tea.String("registry.example.com/ns/repo:v1"),
RegistryConfig: &fcsandbox20260509.CreateTemplateRegistryConfig{
AuthConfig: &fcsandbox20260509.CreateTemplateRegistryAuthConfig{
UserName: tea.String("<username>"),
Password: tea.String("<password>"),
},
},
},
},
},
})
if err != nil {
panic(err)
}
Java
CreateTemplateInput body = new CreateTemplateInput()
.setName("pop-demo-" + System.currentTimeMillis() / 1000)
.setTeamID(teamID)
.setRuntimeConfig(new CreateTemplateRuntimeConfig()
.setSandboxConfig(new CreateTemplateSandboxConfig()
.setImage("registry.example.com/ns/repo:v1")
.setRegistryConfig(new CreateTemplateRegistryConfig()
.setAuthConfig(new CreateTemplateRegistryAuthConfig()
.setUserName("<username>")
.setPassword("<password>")))));
String templateID = popClient
.createTemplate(new CreateTemplateRequest().setBody(body))
.getBody().getTemplateID();
Private OCI registries in a VPC
A self-managed private registry whose domain name is accessible only within a VPC. Example: a self-managed Harbor registry on an Elastic Compute Service (ECS) instance in a VPC.
Limits:
-
The registry must be served over HTTPS and listen on port 443. Custom ports and HTTP are not supported.
-
registry_config.network_configis required. You must specify the VPC parametersvpc_id,v_switch_id, andsecurity_group_idat the same time. -
If the private registry uses a self-signed certificate, you must specify that certificate verification is skipped (
insecure=True) incert_config. Otherwise, the build fails during the source image pull stage due to an x509 certificate error. -
Specify the credentials in
auth_configin the same way as for public OCI registries.
Sample request:
Python
response = pop_client.create_template(
models.CreateTemplateRequest(
body=models.CreateTemplateInput(
name=f"pop-demo-{int(time.time())}",
team_id=team_id,
runtime_config=models.CreateTemplateRuntimeConfig(
sandbox_config=models.CreateTemplateSandboxConfig(
image="registry.internal.example.com/ns/repo:v1",
registry_config=models.CreateTemplateRegistryConfig(
auth_config=models.CreateTemplateRegistryAuthConfig(
user_name="<username>",
password="<password>",
),
network_config=models.CreateTemplateRegistryNetworkConfig(
vpc_id="vpc-xxxxxx",
v_switch_id="vsw-xxxxxx",
security_group_id="sg-xxxxxx",
),
cert_config=models.CreateTemplateRegistryCertConfig(
insecure=True,
),
),
),
),
)
)
)
TypeScript
const created = await popClient.createTemplate(new $FCSandbox20260509.CreateTemplateRequest({
body: new $FCSandbox20260509.CreateTemplateInput({
name: `pop-demo-${Math.floor(Date.now() / 1000)}`,
teamID,
runtimeConfig: new $FCSandbox20260509.CreateTemplateRuntimeConfig({
sandboxConfig: new $FCSandbox20260509.CreateTemplateSandboxConfig({
image: 'registry.internal.example.com/ns/repo:v1',
registryConfig: new $FCSandbox20260509.CreateTemplateRegistryConfig({
authConfig: new $FCSandbox20260509.CreateTemplateRegistryAuthConfig({
userName: '<username>',
password: '<password>',
}),
networkConfig: new $FCSandbox20260509.CreateTemplateRegistryNetworkConfig({
vpcId: 'vpc-xxxxxx',
vSwitchId: 'vsw-xxxxxx',
securityGroupId: 'sg-xxxxxx',
}),
certConfig: new $FCSandbox20260509.CreateTemplateRegistryCertConfig({
insecure: true,
}),
}),
}),
}),
}),
}));
Go
created, err := popClient.CreateTemplate(&fcsandbox20260509.CreateTemplateRequest{
Body: &fcsandbox20260509.CreateTemplateInput{
Name: tea.String(fmt.Sprintf("pop-demo-%d", time.Now().Unix())),
TeamID: tea.String(teamID),
RuntimeConfig: &fcsandbox20260509.CreateTemplateRuntimeConfig{
SandboxConfig: &fcsandbox20260509.CreateTemplateSandboxConfig{
Image: tea.String("registry.internal.example.com/ns/repo:v1"),
RegistryConfig: &fcsandbox20260509.CreateTemplateRegistryConfig{
AuthConfig: &fcsandbox20260509.CreateTemplateRegistryAuthConfig{
UserName: tea.String("<username>"),
Password: tea.String("<password>"),
},
NetworkConfig: &fcsandbox20260509.CreateTemplateRegistryNetworkConfig{
VpcId: tea.String("vpc-xxxxxx"),
VSwitchId: tea.String("vsw-xxxxxx"),
SecurityGroupId: tea.String("sg-xxxxxx"),
},
CertConfig: &fcsandbox20260509.CreateTemplateRegistryCertConfig{
Insecure: tea.Bool(true),
},
},
},
},
},
})
if err != nil {
panic(err)
}
Java
CreateTemplateInput body = new CreateTemplateInput()
.setName("pop-demo-" + System.currentTimeMillis() / 1000)
.setTeamID(teamID)
.setRuntimeConfig(new CreateTemplateRuntimeConfig()
.setSandboxConfig(new CreateTemplateSandboxConfig()
.setImage("registry.internal.example.com/ns/repo:v1")
.setRegistryConfig(new CreateTemplateRegistryConfig()
.setAuthConfig(new CreateTemplateRegistryAuthConfig()
.setUserName("<username>")
.setPassword("<password>"))
.setNetworkConfig(new CreateTemplateRegistryNetworkConfig()
.setVpcId("vpc-xxxxxx")
.setVSwitchId("vsw-xxxxxx")
.setSecurityGroupId("sg-xxxxxx"))
.setCertConfig(new CreateTemplateRegistryCertConfig()
.setInsecure(true)))));
String templateID = popClient
.createTemplate(new CreateTemplateRequest().setBody(body))
.getBody().getTemplateID();
Runtime network
vpc_config specifies the VPC in which the runtime sandbox of the destination template resides. Multiple vSwitches are supported. The network used to pull the source image during the build (registry_config.network_config) is independent of the runtime network. Configure the pull network and the runtime network separately.
If Internet access is disabled (internet_access=False), access to the Internet from the sandbox fails. Sample request:
Python
response = pop_client.create_template(
models.CreateTemplateRequest(
body=models.CreateTemplateInput(
name=f"pop-demo-{int(time.time())}",
team_id=team_id,
runtime_config=models.CreateTemplateRuntimeConfig(
internet_access=False,
vpc_config=models.CreateTemplateVPCConfig(
vpc_id="vpc-xxxxxx",
v_switch_ids=["vsw-xxxxxx"],
security_group_id="sg-xxxxxx",
),
sandbox_config=models.CreateTemplateSandboxConfig(
image="fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49",
),
),
)
)
)
TypeScript
const created = await popClient.createTemplate(new $FCSandbox20260509.CreateTemplateRequest({
body: new $FCSandbox20260509.CreateTemplateInput({
name: `pop-demo-${Math.floor(Date.now() / 1000)}`,
teamID,
runtimeConfig: new $FCSandbox20260509.CreateTemplateRuntimeConfig({
internetAccess: false,
vpcConfig: new $FCSandbox20260509.CreateTemplateVPCConfig({
vpcId: 'vpc-xxxxxx',
vSwitchIds: ['vsw-xxxxxx'],
securityGroupId: 'sg-xxxxxx',
}),
sandboxConfig: new $FCSandbox20260509.CreateTemplateSandboxConfig({
image: 'fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49',
}),
}),
}),
}));
Go
created, err := popClient.CreateTemplate(&fcsandbox20260509.CreateTemplateRequest{
Body: &fcsandbox20260509.CreateTemplateInput{
Name: tea.String(fmt.Sprintf("pop-demo-%d", time.Now().Unix())),
TeamID: tea.String(teamID),
RuntimeConfig: &fcsandbox20260509.CreateTemplateRuntimeConfig{
InternetAccess: tea.Bool(false),
VpcConfig: &fcsandbox20260509.CreateTemplateVPCConfig{
VpcId: tea.String("vpc-xxxxxx"),
VSwitchIds: []*string{tea.String("vsw-xxxxxx")},
SecurityGroupId: tea.String("sg-xxxxxx"),
},
SandboxConfig: &fcsandbox20260509.CreateTemplateSandboxConfig{
Image: tea.String("fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49"),
},
},
},
})
if err != nil {
panic(err)
}
Java
CreateTemplateInput body = new CreateTemplateInput()
.setName("pop-demo-" + System.currentTimeMillis() / 1000)
.setTeamID(teamID)
.setRuntimeConfig(new CreateTemplateRuntimeConfig()
.setInternetAccess(false)
.setVpcConfig(new CreateTemplateVPCConfig()
.setVpcId("vpc-xxxxxx")
.setVSwitchIds(java.util.Arrays.asList("vsw-xxxxxx"))
.setSecurityGroupId("sg-xxxxxx"))
.setSandboxConfig(new CreateTemplateSandboxConfig()
.setImage("fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49")));
String templateID = popClient
.createTemplate(new CreateTemplateRequest().setBody(body))
.getBody().getTemplateID();
Log configuration
Ship sandbox runtime logs to Simple Log Service (SLS) in your Alibaba Cloud account by using log_config in runtime_config. Only the project and logstore parameters are supported. The SLS resources must reside in the same region as FC Agent Sandbox:
Python
response = pop_client.create_template(
models.CreateTemplateRequest(
body=models.CreateTemplateInput(
name=f"pop-demo-{int(time.time())}",
team_id=team_id,
runtime_config=models.CreateTemplateRuntimeConfig(
log_config=models.CreateTemplateLogConfig(
project="<sls-project>",
logstore="<sls-logstore>",
),
sandbox_config=models.CreateTemplateSandboxConfig(
image="fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49",
),
),
)
)
)
TypeScript
const created = await popClient.createTemplate(new $FCSandbox20260509.CreateTemplateRequest({
body: new $FCSandbox20260509.CreateTemplateInput({
name: `pop-demo-${Math.floor(Date.now() / 1000)}`,
teamID,
runtimeConfig: new $FCSandbox20260509.CreateTemplateRuntimeConfig({
logConfig: new $FCSandbox20260509.CreateTemplateLogConfig({
project: '<sls-project>',
logstore: '<sls-logstore>',
}),
sandboxConfig: new $FCSandbox20260509.CreateTemplateSandboxConfig({
image: 'fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49',
}),
}),
}),
}));
Go
created, err := popClient.CreateTemplate(&fcsandbox20260509.CreateTemplateRequest{
Body: &fcsandbox20260509.CreateTemplateInput{
Name: tea.String(fmt.Sprintf("pop-demo-%d", time.Now().Unix())),
TeamID: tea.String(teamID),
RuntimeConfig: &fcsandbox20260509.CreateTemplateRuntimeConfig{
LogConfig: &fcsandbox20260509.CreateTemplateLogConfig{
Project: tea.String("<sls-project>"),
Logstore: tea.String("<sls-logstore>"),
},
SandboxConfig: &fcsandbox20260509.CreateTemplateSandboxConfig{
Image: tea.String("fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49"),
},
},
},
})
if err != nil {
panic(err)
}
Java
CreateTemplateInput body = new CreateTemplateInput()
.setName("pop-demo-" + System.currentTimeMillis() / 1000)
.setTeamID(teamID)
.setRuntimeConfig(new CreateTemplateRuntimeConfig()
.setLogConfig(new CreateTemplateLogConfig()
.setProject("<sls-project>")
.setLogstore("<sls-logstore>"))
.setSandboxConfig(new CreateTemplateSandboxConfig()
.setImage("fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49")));
String templateID = popClient
.createTemplate(new CreateTemplateRequest().setBody(body))
.getBody().getTemplateID();
Destination image and build reuse
When you build an image that is not an official image, the system temporarily creates a Function Compute function to pull the source image, inject the dependencies that are required to run FC Agent Sandbox, and push the result as the destination image. The template uses the destination image to create the sandbox runtime environment. The temporary function is created in your own account, and the build generates a small amount of Function Compute fees.
Specify the destination image by using build_config.copy.image. Example: Push the destination image to a new tag in your image repository. If the destination repository is the same as the repository of the source image, you do not need to provide the credentials of the destination repository again. If you push the destination image to another repository, specify the credentials and network configurations of the destination repository in build_config.copy.registry_config. If multiple builds specify the same destination image, the system reuses the pushed destination image. Only the first build pushes the destination image. Subsequent builds reuse the image and push no new images, which shortens the build time. The manifest digest of the destination tag is the same as that of the first build.
Sample request. The destination and source images reside in the same repository. If build_config.copy is specified, enabled is required:
Python
response = pop_client.create_template(
models.CreateTemplateRequest(
body=models.CreateTemplateInput(
name=f"pop-demo-{int(time.time())}",
team_id=team_id,
runtime_config=models.CreateTemplateRuntimeConfig(
sandbox_config=models.CreateTemplateSandboxConfig(
image="registry.example.com/ns/repo:v1",
registry_config=models.CreateTemplateRegistryConfig(
auth_config=models.CreateTemplateRegistryAuthConfig(
user_name="<username>",
password="<password>",
),
),
),
),
build_config=models.CreateTemplateBuildConfig(
copy=models.CreateTemplateCopyAction(
enabled=True,
image="registry.example.com/ns/repo:v1-fcsandbox",
),
),
)
)
)
TypeScript
const created = await popClient.createTemplate(new $FCSandbox20260509.CreateTemplateRequest({
body: new $FCSandbox20260509.CreateTemplateInput({
name: `pop-demo-${Math.floor(Date.now() / 1000)}`,
teamID,
runtimeConfig: new $FCSandbox20260509.CreateTemplateRuntimeConfig({
sandboxConfig: new $FCSandbox20260509.CreateTemplateSandboxConfig({
image: 'registry.example.com/ns/repo:v1',
registryConfig: new $FCSandbox20260509.CreateTemplateRegistryConfig({
authConfig: new $FCSandbox20260509.CreateTemplateRegistryAuthConfig({
userName: '<username>',
password: '<password>',
}),
}),
}),
}),
buildConfig: new $FCSandbox20260509.CreateTemplateBuildConfig({
copy: new $FCSandbox20260509.CreateTemplateCopyAction({
enabled: true,
image: 'registry.example.com/ns/repo:v1-fcsandbox',
}),
}),
}),
}));
Go
created, err := popClient.CreateTemplate(&fcsandbox20260509.CreateTemplateRequest{
Body: &fcsandbox20260509.CreateTemplateInput{
Name: tea.String(fmt.Sprintf("pop-demo-%d", time.Now().Unix())),
TeamID: tea.String(teamID),
RuntimeConfig: &fcsandbox20260509.CreateTemplateRuntimeConfig{
SandboxConfig: &fcsandbox20260509.CreateTemplateSandboxConfig{
Image: tea.String("registry.example.com/ns/repo:v1"),
RegistryConfig: &fcsandbox20260509.CreateTemplateRegistryConfig{
AuthConfig: &fcsandbox20260509.CreateTemplateRegistryAuthConfig{
UserName: tea.String("<username>"),
Password: tea.String("<password>"),
},
},
},
},
BuildConfig: &fcsandbox20260509.CreateTemplateBuildConfig{
Copy: &fcsandbox20260509.CreateTemplateCopyAction{
Enabled: tea.Bool(true),
Image: tea.String("registry.example.com/ns/repo:v1-fcsandbox"),
},
},
},
})
if err != nil {
panic(err)
}
Java
CreateTemplateInput body = new CreateTemplateInput()
.setName("pop-demo-" + System.currentTimeMillis() / 1000)
.setTeamID(teamID)
.setRuntimeConfig(new CreateTemplateRuntimeConfig()
.setSandboxConfig(new CreateTemplateSandboxConfig()
.setImage("registry.example.com/ns/repo:v1")
.setRegistryConfig(new CreateTemplateRegistryConfig()
.setAuthConfig(new CreateTemplateRegistryAuthConfig()
.setUserName("<username>")
.setPassword("<password>")))))
.setBuildConfig(new CreateTemplateBuildConfig()
.setCopy(new CreateTemplateCopyAction()
.setEnabled(true)
.setImage("registry.example.com/ns/repo:v1-fcsandbox")));
String templateID = popClient
.createTemplate(new CreateTemplateRequest().setBody(body))
.getBody().getTemplateID();
Query the build status
You can call GetTemplate - Query a template to query the configurations and build status of a single template. The build status is obtained from status.state in the response. Valid values:
|
Status |
Description |
|
|
The build is accepted and waits to start. |
|
|
The build is in progress. |
|
|
The build succeeds, and the template can be used to create sandboxes. |
|
|
The build fails, and |
After the build enters the ready or error final state, the response contains status.finished_at, which indicates when the build ended.
The response returns the actual configured parameters, not the system default values. Sensitive parameters such as image pull credentials are not returned.
Manage templates
You can call ListTemplates - Query templates to query the templates in a Team page by page. The templates are returned in descending order of creation time. You can call DeleteTemplate - Delete a template to delete templates that are no longer used:
Python
# Query the templates in the Team by page.
response = pop_client.list_templates(
models.ListTemplatesRequest(team_id=team_id)
)
for template in response.body.templates:
print(template.template_id, template.status.state, template.created_time)
# If a next page exists, pass response.body.next_token as next_token in the next request.
# Delete the template.
pop_client.delete_template(template_id, models.DeleteTemplateRequest(team_id=team_id))
TypeScript
// Query the templates in the Team by page.
const response = await popClient.listTemplates(
new $FCSandbox20260509.ListTemplatesRequest({ teamID }));
for (const template of response.body.templates ?? []) {
console.log(template.templateID, template.status.state, template.createdTime);
}
// If a next page exists, pass response.body.nextToken as nextToken in the next request.
// Delete the template.
await popClient.deleteTemplate(templateID,
new $FCSandbox20260509.DeleteTemplateRequest({ teamID }));
Go
// Query the templates in the Team by page.
resp, err := popClient.ListTemplates(&fcsandbox20260509.ListTemplatesRequest{
TeamID: tea.String(teamID),
})
if err != nil {
panic(err)
}
for _, template := range resp.Body.Templates {
fmt.Println(tea.StringValue(template.TemplateID),
tea.StringValue(template.Status.State),
tea.StringValue(template.CreatedTime))
}
// If a next page exists, pass resp.Body.NextToken as NextToken in the next request.
// Delete the template.
_, err = popClient.DeleteTemplate(tea.String(templateID), &fcsandbox20260509.DeleteTemplateRequest{
TeamID: tea.String(teamID),
})
if err != nil {
panic(err)
}
Java
// Query the templates in the Team by page.
ListTemplatesResponse response = popClient.listTemplates(
new ListTemplatesRequest().setTeamID(teamID));
for (PublicTemplate template : response.getBody().getTemplates()) {
System.out.printf("%s %s %s%n", template.getTemplateID(),
template.getStatus().getState(), template.getCreatedTime());
}
// If a next page exists, pass response.getBody().getNextToken() as nextToken in the next request.
// Delete the template.
popClient.deleteTemplate(templateID,
new DeleteTemplateRequest().setTeamID(teamID));
-
A template can be deleted regardless of its state, including the building state. The deletion terminates the ongoing build.
-
After a template is deleted, the template name is released immediately, so a new template with the same name can be created.
-
Built-in system templates, such as
base, cannot be deleted. -
A new template may appear in the list a few seconds after it is created. This is normal during index synchronization.
GetTemplateis not affected.
Limitations
-
All template API operations require the Team ID. If the Team ID is not specified,
400 InvalidParameteris returned. -
The request body is validated in strict JSON format. Unknown fields, duplicate keys, and explicit
nullvalues cause400to be returned. The maximum size of a request body is 1 MiB. -
Template names must be unique in a Team. If you create a template that has the same name as an existing template,
409 TemplateAlreadyExistsis returned. -
No separate update operation is provided. To update a template, delete the old template and then create a new one.
Build locally with the E2B SDK
The E2B SDK allows you to define a template and submit a build on your on-premises machine. Local builds are suitable for initial verification and personal development. Install the dependencies:
python3 -m venv .venv
source .venv/bin/activate
pip install e2b==2.32.0 e2b-code-interpreter==2.8.1 python-dotenv
Create a .env file:
# Replace the value with your own API key before you use the file
E2B_API_KEY=e2b_xxx
FROM_IMAGE="fc-e2b-registry.cn-beijing.cr.aliyuncs.com/runtime/code-interpreter-v1:v0.0.49"
# Example values for the China (Beijing) production environment
E2B_API_URL=https://api.cn-beijing.e2b.fc.aliyuncs.com
E2B_DOMAIN=cn-beijing.e2b.fc.aliyuncs.com
FROM_IMAGE specifies an official FC Agent Sandbox image by default, and no credentials or network configurations are required. For other official image addresses, see Image sources above. If you want to use a private image source that requires authentication or network configurations, create templates by calling OpenAPI operations as described in this topic.
Run the script to build the image as a template, and then create a sandbox for verification:
#!/usr/bin/env python3
import os
import time
from dotenv import load_dotenv
from e2b import Template, default_build_logger
from e2b_code_interpreter import Sandbox
load_dotenv()
FROM_IMAGE = os.getenv("FROM_IMAGE", "").strip()
RUN_CODE = "print('hello')"
# The SDK automatically reads the E2B_API_KEY / E2B_API_URL / E2B_DOMAIN environment variables.
build = Template.build(
Template().from_image(FROM_IMAGE),
name=f"template-{int(time.time())}",
cpu_count=2,
memory_mb=2048,
on_build_logs=default_build_logger(),
)
sandbox = Sandbox.create(template=build.template_id)
try:
print(f"template_id: {build.template_id}")
print(f"build_id: {build.build_id}")
print(f"sandbox_id: {sandbox.sandbox_id}")
print(f"sandbox_domain: {sandbox.sandbox_domain}")
print(f"envd_api_url: {sandbox.envd_api_url}")
execution = sandbox.run_code(RUN_CODE)
stdout = "".join(execution.logs.stdout or [])
stderr = "".join(execution.logs.stderr or [])
print(f"run_code code: {RUN_CODE}")
print(f"run_code stdout: {stdout.strip()}")
print(f"run_code stderr: {stderr.strip()}")
print(f"run_code error: {execution.error}")
if execution.error is not None:
raise RuntimeError(f"run_code failed: {execution.error}")
if stdout.strip() != "hello":
raise RuntimeError(f"Unexpected run_code stdout: {stdout!r}")
finally:
print(f"killing sandbox: {sandbox.sandbox_id}")
sandbox.kill()
print("sandbox killed")
Use the CLI to view templates and create sandboxes
If the E2B CLI is installed, check the build status in the template list:
export E2B_API_KEY=e2b_xxx
export E2B_API_URL=https://api.cn-beijing.e2b.fc.aliyuncs.com
export E2B_DOMAIN=cn-beijing.e2b.fc.aliyuncs.com
e2b template list
After the template enters the ready state, use the template name or template_id to create a sandbox. The template name can be template-{timestamp} generated in the previous step, and my-code-interpreter-v1 is an example name:
e2b sandbox create my-code-interpreter-v1
After you access the sandbox, verify the key dependencies:
env | sort | head
python3 --version
which python3
Template naming recommendations
Include the business name, base image, version of key dependencies, or date in the template name. Example: agent-python313-20260531. In the production environment, do not overwrite a template that is in use. First, create a new template and verify it through a canary release.
Local builds that use the E2B SDK are suitable for quick verification with official images. To configure the build pull network, runtime VPC, and other settings when you create a template, create templates by calling OpenAPI operations and use the registry_config.network_config and vpc_config fields. For more information, see Image sources and Runtime network above.
FAQ
To troubleshoot API issues, check the code, message, and request_id parameters in the exception object returned by the SDK. When you contact technical support, provide the request_id.
The InvalidParameter error code is returned
Check whether the Team ID is missing, whether the request body contains unknown fields, duplicate keys, or an explicit null, or whether the unsupported start_command or ready_command field is specified.
The TemplateAlreadyExists error code is returned
A template that has the same name exists in the Team. You can call ListTemplates to query the templates, call DeleteTemplate to delete the template that is no longer used, or change the template name.
The TemplateNotFound error code is returned
The template does not exist, has been deleted, or does not belong to the current Team.
The SignatureDoesNotMatch error is returned
The signature verification fails. Common causes include an invalid AccessKey secret, expired Security Token Service (STS) temporary credentials, or a large clock skew on your on-premises machine. Use the official SDK to call API operations and avoid issues caused by manually constructing signatures.
status.state is error
The build fails. Check the specific cause in status.reason.message. Common causes include image pull failures, images that do not meet the requirements, and VPC network configuration errors. For more information about the limits and parameters of image sources, see "Image sources" above. For more information about vSwitch zone issues, see The zone of the vSwitch is not supported below.
Slow template build
First, check your ACR EE image size, network links, image layer cache, and the private network access configurations of the ACR EE instance. In most cases, the larger the base image, the longer the first build takes.
If you only want to check whether the template build pipeline works, temporarily switch to an official FC Agent Sandbox image for comparison. Official images contain the dependencies required to run FC Agent Sandbox, which usually makes it easier to rule out image compatibility issues.
The zone of the vSwitch is not supported
If the vSwitch is in unsupported zone error message is returned during a build or at runtime, Function Compute does not support the zone of the selected vSwitch.
Handle the issue by performing the following steps:
-
Identify the zone in which the current vSwitch resides based on the error message.
-
Select a destination zone from the zones supported by Function Compute.
-
Create a vSwitch in the destination zone in the same VPC.
-
Use the new vSwitch to configure Function Compute or the related network settings.
-
Build the template again and create a sandbox for verification.
By default, vSwitches in different zones of the same VPC can communicate with each other over the internal network. Therefore, even if your business resources are deployed in other zones, add a vSwitch in a zone supported by Function Compute to the same VPC. This vSwitch connects your resources to Function Compute.
The sandbox is created, but run_code fails
run_code calls the python3 command of the image to run code. If the image does not contain python3 or the related dependencies, the execution may fail. In the sandbox, check whether the image contains the dependencies required by the code interpreter:
python3 --version
which python3
env | sort | head -50
Slow sandbox startup
If the sandbox takes a long time to start, use the following script to flatten an image into a single-layer image. Then compare the original image with the flattened image. When you run tests, use the same template specifications, region, concurrency, and image startup command, and separately record how long template builds, sandbox creation, and the first execution take.
The script requires Docker and Python 3. Before you run the script, make sure that the source image is pulled to your on-premises machine, and use a new tag for the destination image. Verify the flattened image before you use it.
#!/usr/bin/env bash
set -euo pipefail
PLATFORM="linux/amd64"
SRC="${1:?Usage: $0 <source-image> [destination-tag]}"
if [ "$#" -ge 2 ]; then
DST="$2"
elif [[ "$SRC" == *@* ]] || [[ "${SRC##*/}" != *:* ]]; then
echo "Error: Specify a destination tag if the source image uses a digest or has no tag." >&2
exit 2
else
DST="${SRC}-flat"
fi
echo "==> Source image: $SRC"
echo "==> Destination image: $DST"
echo "==> Platform: $PLATFORM"
echo "==> Extracting image metadata..."
RAW_CMD=$(docker inspect --format='{{json .Config.Cmd}}' "$SRC")
RAW_ENTRYPOINT=$(docker inspect --format='{{json .Config.Entrypoint}}' "$SRC")
RAW_ENV=$(docker inspect --format='{{json .Config.Env}}' "$SRC")
RAW_EXPOSE=$(docker inspect --format='{{json .Config.ExposedPorts}}' "$SRC")
RAW_WORKDIR=$(docker inspect --format='{{.Config.WorkingDir}}' "$SRC")
RAW_USER=$(docker inspect --format='{{.Config.User}}' "$SRC")
RAW_VOLUMES=$(docker inspect --format='{{json .Config.Volumes}}' "$SRC")
RAW_LABELS=$(docker inspect --format='{{json .Config.Labels}}' "$SRC")
RAW_STOPSIGNAL=$(docker inspect --format='{{.Config.StopSignal}}' "$SRC")
CHANGES=()
if [ "$RAW_CMD" != "null" ] && [ -n "$RAW_CMD" ]; then
CHANGES+=(--change "CMD $RAW_CMD")
fi
if [ "$RAW_ENTRYPOINT" != "null" ] && [ -n "$RAW_ENTRYPOINT" ]; then
CHANGES+=(--change "ENTRYPOINT $RAW_ENTRYPOINT")
fi
if [ "$RAW_ENV" != "null" ] && [ "$RAW_ENV" != "[]" ] && [ -n "$RAW_ENV" ]; then
while IFS= read -r env_entry; do
CHANGES+=(--change "ENV ${env_entry%%=*}=\"${env_entry#*=}\"")
done < <(echo "$RAW_ENV" | python3 -c '
import json
import sys
for entry in json.load(sys.stdin):
print(entry)
')
fi
if [ "$RAW_EXPOSE" != "null" ] && [ "$RAW_EXPOSE" != "{}" ] && [ -n "$RAW_EXPOSE" ]; then
while IFS= read -r port; do
CHANGES+=(--change "EXPOSE $port")
done < <(echo "$RAW_EXPOSE" | python3 -c '
import json
import sys
for key in json.load(sys.stdin):
print(key)
')
fi
if [ -n "$RAW_WORKDIR" ]; then
CHANGES+=(--change "WORKDIR $RAW_WORKDIR")
fi
if [ -n "$RAW_USER" ]; then
CHANGES+=(--change "USER $RAW_USER")
fi
if [ "$RAW_VOLUMES" != "null" ] && [ "$RAW_VOLUMES" != "{}" ] && [ -n "$RAW_VOLUMES" ]; then
while IFS= read -r volume; do
CHANGES+=(--change "VOLUME $volume")
done < <(echo "$RAW_VOLUMES" | python3 -c '
import json
import sys
for key in json.load(sys.stdin):
print(key)
')
fi
if [ "$RAW_LABELS" != "null" ] && [ "$RAW_LABELS" != "{}" ] && [ -n "$RAW_LABELS" ]; then
while IFS= read -r label; do
CHANGES+=(--change "LABEL $label")
done < <(echo "$RAW_LABELS" | python3 -c '
import json
import sys
for key, value in json.load(sys.stdin).items():
print(f"{key}=\"{value}\"")
')
fi
if [ -n "$RAW_STOPSIGNAL" ]; then
CHANGES+=(--change "STOPSIGNAL $RAW_STOPSIGNAL")
fi
ORIG_LAYERS=$(docker inspect --format='{{len .RootFS.Layers}}' "$SRC")
echo "==> Layers of the original image: $ORIG_LAYERS"
echo "==> Flattening image layers..."
CONTAINER_ID=$(docker create --platform "$PLATFORM" "$SRC" /bin/true)
trap 'docker rm -f "${CONTAINER_ID:-}" >/dev/null 2>&1 || true' EXIT
docker export "$CONTAINER_ID" | docker import \
--platform "$PLATFORM" \
"${CHANGES[@]}" \
- "$DST"
NEW_LAYERS=$(docker inspect --format='{{len .RootFS.Layers}}' "$DST")
ORIG_SIZE=$(docker inspect --format='{{.Size}}' "$SRC" | awk '{printf "%.0f MB", $1/1024/1024}')
NEW_SIZE=$(docker inspect --format='{{.Size}}' "$DST" | awk '{printf "%.0f MB", $1/1024/1024}')
ORIG_ARCH=$(docker inspect --format='{{.Architecture}}' "$SRC")
NEW_ARCH=$(docker inspect --format='{{.Architecture}}' "$DST")
echo ""
echo "==> Done"
echo " Original image: $ORIG_LAYERS layers, $ORIG_SIZE, arch=$ORIG_ARCH"
echo " Flattened image: $NEW_LAYERS layers, $NEW_SIZE, arch=$NEW_ARCH"
echo " Tag: $DST"
Examples
Save the preceding script as flatten-image.sh and make it executable. The following example flattens the source image into a single-layer image and generates a new destination tag:
chmod +x flatten-image.sh
./flatten-image.sh \
registry.example.com/runtime/python:3.12-v1 \
registry.example.com/runtime/python:3.12-v1-flat
After the script runs, check whether the number of image layers and the image size in the output meet your expectations. Then, push the destination image to the image repository and use the destination image address to build the template:
docker push registry.example.com/runtime/python:3.12-v1-flat
If the flattened image starts faster under the same conditions, merge build steps to reduce the number of image layers when you build images.