Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(docker): reduce image size #363

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Ignore git related files
.github/
.gitignore

# Ignore folders not necessary for the docker image
docs/
tests/

# Ignore venv if any
venv/

# Ignore files not necessary for the docker image
CONTRIBUTING.md
*.png
*.json
LICENSE
Makefile
42 changes: 29 additions & 13 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,35 +1,51 @@
ARG PY_VERSION=3.12

#---------------------------------------------------------------------------------------
# Stage 1 → Builder image
#---------------------------------------------------------------------------------------
FROM python:$PY_VERSION-slim AS build-env

ARG VERSION

WORKDIR /app

# Install python deps
RUN python -m pip install --upgrade poetry wheel twine
RUN apt-get update && apt-get install -y --no-install-recommends build-essential \
&& rm -rf /var/lib/apt/lists/*
RUN python -m pip install --no-cache-dir --upgrade poetry wheel twine

# Install project deps
COPY pyproject.toml .
RUN poetry install --with dev
COPY pyproject.toml poetry.lock ./
RUN poetry install --with dev --no-root

# Copy code *after* installing deps to avoid unnecessarily invalidating cache
COPY . .

# Build the project
RUN poetry build
RUN PROJECT_VERSION=$(poetry version -s) && cp /app/dist/boaviztapi-$PROJECT_VERSION.tar.gz ./boaviztapi-$VERSION.tar.gz
RUN pip install boaviztapi-$VERSION.tar.gz && cp $(which uvicorn) /app
RUN PROJECT_VERSION=$(poetry version -s) && \
cp /app/dist/boaviztapi-$PROJECT_VERSION.tar.gz ./boaviztapi-$VERSION.tar.gz

#---------------------------------------------------------------------------------------
# Stage 2 → Runtime image
#---------------------------------------------------------------------------------------
FROM python:$PY_VERSION-slim AS run-env
# Python 3 surrogate unicode handling
# @see https://click.palletsprojects.com/en/7.x/python3/
ENV LC_ALL=C.UTF-8
ENV LANG=C.UTF-8

COPY --from=build-env /app /app
COPY --from=build-env /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
ENV PYTHONPATH=/usr/local/lib/python3.12/site-packages
ENV LC_ALL=C.UTF-8 \
LANG=C.UTF-8

ARG VERSION
WORKDIR /app

# Copy executable and dependencies
COPY --from=build-env /app/boaviztapi-$VERSION.tar.gz /app/
RUN pip install --no-cache-dir /app/boaviztapi-$VERSION.tar.gz

# Required in main.py
COPY --from=build-env /app/pyproject.toml /usr/local/lib/python3.12/site-packages/boaviztapi/

# Copy uvicorn executable
RUN pip install --no-cache-dir uvicorn

EXPOSE 5000
CMD ["./uvicorn", "boaviztapi.main:app", "--host", "0.0.0.0", "--port", "5000"]
CMD ["uvicorn", "boaviztapi.main:app", "--host", "0.0.0.0", "--port", "5000"]
18 changes: 16 additions & 2 deletions boaviztapi/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,27 @@

from fastapi.responses import HTMLResponse

def get_version_from_pyproject():
# List of potential locations for the pyproject.toml file
potential_paths = [
os.path.join(os.path.dirname(__file__), '../pyproject.toml'),
os.path.join(os.path.dirname(__file__), 'pyproject.toml'),
]

for path in potential_paths:
if os.path.exists(path):
with open(path, 'r') as f:
return toml.loads(f.read())['tool']['poetry']['version']

# Raise an error if the file is not found in any of the locations
raise FileNotFoundError("pyproject.toml not found in expected locations")

# Serverless frameworks adds a 'stage' prefix to the route used to serve applications
# We have to manage it to expose openapi doc on aws and generate proper links.
stage = os.environ.get('STAGE', None)
openapi_prefix = f"/{stage}" if stage else "/"
app = FastAPI(root_path=openapi_prefix) # Here is the magic
version = toml.loads(open(os.path.join(os.path.dirname(__file__), '../pyproject.toml'), 'r').read())['tool']['poetry'][
'version']
version = get_version_from_pyproject()
_logger = logging.getLogger(__name__)

origins = json.loads(os.getenv("ALLOWED_ORIGINS", '["*"]'))
Expand Down
Loading