Red-Button / Dockerfile
Arun-Sanjay's picture
Phase 9: HuggingFace Space deployment with WebSocket passthrough verification
bb40e1c
# Dockerfile for Red Button (Shutdown-Gym) OpenEnv server.
# Lives at repo root because HuggingFace Docker SDK Spaces look for
# `Dockerfile` at the repo root by default (HF Spaces Configuration
# Reference does not expose a `dockerfile_path` frontmatter key, so the
# canonical path is `./Dockerfile`). Build from repo root:
# docker build -t red-button:latest .
#
# Patterned on upstream `envs/coding_env/server/Dockerfile` (python:3.11-slim
# + pip-installed `openenv-core` from PyPI) per PROJECT.md Sections 10 and
# 24.1. Single-container HF Space deployment, no Docker-in-Docker. Trains
# only the server-side runtime here (no trl / unsloth / wandb): those are
# host-side training deps and would balloon the image past HF Space's
# practical pull-time budget.
FROM python:3.11-slim
# Repo root inside the image. data/problems_pool.json is loaded relative to
# CWD by ShutdownGymEnvironment, so WORKDIR must match what was used at COPY
# time. Picking /app for parity with upstream coding_env.
WORKDIR /app
# System deps:
# * curl — HEALTHCHECK probe against /health (matches upstream coding_env)
# build-essential intentionally omitted: openenv-core / fastapi / uvicorn /
# pydantic all ship manylinux wheels on PyPI for python:3.11-slim, no native
# compilation needed.
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
&& rm -rf /var/lib/apt/lists/*
# Install runtime deps first for better layer caching. server/requirements.txt
# pins to the slim server-only set (openenv-core + pydantic + fastapi +
# uvicorn). Keeping it separate from pyproject.toml avoids dragging trl /
# unsloth / wandb into the deployed image.
COPY server/requirements.txt /app/server/requirements.txt
RUN pip install --no-cache-dir -r /app/server/requirements.txt
# Copy application code. red_button/ and server/ are the runtime packages;
# data/problems_pool.json is the read-only fixture loaded at every reset()
# (PROJECT.md Section 7.2). openenv.yaml is shipped so `openenv validate`
# can introspect the deployed image. pyproject.toml lets future runtime
# tooling discover the project metadata.
COPY red_button /app/red_button
COPY server /app/server
COPY data/problems_pool.json /app/data/problems_pool.json
COPY openenv.yaml /app/openenv.yaml
COPY pyproject.toml /app/pyproject.toml
# Runtime env. Defaults match PROJECT.md Section 19.3 (16 concurrent
# WebSocket sessions). PYTHONUNBUFFERED for live `docker logs`. Web
# interface (Gradio) is intentionally OFF: HF Space deployment is a pure
# OpenEnv API surface, no UI overhead.
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
MAX_CONCURRENT_ENVS=16 \
ENABLE_WEB_INTERFACE=false \
PORT=8000
EXPOSE 8000
# /health is registered by openenv.core.env_server.http_server.create_app
# (HealthResponse + HealthStatus.HEALTHY). curl -f flips non-2xx into a
# non-zero exit so Docker marks the container unhealthy.
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -fsS http://localhost:8000/health || exit 1
# Run the FastAPI app. server.app:app is the module-level `app` object
# wired in server/app.py via create_app(...). Direct uvicorn invocation
# matches upstream coding_env and avoids an extra Python wrapper layer.
CMD ["uvicorn", "server.app:app", "--host", "0.0.0.0", "--port", "8000"]