Skip to content

Commit a85e20f

Browse files
committed
Fix OpenSpiel docker builds
1 parent 2387696 commit a85e20f

File tree

5 files changed

+237
-117
lines changed

5 files changed

+237
-117
lines changed

.github/workflows/deploy-hf-env.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ jobs:
167167
# Cleanup
168168
cd ..
169169
rm -rf hf-space
170-
rm -rf hf-staging_$ENV_NAME_$ENV_NAME
170+
rm -rf hf-staging_$ENV_NAME
171171
172172
# Job to deploy single environment
173173
deploy-single:
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
name: Build OpenSpiel Base Image
2+
3+
on:
4+
workflow_dispatch: # Manual trigger only
5+
inputs:
6+
force_rebuild:
7+
description: 'Force rebuild even if base image exists'
8+
required: false
9+
default: 'false'
10+
type: boolean
11+
12+
env:
13+
REGISTRY: ghcr.io
14+
IMAGE_PREFIX: ${{ github.repository_owner }}/openenv
15+
16+
jobs:
17+
# Job 1: Build base image first
18+
build-base:
19+
runs-on: ubuntu-latest
20+
permissions:
21+
contents: read
22+
packages: write
23+
24+
steps:
25+
- name: Checkout code
26+
uses: actions/checkout@v4
27+
28+
- name: Set up Docker Buildx
29+
uses: docker/setup-buildx-action@v3
30+
31+
- name: Log in to GHCR
32+
uses: docker/login-action@v3
33+
with:
34+
registry: ${{ env.REGISTRY }}
35+
username: ${{ github.actor }}
36+
password: ${{ secrets.GITHUB_TOKEN }}
37+
38+
- name: Extract metadata for base image
39+
id: meta
40+
uses: docker/metadata-action@v5
41+
with:
42+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-base
43+
tags: |
44+
type=raw,value=latest,enable={{is_default_branch}}
45+
type=sha
46+
47+
- name: Build and push base image
48+
uses: docker/build-push-action@v5
49+
with:
50+
context: .
51+
file: src/core/containers/images/Dockerfile
52+
push: true
53+
platforms: linux/amd64,linux/arm64
54+
tags: ${{ steps.meta.outputs.tags }}
55+
labels: ${{ steps.meta.outputs.labels }}
56+
cache-from: type=gha,scope=base
57+
cache-to: type=gha,mode=max,scope=base
58+
59+
# Job 2: Build OpenSpiel base image (depends on base)
60+
build-openspiel-base:
61+
runs-on: 8-core-ubuntu
62+
needs: build-base # Wait for base image to be built
63+
permissions:
64+
contents: read
65+
packages: write
66+
67+
steps:
68+
- name: Checkout code
69+
uses: actions/checkout@v4
70+
71+
- name: Set up Docker Buildx
72+
uses: docker/setup-buildx-action@v3
73+
74+
- name: Log in to GHCR
75+
uses: docker/login-action@v3
76+
with:
77+
registry: ${{ env.REGISTRY }}
78+
username: ${{ github.actor }}
79+
password: ${{ secrets.GITHUB_TOKEN }}
80+
81+
- name: Extract metadata for OpenSpiel base image
82+
id: meta-openspiel-base
83+
uses: docker/metadata-action@v5
84+
with:
85+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}-openspiel-base
86+
tags: |
87+
type=raw,value=latest,enable={{is_default_branch}}
88+
type=sha
89+
90+
- name: Build and push OpenSpiel base image
91+
uses: docker/build-push-action@v5
92+
with:
93+
context: .
94+
file: src/envs/openspiel_env/server/Dockerfile.openspiel-base
95+
push: true
96+
platforms: linux/amd64,linux/arm64
97+
tags: ${{ steps.meta-openspiel-base.outputs.tags }}
98+
labels: ${{ steps.meta-openspiel-base.outputs.labels }}
99+
cache-from: type=gha,scope=openspiel-base
100+
cache-to: type=gha,mode=max,scope=openspiel-base
101+
102+
- name: Build summary
103+
run: |
104+
echo "✅ OpenSpiel base image built and pushed successfully!"
105+
echo "📦 Image: ${{ steps.meta-openspiel-base.outputs.tags }}"
106+
echo "🚀 Next regular build will use this new base image"

scripts/prepare_hf_deployment.sh

Lines changed: 57 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -94,63 +94,23 @@ DOCKERFILE_EOF
9494
"openspiel_env")
9595
# OpenSpiel requires special C++ build process - replace entire Dockerfile
9696
cat > $CURRENT_STAGING_DIR/Dockerfile << DOCKERFILE_EOF
97-
# OpenSpiel requires complex C++ build - using special multi-stage approach
98-
# Stage 1: Build OpenSpiel C++ bindings
99-
FROM python:3.11 AS openspiel-builder
100-
101-
# Avoid interactive prompts during build
102-
ENV DEBIAN_FRONTEND=noninteractive
103-
ENV TZ=UTC
104-
105-
# Install build dependencies
106-
RUN apt-get update && apt-get install -y --no-install-recommends \
107-
build-essential \
108-
clang \
109-
cmake \
110-
curl \
111-
git \
112-
sudo \
113-
&& rm -rf /var/lib/apt/lists/*
114-
115-
# Set up OpenSpiel build directory
116-
RUN mkdir /repo
117-
WORKDIR /repo
118-
119-
# Clone OpenSpiel
120-
RUN git clone https://github.com/google-deepmind/open_spiel.git .
121-
122-
# Run OpenSpiel's installation script (downloads C++ dependencies)
123-
RUN ./install.sh
124-
125-
# Install Python dependencies
126-
RUN pip3 install --no-cache-dir --upgrade setuptools testresources importlib_metadata
127-
RUN pip3 install --no-cache-dir --upgrade -r requirements.txt cmake
128-
129-
# Build OpenSpiel with Python 3.11
130-
RUN mkdir -p build
131-
WORKDIR /repo/build
132-
RUN cmake -DPython3_EXECUTABLE=$(which python3) -DCMAKE_CXX_COMPILER=$(which clang++) ../open_spiel
133-
RUN make -j$(nproc) pyspiel
134-
135-
# Stage 2: Use the specified openenv-base image
136-
FROM $BASE_IMAGE_REF
137-
138-
# Copy OpenSpiel build artifacts from builder
139-
RUN mkdir -p /repo
140-
COPY --from=openspiel-builder /repo /repo
141-
142-
# Install OpenSpiel Python requirements in runtime
143-
WORKDIR /repo
144-
RUN pip3 install --no-cache-dir --upgrade -r requirements.txt
145-
146-
# Set Python path for OpenSpiel
147-
ENV PYTHONPATH=/repo:/repo/build/python:${PYTHONPATH}
148-
149-
# Copy OpenEnv core
97+
# OpenSpiel environment using pre-built OpenSpiel base image
98+
# Use the pre-built OpenSpiel base image (contains compiled OpenSpiel)
99+
# Built from: docker build -t openspiel-base:latest -f src/envs/openspiel_env/server/Dockerfile.openspiel-base .
100+
# In GitHub Actions, this is overridden to use the GHCR base image
101+
ARG OPENSPIEL_BASE_IMAGE=openspiel-base:latest
102+
FROM \${OPENSPIEL_BASE_IMAGE}
103+
104+
# Copy OpenEnv core (base image already set WORKDIR=/app)
150105
WORKDIR /app
151106
COPY src/core/ /app/src/core/
107+
108+
# Copy OpenSpiel environment
152109
COPY src/envs/openspiel_env/ /app/src/envs/openspiel_env/
153110
111+
# Copy README for web interface documentation
112+
COPY src/envs/openspiel_env/README.md /app/README.md
113+
154114
# Extend Python path for OpenEnv (base image set PYTHONPATH=/app/src)
155115
# We prepend OpenSpiel paths
156116
ENV PYTHONPATH=/repo:/repo/build/python:/app/src
@@ -160,11 +120,13 @@ ENV OPENSPIEL_GAME=catch
160120
ENV OPENSPIEL_AGENT_PLAYER=0
161121
ENV OPENSPIEL_OPPONENT_POLICY=random
162122
163-
# Health check
123+
# Health check (curl is provided by openenv-base)
164124
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
165125
CMD curl -f http://localhost:8000/health || exit 1
166126
167-
# Run the FastAPI server
127+
# Note: EXPOSE 8000 already set by openenv-base
128+
129+
# Run the FastAPI server (uvicorn installed by openenv-base)
168130
CMD ["uvicorn", "envs.openspiel_env.server.app:app", "--host", "0.0.0.0", "--port", "8000"]
169131
DOCKERFILE_EOF
170132
echo "Created special OpenSpiel Dockerfile with C++ build process"
@@ -205,12 +167,46 @@ create_readme() {
205167
# Capitalize first letter of environment name
206168
env_title=$(echo "$env_name" | awk '{print toupper(substr($0,1,1)) substr($0,2)}')
207169

170+
# Set environment-specific colors and emoji
171+
case $env_name in
172+
"atari_env")
173+
EMOJI="🕹️"
174+
COLOR_FROM="#FF6200"
175+
COLOR_TO="#D4151B"
176+
;;
177+
"coding_env")
178+
EMOJI="💻"
179+
COLOR_FROM="#007ACC"
180+
COLOR_TO="#1E1E1E"
181+
;;
182+
"openspiel_env")
183+
EMOJI="🎮"
184+
COLOR_FROM="#9146FF"
185+
COLOR_TO="#00FFA3"
186+
;;
187+
"echo_env")
188+
EMOJI="🔊"
189+
COLOR_FROM="#00C9FF"
190+
COLOR_TO="#1B2845"
191+
;;
192+
"chat_env")
193+
EMOJI="💬"
194+
COLOR_FROM="#0084FF"
195+
COLOR_TO="#25D366"
196+
;;
197+
*)
198+
EMOJI="🐳"
199+
COLOR_FROM="blue"
200+
COLOR_TO="green"
201+
;;
202+
esac
203+
208204
cat > $CURRENT_STAGING_DIR/README.md << README_EOF
209205
---
210206
title: ${env_title} Environment Server
211-
emoji: 🐳
212-
colorFrom: blue
213-
colorTo: green
207+
emoji: ${EMOJI}
208+
colorFrom: ${COLOR_FROM}
209+
colorTo: ${COLOR_TO}
214210
sdk: docker
215211
pinned: false
216212
app_port: 8000
@@ -310,9 +306,10 @@ Provides access to OpenSpiel games for multi-agent reinforcement learning.
310306
Send a POST request to `/step` with:
311307
```json
312308
{
313-
"action": 0
309+
"action": {
310+
"action_id": 1
311+
}
314312
}
315-
```
316313
README_EOF
317314
;;
318315
esac

src/envs/openspiel_env/server/Dockerfile

Lines changed: 8 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -4,60 +4,12 @@
44
# This source code is licensed under the BSD-style license found in the
55
# LICENSE file in the root directory of this source tree.
66

7-
# Multi-stage build for OpenSpiel + OpenEnv
8-
# Stage 1: Build OpenSpiel C++ bindings
9-
# Using Python 3.11 to match envtorch-base
10-
FROM python:3.11 AS openspiel-builder
7+
# Use the pre-built OpenSpiel base image
8+
# Built from: docker build -t openspiel-base:latest -f src/envs/openspiel_env/server/Dockerfile.openspiel-base .
9+
# In GitHub Actions, this is overridden to use the GHCR base image
1110

12-
# Avoid interactive prompts during build
13-
ENV DEBIAN_FRONTEND=noninteractive
14-
ENV TZ=UTC
15-
16-
# Install build dependencies
17-
RUN apt-get update && apt-get install -y --no-install-recommends \
18-
build-essential \
19-
clang \
20-
cmake \
21-
curl \
22-
git \
23-
sudo \
24-
&& rm -rf /var/lib/apt/lists/*
25-
26-
# Set up OpenSpiel build directory
27-
RUN mkdir /repo
28-
WORKDIR /repo
29-
30-
# Clone OpenSpiel
31-
RUN git clone https://github.com/google-deepmind/open_spiel.git .
32-
33-
# Run OpenSpiel's installation script (downloads C++ dependencies)
34-
RUN ./install.sh
35-
36-
# Install Python dependencies
37-
RUN pip3 install --no-cache-dir --upgrade setuptools testresources importlib_metadata
38-
RUN pip3 install --no-cache-dir --upgrade -r requirements.txt cmake
39-
40-
# Build OpenSpiel with Python 3.11
41-
RUN mkdir -p build
42-
WORKDIR /repo/build
43-
RUN cmake -DPython3_EXECUTABLE=$(which python3) -DCMAKE_CXX_COMPILER=$(which clang++) ../open_spiel
44-
RUN make -j$(nproc) pyspiel
45-
46-
# Stage 2: Runtime image using published openenv-base
47-
# Uses the standardized base image from GitHub Container Registry
48-
# See: https://github.com/meta-pytorch/OpenEnv/pkgs/container/openenv-base
49-
FROM ghcr.io/meta-pytorch/openenv-base:latest
50-
51-
# Copy OpenSpiel build artifacts from builder
52-
RUN mkdir -p /repo
53-
COPY --from=openspiel-builder /repo /repo
54-
55-
# Install OpenSpiel Python requirements in runtime
56-
WORKDIR /repo
57-
RUN pip3 install --no-cache-dir --upgrade -r requirements.txt
58-
59-
# Set Python path for OpenSpiel
60-
ENV PYTHONPATH=/repo:/repo/build/python:${PYTHONPATH}
11+
ARG OPENSPIEL_BASE_IMAGE=openspiel-base:latest
12+
FROM ${OPENSPIEL_BASE_IMAGE}
6113

6214
# Copy OpenEnv core (base image already set WORKDIR=/app)
6315
WORKDIR /app
@@ -78,11 +30,11 @@ ENV OPENSPIEL_GAME=catch
7830
ENV OPENSPIEL_AGENT_PLAYER=0
7931
ENV OPENSPIEL_OPPONENT_POLICY=random
8032

81-
# Health check (curl is provided by envtorch-base)
33+
# Health check (curl is provided by openenv-base)
8234
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
8335
CMD curl -f http://localhost:8000/health || exit 1
8436

85-
# Note: EXPOSE 8000 already set by envtorch-base
37+
# Note: EXPOSE 8000 already set by openenv-base
8638

87-
# Run the FastAPI server (uvicorn installed by envtorch-base)
39+
# Run the FastAPI server (uvicorn installed by openenv-base)
8840
CMD ["uvicorn", "envs.openspiel_env.server.app:app", "--host", "0.0.0.0", "--port", "8000"]

0 commit comments

Comments
 (0)