”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > NextJS 应用程序的 Docker 和 Docker-Compose 最佳实践。

NextJS 应用程序的 Docker 和 Docker-Compose 最佳实践。

发布于2024-11-07
浏览:536

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]删除
最新教程 更多>
  • 找到最大计数时,如何解决mySQL中的“组函数\”错误的“无效使用”?
    找到最大计数时,如何解决mySQL中的“组函数\”错误的“无效使用”?
    如何在mySQL中使用mySql 检索最大计数,您可能会遇到一个问题,您可能会在尝试使用以下命令:理解错误正确找到由名称列分组的值的最大计数,请使用以下修改后的查询: 计数(*)为c 来自EMP1 按名称组 c desc订购 限制1 查询说明 select语句提取名称列和每个名称...
    编程 发布于2025-07-16
  • 我可以将加密从McRypt迁移到OpenSSL,并使用OpenSSL迁移MCRYPT加密数据?
    我可以将加密从McRypt迁移到OpenSSL,并使用OpenSSL迁移MCRYPT加密数据?
    将我的加密库从mcrypt升级到openssl 问题:是否可以将我的加密库从McRypt升级到OpenSSL?如果是这样,如何?答案:是的,可以将您的Encryption库从McRypt升级到OpenSSL。可以使用openssl。附加说明: [openssl_decrypt()函数要求iv参...
    编程 发布于2025-07-16
  • 为什么PYTZ最初显示出意外的时区偏移?
    为什么PYTZ最初显示出意外的时区偏移?
    与pytz 最初从pytz获得特定的偏移。例如,亚洲/hong_kong最初显示一个七个小时37分钟的偏移: 差异源利用本地化将时区分配给日期,使用了适当的时区名称和偏移量。但是,直接使用DateTime构造器分配时区不允许进行正确的调整。 example pytz.timezone(...
    编程 发布于2025-07-16
  • Spark DataFrame添加常量列的妙招
    Spark DataFrame添加常量列的妙招
    在Spark Dataframe ,将常数列添加到Spark DataFrame,该列具有适用于所有行的任意值的Spark DataFrame,可以通过多种方式实现。使用文字值(SPARK 1.3)在尝试提供直接值时,用于此问题时,旨在为此目的的column方法可能会导致错误。 df.withco...
    编程 发布于2025-07-16
  • 如何克服PHP的功能重新定义限制?
    如何克服PHP的功能重新定义限制?
    克服PHP的函数重新定义限制在PHP中,多次定义一个相同名称的函数是一个no-no。尝试这样做,如提供的代码段所示,将导致可怕的“不能重新列出”错误。 但是,PHP工具腰带中有一个隐藏的宝石:runkit扩展。它使您能够灵活地重新定义函数。 runkit_function_renction_re...
    编程 发布于2025-07-16
  • 在UTF8 MySQL表中正确将Latin1字符转换为UTF8的方法
    在UTF8 MySQL表中正确将Latin1字符转换为UTF8的方法
    在UTF8表中将latin1字符转换为utf8 ,您遇到了一个问题,其中含义的字符(例如,“jáuòiñe”)在utf8 table tabled tablesset中被extect(例如,“致电。为了解决此问题,您正在尝试使用“ mb_convert_encoding”和“ iconv”转换受...
    编程 发布于2025-07-16
  • 如何使用FormData()处理多个文件上传?
    如何使用FormData()处理多个文件上传?
    )处理多个文件输入时,通常需要处理多个文件上传时,通常是必要的。 The fd.append("fileToUpload[]", files[x]); method can be used for this purpose, allowing you to send multi...
    编程 发布于2025-07-16
  • 图片在Chrome中为何仍有边框?`border: none;`无效解决方案
    图片在Chrome中为何仍有边框?`border: none;`无效解决方案
    在chrome 在使用Chrome and IE9中的图像时遇到的一个频繁的问题是围绕图像的持续薄薄边框,尽管指定了图像,尽管指定了;和“边境:无;”在CSS中。要解决此问题,请考虑以下方法: Chrome具有忽略“ border:none; none;”的已知错误,风格。要解决此问题,请使用以下...
    编程 发布于2025-07-16
  • 人脸检测失败原因及解决方案:Error -215
    人脸检测失败原因及解决方案:Error -215
    错误处理:解决“ error:((-215)!empty()in Function Multultiscale中的“ openCV 要解决此问题,必须确保提供给HAAR CASCADE XML文件的路径有效。在提供的代码片段中,级联分类器装有硬编码路径,这可能对您的系统不准确。相反,OPENCV提...
    编程 发布于2025-07-16
  • \“(1)vs.(;;):编译器优化是否消除了性能差异?\”
    \“(1)vs.(;;):编译器优化是否消除了性能差异?\”
    答案: 在大多数现代编译器中,while(1)和(1)和(;;)之间没有性能差异。编译器: perl: 1 输入 - > 2 2 NextState(Main 2 -E:1)V-> 3 9 Leaveloop VK/2-> A 3 toterloop(next-> 8 last-> 9 ...
    编程 发布于2025-07-16
  • 如何处理PHP文件系统功能中的UTF-8文件名?
    如何处理PHP文件系统功能中的UTF-8文件名?
    在PHP的Filesystem functions中处理UTF-8 FileNames 在使用PHP的MKDIR函数中含有UTF-8字符的文件很多flusf-8字符时,您可能会在Windows Explorer中遇到comploreer grounder grounder grounder gro...
    编程 发布于2025-07-16
  • 如何从Python中的字符串中删除表情符号:固定常见错误的初学者指南?
    如何从Python中的字符串中删除表情符号:固定常见错误的初学者指南?
    从python import codecs import codecs import codecs 导入 text = codecs.decode('这狗\ u0001f602'.encode('utf-8'),'utf-8') 印刷(文字)#带有...
    编程 发布于2025-07-16
  • 解决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-07-16
  • 如何使用Depimal.parse()中的指数表示法中的数字?
    如何使用Depimal.parse()中的指数表示法中的数字?
    在尝试使用Decimal.parse(“ 1.2345e-02”中的指数符号表示法表示的字符串时,您可能会遇到错误。这是因为默认解析方法无法识别指数符号。 成功解析这样的字符串,您需要明确指定它代表浮点数。您可以使用numbersTyles.Float样式进行此操作,如下所示:[&& && && ...
    编程 发布于2025-07-16
  • 如何使用不同数量列的联合数据库表?
    如何使用不同数量列的联合数据库表?
    合并列数不同的表 当尝试合并列数不同的数据库表时,可能会遇到挑战。一种直接的方法是在列数较少的表中,为缺失的列追加空值。 例如,考虑两个表,表 A 和表 B,其中表 A 的列数多于表 B。为了合并这些表,同时处理表 B 中缺失的列,请按照以下步骤操作: 确定表 B 中缺失的列,并将它们添加到表的末...
    编程 发布于2025-07-16

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3