DEV Community

Uchechukwu Enyi
Uchechukwu Enyi

Posted on

UC Pocket Ubuntu OS: From 303MB to 80MB with Docker Optimization

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"]
Enter fullscreen mode Exit fullscreen mode

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"]
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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


Top comments (0)