-
-
Notifications
You must be signed in to change notification settings - Fork 268
Optimize frontend docker image #1323
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimize frontend docker image #1323
Conversation
1. Automatic copying of traced files to standalone folder by enabling it in next.config.ts Ref: https://nextjs.org/docs/pages/api-reference/config/next-config-js/output#automatically-copying-traced-files - Next.js automatically creates a standalone folder that copies only the necessary files for a production deployment including select files in node_modules. - Reduces the size by 10x for this frontend - Reduces build time by 5x for this frontend 2. Added non-root users 3. Added multi-stage docker image with build and run stage as final image
Summary by CodeRabbit
WalkthroughThis pull request restructures the Docker build process and updates the Next.js configuration. The Dockerfile now defines separate build stages—renaming the initial stage from "builder" to "base", introducing a new "builder" stage, and adding a "runner" stage that runs the application under a non-root user with proper ownership and permission settings. It simplifies dependency installation and uses explicit file permission options. Additionally, the Next.js configuration is enhanced by adding an output option. Changes
Possibly related PRs
Suggested labels
Suggested reviewers
📜 Recent review detailsConfiguration used: .coderabbit.yaml 📒 Files selected for processing (1)
⏰ Context from checks skipped due to timeout of 90000ms (3)
🔇 Additional comments (23)
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
frontend/docker/Dockerfile (1)
1-1: Consider using a more stable Node.js LTS versionWhile Node.js 22 is the latest version, it's very new (released in April 2024) and may have undiscovered issues. For production environments, consider using a more stable LTS version like Node.js 20.
-FROM node:22-alpine AS base +FROM node:20-alpine AS base
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
frontend/docker/Dockerfile(1 hunks)frontend/next.config.ts(1 hunks)
🔇 Additional comments (11)
frontend/next.config.ts (1)
25-25: Great optimization with the standalone output mode!Adding
output: "standalone"enables Next.js to create a minimal production build with only necessary files. This optimization will significantly reduce the Docker image size (by 10x according to PR objectives) and build time (by 5x), which aligns perfectly with the optimization goals.frontend/docker/Dockerfile (10)
1-4: Good implementation of multi-stage Docker buildRenaming the initial stage to "base" and creating a separate "builder" stage improves clarity and follows Docker best practices for multi-stage builds. This separation allows for better isolation between build and runtime environments.
5-6: Excellent addition of libc6-compat for Alpine compatibilityAdding libc6-compat is necessary when using Alpine-based Node.js images to ensure compatibility with native modules. The comment also provides helpful context about why this is needed.
9-11: Simplified dependency installationThe simplified approach to dependency installation using just
pnpm install --ignore-scriptsis cleaner and more maintainable than before. The--ignore-scriptsflag is a good security practice to prevent potentially malicious scripts from running during installation.
13-13: Good use of explicit file permissionsUsing the
--chmod=444option ensures configuration files are copied with read-only permissions, which is good for security. This prevents accidental modification of these files at runtime.
17-20: Privacy-focused configuration with telemetry disabledDisabling Next.js telemetry is a good privacy practice, especially for production environments. The comments also provide clear context about what this setting does.
23-30: Well-structured runner stage with proper environment configurationThe runner stage is properly configured with production environment variables and telemetry settings. This separation of build and runtime environments is a best practice for Docker images.
31-32: Excellent security enhancement with non-root userCreating a dedicated non-root user for running the application is a critical security best practice. This limits the potential impact if the application is compromised.
36-40: Effective use of Next.js standalone outputThe approach of copying only the necessary files from the standalone output significantly reduces the final image size. The use of proper ownership with
--chown=nextjs:nodejsensures the application runs with the correct permissions.
41-41: Security best practice with user switchingExplicitly switching to the non-root user before running the application ensures that the container runs with minimal privileges.
47-50: Properly configured container startupSetting HOSTNAME to "0.0.0.0" ensures the application binds to all network interfaces, which is appropriate for containerized environments. Using
node server.jsdirectly is efficient for the standalone output.
1. Resolve no write permission to running user for the copied resource, to make container immutable and reproducible Ref: https://sonarcloud.io/project/security_hotspots?id=OWASP_Nest&pullRequest=1323&issueStatuses=OPEN%2CCONFIRMED&sinceLeakPeriod=true&tab=code
|
Please review the PR @Rajgupta36 and @arkid15r . |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
frontend/docker/Dockerfile (4)
3-3: Typographical Note:
The comment on line 3 has a minor typo—“depencies” should be “dependencies.”
4-6: Builder Stage Configuration:
The transition from the base image to a dedicated builder stage (FROM base AS builder) is well implemented. Additionally, installinglibc6-compat(line 6) is appropriately documented with a helpful reference link. Consider verifying that this package is strictly necessary to avoid any unnecessary bloat.
13-15: File Copying with Specific Permissions:
Copying configuration files (.env,next.config.ts, etc.) with--chmod=444and the directories (publicandsrc) with--chmod=555is a thoughtful security measure to enforce immutability in the production image. It’s worth double-checking that setting executable permissions on these directories aligns with your application's runtime needs.
39-41: Cache and Static Directory Setup:
The creation and permission assignment for the cache directory (/app/.next/cacheon line 40) is well-handled, ensuring thenextjsuser has the necessary write permissions. Similarly, copying static assets (line 41) with proper permissions fosters immutability. Note: There’s a minor typo in the comment on line 39—“cahce” should be “cache.”
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
frontend/docker/Dockerfile(1 hunks)
🔇 Additional comments (11)
frontend/docker/Dockerfile (11)
1-1: Base Image Selection:
Usingnode:22-alpineas the base image is a solid choice for a lightweight and modern Node.js environment. Ensure that this version is fully compatible with your application's requirements.
9-11: Dependency Installation Process:
Usingnpm install --ignore-scripts -g pnpm(line 9) followed by copying the package files with enforced read-only permissions (line 10) and installing dependencies withpnpm install --ignore-scripts(line 11) provides a clear and efficient dependency setup. Make sure that ignoring scripts does not omit any critical post-install steps your project might require.
17-20: Telemetry Configuration in Build Stage:
Disabling Next.js telemetry during the build viaENV NEXT_TELEMETRY_DISABLED=1(line 20) helps to reduce unnecessary logging and data collection. Ensure this decision is in line with your analytics and telemetry strategy.
23-25: Production Stage Initialization:
The initiation of the production (runner) stage withFROM base AS runner(line 24) and setting the working directory (line 25) is a clear and efficient strategy for separating build and runtime environments. This not only reduces the final image size but also enhances security by excluding build dependencies.
27-29: Runtime Environment Setup:
SettingENV NODE_ENV=production(line 27) coupled with disabling telemetry at runtime (line 29) ensures that the production environment is optimized for both performance and security. Consistency between build-time and runtime configurations is maintained well.
31-32: Non-root User Creation:
The commands to create a system group (nodejs) and user (nextjs) with fixed UID/GID (lines 31–32) are exemplary practices for running containers with non-root privileges. Just verify that the chosen UID/GID do not conflict with any mounted volumes or host configurations.
34-34: Public Directory Copying:
Copying thepublicdirectory with enforced ownership (--chown=root:root) and read-execute permissions (--chmod=555) ensures that these assets remain immutable during runtime. Confirm that these permissions are sufficient for file serving without needing write access.
36-38: Standalone Output Integration:
Leveraging the standalone output by copying/app/.next/standalone(line 38) significantly minimizes the final image size. This change relies on the Next.js configuration (output: "standalone"innext.config.ts), so ensure that it remains in sync with your build strategy.
43-43: Switch to Non-root User:
Changing the user context tonextjs(line 43) is a critical security improvement, ensuring the application does not run with root privileges.
47-48: Port Environment Configuration:
DefiningENV PORT=3000(line 47) clarifies which port the application expects to serve traffic on. Ensure that this setting is consistent with your container orchestration and any external port mappings.
49-52: Application Startup Configuration:
The comments (lines 49–50) provide clear documentation thatserver.jsis generated by Next.js from the standalone output. Setting the hostname (ENV HOSTNAME="0.0.0.0"on line 51) and specifying the startup command (CMD ["node", "server.js"]on line 52) correctly configure the container to listen on all interfaces and launch the application. Double-check thatserver.jsexists and is functioning as expected in the production environment.
arkid15r
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
Nicely done, let's try it in staging.
There was a problem hiding this 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
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
frontend/docker/Dockerfile(1 hunks)frontend/next.config.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- frontend/next.config.ts
🔇 Additional comments (10)
frontend/docker/Dockerfile (10)
1-2: Base Image Definition is Clear
The use of the officialnode:22-alpineimage as the base is appropriate. This lightweight image helps maintain a small overall size.
4-8: Builder Stage Setup with Compatibility Package
The builder stage is well established by extending from the base image. The installation oflibc6-compat(with a useful reference comment) ensures compatibility in Alpine environments. This attention to detail avoids potential runtime issues.
10-12: Efficient Dependency Management
Installingpnpmglobally with npm and then copying the package files with read-only permissions (--chmod=444) is a good practice. Runningpnpm install --ignore-scriptsimmediately after ensures that your dependencies are installed in a controlled manner without unintended script execution.
14-16: Securing Configuration and Source Files via Permissions
Copying configuration files (like.env,next.config.ts, etc.) with strict (read-only) permissions and copying thepublicandsrcdirectories with executable permissions demonstrates an intentional approach to file security and immutability. This minimizes the risk of unwanted modifications in the built image.
18-21: Proper Build-Time Telemetry and Execution
Setting theNEXT_TELEMETRY_DISABLED=1environment variable to disable telemetry (and documenting it) is good for privacy and predictability. The build commandpnpm run buildis correctly placed to generate the production assets.
24-29: Runner Stage Configuration Optimized for Production
Reusing the base image for the runner stage and explicitly setting production environment variables (i.e.NODE_ENV=productionand telemetry disabled) is excellent. It supports a more secure and performant container runtime.
33-33: Copying of Static and Standalone Files is Well-Configured
The commands to copy thepublicdirectory and the Next.js standalone output (/app/.next/standalone) with specific ownership (--chown=root:root) and permissions (--chmod=555) are well thought out. This guarantees that files have the correct, secure permissions while reducing the final image size by including only necessary artifacts.Also applies to: 35-37
39-41: Cache Directory Handling for Write Permissions
Creating the.next/cachedirectory, adjusting its ownership tonextjs:nodejs, and setting it to writable (755) is an important step to enable caching during runtime without compromising the rest of the filesystem's immutability.
43-45: Runtime Security and Port Exposure
Switching the user tonextjsbefore exposing the application port (3000) is a solid security practice. Explicitly setting theHOSTNAMEandPORTenvironment variables further clarifies network binding details.
50-52: Correct Final Command for Standalone Output
The comment clearly explains thatserver.jsis generated during the build. UsingCMD ["node", "server.js"]directly is appropriate for running the standalone Next.js server. Verify that the standalone output includesserver.jsas expected.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
|
* Optimize docker image 1. Automatic copying of traced files to standalone folder by enabling it in next.config.ts Ref: https://nextjs.org/docs/pages/api-reference/config/next-config-js/output#automatically-copying-traced-files - Next.js automatically creates a standalone folder that copies only the necessary files for a production deployment including select files in node_modules. - Reduces the size by 10x for this frontend - Reduces build time by 5x for this frontend 2. Added non-root users 3. Added multi-stage docker image with build and run stage as final image * Hardening the image 1. Resolve no write permission to running user for the copied resource, to make container immutable and reproducible Ref: https://sonarcloud.io/project/security_hotspots?id=OWASP_Nest&pullRequest=1323&issueStatuses=OPEN%2CCONFIRMED&sinceLeakPeriod=true&tab=code * Merge RUN instuctions for maintainability - Resolves issue : https://sonarcloud.io/project/issues?id=OWASP_Nest&pullRequest=1323&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true * Update code * Update frontend/docker/Dockerfile Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Arkadii Yakovets <[email protected]> Co-authored-by: Arkadii Yakovets <[email protected]> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>



Resolves large size of the docker image for Nextjs based
frontend.
Ref: https://nextjs.org/docs/pages/api-reference/config/next-config-js/output#automatically-copying-traced-files
Next.js automatically creates a standalone folder that copies only the necessary files for a production deployment including select files in node_modules.
Reduces the size by 10x

Reduces build time by 5x


Referenced the repo for constructing optimized nextjs app docker image :