Skip to content

Reduce Docker image size using multi-stage builds#1161

Open
mrz948 wants to merge 2 commits intoAudionut:masterfrom
mrz948:master
Open

Reduce Docker image size using multi-stage builds#1161
mrz948 wants to merge 2 commits intoAudionut:masterfrom
mrz948:master

Conversation

@mrz948
Copy link

@mrz948 mrz948 commented Jan 24, 2026

This PR introduces multi-stage Docker builds to reduce the final image size by excluding build-time dependencies from the runtime image.

Results

  • Before: 2.86 GB
  • After: 1.63 GB (-1.23 GB)

EDIT: New results:

  • slim: 1.27 GB
  • alpine: 0.85 GB

Changes

  • Added dedicated build stages for compiling/installing dependencies
  • Final stage contains only runtime requirements
  • Added an alternative alpine image that is even smaller (1.2GB0.85 GB)

I tested each final image by processing a full disc and movie.

Summary by CodeRabbit

  • Chores
    • Added Alpine Linux-based Docker image for the application with multi-stage build optimization, resulting in a smaller and more efficient container image.

@coderabbitai
Copy link

coderabbitai bot commented Jan 24, 2026

📝 Walkthrough

Walkthrough

Introduces a new multi-stage Dockerfile.alpine for a Python application. The build uses separate stages for virtual environment preparation and application assembly, installs system dependencies, Python requirements, and additional binaries (mkbrr and DVD MediaInfo). The final image is optimized with proper file permissions, writable temporary directory configuration, and application entrypoint.

Changes

Cohort / File(s) Summary
Alpine Dockerfile Introduction
Dockerfile.alpine
New multi-stage Dockerfile establishing Python 3.12-alpine base, builder stages for venv and application, dependency installation, binary downloads (mkbrr, MediaInfo), and final image configuration with executable permissions and entrypoint setup.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A nimble Alpine build appears,
With stages lean through the frontier,
Virtual venv and app so tight,
Multi-stage magic, Docker's delight!
Binaries bundled, permissions set right,
Our Python home takes flight! 🚀

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Reduce Docker image size using multi-stage builds' directly and clearly describes the main change: introducing multi-stage Docker builds to reduce image size, which aligns with the raw_summary and PR objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Audionut
Copy link
Owner

Thanks for the PR. I don't use docker, and everytime I push a PR for docker, it seems to cause issues for users, somewhere, somehow.

I'll focus on this after I get an overdue release pushed. Thanks.

@mrz948
Copy link
Author

mrz948 commented Feb 2, 2026

Nice, no pressure, if there are any issues that come up afterwards feel free to tag me in them, so I can help.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Dockerfile (1)

65-92: ⚠️ Potential issue | 🟠 Major

Run the container as a non‑root user.

The final image defaults to root; this is a common security risk and flagged by Trivy. Create a dedicated user and switch to it after setting ownership.

✅ Suggested fix
 # Create tmp directory with appropriate permissions
 RUN mkdir -p /Upload-Assistant/tmp && chmod 777 /Upload-Assistant/tmp
 ENV TMPDIR=/Upload-Assistant/tmp

+# Create non-root user and switch
+RUN useradd -u 1000 -m app && \
+    chown -R app:app /Upload-Assistant /venv
+USER app
+
 # Set the entry point for the container
 ENTRYPOINT ["python", "/Upload-Assistant/upload.py"]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile` around lines 65 - 92, The image currently runs as root; update
the Dockerfile to create a dedicated non-root user (e.g., add a user/group like
appuser with a fixed UID/GID), chown the application directories to that UID/GID
(you already call chown on /Upload-Assistant/bin/mkbrr and
/Upload-Assistant/bin/MI — extend ownership to /Upload-Assistant and
/Upload-Assistant/tmp), and add a USER instruction before the ENTRYPOINT so the
container runs as that non-root user; ensure the TMPDIR and PATH usage (ENV
PATH="/venv/bin:$PATH" and ENV TMPDIR) remain valid for the new user and that
any files the app needs are writable by the new user.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Dockerfile.alpine`:
- Around line 67-95: The image currently runs as root; create a non-root user
and drop privileges before the final ENTRYPOINT: add a dedicated user/group
(e.g., uid 1000 and a name like uploadassistant) after copying files, chown the
application directories to that user (update references to /Upload-Assistant for
bin/mkbrr, bin/MI and tmp ownership), then use USER <username> (or USER 1000)
before the ENTRYPOINT so the container runs unprivileged; ensure TMPDIR and PATH
remain accessible to that user and that any files the app changes at runtime are
owned or world-writable as needed.

---

Outside diff comments:
In `@Dockerfile`:
- Around line 65-92: The image currently runs as root; update the Dockerfile to
create a dedicated non-root user (e.g., add a user/group like appuser with a
fixed UID/GID), chown the application directories to that UID/GID (you already
call chown on /Upload-Assistant/bin/mkbrr and /Upload-Assistant/bin/MI — extend
ownership to /Upload-Assistant and /Upload-Assistant/tmp), and add a USER
instruction before the ENTRYPOINT so the container runs as that non-root user;
ensure the TMPDIR and PATH usage (ENV PATH="/venv/bin:$PATH" and ENV TMPDIR)
remain valid for the new user and that any files the app needs are writable by
the new user.

Comment on lines +67 to +95
# START BUILDING SLIM IMAGE
FROM base

# Copy venv
COPY --from=builder-venv /venv /venv
ENV PATH="/venv/bin:$PATH"

# Copy application
COPY --from=builder-app /Upload-Assistant /Upload-Assistant

# Set workdir
WORKDIR /Upload-Assistant

# Ensure mkbrr is executable
RUN find bin/mkbrr -name "mkbrr" -exec chmod +x {} \; && \
find bin/bdinfo -name "bdinfo" -exec chmod +x {} \;

# Enable non-root access while still letting Upload-Assistant tighten mkbrr permissions at runtime
RUN chown -R 1000:1000 /Upload-Assistant/bin/mkbrr

# Enable non-root access for DVD MediaInfo binary
RUN chown -R 1000:1000 /Upload-Assistant/bin/MI

# Create tmp directory with appropriate permissions
RUN mkdir -p /Upload-Assistant/tmp && chmod 777 /Upload-Assistant/tmp
ENV TMPDIR=/Upload-Assistant/tmp

# Set the entry point for the container
ENTRYPOINT ["python", "/Upload-Assistant/upload.py"]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Run the container as a non‑root user.

The final image defaults to root; this is a common security risk and flagged by Trivy. Create a dedicated user and switch to it after setting ownership.

✅ Suggested fix
 # Create tmp directory with appropriate permissions
 RUN mkdir -p /Upload-Assistant/tmp && chmod 777 /Upload-Assistant/tmp
 ENV TMPDIR=/Upload-Assistant/tmp

+# Create non-root user and switch
+RUN addgroup -S app && adduser -S -G app -u 1000 app && \
+    chown -R app:app /Upload-Assistant /venv
+USER app
+
 # Set the entry point for the container
 ENTRYPOINT ["python", "/Upload-Assistant/upload.py"]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile.alpine` around lines 67 - 95, The image currently runs as root;
create a non-root user and drop privileges before the final ENTRYPOINT: add a
dedicated user/group (e.g., uid 1000 and a name like uploadassistant) after
copying files, chown the application directories to that user (update references
to /Upload-Assistant for bin/mkbrr, bin/MI and tmp ownership), then use USER
<username> (or USER 1000) before the ENTRYPOINT so the container runs
unprivileged; ensure TMPDIR and PATH remain accessible to that user and that any
files the app changes at runtime are owned or world-writable as needed.

@mrz948
Copy link
Author

mrz948 commented Mar 3, 2026

I closed this by accident, but since this is not a critical bugfix, I'll leave it as is.

mrz948 added 2 commits March 3, 2026 16:48
smaller image from docker-image-optimization branch, no web ui, docker-entrypoint script etc.
integrate most of upstream's changes
@mrz948
Copy link
Author

mrz948 commented Mar 3, 2026

On second thought maybe this is useful for someone.

Current alpine image size: 770MB

@mrz948 mrz948 reopened this Mar 3, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
Dockerfile.alpine (1)

80-100: ⚠️ Potential issue | 🟠 Major

Final image still runs as root (missing USER).

There is no privilege drop in the final stage, so the process runs as root. This issue was already raised earlier and still applies.

✅ Suggested hardening patch
 FROM base
 
 # Copy venv
 COPY --from=builder-venv /venv /venv
 ENV PATH="/venv/bin:$PATH"
 
 # Copy application
 COPY --from=builder-app /Upload-Assistant /Upload-Assistant
 
 WORKDIR /Upload-Assistant
+
+# Drop privileges in runtime image
+RUN addgroup -S uploadassistant && adduser -S -G uploadassistant -u 1000 uploadassistant && \
+    chown -R uploadassistant:uploadassistant /Upload-Assistant /venv
+USER uploadassistant
 
 EXPOSE 5000
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Dockerfile.alpine` around lines 80 - 100, The final image's container process
still runs as root because the final stage (FROM base) lacks a USER directive;
modify the final stage to switch to a non-root user (e.g., create or reuse a
low‑privilege user) and add a USER instruction before ENTRYPOINT, ensuring
ownership and permissions are correct for /venv and /Upload-Assistant (use
chown/chmod during the build or copy steps) so python
/Upload-Assistant/upload.py runs unprivileged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@Dockerfile.alpine`:
- Around line 80-100: The final image's container process still runs as root
because the final stage (FROM base) lacks a USER directive; modify the final
stage to switch to a non-root user (e.g., create or reuse a low‑privilege user)
and add a USER instruction before ENTRYPOINT, ensuring ownership and permissions
are correct for /venv and /Upload-Assistant (use chown/chmod during the build or
copy steps) so python /Upload-Assistant/upload.py runs unprivileged.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 215da3e and 04a243a.

📒 Files selected for processing (1)
  • Dockerfile.alpine

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants