Skip to content

Commit 29cddb1

Browse files
authored
Merge pull request #3742 from Agenta-AI/chore/improve-gh-images
[chore] Improve gh images
2 parents e966fe5 + 466b984 commit 29cddb1

File tree

20 files changed

+1812
-319
lines changed

20 files changed

+1812
-319
lines changed

.gitignore

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ web/oss/public/__env.js
4949

5050
web/oss/tests/datalayer/results
5151
.*
52+
!api/.dockerignore
53+
!services/.dockerignore
54+
55+
# Temporary SDK symlinks created by run.sh --local
56+
api/sdk
57+
services/sdk
5258

5359
# IDE/LSP config (local tooling)
54-
pyrightconfig.json
60+
pyrightconfig.json

api/.dockerignore

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Version control
2+
.git
3+
.github
4+
.gitignore
5+
6+
# Python caches and artifacts
7+
.pytest_cache
8+
.ruff_cache
9+
.mypy_cache
10+
__pycache__
11+
*.pyc
12+
*.pyo
13+
*.pyd
14+
.Python
15+
*.so
16+
*.egg
17+
*.egg-info
18+
dist/
19+
build/
20+
.eggs/
21+
22+
# Environment and secrets
23+
.env
24+
.env.*
25+
26+
# Test and coverage
27+
.coverage
28+
htmlcov
29+
oss/tests
30+
ee/tests
31+
32+
# Documentation
33+
*.md
34+
docs/
35+
36+
# IDE and editor files
37+
.vscode/
38+
.idea/
39+
*.swp
40+
*.swo
41+
*~
42+
.DS_Store
43+
44+
# Logs
45+
*.log

api/ee/docker/Dockerfile.gh

Lines changed: 93 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,115 @@
1-
FROM python:3.11-slim-bookworm
1+
FROM python:3.11-slim-bookworm AS builder
2+
3+
ARG POETRY_VERSION=2.3.1
24

35
WORKDIR /app
46

5-
RUN apt-get update && \
6-
apt-get install -y curl cron gnupg2 lsb-release && \
7-
echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
8-
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | \
9-
gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg && \
10-
apt-get update && \
11-
apt-get install -y postgresql-client-16 && \
12-
apt-get clean && \
13-
rm -rf /var/lib/apt/lists/*
7+
ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
8+
PIP_NO_CACHE_DIR=0 \
9+
PYTHONDONTWRITEBYTECODE=1 \
10+
PYTHONUNBUFFERED=1
1411

15-
RUN pip install --upgrade pip \
16-
&& pip install poetry
12+
# Install poetry system-level (outside venv) — only used for export
13+
RUN --mount=type=cache,target=/root/.cache/pip \
14+
pip install --timeout=300 "poetry==${POETRY_VERSION}" "poetry-plugin-export"
1715

1816
COPY ./pyproject.toml ./poetry.lock* /app/
1917

20-
RUN poetry config virtualenvs.create false
18+
# Create clean venv, install app deps, strip heavy unused deps, add stubs
19+
# Merged into one layer so stripped files don't persist in a previous layer.
20+
# Stripped:
21+
# - phonenumbers/twilio: required by supertokens at import-time but never called
22+
# - hf_xet: transitive, never imported by app code
23+
# Kept: litellm + chain (tokenizers, huggingface_hub, tiktoken) — needed by agenta SDK
24+
# Kept: newrelic — used for observability
2125
RUN --mount=type=cache,target=/root/.cache/pip \
2226
--mount=type=cache,target=/root/.cache/pypoetry \
23-
poetry install --no-interaction --no-ansi
27+
python -m venv /opt/venv \
28+
&& . /opt/venv/bin/activate \
29+
&& poetry export --only main --without-hashes --format requirements.txt --output /tmp/requirements.txt \
30+
&& pip install -r /tmp/requirements.txt \
31+
&& rm -f /tmp/requirements.txt \
32+
&& (pip uninstall -y pip setuptools 2>/dev/null || true) \
33+
&& SITE=$(python -c 'import site; print(site.getsitepackages()[0])') \
34+
&& rm -rf \
35+
${SITE}/phonenumbers* \
36+
${SITE}/twilio* \
37+
${SITE}/hf_xet* \
38+
&& mkdir -p ${SITE}/phonenumbers ${SITE}/twilio/rest \
39+
&& printf 'PhoneNumberFormat=type("PhoneNumberFormat",(),{"E164":0,"INTERNATIONAL":1,"NATIONAL":2})()\ndef parse(*a,**k):return None\ndef format_number(*a,**k):return ""\ndef is_valid_number(*a,**k):return False\n' \
40+
> ${SITE}/phonenumbers/__init__.py \
41+
&& printf 'class Client:\n def __init__(self,*a,**k):raise NotImplementedError("twilio stub")\n' \
42+
> ${SITE}/twilio/__init__.py \
43+
&& cp ${SITE}/twilio/__init__.py ${SITE}/twilio/rest/__init__.py \
44+
&& find /opt/venv -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null; true
45+
46+
# Copy and install SDK first (changes less frequently than app code)
47+
RUN mkdir -p /app/sdk
48+
COPY ./sd[k] /app/sdk/
2449

50+
RUN if [ -f /app/sdk/pyproject.toml ]; then \
51+
. /opt/venv/bin/activate && \
52+
pip install pip && \
53+
pip install --editable /app/sdk && \
54+
(pip uninstall -y pip 2>/dev/null || true); \
55+
fi
56+
57+
# Copy app code last (changes more frequently)
2558
COPY ./ee /app/ee/
2659
COPY ./oss /app/oss/
2760
COPY ./entrypoints /app/entrypoints/
2861

29-
# Copy local SDK if present (synced by build.sh before docker build)
30-
# Uses glob pattern sd[k] to avoid failure if sdk/ doesn't exist (for OSS users)
31-
COPY ./sd[k] /app/sdk/
3262

33-
# Install local SDK in editable mode if present (overrides the PyPI version)
34-
RUN if [ -f /app/sdk/pyproject.toml ]; then pip install -e /app/sdk; fi
63+
FROM python:3.11-slim-bookworm AS runner
3564

36-
# Verify which agenta package is active (output visible in build logs)
37-
RUN python -c "\
38-
import agenta; loc = getattr(agenta, '__file__', '?'); \
39-
print(f'[SDK CHECK] agenta={loc}'); \
40-
print(f'[SDK CHECK] is_local={\"app/sdk\" in (loc or \"\")}')" \
41-
|| echo '[SDK CHECK] verification failed'
65+
ARG BUILD_DATE
66+
ARG VCS_REF
67+
ARG VERSION=0.0.0
4268

43-
# PYTHONPATH includes /app/sdk - if local SDK exists it takes precedence over PyPI version
44-
ENV PYTHONPATH=/app:/app/sdk
45-
46-
COPY ./oss/src/crons/queries.sh /queries.sh
47-
COPY ./oss/src/crons/queries.txt /etc/cron.d/queries-cron
48-
RUN sed -i -e '$a\' /etc/cron.d/queries-cron
49-
RUN cat -A /etc/cron.d/queries-cron
50-
51-
RUN chmod +x /queries.sh \
52-
&& chmod 0644 /etc/cron.d/queries-cron
53-
54-
COPY ./ee/src/crons/meters.sh /meters.sh
55-
COPY ./ee/src/crons/meters.txt /etc/cron.d/meters-cron
56-
RUN sed -i -e '$a\' /etc/cron.d/meters-cron
57-
RUN cat -A /etc/cron.d/meters-cron
69+
WORKDIR /app
5870

59-
RUN chmod +x /meters.sh \
60-
&& chmod 0644 /etc/cron.d/meters-cron
71+
ENV PYTHONDONTWRITEBYTECODE=1 \
72+
PYTHONUNBUFFERED=1 \
73+
PYTHONPATH=/app:/app/sdk \
74+
PATH="/opt/venv/bin:${PATH}"
6175

62-
COPY ./ee/src/crons/spans.sh /spans.sh
63-
COPY ./ee/src/crons/spans.txt /etc/cron.d/spans-cron
64-
RUN sed -i -e '$a\' /etc/cron.d/spans-cron
65-
RUN cat -A /etc/cron.d/spans-cron
76+
# Hardcode bookworm codename to avoid pulling in lsb-release (+ perl ~56MB)
77+
RUN apt-get update && \
78+
apt-get install -y --no-install-recommends curl cron gnupg2 && \
79+
echo "deb http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
80+
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | \
81+
gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg && \
82+
apt-get update && \
83+
apt-get install -y --no-install-recommends postgresql-client-17 && \
84+
apt-get purge -y --auto-remove gnupg2 && \
85+
rm -rf /var/lib/apt/lists/*
6686

67-
RUN chmod +x /spans.sh \
68-
&& chmod 0644 /etc/cron.d/spans-cron
87+
# Copy stable cron files first (change less frequently)
88+
COPY --chmod=755 ./oss/src/crons/queries.sh /queries.sh
89+
COPY --chmod=644 ./oss/src/crons/queries.txt /etc/cron.d/queries-cron
90+
COPY --chmod=755 ./ee/src/crons/meters.sh /meters.sh
91+
COPY --chmod=644 ./ee/src/crons/meters.txt /etc/cron.d/meters-cron
92+
COPY --chmod=755 ./ee/src/crons/spans.sh /spans.sh
93+
COPY --chmod=644 ./ee/src/crons/spans.txt /etc/cron.d/spans-cron
94+
95+
# Copy dependencies from builder
96+
COPY --from=builder /opt/venv /opt/venv
97+
98+
# Copy app code last (changes most frequently)
99+
COPY --from=builder /app/ee /app/ee
100+
COPY --from=builder /app/oss /app/oss
101+
COPY --from=builder /app/entrypoints /app/entrypoints
102+
COPY --from=builder /app/sdk /app/sdk
103+
104+
RUN set -eux; \
105+
for cron_file in /etc/cron.d/queries-cron /etc/cron.d/meters-cron /etc/cron.d/spans-cron; do \
106+
sed -i -e '$a\' "${cron_file}"; \
107+
done
108+
109+
LABEL org.opencontainers.image.title="agenta-api-ee" \
110+
org.opencontainers.image.description="Agenta API EE GH runtime image" \
111+
org.opencontainers.image.version="${VERSION}" \
112+
org.opencontainers.image.revision="${VCS_REF}" \
113+
org.opencontainers.image.created="${BUILD_DATE}"
69114

70115
EXPOSE 8000

api/oss/docker/Dockerfile.gh

Lines changed: 84 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,108 @@
1-
FROM python:3.11-slim-bookworm
1+
FROM python:3.11-slim-bookworm AS builder
2+
3+
ARG POETRY_VERSION=2.3.1
24

35
WORKDIR /app
46

5-
RUN apt-get update && \
6-
apt-get install -y curl cron gnupg2 lsb-release && \
7-
echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
8-
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | \
9-
gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg && \
10-
apt-get update && \
11-
apt-get install -y postgresql-client-16 && \
12-
apt-get clean && \
13-
rm -rf /var/lib/apt/lists/*
7+
ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
8+
PIP_NO_CACHE_DIR=0 \
9+
PYTHONDONTWRITEBYTECODE=1 \
10+
PYTHONUNBUFFERED=1
1411

15-
RUN pip install --upgrade pip \
16-
&& pip install poetry
12+
# Install poetry system-level (outside venv) — only used for export
13+
RUN --mount=type=cache,target=/root/.cache/pip \
14+
pip install --timeout=300 "poetry==${POETRY_VERSION}" "poetry-plugin-export"
1715

1816
COPY ./pyproject.toml ./poetry.lock* /app/
1917

20-
RUN poetry config virtualenvs.create false
18+
# Create clean venv, install app deps, strip heavy unused deps, add stubs
19+
# Merged into one layer so stripped files don't persist in a previous layer.
20+
# Stripped:
21+
# - phonenumbers/twilio: required by supertokens at import-time but never called
22+
# - hf_xet: transitive, never imported by app code
23+
# Kept: litellm + chain (tokenizers, huggingface_hub, tiktoken) — needed by agenta SDK
24+
# Kept: newrelic — used for observability
2125
RUN --mount=type=cache,target=/root/.cache/pip \
2226
--mount=type=cache,target=/root/.cache/pypoetry \
23-
poetry install --no-interaction --no-ansi
27+
python -m venv /opt/venv \
28+
&& . /opt/venv/bin/activate \
29+
&& poetry export --only main --without-hashes --format requirements.txt --output /tmp/requirements.txt \
30+
&& pip install -r /tmp/requirements.txt \
31+
&& rm -f /tmp/requirements.txt \
32+
&& (pip uninstall -y pip setuptools 2>/dev/null || true) \
33+
&& SITE=$(python -c 'import site; print(site.getsitepackages()[0])') \
34+
&& rm -rf \
35+
${SITE}/phonenumbers* \
36+
${SITE}/twilio* \
37+
${SITE}/hf_xet* \
38+
&& mkdir -p ${SITE}/phonenumbers ${SITE}/twilio/rest \
39+
&& printf 'PhoneNumberFormat=type("PhoneNumberFormat",(),{"E164":0,"INTERNATIONAL":1,"NATIONAL":2})()\ndef parse(*a,**k):return None\ndef format_number(*a,**k):return ""\ndef is_valid_number(*a,**k):return False\n' \
40+
> ${SITE}/phonenumbers/__init__.py \
41+
&& printf 'class Client:\n def __init__(self,*a,**k):raise NotImplementedError("twilio stub")\n' \
42+
> ${SITE}/twilio/__init__.py \
43+
&& cp ${SITE}/twilio/__init__.py ${SITE}/twilio/rest/__init__.py \
44+
&& find /opt/venv -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null; true
45+
46+
# Copy and install SDK first (changes less frequently than app code)
47+
RUN mkdir -p /app/sdk
48+
COPY ./sd[k] /app/sdk/
49+
50+
RUN if [ -f /app/sdk/pyproject.toml ]; then \
51+
. /opt/venv/bin/activate && \
52+
pip install pip && \
53+
pip install --editable /app/sdk && \
54+
(pip uninstall -y pip 2>/dev/null || true); \
55+
fi
2456

25-
#
57+
# Copy app code last (changes more frequently)
2658
COPY ./oss /app/oss/
2759
COPY ./entrypoints /app/entrypoints/
2860

29-
# Copy local SDK if present (synced by build.sh before docker build)
30-
# Uses glob pattern sd[k] to avoid failure if sdk/ doesn't exist (for OSS users)
31-
COPY ./sd[k] /app/sdk/
3261

33-
# Install local SDK in editable mode if present (overrides the PyPI version)
34-
RUN if [ -f /app/sdk/pyproject.toml ]; then pip install -e /app/sdk; fi
62+
FROM python:3.11-slim-bookworm AS runner
63+
64+
ARG BUILD_DATE
65+
ARG VCS_REF
66+
ARG VERSION=0.0.0
3567

36-
# Verify which agenta package is active (output visible in build logs)
37-
RUN python -c '\
38-
import agenta; loc = getattr(agenta, "__file__", "?"); \
39-
print(f"[SDK CHECK] agenta={loc}"); \
40-
print(f"[SDK CHECK] is_local={"app/sdk" in (loc or "")}")' \
41-
|| echo "[SDK CHECK] verification failed"
68+
WORKDIR /app
4269

43-
# PYTHONPATH includes /app/sdk - if local SDK exists it takes precedence over PyPI version
44-
ENV PYTHONPATH=/app:/app/sdk
70+
ENV PYTHONDONTWRITEBYTECODE=1 \
71+
PYTHONUNBUFFERED=1 \
72+
PYTHONPATH=/app:/app/sdk \
73+
PATH="/opt/venv/bin:${PATH}"
4574

46-
COPY ./oss/src/crons/queries.sh /queries.sh
47-
COPY ./oss/src/crons/queries.txt /etc/cron.d/queries-cron
48-
RUN sed -i -e '$a\' /etc/cron.d/queries-cron
49-
RUN cat -A /etc/cron.d/queries-cron
75+
# Hardcode bookworm codename to avoid pulling in lsb-release (+ perl ~56MB).
76+
# IMPORTANT: This codename must match the Debian release used in the base image (python:3.11-slim-bookworm).
77+
RUN apt-get update && \
78+
apt-get install -y --no-install-recommends curl cron gnupg2 && \
79+
echo "deb http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
80+
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | \
81+
gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg && \
82+
apt-get update && \
83+
apt-get install -y --no-install-recommends postgresql-client-17 && \
84+
apt-get purge -y --auto-remove gnupg2 && \
85+
rm -rf /var/lib/apt/lists/*
5086

51-
RUN chmod +x /queries.sh \
52-
&& chmod 0644 /etc/cron.d/queries-cron
87+
# Copy stable cron files first (change less frequently)
88+
COPY --chmod=755 ./oss/src/crons/queries.sh /queries.sh
89+
COPY --chmod=644 ./oss/src/crons/queries.txt /etc/cron.d/queries-cron
5390

54-
#
55-
#
56-
#
57-
#
91+
# Copy dependencies from builder
92+
COPY --from=builder /opt/venv /opt/venv
5893

59-
#
60-
#
94+
# Copy app code last (changes most frequently)
95+
COPY --from=builder /app/oss /app/oss
96+
COPY --from=builder /app/entrypoints /app/entrypoints
97+
COPY --from=builder /app/sdk /app/sdk
6198

62-
#
63-
#
64-
#
65-
#
99+
RUN set -eux; \
100+
sed -i -e '$a\' /etc/cron.d/queries-cron
66101

67-
#
68-
#
102+
LABEL org.opencontainers.image.title="agenta-api" \
103+
org.opencontainers.image.description="Agenta API GH runtime image" \
104+
org.opencontainers.image.version="${VERSION}" \
105+
org.opencontainers.image.revision="${VCS_REF}" \
106+
org.opencontainers.image.created="${BUILD_DATE}"
69107

70108
EXPOSE 8000

0 commit comments

Comments
 (0)