Ctrl K
ComunidadGuías…

Dockerfile

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# ─────────────────────────────────────────────
# Stage 1: Build the Vite / React frontend
# ─────────────────────────────────────────────
FROM node:22-alpine AS frontend-builder

# pnpm via corepack — version pinned in root package.json ("packageManager")
RUN corepack enable

WORKDIR /app

COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
# patches/ es necesario: pnpm-workspace.yaml referencia un patchedDependency
# (react-native-css-interop) y `pnpm install --frozen-lockfile` falla con ENOENT
# si el archivo del patch no está en el contexto.
COPY patches/ ./patches/
COPY apps/web/package.json apps/web/
COPY packages/core/package.json packages/core/
RUN pnpm install --frozen-lockfile

COPY apps/web/ apps/web/
COPY packages/core/ packages/core/

# Empty → pocketbase.js falls back to window.location.origin
ARG VITE_POCKETBASE_URL=""
ENV VITE_POCKETBASE_URL=$VITE_POCKETBASE_URL

# Empty in dev (uses Vite proxy). In prod: absolute URL of the AI API service.
ARG VITE_AI_API_URL=""
ENV VITE_AI_API_URL=$VITE_AI_API_URL

# VAPID public key for Web Push subscriptions (baked into frontend JS)
ARG VITE_VAPID_PUBLIC_KEY=""
ENV VITE_VAPID_PUBLIC_KEY=$VITE_VAPID_PUBLIC_KEY

# Release de Sentry, única por deploy: `calistenia-app@<version>+<sha corto>`.
# Es solo un identificador, no un secreto, así que ARG normal. Vacío en un build
# local → vite.config.js cae al semver de package.json.
ARG SENTRY_RELEASE=""
ENV SENTRY_RELEASE=$SENTRY_RELEASE

# El token va como SECRET de buildkit, NO como ARG: un build-arg queda escrito
# en los metadatos de la imagen y `docker history` lo enseña. Montado así solo
# existe durante este RUN y no toca ninguna capa.
#
# `|| true` porque en un build sin el secreto (local, o un PR de un fork) el
# fichero no existe: el build debe seguir, y sentryVitePlugin se apaga solo al
# no ver token. Subir source maps NUNCA debe poder tumbar un deploy.
RUN --mount=type=secret,id=sentry_auth_token \
    SENTRY_AUTH_TOKEN="$(cat /run/secrets/sentry_auth_token 2>/dev/null || true)" \
    pnpm --filter @calistenia/web build

# ─────────────────────────────────────────────
# Stage 2: Download PocketBase
# ─────────────────────────────────────────────
FROM alpine:3.19 AS pb-downloader

# Mantener en sync con Dockerfile.pb-dev y el job e2e-smoke de ci.yml — el
# smoke E2E corre contra esta misma versión de PocketBase.
ARG PB_VERSION=0.36.8

RUN apk add --no-cache curl unzip \
    && curl -fsSL --retry 5 --retry-all-errors --retry-delay 3 \
       "https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_amd64.zip" \
       -o /tmp/pocketbase.zip \
    && unzip /tmp/pocketbase.zip -d /tmp/pb \
    && chmod +x /tmp/pb/pocketbase

# ─────────────────────────────────────────────
# Stage 3: Final runtime image
# ─────────────────────────────────────────────
FROM alpine:3.19

RUN apk add --no-cache ca-certificates wget

RUN adduser -D -u 1001 pbuser

WORKDIR /app

COPY --from=pb-downloader /tmp/pb/pocketbase ./pocketbase
COPY pb_migrations/ ./pb_migrations/
COPY pb_hooks/ ./pb_hooks/
COPY --from=frontend-builder /app/apps/web/dist ./pb_public

RUN mkdir -p /app/pb_data && chown -R pbuser:pbuser /app

USER pbuser

EXPOSE 8090

HEALTHCHECK --interval=10s --timeout=3s --start-period=5s \
  CMD wget -qO- http://localhost:8090/api/health || exit 1

CMD ["./pocketbase", "serve", \
     "--http=0.0.0.0:8090", \
     "--dir=/app/pb_data", \
     "--migrationsDir=/app/pb_migrations", \
     "--hooksDir=/app/pb_hooks", \
     "--publicDir=/app/pb_public"]