默认的 docker 镜像使用 Linux 来当作基础镜像
01. 使用 alpine 镜像,而不是默认的 linux 镜像
PS: alpine 译为高山植物,就是很少的资源就能存活的意思。alpine 裁剪了很多不必要的 linux 功能,使得镜像体积大幅减小了。
- 比如 FROM node:18 可改为 FROM node:18-alpine3.14
Dockerfile 会给每一行都增加缓存,所以尽可能的复用缓存可以提高速度,另外就是源码和很多构建的依赖是不需要的,但是现在都保存在了镜像里。比如 Vue 项目实际上我们只需要构建出来的 ./dist 目录下的文件还有运行时的依赖。
02. 使用多阶段构建
- 例子
FROM node:18-alpine3.14 as build-stageWORKDIR /appCOPY package.json .RUN npm installCOPY . .RUN npm run build#production stage
FROM node:18-alpine3.14 as production-stageCOPY --from=build-stage /app/dist /app
COPY --from=build-stage /app/package.json /app/package.jsonWORKDIR /appRUN npm install --productionEXPOSE 3000CMD ["node", "/app/main.js"]
FROM 后面添加一个 as 来指定当前构建阶段的名字。
通过 COPY --from=xxx 可以从上个阶段复制文件过来。
然后 npm install 的时候添加 --production,这样只会安装 dependencies 的依赖。
docker build 之后,只会留下最后一个阶段的镜像。
也就是说,最终构建出来的镜像里是没有源码的,有的只是 dist 的文件和运行时依赖。
这样镜像就会小很多。
03. 使用 ARG 增加构建灵活性
- 例子
FROM node:18-alpine3.14ARG aaa
ARG bbbWORKDIR /appCOPY ./test.js .ENV aaa=${aaa} \bbb=${bbb}CMD ["node", "/app/test.js"]
使用 ARG 声明构建参数,使用 ${xxx} 来取
然后用 ENV 声明环境变量。
dockerfile 内换行使用 \
之后构建的时候传入构建参数:
docker build --build-arg aaa=3 --build-arg bbb=4 -t arg-test -f 333.Dockerfile .
通过 --build-arg xxx=yyy 传入 ARG 参数的值。
04. CMD 结合 ENTRYPOINT
前面的 CMD 其实可以换成 ENTRYPOINT。
这两种写法有什么区别么?
- 用 CMD 的时候,启动命令是可以重写的
- ENTRYPOINT 不会也不能重写命令
05. COPY vs ADD
这俩都可以把宿主机的文件复制到容器内。但有一点区别,就是对于 tar.gz 这种压缩文件的处理上:
ADD、COPY 都可以用于把目录下的文件复制到容器内的目录下。但是 ADD 还可以解压 tar.gz 文件。
一般情况下,还是用 COPY 居多。
总结下来
Dockerfile 有挺多技巧:
- 使用 alpine 的镜像,而不是默认的 linux 镜像,可以极大减小镜像体积,比如 node:18-alpine3.14 这种
- 使用多阶段构建,比如一个阶段来执行 build,一个阶段把文件复制过去,跑起服务来,最后只保留最后一个阶段的镜像。这样使镜像内只保留运行需要的文件以及 dependencies。
- 使用 ARG 增加构建灵活性,ARG 可以在 docker build 时通过 --build-arg xxx=yyy 传入,在 dockerfile 中生效,可以使构建过程更灵活。如果是想定义运行时可以访问的变量,可以通过 ENV 定义环境变量,值使用 ARG 传入。
- CMD 和 ENTRYPOINT 都可以指定容器跑起来之后运行的命令,CMD 可以被覆盖,而 ENTRYPOINT 不可以,两者结合使用可以实现参数默认值的功能。
- ADD 和 COPY 都可以复制文件到容器内,但是 ADD 处理 tar.gz 的时候,还会做一下解压。
ADD方法会解压压缩包,但是注意太大的文件不要使用ADD方法。docker build的过程会加载到内存里面去。太大的文件使用ADD存在内存问题。
alpine 镜像有部分一些链接文件缺失的。比如golang打包,alpine 镜像中可能会缺少一些C语言的依赖文件。这个时候可以通过COPY复制到容器内。也可以FROM别人制作好的镜像操作。