Building Ultra-Lightweight Docker Images with Free Pascal: From Scratch in just over 1MB! 🚀
Sempare Limited

Sempare Limited @sempare

About: Sempare Limited is a small consultancy. We are an Embarcadero Tech Partner and have developed a number of tools and libraries for Delphi and RAD Studio. Contact us for more information.

Location:
Amersham, Buckinghamshire, United Kingdom
Joined:
Oct 16, 2024

Building Ultra-Lightweight Docker Images with Free Pascal: From Scratch in just over 1MB! 🚀

Publish Date: Aug 25
0 0

Ever wondered how small you can make a Docker image for Free Pascal based of Docker scratch? In this article I'll show you how to create a fully functional application using Free Pascal and containerise it that fits in just 1.24MB - smaller than most profile pictures!

Why This Matters

In the world of microservices and containerised applications, image size matters:

  • Faster deployments - Less data to transfer
  • Reduced storage costs - Especially important at scale
  • Improved security - Smaller attack surface
  • Better performance - Less memory footprint

The Magic: Docker's scratch Image

Docker's scratch image is literally empty - it contains absolutely nothing. This makes it the ultimate starting point for minimal containers, but it also means your binary needs to be completely self-contained.

The Setup

Here's what we're working with:

hello.pas - A simple Free Pascal program that makes an HTTP request:

program hello;

uses
    SysUtils,
    fphttpclient;
begin
    writeln(TFPCustomHTTPClient.SimpleGet('http://www.somedomain.com'));
end.
Enter fullscreen mode Exit fullscreen mode

fpc.cfg - Compiler configuration for static linking:

-O4 
-Os 
-Xs 
-XX 
-XS 
-k-static
-Fu/usr/lib/fpc/3.2.2/units/aarch64-linux/fcl-net
-Fu/usr/lib/fpc/3.2.2/units/aarch64-linux/fcl-web 
-Fu/usr/lib/fpc/3.2.2/units/aarch64-linux/fcl-base
-Fu/usr/lib/fpc/3.2.2/units/aarch64-linux/rtl-extra 
-Fu/usr/lib/fpc/
-Fu/usr/lib/fpc/3.2.2/units/aarch64-linux/rtl-objpas
Enter fullscreen mode Exit fullscreen mode

Key compiler flags explained:

  • -O4 -Os: Maximum optimization for size
  • -Xs -XX -XS: Strip symbols and create smart-linked executable
  • -k-static: Static linking (crucial for scratch containers)

The Multi-Stage Dockerfile

FROM freepascal/fpc:3.2.2-alpine-3.19-full AS build

RUN apk add --no-cache musl-dev 

RUN mkdir /build

WORKDIR /build

COPY fpc.cfg /etc/
COPY hello.pas /build/

RUN fpc hello.pas 

FROM scratch
COPY --from=build /build/hello /app/hello
CMD ["/app/hello"]
Enter fullscreen mode Exit fullscreen mode

This uses a multi-stage build:

  1. Stage 1: Use the full Free Pascal Alpine image to compile
  2. Stage 2: Copy only the compiled binary to scratch

Building and Testing

# Build the image
docker build -t hello-fpc .

# Check the size
docker images hello-fpc
# Output: hello-fpc latest 1.24MB

# Run it
docker run hello-fpc
# Output: Full HTML response from the test site!
Enter fullscreen mode Exit fullscreen mode

Why This is So Cool

  1. Incredible Size Efficiency: At 1.24MB, this is smaller than:

    • A single high-resolution photo
    • Most JavaScript frameworks
    • Basic Python/Node.js containers (often 100MB+)
  2. Security Benefits:

    • No shell, package manager, or unnecessary tools
    • Minimal attack surface
    • Only contains your application
  3. Performance:

    • Lightning-fast container startup
    • Minimal memory usage
    • Perfect for serverless/edge computing

Free Pascal Advantages

Free Pascal shines in this use case because:

  • Static compilation: Creates self-contained binaries
  • Small runtime: No large runtime environment needed
  • Fast execution: Compiled code runs efficiently
  • Rich libraries: Full HTTP client capabilities built-in
  • Cross-platform: Same code works on multiple architectures

Comparison with Other Languages

Language Typical Container Size Notes
Free Pascal 1.24MB This example
Go 5-20MB With scratch base
Rust 10-30MB With alpine/scratch
Node.js 150-300MB Even with Alpine
Python 100-500MB Various base images
Java 200-400MB JRE required

Real-World Applications

This approach is perfect for:

  • Microservices: Minimal overhead
  • Edge computing: Fast deployment
  • IoT applications: Resource constraints
  • Serverless functions: Quick cold starts
  • Health check services: Minimal footprint
  • API gateways: High performance needs

Tips for Success

  1. Always use static linking (-k-static flag)
  2. Optimize for size (-Os, -O4 flags)
  3. Strip symbols (-Xs, -XX flags)
  4. Test thoroughly - No debugging tools in scratch!
  5. Handle errors gracefully - No shell for troubleshooting

Conclusion

Free Pascal + Docker scratch images = Ultimate efficiency!

At just 1.24MB, we've created a fully functional web client that's:

  • ✅ Secure by design
  • ✅ Lightning fast
  • ✅ Resource efficient
  • ✅ Secured intellectual property

This approach proves that modern applications don't need to be bloated. Not bad when working with with your daddy's pascal! ;)

Thank you to our supporters!

We need your help to maintain our Sempare Template Engine (https://github.com/sempare/sempare-delphi-template-engine).

Support us via GitHub Sponsors (https://github.com/sponsors/sempare) or Stripe (https://buy.stripe.com/aEU7t61N88pffQIdQQ).

Some interesting developments are coming regarding our Sempare Boot framework with native support in Free Pascal (currently self funded).


What's the smallest Docker image you've ever created?

Comments 0 total

    Add comment