首页

    build go docker image using layer cache

    标签:go,docker

    问题

    之前的go代码在构建镜像的过程中,经常不用layer cache。Dockerfile是这样的

    FROM golang:1.11.5-alpine3.8
    COPY . .
    RUN go get -t -d -v ./...
    

    查了下文档

    Aside from the ADD and COPY commands, cache checking does not look at the files in the container to determine a cache match. For example, when processing a RUN apt-get -y update command the files updated in the container are not examined to determine if a cache hit exists. In that case just the command string itself is used to find a match.

    除开ADD,COPY,其他的指令都不会看指令执行后文件的变化,只会看指令是否和之前一样.一样的话,就使用layer cache.既然这样,为什么没用到layer cache呢?

    再看ADD指令文档有说到

    The first encountered ADD instruction will invalidate the cache for all following instructions from the Dockerfile if the contents of have changed. This includes invalidating the cache for RUN instructions.

    ADD的文件变了,则后面所有指令的cache全部失效
    另外leverage-build-cache有说到

    For the ADD and COPY instructions, the contents of the file(s) in the image are examined and a checksum is calculated for each file. The last-modified and last-accessed times of the file(s) are not considered in these checksums. During the cache lookup, the checksum is compared against the checksum in the existing images. If anything has changed in the file(s), such as the contents and metadata, then the cache is invalidated.

    COPYADD应该是一样的,即COPY的文件变了,则后面所有指令(包括RUN)的cache全部失效.这就解释了RUN go get -t -d -v ./...没用layer cache的原因:只要有文件不一样,即使后面RUN指令没变,layer cache仍然失效.

    go module

    Go从1.11开始支持go modules,可以参考跳出Go module的泥潭.go module会将所需的依赖及其版本号记录在go.mod文件,并且会生成一个go.sum记录每个依赖库的版本和哈希值,使用go mod download可以下载所需要的依赖。这样就可以

    FROM golang:1.12.5-alpine
    
    ENV GO111MODULE=on
    COPY go.mod .
    COPY go.sum .
    RUN go mod download
    
    COPY . .
    ....
    

    将go.mod和go.sum单独COPY,以保证代码其他部分(除开go.mod,go.sum文件)有改变时,不会影响代码的依赖部分,RUN go mod download还是能用layer cache.

    类似的操作,还有gitlab CI/CD优化中提到的缓存npm依赖

    FROM node:alpine
    WORKDIR /blog
    
    ADD package.json /tmp/package.json
    RUN cd /tmp && npm install --only=production \
        && cp -a /tmp/node_modules /blog
    
    ADD . /blog
    
    RUN ./node_modules/.bin/gulp --gulpfile gulpfile-prod.js \
        && mv html/index.html . \
        && rm -r node_modules src package* gulpfile* /tmp
    

    不定期更新