Dockerfile与镜像构建
大约 3 分钟
Dockerfile 与镜像构建
Dockerfile 是什么
Dockerfile 就是用来构建 docker 镜像的构建文件,就是一段命令脚本,通过脚本生成镜像。文件中的内容为 指令(大写) 参数,这里每个命令就是镜像的一层(联合文件系统)。
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "-----end-----"
CMD /bin/bash

常用指令
| 指令 | 说明 | 示例 |
|---|---|---|
| FROM | 基础镜像,一切从这里开始 | FROM node:16 |
| MAINTAINER | 作者信息(新写法 LABEL) | LABEL author="sunshine" |
| RUN | 构建镜像时执行的命令(每个 RUN 一层) | RUN npm install |
| COPY | 从构建上下文复制文件进镜像 | COPY . /app |
| ADD | 类似 COPY,会自动解压 tar、支持 URL | ADD jdk.tar.gz /opt |
| WORKDIR | 设置工作目录 | WORKDIR /app |
| ENV | 构建时环境变量 | ENV NODE_ENV production |
| EXPOSE | 声明容器监听端口(仅声明,映射靠 -p) | EXPOSE 80 |
| VOLUME | 匿名挂载数据卷 | VOLUME ["/data"] |
| CMD | 容器启动时执行的命令,只有最后一条生效,可被 run 参数覆盖 | CMD ["nginx","-g","daemon off;"] |
| ENTRYPOINT | 同 CMD,但参数会追加而不是覆盖 | ENTRYPOINT ["java","-jar","app.jar"] |
| ONBUILD | 构建子镜像时触发 | ONBUILD RUN npm build |
| ARG | 构建参数(docker build --build-arg 传入) | ARG VERSION=1.0 |
CMD 与 ENTRYPOINT 的区别:
docker run image ls -a时,CMD 定义的整体被ls -a替换;ENTRYPOINT 则把ls -a追加在其后执行。
构建与推送
# -f 指定 Dockerfile 路径,-t 名字:tag,最后的 . 是构建上下文目录
docker build -f Dockerfile -t myapp:1.0 .
# 运行验证
docker run -d -p 8080:80 myapp:1.0
# 登录仓库推送(docker hub / harbor / 阿里云镜像仓库)
docker login
docker tag myapp:1.0 username/myapp:1.0
docker push username/myapp:1.0
.dockerignore
构建上下文中有时候不该把所有文件发给 docker daemon:
node_modules
dist
.git
*.log
.dockerignore
Dockerfile
Demo 1:构建自己的 CentOS(带 vim/ifconfig)
FROM centos
MAINTAINER sunshine
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "-----end-----"
CMD /bin/bash
对比:官方 centos 镜像没有 vim、ifconfig,通过 Dockerfile 增强后打包成自己的镜像,这就是"镜像分层增量构建"的意义。
Demo 2:多阶段构建前端项目(Vue/React 通用)
一次构建同时用到 node(构建)和 nginx(运行),最终镜像只保留 nginx 层,体积从 1GB+ 降到 20MB 级:
# ========== 阶段1:构建 ==========
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install --registry=https://registry.npmmirror.com
COPY . .
RUN npm run build
# ========== 阶段2:运行 ==========
FROM nginx:1.21
# 从 builder 阶段拷贝构建产物,注意 --from
COPY /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
配套 nginx.conf(history 路由兜底):
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html; # vue-router history 模式刷新 404 兜底
}
}
docker build -t blog-web:1.0 .
docker run -d -p 8080:80 --name blog-web blog-web:1.0
构建优化建议
- 尽量使用小基础镜像:
alpine/slim版本(如node:16-alpine) - 依赖文件先 COPY 再 install(利用层缓存,代码变动不会重装依赖)
- 多阶段构建,构建工具链不进最终镜像
- 合并 RUN 并清理缓存:
RUN npm install && npm cache clean --force && rm -rf /var/cache/apk/* - .dockerignore 排除无用文件,加快上下文传输
Loading...
