Introduction
As developers and DevOps engineers, we constantly seek ways to optimize our environments—reducing image sizes, improving security, and maintaining performance. In this article, I'll walk you through how I transformed a standard 303MB Ubuntu Docker image into a lean 80MB distroless-based container while retaining full functionality (SSH, Apache, and persistent storage).
We'll cover:
✅ Multi-stage builds to eliminate unnecessary dependencies
✅ Distroless optimization for security and size reduction
✅ Persistent storage to retain data across container restarts
✅ DevSecOps benefits (smaller attack surface, faster CI/CD)
✅ How non-Linux users can replace VMs with this pocket Ubuntu
The Problem: Bloated Ubuntu Images
Initially, my Dockerfile used a standard Ubuntu base with SSH and Apache:
Original Dockerfile (303MB)
FROM ubuntu:latest
# Set environment variables
ENV TZ=Africa/Lagos
ENV LANG=en_US.UTF-8
# Install packages
RUN apt-get update && \
apt-get install -y \
tzdata \
locales \
openssh-server \
apache2 \
&& rm -rf /var/lib/apt/lists/*
# Configure timezone & locale
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
echo $TZ > /etc/timezone && \
locale-gen en_US.UTF-8
# Set up SSH
RUN mkdir /var/run/sshd && \
echo 'root:password' | chpasswd && \
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
# Expose ports
EXPOSE 22 80
# Persistent data volume
RUN mkdir /data
# Keep container running
RUN echo '#!/bin/bash\n\
service ssh start\n\
service apache2 start\n\
tail -f /dev/null' > /entrypoint.sh && \
chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
Issues with this approach:
❌ 303MB is too large for a minimal Ubuntu environment
❌ Unnecessary packages increase security risks
❌ No multi-stage optimization
The Solution: Distroless + Multi-Stage Builds
By using multi-stage builds and distroless base images, we reduce bloat while keeping essential functionality.
Optimized Dockerfile (80MB)
# Stage 1: Builder (Full Ubuntu)
FROM ubuntu:22.04 AS builder
# Install only essentials
RUN apt-get update && \
apt-get install -y --no-install-recommends \
openssh-server \
apache2 \
&& rm -rf /var/lib/apt/lists/*
# Configure SSH
RUN mkdir /var/run/sshd && \
echo 'root:password' | chpasswd && \
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
# Stage 2: Distroless Runtime
FROM gcr.io/distroless/base-debian11
# Copy only necessary binaries
COPY --from=builder /usr/sbin/sshd /usr/sbin/
COPY --from=builder /usr/sbin/apache2 /usr/sbin/
COPY --from=builder /bin/bash /bin/
# Copy essential libraries
COPY --from=builder /lib/x86_64-linux-gnu/ /lib/x86_64-linux-gnu/
COPY --from=builder /lib64/ld-linux-x86-64.so.2 /lib64/
# Set up persistent storage
RUN mkdir /data && chmod 777 /data
VOLUME /data
# Entrypoint script
RUN echo '#!/bin/bash\n\
/usr/sbin/sshd -D &\n\
/usr/sbin/apache2 -DFOREGROUND &\n\
tail -f /dev/null' > /entrypoint.sh && \
chmod +x /entrypoint.sh
EXPOSE 22 80
ENTRYPOINT ["/entrypoint.sh"]
Key Optimizations
✔ Multi-stage build separates build and runtime dependencies
✔ Distroless base removes unnecessary packages (no shell, no bloat)
✔ Only essential binaries copied (SSH, Apache, Bash)
✔ Persistent /data
volume for file storage
How to Use UC Pocket Ubuntu
1. First, Run the Container in Detached Mode
docker run -d \
-p 2222:22 -p 8080:80 \
-v ~/ubuntu-data:/data \
--name my-ubuntu \
ucheenyi/uc-pocket-ubuntu
2. Then, Execute Commands Inside the Running Container
# Get an interactive bash shell
docker exec -it my-ubuntu bash
# Or run single commands
docker exec my-ubuntu ls /data
docker exec my-ubuntu apt-get update
3. Access Services
-
SSH:
ssh root@localhost -p 2222
(password:password
) -
Apache: Open
http://localhost:8080
4. Stop and Remove When Done
docker stop my-ubuntu
docker rm my-ubuntu
# Your data persists in ~/ubuntu-data on host
Why This Matters for DevSecOps & DevOps
🔹 Smaller Attack Surface (No unnecessary packages = fewer CVEs)
🔹 Faster CI/CD Pipelines (Smaller images = quicker deployments)
🔹 Cost-Efficient (Replaces heavy VMs with lightweight containers)
🔹 Cross-Platform (Windows/Mac users get full Ubuntu CLI without VMs)
Final Thoughts
By applying multi-stage builds and distroless optimization, we reduced the image size by 73% while keeping all functionality.
My Dockerhub link for the image:
https://hub.docker.com/r/ucheenyi/uc-pocket-ubuntu
This approach is perfect for:
✅ Developers needing a lightweight Ubuntu environment
✅ DevOps teams optimizing CI/CD pipelines
✅ Security teams minimizing attack surfaces