为什么每次更改构建参数时docker都会重建所有层

时间:2020-03-07 14:40:19

标签: docker dockerfile

我有一个docker文件,其中包含很多层。在文件的顶部,我有一些

FROM ubuntu:18.04

ARGS USER=test-user
ARGS UID=1000
#ARGS PW=test-user

# Then several Layers which does not use any ARGS. Example
LABEL version="1.0"

ENV LANG=C.UTF-8 LC_ALL=C.UTF-8

RUN mkdir ~/mapped-volume

RUN apt-get update && apt-get install -y wget bzip2 ca-certificates build-essential curl git-core htop pkg-config unzip unrar tree freetds-dev vim \
sudo nodejs npm net-tools flex perl automake bison libtool byacc

# And so on 
# And finally towards the end
# Setup User
RUN useradd -m -d /home/${USER} --uid ${UID} -G sudo -s /bin/bash ${USER} 
# && echo "${USER}:${PW}" | chpasswd

# Couple of  more commands to change dir, entry point etc. Example

当我使用与上次构建不同的arg值构建此docker文件时,和/或在对后两层进行细微更改后,该构建将再次构建所有内容。它不使用缓存层。我用来构建的命令是这样的

docker build --build-arg USER=new-user --build-arg UID=$UID -t my-image:1.0 .

每次更改值时,构建都会重新进行一次。顶部像下面这样截短

UID -t my-image:1.0 .
Sending build context to Docker daemon  44.54kB
Step 1/23 : FROM ubuntu:18.04
 ---> ccc6e87d482b
Step 2/23 : ARG USER=ml-user
 ---> Using cache
 ---> 6c0c5d5c5056
Step 3/23 : ARG UID=1000
 ---> Using cache
 ---> b25867c282c7
Step 4/23 : LABEL version="1.0"
 ---> Running in 1ffff70d56c1
Removing intermediate container 1ffff70d56c1
 ---> 0f1277def3ca
Step 5/23 : ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
 ---> Running in 49d08c41b233
Removing intermediate container 49d08c41b233
 ---> f5b345573c1f
Step 6/23 : RUN mkdir ~/mapped-volume
 ---> Running in e4f8a5956450
Removing intermediate container e4f8a5956450
 ---> 1b22731d9051
Step 7/23 : RUN apt-get update && apt-get install -y wget bzip2 ca-certificates build-essential curl git-core htop pkg-config unzip unrar tree freetds-dev vim sudo nodejs npm net-tools flex perl automake bison libtool byacc
 ---> Running in ffc297de6234
Get:1 http://archive.ubuntu.com/ubuntu bionic InRelease [242 kB]

因此从第7步开始,它将继续执行所有步骤,而无需使用该层的缓存,该缓存应具有一堆软件包 为什么?我该如何阻止呢?以前,当我没有args时,该层和其他层以前都是从缓存中提取的。

1 个答案:

答案 0 :(得分:2)

将args移到需要它们之前。在运行它们之前,Docker不会替换RUN命令中的参数。相反,args作为环境变量传递,并由外壳在临时容器中扩展。因此,对arg的更改就是对环境的更改,并且是该步骤的构建缓存缺失。一旦某一步骤错过了缓存,则必须重新构建以下所有步骤。

FROM ubuntu:18.04

# Then several Layers which does not use any ARGS. Example

ENV LANG=C.UTF-8 LC_ALL=C.UTF-8

RUN mkdir ~/mapped-volume

RUN apt-get update && apt-get install -y wget bzip2 ca-certificates build-essential curl git-core htop pkg-config unzip unrar tree freetds-dev vim \
sudo nodejs npm net-tools flex perl automake bison libtool byacc

# And so on 
# And finally towards the end
# Setup User
ARGS USER=test-user
ARGS UID=1000
RUN useradd -m -d /home/${USER} --uid ${UID} -G sudo -s /bin/bash ${USER} 
# && echo "${USER}:${PW}" | chpasswd

# Couple of  more commands to change dir, entry point etc. Example

LABEL version="1.0"

此外,在构建时不需要的标签,环境变量,暴露的端口以及任何其他元数据通常最好留在Dockerfile的末尾,因为它们对构建时间的影响最小,因此无需错过它们更改时的缓存。