Ctrl K
ComunidadGuías…

Dockerfile

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

Archivo original ↗Preguntar a KiBot
# IsItDown ships two editions from one source tree and one Dockerfile.
#
#   docker build --target light -t isitdown:light .
#   docker build --target ui    -t isitdown:ui    .
#
# A third target, `dev`, exists only for docker-compose.dev.yml — it is never
# built by `docker compose --profile ui up` (that pins `target: ui`) and it is
# tagged `isitdown:dev`, never `isitdown:ui`, so a dev build cannot overwrite
# the production image. `ui` is deliberately the last stage in this file, so a
# target-less `docker build .` still builds `ui`.
#
# The `ui` stage starts FROM `light`, so the UI image is the Light image plus a
# single thin layer: everything below it — base image, production dependencies,
# core engine — is shared on disk and in a registry.

# --- Build stage ---------------------------------------------------------------
# Pinned to the machine running the build, not the image's target platform: the
# output is plain JavaScript, identical on every architecture, so an arm64
# release compiles natively and copies the result across instead of running
# npm ci, tsc and Vite under QEMU — which was most of the release's wall clock.
FROM --platform=$BUILDPLATFORM node:24-alpine AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY tsconfig.json tsconfig.light.json tsconfig.web.json vite.config.ts components.json ./
COPY tools ./tools
COPY src ./src
# Builds every edition once, so this layer is shared by both runtime stages.
RUN npm run build

# --- Light edition -------------------------------------------------------------
FROM node:24-alpine AS light
WORKDIR /app
ENV NODE_ENV=production
ENV CONFIG_PATH=/app/config/config.yml
ENV DATA_PATH=/app/data/state.json
COPY package.json package-lock.json ./
RUN npm ci --omit=dev && npm cache clean --force
COPY --from=builder /app/dist/core ./dist/core
COPY --from=builder /app/dist/adapters ./dist/adapters
COPY --from=builder /app/dist/notifiers ./dist/notifiers
COPY --from=builder /app/dist/light ./dist/light
# The outpost (roadmap 1.7) is core + adapters behind one route, so it rides in
# this image under its own command rather than costing a third one — see the
# `outpost` profile in docker-compose.yml.
COPY --from=builder /app/dist/outpost ./dist/outpost
RUN mkdir -p /app/config /app/data && chown -R node:node /app
USER node
VOLUME ["/app/config", "/app/data"]
# No EXPOSE and no server: this edition only polls and notifies.
# The state file is rewritten by every cycle, so its age is the liveness signal.
HEALTHCHECK --interval=30s --timeout=5s --start-period=40s --retries=3 \
  CMD ["node", "dist/light/healthcheck.js"]
CMD ["node", "dist/light/index.js"]

# --- UI edition, dev mode: the builder stage, live -----------------------------
# FROM builder, not light/ui: dev mode needs the full devDependencies tree
# (vite) and node_modules that npm ci --omit=dev deliberately drops from the
# runtime stages. docker-compose.dev.yml mounts ./src read-only over this and
# Vite rewrites the React bundle into this stage's own /app/dist on save —
# writable because the stage stays root, and deliberately not a volume, so the
# tree never outlives the image it was built from.
#
# NODE_ENV and the healthcheck are this stage's own, not inherited from
# light/ui: the image says development rather than leaving it to the compose
# override, and readiness is judged on the source tree the stage actually runs
# (types stripped at load) rather than on a compiled artifact it never loads.
FROM builder AS dev
ENV NODE_ENV=development
ENV DB_PATH=/app/data/isitdown.db
ENV PORT=3000
# Inside a container the published port reaches the container's own interface, so
# loopback there would be unreachable; exposure is decided by the compose `ports` mapping.
ENV BIND_HOST=0.0.0.0
EXPOSE 3000
# Same start period as the ui stage, and for the same reason: the probe is
# readiness, so it stays 503 until the first cycle has read the fleet.
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
  CMD ["node", "src/ui/healthcheck.ts"]
CMD ["sh", "-c", "npx vite build --watch & exec node --watch src/ui/server.ts"]

# --- UI edition: the light image plus the server layer ----------------------------
# Starting FROM light means every layer below this point — base image, production
# dependencies, core engine — is shared with isitdown:light on disk and in a
# registry. The UI image is that image plus one thin layer. Kept as the last
# stage in the file so a target-less `docker build .` still builds this one.
FROM light AS ui
ENV DB_PATH=/app/data/isitdown.db
ENV PORT=3000
# Inside a container the published port reaches the container's own interface, so
# loopback there would be unreachable; exposure is decided by the compose `ports` mapping.
ENV BIND_HOST=0.0.0.0
USER root
COPY --from=builder /app/dist/ui ./dist/ui
RUN chown -R node:node /app/dist/ui
USER node
EXPOSE 3000
# The probe is readiness, not liveness (roadmap 6.9): it stays 503 until the
# first cycle has actually read the fleet, so the start period covers the
# history backfill plus that first cycle rather than just the listen.
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --retries=3 \
  CMD ["node", "dist/ui/healthcheck.js"]
CMD ["node", "dist/ui/server.js"]