#!/bin/bash # Optimized Docker Builder for Cloudron Applications set -e # Configuration BUILDER_IMAGE="cloudron-builder:latest" REGISTRY="registry.cloudron.io" # Create builder image with all common tools create_builder_image() { echo "Creating optimized builder image..." docker build -t "$BUILDER_IMAGE" - << 'EOF' FROM ubuntu:22.04 # Install all common build tools RUN apt-get update && apt-get install -y \ git \ curl \ wget \ build-essential \ python3 \ python3-pip \ nodejs \ npm \ golang-go \ openjdk-17-jdk \ ruby \ ruby-dev \ rustc \ cargo \ php \ composer \ maven \ gradle \ && rm -rf /var/lib/apt/lists/* # Install common global packages RUN npm install -g @angular/cli @vue/cli create-react-app RUN pip3 install django flask fastapi RUN gem install bundler rails WORKDIR /workspace EOF echo "Builder image created successfully" } # Build application in container build_app() { local app_dir="$1" local app_name=$(basename "$app_dir") echo "Building $app_name in optimized container..." # Run build in container with volume mount docker run --rm \ -v "$app_dir:/workspace" \ -w /workspace \ "$BUILDER_IMAGE" \ bash -c " # Detect and build based on application type if [ -f 'package.json' ]; then echo 'Building Node.js application...' npm ci --only=production npm run build 2>/dev/null || echo 'No build script found' elif [ -f 'go.mod' ]; then echo 'Building Go application...' go mod download go build -o app . elif [ -f 'requirements.txt' ] || [ -f 'setup.py' ]; then echo 'Building Python application...' pip3 install -r requirements.txt 2>/dev/null || true elif [ -f 'Cargo.toml' ]; then echo 'Building Rust application...' cargo build --release elif [ -f 'pom.xml' ]; then echo 'Building Maven application...' mvn clean package -DskipTests elif [ -f 'build.gradle' ]; then echo 'Building Gradle application...' gradle build -x test else echo 'Unknown application type, skipping build' fi " echo "Build completed for $app_name" } # Create Cloudron-optimized Dockerfile create_optimized_dockerfile() { local app_dir="$1" local app_type="$2" local app_name=$(basename "$app_dir") echo "Creating optimized Dockerfile for $app_name ($app_type)..." case "$app_type" in "nodejs") cat > "$app_dir/app/Dockerfile" << 'EOF' # Multi-stage build for Node.js application FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci --only=production && npm cache clean --force FROM node:18-alpine AS runtime RUN addgroup -g 1001 -S nodejs && adduser -S nextjs -u 1001 WORKDIR /app COPY --from=builder /app/node_modules ./node_modules COPY --chown=nextjs:nodejs . . USER nextjs EXPOSE 8080 CMD ["npm", "start"] EOF ;; "golang") cat > "$app_dir/app/Dockerfile" << 'EOF' # Multi-stage build for Go application FROM golang:1.21-alpine AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download && go mod verify COPY . . RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o main . FROM alpine:latest AS runtime RUN apk --no-cache add ca-certificates tzdata WORKDIR /root/ COPY --from=builder /app/main . RUN chmod +x main EXPOSE 8080 CMD ["./main"] EOF ;; "python") cat > "$app_dir/app/Dockerfile" << 'EOF' # Multi-stage build for Python application FROM python:3.11-alpine AS builder WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir --user -r requirements.txt FROM python:3.11-alpine AS runtime RUN addgroup -g 1001 -S python && adduser -S python -u 1001 WORKDIR /app COPY --from=builder /root/.local /home/python/.local COPY --chown=python:python . . USER python ENV PATH=/home/python/.local/bin:$PATH EXPOSE 8080 CMD ["python", "app.py"] EOF ;; esac echo "Optimized Dockerfile created for $app_name" } # Main execution main() { local app_dir="$1" local app_type="$2" if [ -z "$app_dir" ] || [ -z "$app_type" ]; then echo "Usage: $0 " exit 1 fi # Create builder image if needed if ! docker image inspect "$BUILDER_IMAGE" >/dev/null 2>&1; then create_builder_image fi # Create optimized Dockerfile create_optimized_dockerfile "$app_dir" "$app_type" # Build application build_app "$app_dir" echo "Optimization complete for $(basename "$app_dir")" } # Run if called directly if [ "${BASH_SOURCE[0]}" = "${0}" ]; then main "$@" fi