自己动手写 Dockerfile:构建你的第一个镜像
Dockerfile 长啥样?
Dockerfile 其实就是一个文本文件,里面一条一条指令,告诉 Docker 怎么一步步构建你的镜像。来看一个最简单的例子,我们要做一个能提供静态文件的 HTTP 服务镜像:
# 使用官方 Node 镜像作为基础
FROM node:18-alpine3.14
# 设置容器内的工作目录
WORKDIR /app
# 把当前目录下的所有文件复制到容器的工作目录
COPY . .
# 安装依赖(如果有 package.json 的话)
RUN npm install
# 声明容器运行时监听的端口
EXPOSE 3000
# 容器启动时执行的命令
CMD ["node", "server.js"]这个文件里每一条指令都会生成一个“镜像层”,一层叠一层,最后变成一个完整的镜像。接下来我们一条条解释。
指令详解
- FROM:指定基础镜像。几乎所有镜像都基于一个已有的操作系统或环境镜像,比如
node、nginx、alpine等。这里我们选了node:18-alpine3.14,因为 Alpine Linux 非常小巧,能让最终镜像体积小很多。 - WORKDIR:设置工作目录。后续的
COPY、RUN、CMD等指令都会在这个目录下执行。如果目录不存在,Docker 会自动创建。 - COPY:把构建上下文(我们马上会讲)中的文件复制到镜像里。这里
COPY . .表示把当前目录(构建上下文)的所有内容复制到镜像的/app下。 - RUN:在构建过程中执行命令。比如这里运行
npm install安装依赖。每一条RUN都会生成一个新层。 - EXPOSE:告诉 Docker 容器内的应用会监听哪个端口。这只是一个声明,实际运行时还需要用
-p做端口映射。 - CMD:指定容器启动时执行的命令。注意,这个命令可以被
docker run后面跟着的命令覆盖。比如你docker run myimage node server.js就会覆盖掉 CMD。
VOLUME 指令是干嘛的?
你可能注意到文件里没写 VOLUME,但文件内容里提到了它。VOLUME 指令的作用是声明容器内的某个目录应该被持久化。即使你运行容器时没挂载数据卷,Docker 也会自动为这个目录创建一个匿名卷,保证里面的数据不会因为容器删除而丢失。比如:
VOLUME /data这样即使你忘了 -v,/data 下的数据也会被保留在某个卷里。不过实际生产环境一般还是会手动挂载,便于管理。
构建上下文与 .dockerignore
当你执行 docker build 命令时,会指定一个构建上下文,通常是当前目录。比如:
docker build -t my-http-server .这个点 . 就是构建上下文。Docker 会把该目录下的所有文件(包括子目录)打包发送给 Docker 守护进程(daemon),然后才开始构建。如果你的目录里有 node_modules、日志文件等不必要的东西,发送过去不仅慢,还会让镜像变大(因为 COPY 时会复制它们)。
这时候就需要 .dockerignore 文件,写法类似 .gitignore,在里面列出不需要发送的文件和文件夹,比如:
node_modules
.git
*.log
Dockerfile这样构建时就忽略它们,加快构建速度,减小镜像体积。
多阶段构建:瘦身利器
有时我们构建应用需要编译工具、依赖包,但运行应用时并不需要它们。比如一个前端项目,构建时需要 Node 和 Webpack,但运行只需要生成的静态文件。多阶段构建就是用来解决这个问题的。
看个例子:
# 第一阶段:构建
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 第二阶段:运行
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]这里我们用了两个 FROM,第一个阶段叫 builder,专门用来构建,生成了 dist 目录。第二阶段直接用 Nginx 镜像,把第一阶段生成的 dist 目录复制过来。最终镜像只有 Nginx 和静态文件,体积非常小。多阶段构建不仅减小了镜像,还提高了安全性,因为运行环境里没有源代码和构建工具。
Alpine 基础镜像的妙处
前面我们多次提到 alpine,它到底有多小?以 Node 为例,node:18 镜像大概 1GB 左右,而 node:18-alpine 只有 100 多 MB。因为 Alpine 是一个极简的 Linux 发行版,只包含最基本的工具,像 sh、apk 包管理器等。用它做基础镜像,构建出来的镜像体积小,传输快,部署也快。
总结
通过写一个 Dockerfile,你可以精确控制镜像的每一层。记住几个要点:选择合适的 FROM(优先 Alpine),利用 .dockerignore 减少上下文,用 多阶段构建 瘦身,理解 CMD 和 ENTRYPOINT 的区别(我们后面会细讲)。现在你可以试着为自己的 Node 项目写个 Dockerfile 了。

Comments | NOTHING