FROM crystallang/crystal:1.14.0-alpine AS builder # Install build dependencies RUN apk add --no-cache \ yaml-dev \ openssl-dev \ zlib-dev \ sqlite-dev \ postgresql-dev \ git \ curl # Set build arguments ARG APP_NAME=web-portal WORKDIR /app # Copy dependencies first COPY src/web-portal/shard.yml ./ RUN shards install # Copy shared types and client COPY src/types.cr src/ COPY src/kubernetes_client.cr src/ # Copy service-specific files COPY src/web-portal/ src/web-portal/ # Ensure config directory exists and copy database.yml RUN mkdir -p /app/config COPY src/web-portal/config/database.yml /app/config/ # Build the binary with standalone flag RUN crystal build --release --static src/web-portal/app.cr -o "web-portal" -D standalone # Runtime stage FROM alpine:3.19 # Install runtime dependencies RUN apk add --no-cache \ ca-certificates \ tzdata \ openssl \ yaml WORKDIR /app # Copy the binary, views, and config from builder COPY --from=builder /app/${APP_NAME} . COPY --from=builder /app/src/web-portal/views ./views COPY --from=builder /app/config ./config # Create non-root user and set permissions RUN adduser -D appuser && \ find /app -type d -exec chmod 755 {} \; && \ find /app -type f -exec chmod 500 {} \; && \ chmod 755 /app/web-portal && \ chmod -R 644 ./views/* && \ chmod -R 644 ./config/* && \ chown -R appuser:appuser /app USER appuser # Set environment variables ENV PORT=3000 # Expose ports EXPOSE 3000 ENTRYPOINT ["/app/web-portal"]