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

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

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

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]刪除
最新教學 更多>
  • 圖片在Chrome中為何仍有邊框? `border: none;`無效解決方案
    圖片在Chrome中為何仍有邊框? `border: none;`無效解決方案
    在chrome 中刪除一個頻繁的問題時,在與Chrome and IE9中的圖像一起工作時,遇到了一個頻繁的問題。和“邊境:無;”在CSS中。要解決此問題,請考慮以下方法: Chrome具有忽略“ border:none; none;”的已知錯誤,風格。要解決此問題,請使用以下CSS ID塊創建帶...
    程式設計 發佈於2025-05-21
  • PHP陣列鍵值異常:了解07和08的好奇情況
    PHP陣列鍵值異常:了解07和08的好奇情況
    PHP數組鍵值問題,使用07&08 在給定數月的數組中,鍵值07和08呈現令人困惑的行為時,就會出現一個不尋常的問題。運行print_r($月份)返回意外結果:鍵“ 07”丟失,而鍵“ 08”分配給了9月的值。 此問題源於PHP對領先零的解釋。當一個數字帶有0(例如07或08)的前綴時,PHP...
    程式設計 發佈於2025-05-21
  • 解決MySQL插入Emoji時出現的\\"字符串值錯誤\\"異常
    解決MySQL插入Emoji時出現的\\"字符串值錯誤\\"異常
    Resolving Incorrect String Value Exception When Inserting EmojiWhen attempting to insert a string containing emoji characters into a MySQL database us...
    程式設計 發佈於2025-05-21
  • 如何為PostgreSQL中的每個唯一標識符有效地檢索最後一行?
    如何為PostgreSQL中的每個唯一標識符有效地檢索最後一行?
    postgresql:為每個唯一標識符在postgresql中提取最後一行,您可能需要遇到與數據集合中每個不同標識的信息相關的信息。考慮以下數據:[ 1 2014-02-01 kjkj 在數據集中的每個唯一ID中檢索最後一行的信息,您可以在操作員上使用Postgres的有效效率: id dat...
    程式設計 發佈於2025-05-21
  • 使用jQuery如何有效修改":after"偽元素的CSS屬性?
    使用jQuery如何有效修改":after"偽元素的CSS屬性?
    在jquery中了解偽元素的限制:訪問“ selector 嘗試修改“:”選擇器的CSS屬性時,您可能會遇到困難。 This is because pseudo-elements are not part of the DOM (Document Object Model) and are th...
    程式設計 發佈於2025-05-21
  • 為什麼使用Firefox後退按鈕時JavaScript執行停止?
    為什麼使用Firefox後退按鈕時JavaScript執行停止?
    導航歷史記錄問題:JavaScript使用Firefox Back Back 此行為是由瀏覽器緩存JavaScript資源引起的。要解決此問題並確保在後續頁面訪問中執行腳本,Firefox用戶應設置一個空功能。 警報'); }; alert('inline Alert')...
    程式設計 發佈於2025-05-21
  • 如何避免Go語言切片時的內存洩漏?
    如何避免Go語言切片時的內存洩漏?
    ,a [j:] ...雖然通常有效,但如果使用指針,可能會導致內存洩漏。這是因為原始的備份陣列保持完整,這意味著新切片外部指針引用的任何對象仍然可能佔據內存。 copy(a [i:] 對於k,n:= len(a)-j i,len(a); k
    程式設計 發佈於2025-05-21
  • 左連接為何在右表WHERE子句過濾時像內連接?
    左連接為何在右表WHERE子句過濾時像內連接?
    左JOIN CONUNDRUM:WITCHING小時在數據庫Wizard的領域中變成內在的加入很有趣,當將c.foobar條件放置在上面的Where子句中時,據說左聯接似乎會轉換為內部連接。僅當滿足A.Foo和C.Foobar標準時,才會返回結果。 為什麼要變形?關鍵在於其中的子句。當左聯接的右側...
    程式設計 發佈於2025-05-21
  • 如何使用“ JSON”軟件包解析JSON陣列?
    如何使用“ JSON”軟件包解析JSON陣列?
    parsing JSON與JSON軟件包 QUALDALS:考慮以下go代碼:字符串 } func main(){ datajson:=`[“ 1”,“ 2”,“ 3”]`` arr:= jsontype {} 摘要:= = json.unmarshal([] byte(...
    程式設計 發佈於2025-05-21
  • 如何在鼠標單擊時編程選擇DIV中的所有文本?
    如何在鼠標單擊時編程選擇DIV中的所有文本?
    在鼠標上選擇div文本單擊帶有文本內容,用戶如何使用單個鼠標單擊單擊div中的整個文本?這允許用戶輕鬆拖放所選的文本或直接複製它。 在單個鼠標上單擊的div元素中選擇文本,您可以使用以下Javascript函數: function selecttext(canduterid){ if(d...
    程式設計 發佈於2025-05-21
  • Java中Lambda表達式為何需要“final”或“有效final”變量?
    Java中Lambda表達式為何需要“final”或“有效final”變量?
    Lambda Expressions Require "Final" or "Effectively Final" VariablesThe error message "Variable used in lambda expression shou...
    程式設計 發佈於2025-05-21
  • 如何高效地在一個事務中插入數據到多個MySQL表?
    如何高效地在一個事務中插入數據到多個MySQL表?
    mySQL插入到多個表中,該數據可能會產生意外的結果。雖然似乎有多個查詢可以解決問題,但將從用戶表的自動信息ID與配置文件表的手動用戶ID相關聯提出了挑戰。 使用Transactions和last_insert_id() 插入用戶(用戶名,密碼)值('test','tes...
    程式設計 發佈於2025-05-21
  • Python不會對超範圍子串切片報錯的原因
    Python不會對超範圍子串切片報錯的原因
    在python中用索引切片範圍:二重性和空序列索引單個元素不同,該元素會引起錯誤,切片在序列的邊界之外沒有。 這種行為源於索引和切片之間的基本差異。索引一個序列,例如“示例” [3],返回一個項目。但是,切片序列(例如“示例” [3:4])返回項目的子序列。 索引不存在的元素時,例如“示例” [9...
    程式設計 發佈於2025-05-21
  • 同實例無需轉儲複製MySQL數據庫方法
    同實例無需轉儲複製MySQL數據庫方法
    在同一實例上複製一個MySQL數據庫而無需轉儲在同一mySQL實例上複製數據庫,而無需創建InterMediate sqql script。以下方法為傳統的轉儲和IMPORT過程提供了更簡單的替代方法。 直接管道數據 MySQL手動概述了一種允許將mysqldump直接輸出到MySQL cli...
    程式設計 發佈於2025-05-21
  • Go web應用何時關閉數據庫連接?
    Go web應用何時關閉數據庫連接?
    在GO Web Applications中管理數據庫連接很少,考慮以下簡化的web應用程序代碼:出現的問題:何時應在DB連接上調用Close()方法? ,該特定方案將自動關閉程序時,該程序將在EXITS EXITS EXITS出現時自動關閉。但是,其他考慮因素可能保證手動處理。 選項1:隱式關閉終...
    程式設計 發佈於2025-05-21

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

Copyright© 2022 湘ICP备2022001581号-3