Docker image build OOM

I’m trying to package a Julia app as a docker image. Since, as of writing this, package relocatability is not solved; hence, this is the only way to share an app.

In my dockerfile I run:

###############################################################################################
# Stage 1: Build Stage
FROM julia:1.11.2-bullseye AS builder

# Install C compiler required for PackageCompiler and clean up afterward to reduce image size
RUN apt-get update && \
    apt-get install -y --no-install-recommends g++ && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# Set environment for Julia compilation
ENV JULIA_CPU_TARGET=generic

# Create a non-root user and set up directories
RUN useradd --create-home --shell /bin/bash jl && mkdir /home/jl/app && chown -R jl:jl /home/jl/
WORKDIR /home/jl/app

# Switch to non-root user
USER jl

ENV JULIA_DEPOT_PATH "/home/jl/.julia"
ENV JULIA_REVISE "off"
ENV EARLYBIND "true"
ENV JULIA_NUM_PRECOMPILE_TAKS "4"

# Copy dependency files first to leverage Docker caching for dependencies
COPY --chown=jl:jl Project.toml .
COPY --chown=jl:jl deps/ deps/
RUN julia --project -e "using Pkg; Pkg.instantiate(); Pkg.precompile();"

# Copy the full application code and precompile with sysimage
COPY --chown=jl:jl compiled/ compiled/
COPY --chown=jl:jl App/ App/
# copy test data so that precompiling works
COPY --chown=jl:jl data/ data/
RUN julia --project -t auto -O3 --startup-file=no compiled/make.jl

###############################################################################################
# Stage 2: Production Stage
FROM debian:bullseye-slim  
# Install curl (for BinaryProvider) compiler required for PackageCompiler and clean up afterward to reduce image size
RUN apt-get update && \
    apt-get install -y --no-install-recommends curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# Set up a non-root user for running the app
RUN useradd --create-home --shell /bin/bash jl && mkdir /home/jl/app && chown -R jl:jl /home/jl/
WORKDIR /home/jl/app
USER jl

# Set environment variables
ENV JULIA_REVISE "off"
ENV EARLYBIND "true"

# Copy only essential files from the build stage to the production stage
COPY --from=builder /home/jl/app/compiled/App /home/jl/app

# Since Julia's relocatability depends on each package, simply make a symlink to the artifacts directory in the compiled app
RUN mkdir -p /home/jl/.julia/artifacts && ln -s /home/jl/app/share/julia/artifacts /home/jl/.julia/artifacts

# Command to run the application
ENTRYPOINT ["/home/jl/app/bin/App"]
CMD ["--julia-args", "-t", "auto", "-O3", "--startup-file=no"]

and my make.jl file is:

using PackageCompiler

PackageCompiler.create_app(
    "App",
    "compiled/App";
    cpu_target="generic",
    sysimage_build_args=`-O3`,
    precompile_execution_file="compiled/precompile.jl",
    include_transitive_dependencies=false,
    include_lazy_artifacts=true,
    incremental=true,
    # filter_stdlibs=true,
)

I also have a precompile.jl script with a representative workload.
When I run docker build I get as far as to compiling the incremental sysimage. Then I get OOMs. I just have 8 GB of RAM and 2 GB of swap availiable. The same runs fine on a machine with 16 GB or 24 GB RAM.

My question: How can I reduce the resource need of PackageCompiler.jl?

BTW, the secrete sauce is this line:

RUN mkdir -p /home/jl/.julia/artifacts && ln -s /home/jl/app/share/julia/artifacts /home/jl/.julia/artifacts

which solves the relocatable issue, since I copy over the app from the build stage.