ARG APP_RELEASE=dev ARG PUBLIC_SOURCEMAPS=false # UI build stage ARG TARGETOS ARG TARGETARCH FROM node:alpine AS ui-builder ARG APP_RELEASE ENV VITE_APP_RELEASE=${APP_RELEASE} WORKDIR /app COPY otel-ui/ . RUN npm install && npm run build # Go build stage FROM --platform=$BUILDPLATFORM golang:1.27-alpine AS go-builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY cmd/ ./cmd COPY internal/ ./internal # Copy built UI dist COPY --from=ui-builder /app/dist ./otel-ui/dist RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -a -installsuffix cgo -o /go-otel ./cmd/server # Final stage FROM alpine:latest ARG PUBLIC_SOURCEMAPS RUN apk --no-cache add ca-certificates nmap nmap-scripts # Create non-root user RUN addgroup -S appgroup && adduser -S appuser -G appgroup WORKDIR /home/appuser/ COPY --from=go-builder /go-otel . COPY --from=go-builder /app/otel-ui/dist ./dist COPY static/ ./static COPY db/GeoLite2-City.mmdb db/GeoLite2-ASN.mmdb ./db/ COPY agents_example.md . COPY instrumentation.md . # Private server-side maps are the default. Staging/dev can opt into public # maps for Chrome DevTools with --build-arg PUBLIC_SOURCEMAPS=true. RUN if [ "${PUBLIC_SOURCEMAPS}" != "true" ]; then find ./dist -type f -name '*.map' -delete; fi # Ensure the appuser owns the files RUN chown -R appuser:appgroup /home/appuser/ USER appuser ENV OTEL_GEOIP_CITY_DB=/home/appuser/db/GeoLite2-City.mmdb \ OTEL_GEOIP_ASN_DB=/home/appuser/db/GeoLite2-ASN.mmdb EXPOSE 8080 CMD ["./go-otel"]