Ctrl K
ComunidadGuías…

Dockerfile

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

Archivo original ↗Preguntar a KiBot
# syntax=docker/dockerfile:1.7
FROM node:22-bookworm-slim AS spa-builder
WORKDIR /src/frontend

COPY frontend/package.json frontend/package-lock.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci --ignore-scripts

COPY frontend/ ./
RUN npm run build-only

FROM golang:1.26-alpine AS builder

RUN apk add --no-cache gcc musl-dev

WORKDIR /src
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod \
    go mod download

COPY cmd/ ./cmd/
COPY internal/ ./internal/
COPY --from=spa-builder /src/frontend/dist cmd/maintenant/web/dist/

ARG VERSION=dev
ARG COMMIT=unknown
ARG BUILD_DATE=unknown
ARG LICENSE_PUBLIC_KEY
ARG DEMO_MODE=false

RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    CGO_ENABLED=1 go build \
        -ldflags="-s -w \
          -X main.version=${VERSION} \
          -X main.commit=${COMMIT} \
          -X main.buildDate=${BUILD_DATE} \
          -X main.publicKeyB64=${LICENSE_PUBLIC_KEY} \
          -X main.demoMode=${DEMO_MODE}" \
        -o /out/maintenant \
        ./cmd/maintenant

FROM alpine:3.21

RUN apk upgrade --no-cache \
    && apk add --no-cache ca-certificates tzdata setpriv \
    && mkdir -p /data \
    && chown 65534:65534 /data

# Keep SQLite's temp files (statement journals, temp B-trees used by the one-time
# UUID conversion of large tables) on the data volume. The hardened runtime mounts
# /tmp as a tiny tmpfs, which SQLITE_FULL-fails the conversion; /data has real space.
ENV SQLITE_TMPDIR=/data

# Its directory also holds the licence cache and the update window, PostgreSQL or not.
ENV MAINTENANT_DB=/data/maintenant.db

# Tells the OS identity reader it must not fall back to the image's own
# /etc/os-release, which describes the container rather than the host.
ENV MAINTENANT_CONTAINER=1

COPY --from=builder --chmod=555 /out/maintenant /app/maintenant
COPY --chmod=555 docker-entrypoint.sh /docker-entrypoint.sh

ARG VERSION=dev
ARG COMMIT=unknown
ARG BUILD_DATE=unknown
LABEL org.opencontainers.image.title="maintenant" \
      org.opencontainers.image.description="Monitor everything. Manage nothing." \
      org.opencontainers.image.url="https://github.com/kOlapsis/maintenant" \
      org.opencontainers.image.source="https://github.com/kOlapsis/maintenant" \
      org.opencontainers.image.vendor="kOlapsis" \
      org.opencontainers.image.licenses="Apache-2.0 AND LicenseRef-Maintenant-Commercial" \
      io.modelcontextprotocol.server.name="io.github.kOlapsis/maintenant" \
      org.opencontainers.image.version="${VERSION}" \
      org.opencontainers.image.revision="${COMMIT}" \
      org.opencontainers.image.created="${BUILD_DATE}"

EXPOSE 8080
VOLUME /data

# One image, two modes: the binary knows how to check itself. A server answers on
# the address it was configured with, an agent has no port at all and reports
# liveness through a file, so an HTTP probe here would fail every agent forever.
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
    CMD ["/app/maintenant", "healthcheck"]

# Entrypoint runs as root only to chown root-owned volume mounts and auto-detect
# the Docker socket group, then drops to uid 65534 via setpriv (see
# docker-entrypoint.sh); a build-time USER would break that chown and detection.
# nosemgrep: dockerfile.security.missing-user-entrypoint.missing-user-entrypoint
ENTRYPOINT ["/docker-entrypoint.sh"]
# nosemgrep: dockerfile.security.missing-user.missing-user
CMD ["/app/maintenant"]