」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > NextJS 應用程式的 Docker 和 Docker-Compose 最佳實務。

NextJS 應用程式的 Docker 和 Docker-Compose 最佳實務。

發佈於2024-11-07
瀏覽:289

Best Practices of Docker & Docker-Compose for NextJS application.

Best Practices of Docker & Docker-Compose for NextJS application.

To create an optimized Dockerfile for a Next.js 14 application that supports both development and production environments, you can follow a multi-stage build approach. This method ensures that the development environment has hot-reloading and source maps, while the production environment builds the app for production with optimizations like smaller image sizes and improved runtime performance.

Here's a Dockerfile for both development and production environments:


# Stage 1: Base build environment
FROM node:18-alpine AS base
WORKDIR /app
COPY package.json package-lock.json ./

# Install dependencies
RUN npm ci --legacy-peer-deps
COPY . .
# Install necessary dependencies for sharp (for image optimization)
RUN apk add --no-cache libc6-compat
# Stage 2: Development environment
FROM base AS development
ARG ENVIRONMENT=development
ENV NODE_ENV=$ENVIRONMENT
EXPOSE 3000
CMD ["npm", "run", "dev"]

# Stage 3: Production build
FROM base AS build
ARG ENVIRONMENT=production
ENV NODE_ENV=$ENVIRONMENT
RUN npm run build

# Stage 4: Production runtime environment
FROM node:18-alpine AS production
WORKDIR /app
COPY --from=build /app/.next ./.next
COPY --from=build /app/package.json ./package.json
COPY --from=build /app/package-lock.json ./package-lock.json
COPY --from=build /app/public ./public
COPY --from=build /app/node_modules ./node_modules
EXPOSE 3000
CMD ["npm", "run", "start"]



Key Points in the Dockerfile:

Base Image (node:18-alpine): This is a lightweight version of Node.js based on Alpine Linux. It is both fast and optimized for smaller container sizes.

Multi-stage Build:

  • Base Stage: This sets up the basic environment, installs dependencies, and prepares the application. It’s used as the foundation for both the development and production stages.
  • Development Stage: Installs all necessary development dependencies.Runs the Next.js development server (npm run dev) with hot-reloading.
  • Build Stage: Runs the Next.js production build (npm run build), preparing the .next folder for production.
  • Production Runtime Stage: Only copies the built .next folder, public assets, and production dependencies (node_modules). Starts the app using npm run start, which serves the production-optimized app.

Optimizations:

  • Alpine Image: Using node:18-alpine ensures a minimal image size.
  • Dependency Caching: Dependencies are cached properly by separating the package.json and package-lock.json copying step before copying the app's source files.
  • Image Layers: Using multi-stage builds minimizes the size of the final production image by keeping the build-related dependencies and files out of the final runtime image.
  • apk add for sharp: Installs necessary dependencies for sharp, a popular library for image optimization that Next.js uses internally.

How to Use the Dockerfile

To build for development, run:


docker build --target development --build-arg ENVIRONMENT=development -t next-app-dev .



To build for production, run:


docker build --target production --build-arg ENVIRONMENT=production -t next-app-prod .


Breakdown of the Command:

  • --target development: This flag tells Docker to build the specific target stage named development in the Dockerfile.

In the multi-stage Dockerfile, each stage has a name (for example, development, build, production). Docker will stop the build process once it reaches the development stage and output an image for that stage.

By specifying --target development, Docker will use this stage as the final image.

  • --build-arg ENVIRONMENT=development: This is a build argument that you are passing to the Docker build process. In your Dockerfile, you've set an argument for the ENVIRONMENT and are using it to set NODE_ENV.
    In the Dockerfile, this is where you use it:
    So, by passing ENVIRONMENT=development, it sets NODE_ENV=development for the development stage.

  • -t next-app-dev: This flag is used to give the resulting Docker image a tag (name). Here, you're tagging the built image as next-app-dev. This makes it easier to refer to the image later when you want to run or push it.

  • . (dot): The dot refers to the current directory as the build context. Docker will look for the Dockerfile in the current directory and include any files and directories in the build process based on the instructions in the Dockerfile.

Once the Docker image has been built and your container is running, you can access your Next.js application in the following steps:

  • Run the Container To start a container from your built Docker image, use the docker run command. For example, assuming your image is tagged next-app-prod and your app is listening on port 3000, you can run the following command:

docker run -p 3000:3000 next-app-prod


Explanation:

  • -p 3000:3000: This flag maps the container's internal port (3000) to your local machine's port (3000). The first 3000 is the port on your machine, and the second 3000 is the port inside the container where the Next.js app is running.
  • next-app-prod: This is the name of the Docker image you built. You are telling Docker to start a container based on this image.

  • Access the App

Once the container is running, you can access your Next.js app by opening your web browser and navigating to:


http://localhost:3000


This is because the -p 3000:3000 flag exposes the app running inside the Docker container on port 3000 of your local machine.

Benefits of a Single Multi-Stage Dockerfile

  • Code Reuse: You avoid duplicating configurations across multiple files by defining different stages (development, build, and production) in a single Dockerfile. You can share common layers between stages, such as base images, dependencies, and configurations.

  • Consistency: Having everything in one file ensures that your environments are consistent. The same base setup (like Node.js version, dependencies, and build tools) is used for both development and production.

  • Image Size Optimization: Multi-stage builds allow you to define a build process in one stage and then use only the necessary output in the production stage, resulting in smaller and more optimized production images.

  • Maintainability: Maintaining one Dockerfile is easier than managing separate files. You can easily update the common parts (like dependencies or configurations) without worrying about syncing changes across multiple files.

  • Simplicity: By using a multi-stage Dockerfile, you simplify your project structure by not needing extra files for different environments.

Use Case for Separate Dockerfiles

In some cases, however, you might want to define separate Dockerfiles for development and production. Here are a few reasons why you might choose this approach:

  • Specialized Development Setup: If the development environment needs significantly different tooling or services (e.g., testing frameworks, live reload tools), and you don't want to clutter the production Dockerfile with them.

  • Faster Iteration in Development: If the development Dockerfile needs to be streamlined for faster iteration (e.g., skipping certain optimizations or using different tooling).

  • Complex Setup: In some complex cases, the production setup might be very different from the development one, and combining them in a single file can be cumbersome.

Example:

When to Use Separate Dockerfiles
If you have very different setups, you might do something like this:

Dockerfile.dev for development

Dockerfile.prod for production

You would then specify which file to use when building the image:


# Build for development
docker build -f Dockerfile.dev -t next-app-dev .



# Build for production
docker build -f Dockerfile.prod -t next-app-prod .


Recommendation

For most cases, especially in typical Next.js apps, the single multi-stage Dockerfile is the best practice. It promotes:

  • Reusability of layers
  • Consistency
  • A smaller image size for production
  • Easier maintenance

However, if your development and production environments are drastically different, separate Dockerfiles might be a better choice, though this is less common.

Docker-Compose

Here is a Docker Compose file to run a Next.js 14 application along with MongoDB. This setup follows best practices, including using environment variables from a .env file and setting up multi-service configuration.

Steps:

  • Create a .env file to store your environment variables.
  • Create a docker-compose.yml file for defining your services. .env File: Make sure this file is in the root of your project. This will contain your environment variables for both Next.js and MongoDB.

# .env
# Next.js Environment Variables
NEXT_PUBLIC_API_URL=https://your-api-url.com
MONGO_URI=mongodb://mongo:27017/yourDatabaseName
DB_USERNAME=yourUsername
DB_PASSWORD=yourPassword
DB_NAME=yourDatabaseName
NODE_ENV=production

# MongoDB Variables
MONGO_INITDB_ROOT_USERNAME=admin
MONGO_INITDB_ROOT_PASSWORD=adminpassword
MONGO_INITDB_DATABASE=yourDatabaseName



docker-compose.yml File:

This file defines both your Next.js app and the MongoDB service. The Next.js service depends on MongoDB, and they are both configured to communicate within the same Docker network.


version: "3.8"

services:
  mongo:
    image: mongo:6.0
    container_name: mongodb
    restart: unless-stopped
    ports:
      - "27017:27017" # Exposing MongoDB port
    environment:
      MONGO_INITDB_ROOT_USERNAME: ${DB_USERNAME}
      MONGO_INITDB_ROOT_PASSWORD: ${DB_PASSWORD}
      MONGO_INITDB_DATABASE: ${DB_NAME}
    networks:
      - app-network
    volumes:
      - mongo-data:/data/db # Persist MongoDB data in a Docker volume

  nextjs-app:
    image: digipros-prod
    container_name: digipros-app
    build:
      context: .
      dockerfile: Dockerfile
    restart: unless-stopped
    ports:
      - "4000:3000" # Exposing Next.js app on port 5000
    depends_on:
      - mongo # Ensures MongoDB starts before Next.js
    env_file:
      - .env
    environment:
      MONGO_URI: ${MONGO_URI}
      DB_USERNAME: ${DB_USERNAME}
      DB_PASSWORD: ${DB_PASSWORD}
      DB_NAME: ${DB_NAME}
    volumes:
      - ./public/uploads:/app/public/uploads # Only persist the uploads folder
    command: "npm run start" # Running the Next.js app in production mode
    networks:
      - app-network
volumes:
  mongo-data: # Named volume to persist MongoDB data
networks:
  app-network:
    driver: bridge


Explanation of docker-compose.yml:

  • version: '3.8': The Compose file version, supporting more features.

  • services:

mongo:

image: mongo:6.0:
Specifies the MongoDB image and version.

container_name: mongodb: Names the MongoDB container.

restart: unless-stopped: Restarts the container unless you explicitly stop it.

ports: "27017:27017": Exposes MongoDB on port 27017 so it can be accessed locally.

environment: Reads environment variables from the .env file.

volumes: Mounts a Docker volume for persistent data storage, even if the container is removed.

nextjs-app: image: next-app-prod: The name of the image to be used (assumes the image is built already).

build: Specifies the build context and the Dockerfile to use for building the Next.js app.

depends_on: mongo: Ensures that MongoDB is started before the Next.js app.

env_file: .env: Loads environment variables from the .env file.

volumes: - ./public/uploads:/app/public/uploads # Only persist the uploads folder

command: "npm run start": Runs the Next.js app in production mode.

  • volumes:

mongo-data: Named volume to persist MongoDB data.

How to Run:

Build the Docker Image for your Next.js application:


docker build -t next-app-prod .


Start the Docker Compose services:


docker-compose up -d


Access the Next.js application at http://localhost:3000.

MongoDB will be available locally on port 27017, or within the Docker network as mongo (for your Next.js app).

Best Practices Followed:

  • Environment variables are managed via a .env file.
  • MongoDB data persistence using Docker volumes.
  • Multi-stage Dockerfile (assumed) for optimized builds.
  • depends_on ensures services are started in the correct order.
  • Restart policy to ensure services remain running.

This setup allows for easy management of the Next.js and MongoDB containers while keeping everything modular and maintainable.

Authors

  • @medAmine

Support

For support, email [email protected]

License

MIT

版本聲明 本文轉載於:https://dev.to/mohamed_amine_78123694764/best-practices-of-docker-docker-compose-for-nextjs-application-2kdm?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 了解網路儲存
    了解網路儲存
    目录 曲奇饼 本地存储 会话存储 索引数据库 对比分析 安全考虑 结论 介绍 数据存储是现代 Web 应用程序的一个重要方面。无论是保存用户首选项、缓存数据以供离线使用还是跟踪会话,在浏览器中管理数据的方式都会显着影响用户体验。我们有多种在浏览器中存储数据的选项,每...
    程式設計 發佈於2024-11-07
  • 指標如何影響 Go 函數中的值修改?
    指標如何影響 Go 函數中的值修改?
    瞭解 Go 中指標的值修改在 Go 中,指標允許間接存取和修改值。然而,在將指標傳遞給函數時,了解指標的工作原理至關重要。 將指標傳遞給函數時,會出現兩種情況:值修改與指標重新指派。 場景 1 : 值修改考慮這段程式碼:type Test struct { Value int } func main...
    程式設計 發佈於2024-11-07
  • 將 django 部署到生產環境
    將 django 部署到生產環境
    我最近将我自己的 django 应用程序部署到生产环境中。该网站名为 videoeiro.com,是用 django HTML/CSS/JS Tailwind 开发的。 设置 我正在使用 debian 12 服务器,它将通过 cloudflare 隧道公开我的应用程序。所有静态文件都...
    程式設計 發佈於2024-11-07
  • 實作雪花 ID 產生器
    實作雪花 ID 產生器
    什麼是雪花 ID? 雪花 ID 在分散式環境中用於產生無衝突、簡短、唯一的 ID。與依賴資料庫產生 ID 或使用長 128 位元 UUID 等傳統方法不同,Snowflake ID 使用時間和簡單的位元運算。這種巧妙的技術允許每個微服務獨立產生唯一的 ID,而不需要中央系統來避免衝...
    程式設計 發佈於2024-11-07
  • 如何在沒有 JS 框架的情況下使用 CSS 設計 SVG 圖像樣式?
    如何在沒有 JS 框架的情況下使用 CSS 設計 SVG 圖像樣式?
    使用CSS 設定SVG 影像樣式:一種新穎的方法在本文中,我們將探索一種使用CSS 嵌入SVG 影像並操縱其外觀的新穎方法,而無需使用CSS使用JS-SVG 框架。 問題陳述以前,整合 SVG 圖片同時透過 CSS 保持對其元素的存取一直是一個挑戰。雖然 JS-SVG 框架提供了解決方案,但對於具有...
    程式設計 發佈於2024-11-07
  • ## 你能確定使用者是否可以在 JavaScript 中按一下後退按鈕嗎?
    ## 你能確定使用者是否可以在 JavaScript 中按一下後退按鈕嗎?
    瀏覽器歷史記錄導航:確定後退按鈕可用性開發Web 應用程式時,確定使用者是否可以在他們的瀏覽器歷史記錄。然而,出於安全考慮,JavaScript 缺乏直接手段來確定瀏覽器歷史記錄是否存在。 嘗試的解決方案及其限制:1。 History.previous:雖然該屬性理論上提供了有關歷史記錄中上一頁的信...
    程式設計 發佈於2024-11-07
  • 如何在保持模糊背景的同時去除子元素的背景模糊?
    如何在保持模糊背景的同時去除子元素的背景模糊?
    從子元素中刪除背景模糊您有一個 ,其背景圖像應用了模糊效果。但是,所有子元素也會受到這種模糊的影響,這是不想要的。本文提供了解決此問題的解決方案,讓您在保持背景影像的模糊效果的同時保留子元素的清晰度。 解決方案:建立疊加元素要實現此目的,您可以在父元素中建立一個單獨的 並將背景圖像和模糊效果應用到這...
    程式設計 發佈於2024-11-07
  • Leetcode:字串的最大公約數
    Leetcode:字串的最大公約數
    問題陳述 1071. 字串的最大公約數 對於兩個字串 s 和 t,當且僅當 s = t t t ... t t (即 t 與自身連接一次或多次)時,我們才說「t 除 s」。 給定兩個字串 str1 和 str2,傳回使 x 整除 str1 和 str2 的最大字串 x。 ...
    程式設計 發佈於2024-11-07
  • Vue 黑暗面備忘錄 |部分反應性
    Vue 黑暗面備忘錄 |部分反應性
    Hi there DEV.to community! This article will include multiple aspects of Vue 3 that are mostly used or are kind of on the dark side and not paid atten...
    程式設計 發佈於2024-11-07
  • 如何在 Pygame 中同時執行多個 While 迴圈?
    如何在 Pygame 中同時執行多個 While 迴圈?
    如何在Pygame中同時實現多個While循環在Pygame中,可以同時執行多個While循環,允許獨立和程序中的連續操作。 克服執行阻塞在提供的程式碼片段中,問題是由於存在兩個試圖同時運行的 while 循環而引起的。第二個迴圈包含 time.sleep() 函數來引入延遲,它會幹擾第一個迴圈的執...
    程式設計 發佈於2024-11-07
  • Go 中如何根據元素的第一次出現來拆分字串?
    Go 中如何根據元素的第一次出現來拆分字串?
    僅根據Go 中元素的第一次出現來拆分字串使用git 分支名稱時,可能需要拆分它們以區分遠端和遠端分支名稱。分支名稱本身。雖然最初採用了按第一個斜杠分割,但由於分支名稱中可能存在多個斜杠,事實證明它是不夠的。 為了解決這個問題,提出了一種更簡潔的方法,可以避免手動元素移動和重新合併。利用strings...
    程式設計 發佈於2024-11-07
  • 如何在Python中檢查清單是按升序還是降序排序?
    如何在Python中檢查清單是按升序還是降序排序?
    驗證列表順序的 Pythonic 方法處理按升序 (ASC) 或降序 (DESC) 順序的值列表時,通常需要驗證元素的正確排序。 Python 以其用戶友好的語法而聞名,提供了一種優雅的方式來執行此檢查。 要確定清單是依ASC 或DESC 排序,請考慮下列Pythonic 解:all(l[i] &l...
    程式設計 發佈於2024-11-07
  • Django 適合所有人。
    Django 適合所有人。
    即使對於“小型”網站,Django 也很棒 我認為人們傾向於認為 Django 要么用於構建老式的、工業強度的整體應用程序,要么用於 API 並使用 React 之類的東西作為前端。我在這裡告訴您,即使對於您的個人網站,普通的 Django 也是一個不錯的選擇!在我看來,如果你需要...
    程式設計 發佈於2024-11-07
  • Go 程式設計教學:掌握時間、函數與並發
    Go 程式設計教學:掌握時間、函數與並發
    您是想要擴展技能的 Go 程式設計師嗎?別再猶豫了!這本包含 7 個 LabEx 教程的集合涵蓋了廣泛的基本 Go 程式設計概念,從處理時間和持續時間到探索並發和介面的強大功能。 ? 在第一個教程中,您將深入了解 Go 的時間和持續時間支持,學習如何有效地使用程式的這些基本構建塊。接下來,您將探索...
    程式設計 發佈於2024-11-07
  • 如何在單一 Google 試算表腳本中組合多個 onEdit 函數?
    如何在單一 Google 試算表腳本中組合多個 onEdit 函數?
    合併多個onEdit函數建立Google表格腳本時,您可能會遇到需要多個onEdit函數來處理不同編輯事件的情況。但是,單一腳本不能有兩個同名的函數。要解決此衝突,請考慮以下方法:合併兩個 onEdit 函數function onEdit(e) { onEdit1(e); onEdit2(e...
    程式設計 發佈於2024-11-07

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3