This tutorial explains how to build and push Docker images inside a Blaxel sandbox. It also explains how to run Docker containers and expose them securely using sandbox preview URLs.
Prerequisites
Blaxel CLI installed and authenticated (bl login)
Node.js 18+ or Python 3.12+ installed
Blaxel SDK installed in your project (npm install @blaxel/core or pip install blaxel)
Create and connect to a sandbox
Blaxel provides a ready-to-use sandbox image (blaxel/docker-in-sandbox) with everything you need to build and run Docker images. This image also includes the Docker CLI, Docker Compose and iptables-legacy (as a replacement for nftables).
Create and deploy a sandbox using the Docker sandbox image:
Blaxel CLI
TypeScript
Python
bl apply -f - << EOF
apiVersion: blaxel.ai/v1alpha1
kind: Sandbox
metadata:
name: my-docker-sandbox
spec:
runtime:
image: blaxel/docker-in-sandbox:latest
generation: mk3
memory: 4096
region: us-pdx-1
EOF
import { SandboxInstance } from "@blaxel/core" ;
const sandbox = await SandboxInstance . create ({
name: "my-docker-sandbox" ,
image: "blaxel/docker-in-sandbox:latest" ,
memory: 4096 ,
region: "us-pdx-1"
});
import asyncio
from blaxel.core import SandboxInstance
async def main ():
sandbox = await SandboxInstance.create({
"name" : "my-docker-sandbox" ,
"image" : "blaxel/docker-in-sandbox:latest" ,
"memory" : 4096 ,
"region" : "us-pdx-1"
if __name__ == "__main__" :
asyncio.run(main())
Connect to the sandbox terminal for subsequent commands:
bl connect sandbox my-docker-sandbox
Run a Docker container
You can run a container from any public image. Here is an example of running an NGINX container:
docker run -d -p 8081:80 --name my-nginx nginx
Check that it is running:
Open a shell into a running Docker container
Use docker exec to open a shell inside the running container:
docker exec -it my-nginx /bin/sh
Expose a Docker container at a sandbox preview URL
Once a Docker container is running inside your sandbox, you can expose it externally via a preview URL .
To see this in action, run an NGINX container on sandbox port 8081:
docker run -d -p 8081:80 nginx
Then, use the Blaxel SDK to create a preview URL for that port:
import { SandboxInstance } from "@blaxel/core" ;
const sandbox = await SandboxInstance . get ( "my-docker-sandbox" );
const preview = await sandbox . previews . create ({
metadata: { name: "nginx-preview" },
spec: {
port: 8081 ,
public: true
}
});
console . log ( "Preview URL:" , preview . spec ?. url );
import asyncio
from blaxel.core import SandboxInstance
async def main ():
sandbox = await SandboxInstance.get( "my-docker-sandbox" )
preview = await sandbox.previews.create({
"metadata" : { "name" : "nginx-preview" },
"spec" : {
"port" : 8081 ,
"public" : True
}
})
print ( "Preview URL:" , preview.spec.url)
if __name__ == "__main__" :
asyncio.run(main())
Now, when you access the preview URL, you should see the default NGINX welcome page.
Build and push a Docker image
You can also build and push images from the sandbox.
To see this in action, first create a minimal Dockerfile in the sandbox’s /app directory:
FROM alpine:latest
CMD [ "echo" , "Hello from Blaxel" ]
Then, build and push it to ttl.sh , a transient image registry:
If you plan to run the final image on a Blaxel sandbox, add the --platform linux/amd64 flag when building so the image runs correctly.
Blaxel CLI
TypeScript
Python
cd /app
docker build --platform linux/amd64 -t ttl.sh/my-app:1h .
docker push ttl.sh/my-app:1h
import { SandboxInstance } from "@blaxel/core" ;
const sandbox = await SandboxInstance . get ( "my-docker-sandbox" );
const image = "ttl.sh/my-app:1h" ;
const build = await sandbox . process . exec ({
command: `docker build --platform linux/amd64 -t ${ image } /app` ,
waitForCompletion: true ,
});
console . log ( build . logs );
const push = await sandbox . process . exec ({
command: `docker push ${ image } ` ,
waitForCompletion: true ,
});
console . log ( push . logs );
import asyncio
from blaxel.core import SandboxInstance
async def main ():
sandbox = await SandboxInstance.get( "my-docker-sandbox" )
image = "ttl.sh/my-app:1h"
build = await sandbox.process.exec({
"command" : f "docker build --platform linux/amd64 -t { image } /app" ,
"wait_for_completion" : True ,
})
print (build.logs)
push = await sandbox.process.exec({
"command" : f "docker push { image } " ,
"wait_for_completion" : True ,
})
print (push.logs)
if __name__ == "__main__" :
asyncio.run(main())
Once the image is published to the registry, you can test it with docker run:
docker run ttl.sh/my-app:1h
Use Docker Compose
The Docker sandbox image includes a sample Docker Compose application in the example directory. Try it with the following commands:
cd example
docker compose up
Ensure that your sandbox is configured with sufficient memory for the build process and output.