Ctrl K
ComunidadGuías…

Dockerfile

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

Archivo original ↗Preguntar a KiBot
# =============================================================================
# Profilarr Dockerfile
# =============================================================================
# Multi-stage build for minimal final image size
#
# Build:  docker build -t profilarr .
# Run:    docker run -v ./config:/config -p 6868:6868 profilarr

# -----------------------------------------------------------------------------
# Stage 1: Build
# -----------------------------------------------------------------------------
ARG NODE_VERSION=24.22.1
ARG PNPM_VERSION=11.28.9
ARG BUN_VERSION=1.4.4

FROM node:${NODE_VERSION}-bookworm-slim AS builder
ARG PNPM_VERSION

# pnpm installs dependencies and runs Vite; Bun only runs the built server
RUN npm install -g pnpm@${PNPM_VERSION}

WORKDIR /build

# Copy dependency files first (cache key)
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./

# Install dependencies, keeping the pnpm store in a build cache mount
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
    pnpm install --frozen-lockfile --store-dir /pnpm/store

# Vite bundles every runtime package into the server, so the image has no
# node_modules for `trivy image` to read. Trivy reads SBOM files instead, so this
# writes a CycloneDX SBOM of the production packages. Trivy 0.70 silently skips
# CycloneDX 1.7, pnpm's default, so pin 1.6. Reading package details from the
# store keeps platform packages that weren't installed out of the list.
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
    pnpm sbom --sbom-format cyclonedx --sbom-spec-version 1.6 \
    --sbom-type application --prod --store-dir /pnpm/store \
    --out /build/sbom.cdx.json

# Copy everything else
COPY . .

# Build the application: Vite builds SvelteKit to dist/build/

# Build-time variables for version card
# TARGETARCH is automatically set by Docker buildx (amd64 or arm64)
ARG TARGETARCH
ARG VITE_CHANNEL=stable
ENV VITE_PLATFORM=docker-${TARGETARCH}
ENV VITE_CHANNEL=${VITE_CHANNEL}

# Build metadata stamped into src/lib/shared/build.ts so the version, channel,
# and commit are inlined into both server and client bundles at vite build time.
# Consumers import this file directly; no runtime config lookup.
ARG PROFILARR_VERSION=dev
ARG PROFILARR_COMMIT=unknown
ARG PROFILARR_BUILT_AT=unknown
RUN cat > src/lib/shared/build.ts <<EOF
// Generated by Dockerfile at image build time. Do not hand-edit.
export type Channel = 'stable' | 'develop' | 'dev';

export interface BuildInfo {
	readonly version: string;
	readonly channel: Channel;
	readonly commit: string | null;
	readonly builtAt: string | null;
}

export const build: BuildInfo = {
	version: '${PROFILARR_VERSION}',
	channel: '${VITE_CHANNEL}',
	commit: '${PROFILARR_COMMIT}',
	builtAt: '${PROFILARR_BUILT_AT}'
};
EOF

ENV APP_BASE_PATH=/build/dist/build
RUN pnpm exec vite build
RUN cp src/runtime/server.js src/runtime/origins.js dist/build/

# -----------------------------------------------------------------------------
# Stage 2: Runtime
# -----------------------------------------------------------------------------
FROM oven/bun:${BUN_VERSION}-alpine

# Labels for container metadata
LABEL org.opencontainers.image.title="Profilarr"
LABEL org.opencontainers.image.description="Configuration management for Radarr and Sonarr"
LABEL org.opencontainers.image.source="https://github.com/Dictionarry-Hub/profilarr"
LABEL org.opencontainers.image.licenses="AGPL-3.0"

# Install runtime dependencies
# - git: PCD repository operations (clone, pull, push)
# - tar: GNU tar for backup compatibility (not busybox tar)
# - curl: Health checks
# - su-exec: Drop privileges to non-root user (Alpine equivalent of gosu)
# - ca-certificates: HTTPS connections
# - bash: Entrypoint uses bash
# - shadow: Provides usermod/groupmod for PUID/PGID runtime changes
# - tini: PID 1 init for signal forwarding and orphaned process reaping
RUN apk add --no-cache \
    git \
    tar \
    curl \
    su-exec \
    ca-certificates \
    bash \
    shadow \
    tini \
    && apk upgrade --no-cache

# Create application directory
WORKDIR /app

# Copy the built server, client assets and runtime entry from the builder stage.
# Vite bundled every npm package into these files; the image has no node_modules.
COPY --from=builder /build/dist/build /app

# SBOM of the bundled npm packages, so `trivy image` can report them
COPY --from=builder /build/sbom.cdx.json /app/sbom.cdx.json

# Copy entrypoint script
COPY scripts/docker/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

# Create a fixed profilarr user/group (UID/GID 1000).
# - Root/PUID mode: entrypoint may reassign UID/GID at runtime via usermod.
# - Non-root mode: set runAsUser: 1000 (K8s) or --user 1000 (Docker) to skip
#   all privilege operations and run directly as this user.
# The Bun image ships a bun user and group on 1000; remove them first.
RUN deluser bun 2>/dev/null || true && \
    delgroup bun 2>/dev/null || true && \
    addgroup -g 1000 profilarr && \
    adduser -u 1000 -G profilarr -D -h /config -s /sbin/nologin profilarr

# Create config directory
RUN mkdir -p /config

# Environment variables
ENV PORT=6868
ENV HOST=0.0.0.0
ENV APP_BASE_PATH=/config
ENV TZ=UTC

# Expose port
EXPOSE 6868

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
    CMD curl -sf http://localhost:${PORT}/api/v1/health || exit 1

# Volume for persistent data
VOLUME /config

# Tini runs as PID 1 to forward signals and reap orphaned child processes.
# The entrypoint handles PUID/PGID/UMASK, then drops privileges and runs the app.
# nosemgrep: dockerfile.security.missing-user-entrypoint.missing-user-entrypoint
ENTRYPOINT ["/sbin/tini", "--", "/entrypoint.sh"]