Dockerfile
Rama main · réplica de lectura del repositorio original.
# Your usual Flagsmith release produces of a number of shippable Docker images:
# - Private cloud: API, Unified
# - SaaS: API
# - Open Source: API, Frontend, Unified
# This Dockerfile is meant to build all of the above via composable, interdependent stages.
# The goal is to have as DRY as possible build for all the targets.
# Usage Examples
# Build an Open Source API image:
# $ docker build -t flagsmith-api:dev --target oss-api .
# Build an Open Source Unified image:
# (`oss-unified` stage is the default one, so there's no need to specify a target stage)
# $ docker build -t flagsmith:dev .
# Build a SaaS API image:
# $ GH_TOKEN=$(gh auth token) docker build -t flagsmith-saas-api:dev --target saas-api \
# --secret="id=sse_pgp_pkey,src=./sse_pgp_pkey.key"\
# --secret="id=github_private_cloud_token,env=GH_TOKEN" .
# Build a Private Cloud Unified image:
# $ GH_TOKEN=$(gh auth token) docker build -t flagsmith-private-cloud:dev --target private-cloud-unified \
# --secret="id=github_private_cloud_token,env=GH_TOKEN" .
# Table of Contents
# Stages are described as stage-name [dependencies]
# - Intermediary stages
# * build-node [node]
# * build-node-django [build-node]
# * build-node-selfhosted [build-node]
# * build-python [wolfi-base]
# * build-python-private [build-python]
# * api-runtime [wolfi-base]
# * api-runtime-private [api-runtime]
# - Internal stages
# * api-test [build-python]
# * api-private-test [build-python-private]
# - Target (shippable) stages
# * private-cloud-api [api-runtime-private, build-python-private]
# * private-cloud-unified [api-runtime-private, build-python-private, build-node-django]
# * saas-api [api-runtime-private, build-python-private]
# * oss-api [api-runtime, build-python]
# * oss-frontend [node:slim, build-node-selfhosted]
# * oss-unified [api-runtime, build-python, build-node-django]
ARG CI_COMMIT_SHA=dev
# Pin runtimes versions
ARG NODE_VERSION=24
ARG PYTHON_VERSION=3.13
FROM public.ecr.aws/docker/library/node:${NODE_VERSION}-bookworm AS node
FROM cgr.dev/chainguard/wolfi-base:latest AS wolfi-base
# - Intermediary stages
# * build-node
FROM node AS build-node
# Copy the files required to install npm packages
WORKDIR /build
COPY frontend/package.json frontend/package-lock.json frontend/.npmrc ./frontend/.nvmrc ./frontend/
COPY frontend/bin/ ./frontend/bin/
COPY frontend/env/ ./frontend/env/
ARG ENV=selfhosted
RUN cd frontend && ENV=${ENV} npm ci --quiet --production
COPY frontend /build/frontend
# * build-node-django [build-node]
FROM build-node AS build-node-django
RUN mkdir /build/api && cd frontend && npm run bundledjango
# * build-node-selfhosted [build-node]
FROM build-node AS build-node-selfhosted
RUN cd frontend && npm run bundle
# * build-python
FROM wolfi-base AS build-python
COPY --from=ghcr.io/astral-sh/uv /uv /uvx /bin/
WORKDIR /build
ARG PYTHON_VERSION
RUN apk add build-base linux-headers curl git \
python-${PYTHON_VERSION} \
python-${PYTHON_VERSION}-dev \
py${PYTHON_VERSION}-pip
COPY api/pyproject.toml api/uv.lock api/Makefile ./
ENV UV_PROJECT_ENVIRONMENT=/build/.venv \
UV_PYTHON_PREFERENCE=only-system \
UV_PYTHON=python${PYTHON_VERSION} \
UV_LINK_MODE=copy \
UV_NO_SYNC=1 \
UV_CACHE_DIR=/root/.cache/uv
RUN --mount=type=cache,target=/root/.cache/uv \
make install opts='--no-install-project'
# * build-python-private [build-python]
FROM build-python AS build-python-private
# Authenticate git with token and install private Python dependencies
ARG EXTRAS="--extra private"
RUN --mount=type=secret,id=github_private_cloud_token \
--mount=type=secret,id=codeartifact_token \
--mount=type=cache,target=/root/.cache/uv \
echo "https://$(cat /run/secrets/github_private_cloud_token):@github.com" > ${HOME}/.git-credentials && \
git config --global credential.helper store && \
UV_INDEX_FLAGSMITH_PYPI_PRODUCTION_USERNAME=aws \
UV_INDEX_FLAGSMITH_PYPI_PRODUCTION_PASSWORD="$(cat /run/secrets/codeartifact_token)" \
make install-packages opts="--no-install-project ${EXTRAS}"
# * api-runtime
FROM wolfi-base AS api-runtime
# Install Python and make it available to venv entrypoints
ARG PYTHON_VERSION
RUN apk add python-${PYTHON_VERSION} && \
mkdir /build/ && ln -s /usr/local/ /build/.venv
WORKDIR /app
COPY api /app/
COPY .release-please-manifest.json /app/.versions.json
ARG PROMETHEUS_MULTIPROC_DIR="/tmp/prometheus"
ARG ACCESS_LOG_LOCATION="/dev/null"
ENV ACCESS_LOG_LOCATION=${ACCESS_LOG_LOCATION} \
PROMETHEUS_MULTIPROC_DIR=${PROMETHEUS_MULTIPROC_DIR} \
DJANGO_SETTINGS_MODULE=app.settings.production \
GUNICORN_WORKERS=3 \
GUNICORN_THREADS=2 \
APPLICATION_LOGGERS="app_analytics,audit,code_references,common,core,dynamodb,edge_api,environments,features,import_export,integrations,mcp,oauth2_metadata,organisations,projects,segment_membership,segments,task_processor,trust_relationships,users,webhooks,workflows"
ARG CI_COMMIT_SHA
RUN echo ${CI_COMMIT_SHA} > /app/CI_COMMIT_SHA && \
mkdir -p ${PROMETHEUS_MULTIPROC_DIR} && \
chmod 01777 ${PROMETHEUS_MULTIPROC_DIR}
EXPOSE 8000
ENTRYPOINT ["flagsmith"]
CMD ["migrate-and-serve"]
HEALTHCHECK --interval=2s --timeout=2s --retries=3 --start-period=20s \
CMD flagsmith healthcheck tcp
# * api-runtime-private [api-runtime]
FROM api-runtime AS api-runtime-private
# Install SAML binary dependency
RUN apk add xmlsec
# - Internal stages
# * api-test [build-python]
FROM build-python AS api-test
COPY api /build/
RUN --mount=type=cache,target=/root/.cache/uv \
make install-packages opts='--extra dev'
CMD ["make", "test"]
# * api-private-test [build-python-private]
FROM build-python-private AS api-private-test
COPY api /build/
RUN --mount=type=secret,id=codeartifact_token \
--mount=type=cache,target=/root/.cache/uv \
UV_INDEX_FLAGSMITH_PYPI_PRODUCTION_USERNAME=aws \
UV_INDEX_FLAGSMITH_PYPI_PRODUCTION_PASSWORD="$(cat /run/secrets/codeartifact_token)" \
make install-packages opts='--extra dev --extra private' && \
make integrate-private-tests && \
git config --global --unset credential.helper && \
rm -f ${HOME}/.git-credentials
CMD ["make", "test"]
# - Target (shippable) stages
# * private-cloud-api [api-runtime-private, build-python-private]
FROM api-runtime-private AS private-cloud-api
COPY --from=build-python-private /build/.venv/ /usr/local/
RUN python manage.py collectstatic --no-input
RUN touch ./ENTERPRISE_VERSION
USER nobody
# * private-cloud-unified [api-runtime-private, build-python-private, build-node-django]
FROM api-runtime-private AS private-cloud-unified
COPY --from=build-python-private /build/.venv/ /usr/local/
COPY --from=build-node-django /build/api/ /app/
RUN python manage.py collectstatic --no-input
RUN touch ./ENTERPRISE_VERSION
USER nobody
# * saas-api [api-runtime-private, build-python-private]
FROM api-runtime-private AS saas-api
# Install GnuPG and import private key
RUN --mount=type=secret,id=sse_pgp_pkey \
apk add gpg gpg-agent && \
gpg --import /run/secrets/sse_pgp_pkey && \
mv /root/.gnupg/ /app/ && \
chown -R nobody /app/.gnupg/
COPY --from=build-python-private /build/.venv/ /usr/local/
RUN python manage.py collectstatic --no-input
RUN touch ./SAAS_DEPLOYMENT
USER nobody
# * oss-api [api-runtime, build-python]
FROM api-runtime AS oss-api
COPY --from=build-python /build/.venv/ /usr/local/
RUN python manage.py collectstatic --no-input
USER nobody
# * oss-frontend [build-node-selfhosted]
FROM wolfi-base AS oss-frontend
ARG NODE_VERSION
RUN apk add nodejs-${NODE_VERSION}
WORKDIR /srv/bt
COPY --from=build-node-selfhosted /build/frontend/ /srv/bt/
ENV NODE_ENV=production
ARG CI_COMMIT_SHA
RUN echo ${CI_COMMIT_SHA} > /srv/bt/CI_COMMIT_SHA
COPY .release-please-manifest.json /srv/bt/.versions.json
EXPOSE 8080
CMD ["node", "./api/index.js"]
USER nobody
# * oss-unified [api-runtime, build-python, build-node-django]
FROM api-runtime AS oss-unified
COPY --from=build-python /build/.venv/ /usr/local/
COPY --from=build-node-django /build/api/ /app/
RUN python manage.py collectstatic --no-input
USER nobody