Docker构建并启动前端完整流程详细代码

使用 Docker 部署前端项目是一种高效且可靠的方法,可以确保项目在不同环境中的一致性,这篇文章主要介绍了docker构建并启动前端的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下。

docker文件示例代码:

# Use a minimal image for development
FROM node:18-alpine
# Set working directory inside the container
WORKDIR /app
# Copy package.json and package-lock.json (or yarn.lock) into the container
COPY package.json package-lock.json* ./
# Install the app dependencies with --legacy-peer-deps to bypass the peer dependency conflict
RUN npm install --legacy-peer-deps
# Copy the rest of the application files into the container
COPY . .
# Expose the port the app will run on
EXPOSE 3000
# Start the Next.js app in development mode
CMD ["npm", "run", "dev"]

这段 Dockerfile 用于构建一个基于 Node.js 18 Alpine 版本的容器,并运行一个 Next.js 应用。

逐行解析

1. 选择基础镜像

FROM node:18-alpine

使用 node:18-alpine 作为基础镜像,alpine 是 轻量级 Linux 版本,比 node:18 体积更小,减少 Docker 镜像的大小。

2. 设置工作目录

WORKDIR /app

在 容器内 创建 /app 目录,并把它作为 当前工作目录。

之后的所有操作都会在 /app 目录下执行。

3. 复制package.json和package-lock.json

COPY package.json package-lock.json* ./

只复制 package.json 和 package-lock.json,避免不必要的文件影响 npm install 缓存。

package-lock.json* 这样写是为了:

兼容 package-lock.json 和 package-lock.json.gz(如果存在)。

4. 安装依赖

RUN npm install --legacy-peer-deps

npm install 安装 Node.js 依赖。

--legacy-peer-deps 选项用于:

跳过 peerDependencies(依赖版本冲突时不报错)。

适用于 旧项目或有冲突的依赖。

5. 复制项目代码

COPY . .

复制 本地所有文件 到 容器的 /app/ 目录。

这里 不会重复安装依赖,因为 npm install 早就运行过了。

6. 开放端口

EXPOSE 3000

这个 只是声明 容器会使用 3000 端口,但默认不会让外部访问。

真正让外部访问时,需要 -p 参数:

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

这样才能 映射端口,让浏览器访问 http://localhost:3000。

7. 运行 Next.js 应用

CMD ["npm", "run", "dev"]

容器启动时执行 npm run dev,即 开发模式运行 Next.js。

这个命令等价于:

npm run dev

dev 脚本通常在 package.json 里:

"scripts": {
"dev": "next dev"
}

Next.js 开发服务器会在 localhost:3000 运行。

完整流程

  1. 基于 node:18-alpine 创建一个容器
  2. 在 /app 目录下工作
  3. 复制 package.json 并安装依赖
  4. 复制整个项目代码
  5. 暴露 3000 端口
  6. 运行 npm run dev 启动 Next.js 服务器

如何使用

1. 构建镜像

docker build -t my-next-app .

2. 运行容器

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

然后在浏览器访问:

http://localhost:3000

如果一切正常,你会看到 Next.js 应用的页面!

设置工作目录,所有操作都会在 /app 目录下执行。

当前app目录下没有内容吧,那怎么复制 package.json 和 package-lock.json

在 WORKDIR /app 之后,/app 目录虽然存在,但还是空的。

但是,Docker COPY 命令不会受这个影响,它会从宿主机(你的电脑)复制文件到 /app 目录下。

详细流程

WORKDIR /app
COPY package.json package-lock.json* ./

第一步:WORKDIR /app

这会 切换到 /app 目录,如果 /app 目录不存在,Docker 会自动创建它。

第二步:COPY package.json package-lock.json* ./

COPY 命令会从 宿主机(你的电脑) 的 当前目录 复制 package.json 和 package-lock.json 到 /app 目录下。

./ 代表目标路径是 当前目录,因为 WORKDIR /app 已经切换到 /app,所以 ./ 实际上就是 /app/。

举个例子

假设你的 项目目录 结构如下:

/my-project
├── Dockerfile
├── package.json
├── package-lock.json
├── src/
├── pages/
└── node_modules/

你在 /my-project 目录下运行:

docker build -t my-next-app .

Docker 执行过程:

  1. WORKDIR /app → 在容器内创建并切换到 /app
  2. COPY package.json package-lock.json* ./ → 把 package.json 和 package-lock.json 复制到 /app/
  3. RUN npm install --legacy-peer-deps → 在 /app/ 里安装依赖
  4. COPY . . → 复制 所有剩余文件(比如 src/、pages/)

总结

WORKDIR /app 只是 切换工作目录,不影响后续 COPY

COPY package.json package-lock.json* ./ 复制 package.json 和 package-lock.json 到 /app/

COPY . . 复制所有剩余文件

这样可以 优化缓存,加快构建速度

如果还是不懂,那就先理解下面的内容。。

COPY package.json package-lock.json ./这行代码的意思

COPY package.json package-lock.json* ./

它的作用是:

从宿主机(你的电脑)复制 package.json 和 package-lock.json 到 Docker 容器的 /app/ 目录下。

拆解解释

COPY package.json package-lock.json* ./

package.json package-lock.json* → 要复制的文件(来自你的 本地电脑)

./ → 目标路径(容器内的 /app/)

为什么./代表/app/?

因为 之前已经有 WORKDIR /app 了:

WORKDIR /app
COPY package.json package-lock.json* ./

WORKDIR /app 让 当前工作目录 变成 /app

COPY package.json package-lock.json* ./ 里的 ./ 指的是 当前工作目录

所以 ./ 实际上等同于 /app/

相当于:

COPY package.json package-lock.json* /app/

举个例子

假设你的 宿主机(电脑)的项目目录:

/my-project
├── Dockerfile
├── package.json
├── package-lock.json
├── src/
├── pages/
└── node_modules/

当你运行:

docker build -t my-next-app .

Docker 会执行:

  1. WORKDIR /app → 现在 /app 是容器内的工作目录
  2. COPY package.json package-lock.json* ./ → 复制 package.json 和 package-lock.json 到 /app/ 目录
  3. RUN npm install --legacy-peer-deps → 在 /app/ 里安装依赖
  4. COPY . . → 复制 剩下的所有文件(比如 src/、pages/)

总结

  • ./ 代表 容器里的 /app/,因为 WORKDIR /app 让 /app 成为了当前目录
  • COPY package.json package-lock.json* ./ 相当于 COPY package.json package-lock.json* /app/
  • 先复制依赖文件再复制整个项目,是为了优化 Docker 缓存,加快构建速度

COPY . .是什么意思,为什么这里是两个..

COPY . .

这条指令的作用是:

把宿主机(你的电脑)的 当前目录(.)的 所有文件 复制到 容器内的当前目录(.)。

由于 WORKDIR /app 设定了工作目录为 /app,所以 . 实际上是 /app/,最终效果是:

把宿主机的整个项目目录复制到容器的 /app/ 目录里。

拆解解释

COPY <源路径> <目标路径>

  • 第一个 .(源路径):指的是 宿主机上的当前目录(Docker 构建时的 Dockerfile 所在目录)
  • 第二个 .(目标路径):指的是 容器内的当前工作目录(WORKDIR /app 已经设置)

所以:

WORKDIR /app

COPY . .

等价于:

COPY . /app/

举个例子

假设你的 本地项目目录(宿主机):

/my-project
├── Dockerfile
├── package.json
├── package-lock.json
├── src/
├── pages/
├── node_modules/
├── public/
└── .gitignore

你运行:

docker build -t my-next-app .

Docker 执行过程:

  1. WORKDIR /app → 切换到 /app/ 目录(如果没有,就创建它)
  2. COPY package.json package-lock.json* ./ → 复制 package.json 和 package-lock.json 到 /app/
  3. RUN npm install --legacy-peer-deps → 安装依赖
  4. COPY . . → 复制整个项目到 /app/,包括 src/、pages/、public/ 等

最终容器内的 /app/ 目录会变成:

/app
├── package.json
├── package-lock.json
├── src/
├── pages/
├── node_modules/  (npm install 之后才有)
├── public/
├── .gitignore

这样容器就拥有了完整的项目代码,可以运行 Next.js 了!

为什么要COPY . .?

  • 把整个项目复制到容器内,保证 npm run dev 可以运行
  • 必须在 npm install 之后执行,避免 node_modules/ 被覆盖
  • 确保 src/、pages/ 这些代码文件都能进入容器

总结

  • COPY . . 就是 COPY . /app/
  • 把宿主机(本机)的项目文件,复制到容器内的 /app/ 目录
  • 必须在 npm install 之后执行,避免影响 node_modules/
  • 这样容器就可以运行 Next.js 应用了

COPY .. → 复制整个项目到 /app/,包括 src/、pages/、public/ 等,这样不就会重复复制前面已经复制过的文件了么,比如package.json package-lock.json

是的,COPY . . 确实会再次复制 package.json 和 package-lock.json,但这不会影响构建结果,主要目的是 优化 Docker 构建缓存,加快构建速度。

为什么先COPY package.json package-lock.json ./再COPY . .?

先单独复制package.json和package-lock.json

COPY package.json package-lock.json* ./
RUN npm install --legacy-peer-deps

这样做的好处:

  • Docker 会缓存 npm install 结果,下次构建时,如果 package.json 没有改动,就不会重新安装依赖,直接用缓存的 node_modules!
  • 避免 npm install 被 COPY . . 之后的代码改动影响(如果 src/ 里的文件改了,不影响 node_modules)。

再复制整个项目

COPY . .

这样做的好处:

  • 确保 所有代码文件(src/、pages/、public/)都能进入容器。
  • 不影响 node_modules/ 缓存,因为 npm install 之前已经执行过了。

如果不先COPY package.json,直接COPY . .会怎样?

如果你只写:

COPY . .
RUN npm install --legacy-peer-deps

问题在于:

每次项目代码有一点改动(比如 src/ 文件变了),COPY . . 都会让 Docker 重新执行 RUN npm install,导致浪费时间!

npm install 需要很久,每次构建都会重新下载依赖,非常慢。

总结

  • 先 COPY package.json package-lock.json ./,让 npm install 结果被缓存,加快构建
  • 再 COPY . .,确保所有代码文件(src/、pages/ 等)被复制
  • 即使 package.json 被重复复制,也不会影响最终构建速度

为什么先COPY package.json package-lock.json ./,可以让 npm install 结果被缓存

Docker 构建时,会缓存每一层命令的结果,如果前面某一层的输入没有变,Docker 就不会重新执行它,而是直接用缓存。

Docker 的缓存机制

当你运行 docker build 时,Docker 会:

  1. 逐行读取 Dockerfile
  2. 检查每一层是否有变动
  3. 如果某一层和上次构建时相同,就复用缓存
  4. 如果某一层变了,后面的所有层都会重新执行(缓存失效)

举个例子

没有单独复制package.json,直接COPY . .

# 设置工作目录
WORKDIR /app
# 直接复制整个项目
COPY . .
# 安装依赖
RUN npm install --legacy-peer-deps

这里的问题

  • COPY . . 会把 所有文件(包括 src/、pages/、public/)都复制到 /app/
  • 如果 src/ 里的代码有改动,整个 COPY . . 就会变动
  • Docker 发现 COPY . . 变了,就会让 npm install 重新执行,缓存失效
  • npm install 需要很长时间,每次构建都要重复下载依赖,太慢了!

优化方法:先COPY package.json package-lock.json ./

# 设置工作目录
WORKDIR /app
# 先复制 package.json 和 package-lock.json
COPY package.json package-lock.json* ./
# 运行 npm install,并缓存 node_modules
RUN npm install --legacy-peer-deps
# 复制剩下的所有文件
COPY . .

为什么这样能加速构建?

1、Docker 先执行 COPY package.json package-lock.json ./

  • 只复制 package.json 和 package-lock.json,不会受 src/ 文件改动影响

2、然后执行 RUN npm install --legacy-peer-deps

  • 如果 package.json 没变,Docker 直接复用上次构建的 node_modules
  • 跳过 npm install,节省时间

3、最后执行 COPY . .

  • 复制 src/、pages/、public/ 等代码文件
  • 即使代码变了,npm install 也不会重新执行

这样做的结果

  • 如果 package.json 没变,Docker 直接复用 node_modules,构建速度快很多
  • 即使 src/ 代码变了,也不会触发 npm install,不会浪费时间
  • 整个构建流程更高效,省时省力 

时间对比

方法 构建时间(假设 npm install 需要 2 分钟)
直接 COPY . . 每次构建都要等 2 分钟(因为 npm install 总是重新运行)
先 COPY package.json,再 COPY . . 如果 package.json 没变,构建只需要几秒!

这样优化后,构建速度可以快 10 倍以上!

如果 Docker 关闭后重新启动,还需要重新安装依赖吗?

如果你只是重启 Docker(比如 docker stop → docker start),不需要重新安装依赖,因为容器的文件系统还在,node_modules/ 也还在。

但是,如果你删除了容器或构建了新镜像,就需要重新安装依赖!

分情况讨论

1. 只是重启 Docker

docker stop my-container  # 关闭容器
docker start my-container # 重新启动

  • node_modules/ 还在,不需要重新安装依赖
  • 应用可以直接运行
  • 适用于日常使用

2. 删除容器后再启动

docker rm my-container   # 删除容器
docker run my-image      # 重新运行

容器被删除,所有文件(包括 node_modules/)都会丢失

需要重新 npm install

这时 Docker 会根据 Dockerfile 重新安装依赖

3. 重新docker build

docker build -t my-app .  # 重新构建镜像
docker run my-app         # 运行新容器

  • 如果 package.json 没变,Docker 可能会复用 npm install 的缓存
  • 如果 package.json 变了,npm install 会重新运行
  • 推荐使用 Docker Volume 来持久化 node_modules/(见下面的方法)

如何让node_modules/不丢失?(Docker Volume 持久化)

方法1:使用docker-compose绑定node_modules目录

创建 docker-compose.yml:

version: '3'
services:
app:
build: .
volumes:
- .:/app
- /app/node_modules
ports:
- "3000:3000"

这样即使你删除容器,node_modules/ 也不会丢失。

方法2:手动挂载 Volume

运行容器时,使用 -v 选项:

docker run -v my-node-modules:/app/node_modules -p 3000:3000 my-app

这样 node_modules/ 会存储在 Docker Volume 里

即使你删除容器,依赖也不会丢失

总结

情况 是否需要重新安装依赖?
仅重启 Docker (docker stop → docker start) 不需要,node_modules/ 还在
删除容器后重新运行 (docker rm + docker run) 需要,文件丢失
重新构建镜像 (docker build)  可能需要,取决于 Docker 缓存
使用 Volume (-v 绑定 node_modules/) 不需要,node_modules/ 保留在 Volume
  • 推荐使用 Volume,这样即使容器被删,依赖也不会丢失

如果你关了电脑、退出了 Docker,下次启动后还需要重新安装依赖吗?

  • 大多数情况下,不需要重新安装依赖!

如果你只是 关机、退出 Docker,再次启动,你的 容器和 node_modules/ 依然会保留,不需要重新 npm install。

但 如果你删除了容器、清理了 Docker 数据,或者用了 --rm 运行容器,就需要重新安装依赖!

具体情况分析

操作 需要重新安装依赖吗? 原因
关机后重新开机 不需要 Docker 会保留容器和 node_modules/
退出 Docker 后重新启动 不需要 只要容器没有被删除,node_modules/ 还在
用 docker stop 停止容器,再 docker start 不需要 node_modules/ 还在,直接启动即可
用 docker rm 删除容器 需要 node_modules/ 被删,需要重新安装
用 docker build 重新构建镜像 可能需要 如果 package.json 没变,可能会用缓存
用 docker run --rm 运行临时容器 需要 --rm 让容器退出时自动删除,node_modules/ 会丢失

如何确保关机后node_modules/不丢失?

方法 1:使用持久化 Volume

docker run -v my-node-modules:/app/node_modules -p 3000:3000 my-app

这样 node_modules/ 会存储在 Docker Volume 里,即使容器被删除,依赖也不会丢失。

方法 2:用docker-compose管理项目

创建 docker-compose.yml:

version: '3'
services:
app:
build: .
volumes:
- .:/app
- /app/node_modules
ports:
- "3000:3000"

然后启动:

docker-compose up -d

这样即使你重启 Docker 或关机,node_modules/ 依然会保留。

总结

如果你只是关机、退出 Docker, 依赖不会丢失,开机后可以直接运行容器 

但如果删除了容器,就需要重新安装 npm install!

到此这篇关于docker构建并启动前端的文章就介绍到这了,更多相关docker构建启动前端内容请继续浏览下面的相关文章!