镜像制作最佳实践
Docker 是用于构建、分发、运行容器的平台和工具。在当下非常流行,已经是事实上的标准。
使用Docker制作镜像有一些注意事项,下面列出总结出的几点:
1. 使用官方的镜像作为基础镜像
官方的镜像更稳定也更符合标准
2. 基础镜像的标签不要使用latest
如果我们需要一个mysql镜像,打开 https://hub.docker.com/_/mysql
发现描述中会列出支持的标签
Supported tags and respective Dockerfile links
8.0.27, 8.0, 8, latest
5.7.36, 5.7, 5
5.6.51, 5.6
说明下面的命令是等价的
docker pull mysql:latest
docker pull mysql:8.0.27
docker pull mysql:8.0
docker pull mysql:8
但是使用docker pull mysql:8.0
比 docker pull mysql:latest
更具体,也不容易出错
3. 使用.dockerignore 文件
.dockerignore文件用于忽略在构建镜像过程中用不到的文件,可以大大减少镜像的体积
比如构建前端项目,可以将node_modules放到.dockerignore文件里
4. 充分利用缓存机制
看下面的Dockerfile
优化前
FROM node:17.0.1-alpine
WORKDIR /app
COPY myapp /app
RUN npm install --production
CMD ["node", "src/index.js"]
优化后
FROM node:17.0.1-alpine
WORKDIR /app
COPY package.json package-lock.json .
RUN npm install --production
COPY myapp /app
CMD ["node", "src/index.js"]
Docker镜像是由一系列层来构成的,每层代表Dockerfile中的一条指令
比如执行FROM node:17.0.1-alpine
后会产生一堆文件,这些文件会缓存都本地,其他Dockerfile也使用了这行命令,就不用重新下载了。
关于COPY命令,如果文件发生了变动会重新构建该层,某层发生了变化其下面的层都要重新构建
明白了这点,记住一个结论就是越容易产生文件变化的命令越放到后面执行
把 copy myapp /app
放到后面,因为myapp是源码目录,是会经常发生变动的,一旦该层内容发生变动,那么后续的层都会重新执行
这是优化后的执行顺序
5. dockerfile中每行命令产生一层,请最大限度减少层数
当Dockerfile的指令修改了,复制的文件变化了,或者构建镜像时指定的变量不同了,对应的镜像层缓存就会失效。某一层的镜像缓存失效之后,它之后的镜像层缓存都会失效
6. 使用多步构建 multi staging
这是一个前端的通用Dockerfile
分两个stage,一个stage引入node构建前端资源,第二个stage引入nginx托管静态资源
最终运行的只是一个安装了nginx容器,node只是临时的
# build stage
FROM node:lts-alpine as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# production stage
FROM nginx:stable-alpine as production-stage
COPY --from=build-stage /dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
7. 不要使用root用户 避免潜在的风险
某些官方镜像已经为我们创建好了用户,比如node
8. 使用 docker scan 命令扫描风险
该命令非常简单docker scan [image-name]
, 是利用snyk 提供的服务 不过现在有次数限制
参考
https://www.youtube.com/watch?v=8vXoMqWgbQQ
https://www.qikqiak.com/post/dockerfile-best-practice/