Ctrl K
ComunidadGuías…

Dockerfile.single

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

Archivo original ↗Preguntar a KiBot
# The single image: Peekaping in single mode (ADR 0002). One process, peekaping, serves the
# web app, the API and the websocket on port 8383. Its database is SQLite in /app/data, or a
# PostgreSQL server in a container of its own (DB_TYPE=postgres).

# Stage 1: Build peekaping and the migration tool
FROM golang:1.27.3-alpine AS go-builder

RUN apk add --no-cache git
WORKDIR /app/server
COPY apps/server/go.mod apps/server/go.sum ./
RUN go mod download
COPY apps/server/ .
RUN CGO_ENABLED=0 GOFLAGS="-trimpath" go build -o peekaping -ldflags="-s -w" ./cmd/peekaping
RUN CGO_ENABLED=0 GOFLAGS="-trimpath" go build -o bun -ldflags="-s -w" ./cmd/bun

# Stage 2: Build the web app
FROM node:22-alpine AS web-builder

WORKDIR /app
# Bun, at the version pinned in package.json
COPY --from=oven/bun:1.4.4-alpine /usr/local/bin/bun /usr/local/bin/bun
COPY package.json bun.lock ./
COPY apps/web/package.json ./apps/web/package.json
RUN bun install --frozen-lockfile --filter web
COPY apps/web/ ./apps/web/
WORKDIR /app/apps/web
RUN bun run build

# Stage 3: Runtime
FROM alpine:3.24

# tini runs as PID 1 and passes docker stop's SIGTERM to peekaping. su-exec drops root for
# peekaping, and shadow's groupmod and usermod apply PUID and PGID (startup.user.sh). Ping
# monitors fall back to busybox's ping where they can't open an ICMP socket themselves.
RUN apk add --no-cache ca-certificates tini su-exec shadow

# PUID and PGID can't take an ID a user or group in the image has, and Alpine gives out IDs
# that Debian, which earlier bundles ran on, leaves free: groups 82 (www-data) and 999 (ping)
# and user 405 (guest), among others. So the users and groups no file in the image belongs to
# are dropped.
# root, nobody and nogroup stay, and so do tty, disk and kmem, the groups Linux gives the
# device files Docker can bring into the container.
RUN for user in $(cut -d: -f1 /etc/passwd); do \
        case "$user" in root | nobody) continue ;; esac; \
        if [ -z "$(find / -xdev -user "$user" | head -n 1)" ]; then userdel "$user" || exit 1; fi; \
    done \
    && for group in $(cut -d: -f1 /etc/group); do \
        case "$group" in root | tty | disk | kmem | nogroup | nobody) continue ;; esac; \
        if [ -z "$(find / -xdev -group "$group" | head -n 1)" ]; then groupdel "$group" || exit 1; fi; \
    done

# The user peekaping runs as; startup.user.sh applies PUID/PGID
RUN addgroup -g 1000 peekaping \
    && adduser -u 1000 -G peekaping -H -D -h /nonexistent -s /sbin/nologin peekaping \
    && mkdir -p /app/data \
    && chown peekaping:peekaping /app/data

COPY --from=go-builder --chmod=755 /app/server/peekaping /app/server/bun /app/server/
COPY --from=go-builder --chmod=755 /app/server/scripts/run-migrations.sh /app/server/run-migrations.sh
COPY --from=web-builder /app/apps/web/dist /app/web
COPY --chmod=755 startup.single.sh /app/startup.sh
COPY startup.single.user.sh /app/startup.user.sh

# peekaping serves the web build itself and generates /env.js. The startup script checks DB_TYPE
# and forces SERVER_PORT to 8383, whatever the .env says.
ENV WEB_DIR=/app/web \
    TZ=UTC

WORKDIR /app/server
EXPOSE 8383

# peekaping takes up to 30 seconds to shut down; give docker stop -t 35 or
# stop_grace_period: 35s so it isn't killed halfway
STOPSIGNAL SIGTERM
HEALTHCHECK --interval=30s --timeout=5s --start-period=60s --start-interval=2s --retries=3 \
    CMD wget -q -O /dev/null http://127.0.0.1:8383/api/v1/health || exit 1

ENTRYPOINT ["/sbin/tini", "--"]
CMD ["/app/startup.sh"]