Ctrl K
ComunidadGuías…

Containerfile

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

Archivo original ↗Preguntar a KiBot
# --------------------------------------------------------------------------
# THIS FILE IS AUTOGENERATED - DO NOT EDIT MANUALLY
#
# Source: Containerfile.j2
# --------------------------------------------------------------------------

# --------------------------------------------------------------------------
# SparkyFitness — FreeBSD daemonless container
# Self-hosted, privacy-first fitness tracker
# --------------------------------------------------------------------------

ARG BASE_VERSION=15
ARG UPSTREAM_URL="https://api.github.com/repos/CodeWithCJ/SparkyFitness/releases/latest"

# ==========================================================================
# Stage 1: Builder
# ==========================================================================
FROM ghcr.io/daemonless/base-exec:${BASE_VERSION} AS builder

ARG UPSTREAM_URL

# Build dependencies
RUN pkg update && pkg install -y \
    node24 npm-node24 corepack \
    git-lite jq \
    && pkg clean -ay

# Enable pnpm via corepack
RUN corepack enable && corepack prepare pnpm@10.33.4 --activate

# Clone latest release
WORKDIR /build
RUN --mount=type=secret,id=github_token \
    GITHUB_TOKEN=$(cat /run/secrets/github_token 2>/dev/null || echo ""); \
    if [ -n "${GITHUB_TOKEN}" ]; then \
      export HTTP_AUTH="basic:*:x-access-token:${GITHUB_TOKEN}"; \
    fi && \
    VERSION=$(fetch -qo - "${UPSTREAM_URL}" | jq -r '.tag_name') && \
    echo "Resolved VERSION=$VERSION" && \
    git clone --depth 1 --branch ${VERSION} \
      https://github.com/CodeWithCJ/SparkyFitness.git . && \
    echo "${VERSION}" > /tmp/app_version

# sharp on FreeBSD is @img/sharp-freebsd-wasm32, a shim over @img/sharp-wasm32
# (cpu: wasm32). Upstream's supportedArchitectures leaves wasm32 out, so the
# server dies with 'Could not load the "sharp" module'. Fail if the list moves.
RUN awk '{ print } /^  cpu:$/ { print "    - wasm32" }' pnpm-workspace.yaml > pnpm-workspace.yaml.new && \
    mv pnpm-workspace.yaml.new pnpm-workspace.yaml && \
    grep -q '^    - wasm32$' pnpm-workspace.yaml

# Install workspace dependencies for frontend + server
RUN pnpm install --frozen-lockfile \
    --filter sparkyfitnessfrontend... \
    --filter sparkyfitnessserver...

# Build frontend (React + Vite)
RUN pnpm --filter sparkyfitnessfrontend run build

# Deploy server to standalone directory (flat node_modules, no workspace symlinks)
RUN pnpm --filter=sparkyfitnessserver deploy --legacy /deploy

# Ensure tsx is available in the deployed server
# (pnpm deploy --legacy may skip devDependencies)
RUN if [ ! -f /deploy/node_modules/.bin/tsx ]; then \
      cd /deploy && npm install tsx; \
    fi

# ==========================================================================
# Stage 2: Runtime
# ==========================================================================
FROM ghcr.io/daemonless/base-rcd:${BASE_VERSION}

ARG FREEBSD_ARCH=amd64
ARG PACKAGES="node24 nginx postgresql18-client"
ARG UPSTREAM_URL="https://api.github.com/repos/CodeWithCJ/SparkyFitness/releases/latest"
ARG UPSTREAM_JQ=".tag_name"
ARG HEALTHCHECK_ENDPOINT="http://localhost:3004"

ENV HEALTHCHECK_URL="${HEALTHCHECK_ENDPOINT}"

LABEL org.opencontainers.image.title="SparkyFitness" \
      org.opencontainers.image.description="Self-hosted privacy-first fitness tracker on FreeBSD" \
      org.opencontainers.image.source="https://github.com/daemonless/sparkyfitness" \
      org.opencontainers.image.url="https://github.com/CodeWithCJ/SparkyFitness" \
      org.opencontainers.image.version="latest" \
      org.opencontainers.image.licenses="NOASSERTION" \
      org.opencontainers.image.vendor="daemonless" \
      org.opencontainers.image.authors="daemonless" \
      io.daemonless.category="Utilities" \
      io.daemonless.port="3004" \
      io.daemonless.arch="${FREEBSD_ARCH}" \
      io.daemonless.upstream-url="${UPSTREAM_URL}" \
      io.daemonless.upstream-jq="${UPSTREAM_JQ}" \
      io.daemonless.healthcheck-url="${HEALTHCHECK_ENDPOINT}" \
      io.daemonless.volumes="/app/server/uploads,/app/server/backup" \
      io.daemonless.packages="${PACKAGES}"

# Install runtime dependencies
RUN pkg update && \
    pkg install -y ${PACKAGES} && \
    mkdir -p /app/server /app/client \
             /var/log/nginx /var/run /var/tmp/nginx && \
    pkg clean -ay && \
    rm -rf /var/cache/pkg/* /var/db/pkg/repos/*

# Copy built artifacts from builder
COPY --from=builder /tmp/app_version /app/version
COPY --from=builder --chown=bsd:bsd /build/SparkyFitnessFrontend/dist /app/client
COPY --from=builder --chown=bsd:bsd /deploy /app/server

# Set ownership — /app and /app/client need to be world-readable for nginx worker (www user)
RUN mkdir -p /app/server/uploads /app/server/backup && \
    chown -R bsd:bsd /app && \
    chmod o+x /app && \
    chmod -R o+rX /app/client

# Copy service files (s6 runners, nginx config, healthz)
COPY root/ /
RUN chmod +x /daemonless/libexec/* /daemonless/init.d/*
RUN chmod +x /healthz

WORKDIR /app

# Pin the server's data dirs to the declared volumes. The values equal the app's defaults
# (utils/uploadsPath.ts and services/backupService.ts resolve uploads/ and backup/ under
# /app/server), so nothing changes today; if upstream moves those defaults, data still lands
# in the declared volumes instead of the container layer. Backups are pinned through the
# lowest-precedence variable (backupService.ts: SPARKY_FITNESS_CUSTOM_BACKUP_DIRECTORY, then
# BACKUP_DIR, then the default), so a user's setting of either variable still wins.
ENV NODE_ENV=production \
    NODE_OPTIONS="--max-old-space-size=256" \
    SPARKY_FITNESS_CUSTOM_UPLOADS_DIRECTORY=/app/server/uploads \
    BACKUP_DIR=/app/server/backup

EXPOSE 3004

VOLUME /app/server/uploads /app/server/backup