Ctrl K
ComunidadGuías…

Dockerfile

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

Archivo original ↗Preguntar a KiBot
# syntax=docker/dockerfile:1.7
# ==============================================================================
# Stage 1: Build Frontend
# ==============================================================================
FROM node:20-alpine AS frontend-builder

WORKDIR /frontend

# Install deps without running prepare/postinstall scripts.
# svelte-kit sync needs the full source tree (svelte.config.js etc.) to work,
# which we don't have yet at this layer.
COPY web/frontend/package*.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci --include=dev --ignore-scripts

# Bring in the rest of the source, including svelte.config.js.
COPY web/frontend/ ./

# Run svelte-kit sync explicitly now that the config is present.
RUN npx svelte-kit sync

RUN --mount=type=cache,target=/root/.npm \
    npm run build

# Output: /frontend/build/ contains production static files (via adapter-static)

# ==============================================================================
# Stage 2: Build Go Binary
# ==============================================================================
FROM golang:1.27-alpine AS go-builder

WORKDIR /build

# Install build dependencies
RUN apk add --no-cache \
    git \
    ca-certificates \
    build-base \
    sqlite-dev

# Copy go module files and download dependencies (cached layer)
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod \
    go mod download

# Copy application source
COPY . .

# Copy built frontend from stage 1
# SvelteKit with adapter-static outputs to build/
COPY --from=frontend-builder /frontend/build ./web/dist

# Build binary with optimizations and version injection
# CGO_ENABLED=1 required for SQLite
ARG VERSION=dev
ARG COMMIT=unknown
ARG BUILD_DATE=unknown

RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    CGO_ENABLED=1 GOOS=linux \
    CGO_CFLAGS="-D_LARGEFILE64_SOURCE" \
    go build \
    -tags sqlite_omit_load_extension \
    -ldflags="-w -s \
    -X github.com/javinizer/javinizer-go/internal/version.Version=${VERSION} \
    -X github.com/javinizer/javinizer-go/internal/version.Commit=${COMMIT} \
    -X github.com/javinizer/javinizer-go/internal/version.BuildDate=${BUILD_DATE}" \
    -o javinizer \
    ./cmd/javinizer

# ==============================================================================
# Stage 3: Runtime
# ==============================================================================
FROM alpine:3.21

ARG VERSION=dev
ARG COMMIT=unknown
ARG BUILD_DATE=unknown

LABEL maintainer="javinizer@example.com" \
      description="JAV metadata scraper and organizer" \
      org.opencontainers.image.title="Javinizer" \
      org.opencontainers.image.description="JAV metadata scraper and organizer" \
      org.opencontainers.image.source="https://github.com/javinizer/javinizer-go" \
      org.opencontainers.image.version="${VERSION}" \
      org.opencontainers.image.revision="${COMMIT}" \
      org.opencontainers.image.created="${BUILD_DATE}" \
      version="${VERSION}"

# Working directory is now /javinizer (app state location)
WORKDIR /javinizer

# Install runtime dependencies including Chromium for browser automation
RUN apk add --no-cache \
    ca-certificates \
    tzdata \
    sqlite \
    su-exec \
    wget \
    chromium \
    nss \
    freetype \
    harfbuzz \
    ttf-freefont

# Preserve image defaults for runtime UID/GID selection. The entrypoint still
# prefers PUID/PGID, then falls back to USER_ID/GROUP_ID, and only uses these
# values when no runtime override is provided.
ARG USER_ID=1000
ARG GROUP_ID=1000

# Copy binary to /usr/local/bin for system-wide access
COPY --from=go-builder /build/javinizer /usr/local/bin/javinizer
RUN chmod +x /usr/local/bin/javinizer

# Copy frontend static files
COPY --from=go-builder /build/web/dist /app/web/dist

# Swagger/OpenAPI docs are embedded in the binary via go:embed (docs/swagger/embed.go)

# Copy entrypoint script
COPY scripts/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh

# Create image-managed state directories. Sticky world-writable permissions are
# only a fallback for containers started with an explicit Docker `user:` that
# bypasses the root bootstrap; mounted volumes still rely on host ownership.
RUN mkdir -p /javinizer/logs /javinizer/cache /javinizer/temp /media && \
    chmod 1777 /javinizer /javinizer/logs /javinizer/cache /javinizer/temp /media

# Environment variables
ENV JAVINIZER_HOME=/javinizer \
    JAVINIZER_CONFIG=/javinizer/config.yaml \
    JAVINIZER_DB=/javinizer/javinizer.db \
    JAVINIZER_LOG_DIR=/javinizer/logs \
    JAVINIZER_TEMP_DIR=/javinizer/temp \
    JAVINIZER_INIT_SERVER_HOST=0.0.0.0 \
    JAVINIZER_INIT_ALLOWED_DIRECTORIES=/media \
    JAVINIZER_INIT_ALLOWED_ORIGINS="http://localhost:8765,http://localhost:5173,http://localhost:5174,http://127.0.0.1:8765,http://127.0.0.1:5173,http://127.0.0.1:5174" \
    JAVINIZER_IMAGE_DEFAULT_UID=${USER_ID} \
    JAVINIZER_IMAGE_DEFAULT_GID=${GROUP_ID} \
    CHROME_BIN=/usr/bin/chromium-browser \
    CHROME_PATH=/usr/bin/chromium-browser \
    XDG_CONFIG_HOME=/tmp/.chromium \
    XDG_CACHE_HOME=/tmp/.chromium \
    PATH="/usr/local/bin:${PATH}"

# Expose API/web port
EXPOSE 8765

# Health check endpoint
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
    CMD wget --no-verbose --tries=1 --method=GET -O /dev/null http://localhost:8765/health || exit 1

# Entrypoint script to initialize config
ENTRYPOINT ["docker-entrypoint.sh"]

# Run web server (will be passed to entrypoint)
CMD ["javinizer", "web"]