-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathContainerfile.mcp-template
More file actions
92 lines (74 loc) · 3.47 KB
/
Containerfile.mcp-template
File metadata and controls
92 lines (74 loc) · 3.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# Multi-stage build for MCP servers
# Build args must be defined before first FROM
ARG SERVICE_NAME
ARG MODULE_NAME
ARG USE_PIP_INSTALL=false
ARG UV_VERSION=0.8.9
# Builder stage
# Use 9.7 tag for glibc >= 2.34-231.el9_7.10
FROM registry.access.redhat.com/ubi9/python-312:9.7 as builder
USER root
ARG UV_VERSION
RUN pip3 install --no-cache-dir uv==${UV_VERSION}
WORKDIR /app
COPY shared-models ./shared-models/
COPY tracing-config/ ./tracing-config
ARG SERVICE_NAME
ARG USE_PIP_INSTALL
WORKDIR /app/${SERVICE_NAME}
COPY ${SERVICE_NAME}/ .
# Conditional dependency installation: USE_PIP_INSTALL=true uses pip (workaround for QEMU on Mac M1)
# Default: uv sync (faster). When USE_PIP_INSTALL=true: pip install from requirements.txt with hash verification
RUN if [ "$USE_PIP_INSTALL" = "true" ]; then \
# Install editable packages first (without --require-hashes), then external packages with hash verification
python3 -m venv .venv && \
grep -E "^(-e |\.\./)" requirements.txt | grep -v "^#" > /tmp/editable-requirements.txt 2>/dev/null || true && \
grep -vE "^(-e |\.\./)" requirements.txt | grep -v "^#" > /tmp/non-editable-requirements.txt && \
if [ -s /tmp/editable-requirements.txt ]; then \
.venv/bin/pip install --no-deps -r /tmp/editable-requirements.txt; \
fi && \
.venv/bin/pip install --require-hashes --use-deprecated=legacy-resolver -r /tmp/non-editable-requirements.txt && \
rm -f /tmp/editable-requirements.txt /tmp/non-editable-requirements.txt; \
else \
# Default: Use uv sync (faster and more reliable)
uv sync --frozen --no-dev; \
fi
# Production stage
# Use 9.7 tag for glibc >= 2.34-231.el9_7.10
FROM registry.access.redhat.com/ubi9/python-312-minimal:9.7
WORKDIR /app
# Ensure pip is at least 26.0 in the final image (CVE-2025-8869: https://nvd.nist.gov/vuln/detail/CVE-2025-8869)
USER root
RUN pip3 install --no-cache-dir --upgrade 'pip>=26.0'
COPY --from=builder /app/shared-models /app/shared-models
COPY --from=builder /app/tracing-config /app/tracing-config
ARG SERVICE_NAME
# Copy virtual environment from builder
COPY --from=builder /app/${SERVICE_NAME}/.venv /app/.venv
# Copy application source
ARG MODULE_NAME
COPY ${SERVICE_NAME}/src/ ./src/
COPY ${SERVICE_NAME}/pyproject.toml ./
# Set environment variables
# Use system python3 with venv site-packages on PYTHONPATH so uvicorn etc. are found regardless of
# which interpreter path is used (e.g. /opt/app-root/bin/python3 in ubi9/python-312-minimal).
ENV VIRTUAL_ENV=/app/.venv
ENV PATH="/usr/bin:${VIRTUAL_ENV}/bin:$PATH"
ENV PYTHONPATH="/usr/lib64/python3.12:${VIRTUAL_ENV}/lib/python3.12/site-packages:/app/src:/app/shared-models/src:/app/tracing-config/src:$PYTHONPATH"
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV OTEL_SERVICE_NAME=${SERVICE_NAME}
ENV OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true
# Set the module name as an environment variable so it can be used in CMD
ENV MODULE_NAME=${MODULE_NAME}
# Drop privileges
USER 1001
# Expose port (MCP servers typically use different ports)
EXPOSE 8000
# Run the MCP server (python3 uses system interpreter; VIRTUAL_ENV ensures venv site-packages are loaded)
# Support optional UVICORN_WORKERS environment variable for multi-process concurrency
CMD if [ -n "$UVICORN_WORKERS" ]; then \
python3 -m uvicorn $MODULE_NAME:app --host 0.0.0.0 --port 8000 --workers $UVICORN_WORKERS; \
else \
python3 -m uvicorn $MODULE_NAME:app --host 0.0.0.0 --port 8000; \
fi