You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

参考Sonata Project Demo:如何实现网页启动容器、就绪跳转及自动销毁?

Hey Bob, great question! Setting up an interactive demo like Sonata Project's—where users can spin up a container right from the web, get redirected once it's ready, and have it auto-destroy after 10 minutes—is totally doable with a mix of container tools, a backend service, and some frontend logic. Let's walk through how to build this step by step.

核心技术栈选型

First, you'll need these foundational tools:

  • Docker: To create and manage the demo containers (we'll use its official SDK for backend integration)
  • A lightweight backend: I'll use Python/Flask for example, but Node.js with dockerode works just as well
  • Basic frontend: HTML/JavaScript for user interaction and status updates
  • Optional: Docker health checks (to reliably verify when the container is ready)
实现步骤详解

1. Backend: Handle Container Startup & Auto-Destruction

Your backend will be the brain here—receiving frontend requests, spinning up containers, and scheduling their cleanup. Here's a Flask example using the Docker SDK:

from flask import Flask, jsonify
import docker
import time
from threading import Thread
from flask_cors import CORS  # If your frontend is on a different origin

app = Flask(__name__)
CORS(app)
client = docker.from_env()  # Connect to local Docker daemon

# Track containers and their expiry times
container_expiry_tracker = {}

def auto_cleanup_container(container_id, delay=600):
    """Wait 10 minutes, then stop and remove the container"""
    time.sleep(delay)
    try:
        container = client.containers.get(container_id)
        if container.status == "running":
            container.stop()
            container.remove()
        del container_expiry_tracker[container_id]
    except docker.errors.NotFound:
        # Container was already removed—no action needed
        pass

@app.route('/start-demo', methods=['POST'])
def start_demo_container():
    # Use your pre-built demo image (replace with your image name)
    demo_image = "sonata-project/demo:latest"
    
    try:
        # Spin up the container with auto-assigned host port
        container = client.containers.run(
            demo_image,
            detach=True,
            ports={"80/tcp": None},  # Let Docker pick an available port
            mem_limit="512m",  # Limit resources to prevent abuse
            cpus=0.75
        )
        
        # Schedule auto-cleanup
        expiry_time = time.time() + 600
        container_expiry_tracker[container.id] = expiry_time
        Thread(target=auto_cleanup_container, args=(container.id,)).start()
        
        # Get the assigned host port
        host_port = container.attrs['NetworkSettings']['Ports']['80/tcp'][0]['HostPort']
        
        return jsonify({
            "container_id": container.id,
            "demo_url": f"http://your-server-ip:{host_port}",
            "expiry_time": expiry_time
        })
    except docker.errors.APIError as e:
        return jsonify({"error": f"Failed to start container: {str(e)}"}), 500

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Key Notes for the Backend:

  • We use a background thread to handle the 10-minute auto-destruction—this way the API doesn't block while waiting.
  • Resource limits (mem_limit, cpus) prevent a single container from hogging your server's resources.
  • The Docker SDK connects to your local Docker daemon—make sure the backend user has permission to access Docker.

2. Frontend: Trigger Startup & Wait for Readiness

The frontend needs to let users start the container, show status updates, and redirect once the demo is ready. Here's a simple implementation:

<div class="demo-controls">
    <button id="startDemoBtn" class="btn">Launch Demo Container</button>
    <div id="statusMessage" class="status"></div>
</div>

<script>
const startBtn = document.getElementById('startDemoBtn');
const statusMsg = document.getElementById('statusMessage');

startBtn.addEventListener('click', async () => {
    startBtn.disabled = true;
    statusMsg.textContent = "Starting your demo container... please wait";

    try {
        const response = await fetch('http://your-backend-url:5000/start-demo', {
            method: 'POST'
        });

        const data = await response.json();
        if (response.ok) {
            const demoUrl = data.demo_url;
            // Poll until the demo service is responsive
            const checkDemoReady = async () => {
                try {
                    const healthCheck = await fetch(`${demoUrl}/health`); // Use your app's health endpoint
                    if (healthCheck.ok) {
                        statusMsg.textContent = "Demo is ready! Redirecting...";
                        setTimeout(() => window.location.href = demoUrl, 1500);
                    } else {
                        setTimeout(checkDemoReady, 2000); // Retry every 2 seconds
                    }
                } catch (err) {
                    setTimeout(checkDemoReady, 2000);
                }
            };
            checkDemoReady();
        } else {
            statusMsg.textContent = `Error: ${data.error}`;
            startBtn.disabled = false;
        }
    } catch (err) {
        statusMsg.textContent = "Failed to connect to backend. Please try again.";
        startBtn.disabled = false;
    }
});
</script>

Optimizing Readiness Checks:

If your demo image doesn't have a /health endpoint, you can:

  1. Add a HEALTHCHECK directive to your Dockerfile (recommended for reliability)
  2. Or have the backend poll the container's status via the Docker API before returning the demo URL to the frontend.

3. Critical Security & Reliability Checks

Don't skip these—they'll prevent abuse and ensure your setup runs smoothly:

  • Restrict allowed images: Modify the backend to only let users start pre-approved images (never let users specify arbitrary image names).
  • Port range limits: Instead of letting Docker pick any port, specify a range like ports={"80/tcp": ("0.0.0.0", range(8000, 9000))} to avoid conflicts with system services.
  • Request throttling: Add rate limiting to the /start-demo endpoint (e.g., with Flask-Limiter) to stop users from spamming container starts.
  • Docker daemon hardening: Run the Docker daemon with minimal privileges, and avoid running the backend as root.

内容的提问来源于stack exchange,提问作者Bob5421

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:48:10