Add Dockerfile and build system for Jupyter image
Created docker/ directory with: - Dockerfile.jupyter: Extends mcp-forge/python:3.12 with ipykernel 6.29.0 - build-images.sh: Build script with testing - README.md: Complete documentation and usage instructions Image Details: - Base: mcp-forge/python:3.12 (python:3.12-slim) - Size: 196 MB (~73 MB added for ipykernel + dependencies) - Includes: ipykernel, jupyter-client, pyzmq, ipython, debugpy, etc. - Version: 6.29.0 (matches host jupyter-client compatibility) Build tested and verified: ✓ ipykernel imports correctly (6.29.0) ✓ kernel launcher works ✓ Image ready for use Next: Update config and run integration tests
This commit is contained in:
parent
8e49c23d36
commit
35e2c3e983
3 changed files with 223 additions and 0 deletions
30
docker/Dockerfile.jupyter
Normal file
30
docker/Dockerfile.jupyter
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Jupyter Kernel Image for MCP-Forge
|
||||||
|
#
|
||||||
|
# This image provides a Python environment with ipykernel for stateful
|
||||||
|
# execution via Jupyter protocol. It runs inside containers managed by
|
||||||
|
# MCP-Forge and communicates with the host via ZMQ.
|
||||||
|
#
|
||||||
|
# Base: mcp-forge/python:3.12 (which is python:3.12-slim)
|
||||||
|
# Adds: ipykernel for Jupyter kernel functionality
|
||||||
|
|
||||||
|
FROM mcp-forge/python:3.12
|
||||||
|
|
||||||
|
LABEL maintainer="MCP-Forge"
|
||||||
|
LABEL description="Python 3.12 with ipykernel for stateful execution"
|
||||||
|
LABEL version="1.0"
|
||||||
|
|
||||||
|
# Install ipykernel
|
||||||
|
# Using --no-cache-dir to keep image size small
|
||||||
|
RUN pip install --no-cache-dir \
|
||||||
|
ipykernel==6.29.0 \
|
||||||
|
&& python -m ipykernel install --user
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
# The container will be run with:
|
||||||
|
# - Host networking (for ZMQ communication)
|
||||||
|
# - Mounted connection file
|
||||||
|
# - Command: python -m ipykernel_launcher -f /tmp/kernel-{id}.json
|
||||||
|
#
|
||||||
|
# No ENTRYPOINT or CMD needed - command specified at runtime
|
||||||
107
docker/README.md
Normal file
107
docker/README.md
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
# Docker Images for MCP-Forge
|
||||||
|
|
||||||
|
This directory contains Dockerfiles for building MCP-Forge container images.
|
||||||
|
|
||||||
|
## Images
|
||||||
|
|
||||||
|
### Jupyter Image (`mcp-forge/jupyter:latest`)
|
||||||
|
|
||||||
|
**Purpose**: Provides Python environment with ipykernel for stateful Jupyter-based execution.
|
||||||
|
|
||||||
|
**Base**: `mcp-forge/python:3.12` (which is `python:3.12-slim`)
|
||||||
|
|
||||||
|
**Added Components**:
|
||||||
|
- `ipykernel` 6.29.0 - Jupyter kernel for Python
|
||||||
|
|
||||||
|
**Build Command**:
|
||||||
|
```bash
|
||||||
|
# From the mcp-forge project root:
|
||||||
|
podman build -f docker/Dockerfile.jupyter -t mcp-forge/jupyter:latest .
|
||||||
|
```
|
||||||
|
|
||||||
|
**Usage**: This image is used automatically by the Jupyter backend when creating stateful sessions. The kernel communicates with the host via ZMQ over host networking.
|
||||||
|
|
||||||
|
**Size**: ~130-140 MB (adds ~10-15 MB to base Python image)
|
||||||
|
|
||||||
|
## Base Python Images
|
||||||
|
|
||||||
|
The base Python images should already exist:
|
||||||
|
```bash
|
||||||
|
podman tag python:3.11-slim mcp-forge/python:3.11
|
||||||
|
podman tag python:3.12-slim mcp-forge/python:3.12
|
||||||
|
```
|
||||||
|
|
||||||
|
If not, pull and tag them:
|
||||||
|
```bash
|
||||||
|
podman pull python:3.11-slim
|
||||||
|
podman tag python:3.11-slim mcp-forge/python:3.11
|
||||||
|
|
||||||
|
podman pull python:3.12-slim
|
||||||
|
podman tag python:3.12-slim mcp-forge/python:3.12
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building All Images
|
||||||
|
|
||||||
|
To build/verify all images at once:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# From project root
|
||||||
|
|
||||||
|
# Ensure base images exist
|
||||||
|
podman pull python:3.11-slim
|
||||||
|
podman pull python:3.12-slim
|
||||||
|
podman tag python:3.11-slim mcp-forge/python:3.11
|
||||||
|
podman tag python:3.12-slim mcp-forge/python:3.12
|
||||||
|
|
||||||
|
# Build Jupyter image
|
||||||
|
podman build -f docker/Dockerfile.jupyter -t mcp-forge/jupyter:latest .
|
||||||
|
|
||||||
|
# Verify all images
|
||||||
|
podman images | grep mcp-forge
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing the Jupyter Image
|
||||||
|
|
||||||
|
Quick test to verify ipykernel is working:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test that ipykernel is installed
|
||||||
|
podman run --rm mcp-forge/jupyter:latest python -c "import ipykernel; print(ipykernel.__version__)"
|
||||||
|
|
||||||
|
# Test kernel launcher exists
|
||||||
|
podman run --rm mcp-forge/jupyter:latest python -m ipykernel_launcher --help
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected output:
|
||||||
|
```
|
||||||
|
6.29.0
|
||||||
|
usage: ipykernel_launcher [-h] [-f FILE] ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Image Sizes
|
||||||
|
|
||||||
|
Expected sizes:
|
||||||
|
- `mcp-forge/python:3.11` - ~129 MB
|
||||||
|
- `mcp-forge/python:3.12` - ~123 MB
|
||||||
|
- `mcp-forge/jupyter:latest` - ~135-140 MB
|
||||||
|
|
||||||
|
## Updating Images
|
||||||
|
|
||||||
|
To update the Jupyter image with a newer ipykernel version:
|
||||||
|
|
||||||
|
1. Edit `docker/Dockerfile.jupyter`
|
||||||
|
2. Update the ipykernel version number
|
||||||
|
3. Rebuild: `podman build -f docker/Dockerfile.jupyter -t mcp-forge/jupyter:latest .`
|
||||||
|
4. Test with integration tests
|
||||||
|
5. Tag with version: `podman tag mcp-forge/jupyter:latest mcp-forge/jupyter:v1.0.1`
|
||||||
|
|
||||||
|
## Security Notes
|
||||||
|
|
||||||
|
All images run with:
|
||||||
|
- `network_mode: host` (for Jupyter kernels only, to enable ZMQ communication)
|
||||||
|
- `read_only: True` (filesystem is read-only except mounted volumes)
|
||||||
|
- `security_opt: ["no-new-privileges"]`
|
||||||
|
- Non-root user (UID:GID 1000:1000)
|
||||||
|
|
||||||
|
The host networking is required for ZMQ port communication between the host-side `jupyter-client` and the container-side `ipykernel`.
|
||||||
86
docker/build-images.sh
Executable file
86
docker/build-images.sh
Executable file
|
|
@ -0,0 +1,86 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Build MCP-Forge container images
|
||||||
|
#
|
||||||
|
# Usage: ./build-images.sh [--all|--jupyter]
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
|
||||||
|
cd "$PROJECT_ROOT"
|
||||||
|
|
||||||
|
build_jupyter() {
|
||||||
|
echo "Building mcp-forge/jupyter:latest..."
|
||||||
|
podman build -f docker/Dockerfile.jupyter -t mcp-forge/jupyter:latest .
|
||||||
|
echo "✓ Built mcp-forge/jupyter:latest"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_base_images() {
|
||||||
|
echo "Ensuring base Python images exist..."
|
||||||
|
|
||||||
|
# Check if images exist
|
||||||
|
if ! podman image exists mcp-forge/python:3.11; then
|
||||||
|
echo " Pulling and tagging python:3.11-slim..."
|
||||||
|
podman pull python:3.11-slim
|
||||||
|
podman tag python:3.11-slim mcp-forge/python:3.11
|
||||||
|
echo " ✓ Created mcp-forge/python:3.11"
|
||||||
|
else
|
||||||
|
echo " ✓ mcp-forge/python:3.11 exists"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! podman image exists mcp-forge/python:3.12; then
|
||||||
|
echo " Pulling and tagging python:3.12-slim..."
|
||||||
|
podman pull python:3.12-slim
|
||||||
|
podman tag python:3.12-slim mcp-forge/python:3.12
|
||||||
|
echo " ✓ Created mcp-forge/python:3.12"
|
||||||
|
else
|
||||||
|
echo " ✓ mcp-forge/python:3.12 exists"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_images() {
|
||||||
|
echo ""
|
||||||
|
echo "Verifying images..."
|
||||||
|
echo ""
|
||||||
|
podman images | grep -E "REPOSITORY|mcp-forge"
|
||||||
|
}
|
||||||
|
|
||||||
|
test_jupyter_image() {
|
||||||
|
echo ""
|
||||||
|
echo "Testing Jupyter image..."
|
||||||
|
|
||||||
|
echo -n " Testing ipykernel import... "
|
||||||
|
VERSION=$(podman run --rm mcp-forge/jupyter:latest python -c "import ipykernel; print(ipykernel.__version__)")
|
||||||
|
echo "✓ ipykernel $VERSION"
|
||||||
|
|
||||||
|
echo -n " Testing kernel launcher... "
|
||||||
|
podman run --rm mcp-forge/jupyter:latest python -m ipykernel_launcher --help > /dev/null 2>&1
|
||||||
|
echo "✓ launcher works"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
ACTION="${1:-jupyter}"
|
||||||
|
|
||||||
|
case "$ACTION" in
|
||||||
|
--all)
|
||||||
|
ensure_base_images
|
||||||
|
build_jupyter
|
||||||
|
verify_images
|
||||||
|
test_jupyter_image
|
||||||
|
;;
|
||||||
|
--jupyter)
|
||||||
|
build_jupyter
|
||||||
|
test_jupyter_image
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $0 [--all|--jupyter]"
|
||||||
|
echo ""
|
||||||
|
echo " --all Ensure base images and build Jupyter image"
|
||||||
|
echo " --jupyter Build Jupyter image only (default)"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "✓ Done!"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue