Dockerfile优化体验
选好镜像,减少最终image体积
Whenever possible, use current Official Repositories as the basis for your image. We recommend the Alpine image since it’s very tightly controlled and kept minimal (currently under 5 mb), while still being a full distribution.
上面这段是来自Docker的官方文档,言语之中极力推荐我们使用Alpine Linux,它的特点是短小精悍,只有不到5M。Base镜像的体积会对最后Build处理的镜像的体积有非常大的影响。举个Docker官方的Node镜像的例子不同Base镜像的Size分别是这样的
Image | Size |
---|---|
8.11-alpine | 23M |
8.11-slim | 92 MB |
8.11 | 266 MB |
太明显了
用好Docker cache,加速构建
Docker image 构建的时候会对当前构建的层(Layer)做缓存,当前层的上一层没有变的时候,会直接在上一层的基础上进行Build,这样的话能大大加快后续的构建速度。当然我们可以强制不使用缓存,在docker build
命令后加上 --no-cache=true
就可以强制让Docker从头开始构建。
先举个例子,假设我们的目录是这样的
web
├── Dockerfile
├── config
├── node_modules
├── package.json
├── src
└── yarn.lock
不太好的Dockerfile
里面是这样的
FROM node:8.11.1-alpine
LABEL maintainer="Iron Lu <lrironsora@gmail.com>"
WORKDIR ./app
COPY ./ ./
RUN yarn install && yarn build --production
...
上面这段代码最大的问题是。会有很大一部分情况,我们是修改了src
目录,但没有更改项目的依赖的,但是yarn install
在每一轮安装的时候都被行了一遍,每次装依赖的时间开销是完全可以用Docker cache避免的。
正确的做法如下
FROM node:8.11.1-alpine
LABEL maintainer="Iron Lu <lrironsora@gmail.com>"
WORKDIR ./app
COPY package.json yarn.lock ./
# Copy package.json和yarn.lock到镜像中
# 当项目的依赖没有改变,仅改变了src中的代码时
# 接下来的构建会直接通过缓存,从下面开始
RUN yarn install
COPY ./ ./
RUN yarn install && yarn build --production
再说一个用错Docker cache的例子
FROM ubuntu:14.04
RUN apt-get update
RUN apt-get install -y curl nginx
RUN apt-get update
那一行会被缓存,导致我们无法安装最新版的package。
所以,在官方文档中,特别强调了这样的一句
Always combine RUN apt-get update with apt-get install in the same RUN statement.
正确的做法当然是
RUN apt-get update && apt-get install -y \
package-bar \
package-baz \
package-foo
移除不必要的文件,进一步减少image体积
使用.dockerignore文件来忽略那些不应该被打包进来的文件。
显然,node_modules
是绝对不能放进来的。这部分是由项目决定的。凡是与镜像构建或容器运行无关的,都不应该被放进来。
下面是我项目中的例子
dist/
node_modules/
Dockerfile
.eslintrc.yml
README.md
sass-lint.yml
yarn-error.log
config/webpack/public
删除镜像内不会再用到的文件
举个例子,我们在Docker中使用webpack
构建了dist
文件,那么src
就不会再被用到。而且node_modules
里的一些依赖也不会再被用到,比如babel
, webpack
等,那么我们就可以把它移除掉来缩减体积。
关于怎么移除node_modules
里无用的依赖,我的做法是:将所有Build相关的依赖放入package.json
的devDependencies
中,在dependencies中只放静态文件服务器所需要的2个package:
express
和connect-history-api-fallback
。
这也许是个不好的实现
我的Dockerfile如下
WORKDIR ./app
ADD package.json ./ yarn.lock ./ package-lock.json ./
RUN yarn install
COPY ./ ./
RUN yarn build:prod &&\
yarn install --production &&\
# 删除node_moudules无用依赖
yarn cache clean &&\
# 这一步可以清掉yarn的缓存
rm -rf config/webpack/public
当执行yarn install --production
时,node_modules
中无用的package都会被移除掉,移除前后的体积对比如下
~/foo/ du -hs node_modules
357M node_modules
~/foo/ yarn install --production
✨ Done in 7.31s.
~/foo du -hs node_modules
2.2M node_modules
差不多少了350M,减肥是很有效果的。
移除安装过程中的下载的包
rm -rf /var/lib/apt/lists/*
# 删除Ubuntu apt-get 的缓存
yum clean all
# 删除CentOS yum的缓存
yarn clean
# 删除yarn的缓存