目录

    1. 分阶段构建

    编译项目需要借助一系列特定的工具,但在运行阶段并不需要这些工具。为了减小镜像体积,可以分阶段构建。在第一阶段进行构建,然后将编译生成的文件传入下一个阶段,生成更小体积的镜像。

    FROM golang:1.12 as builder
    
    COPY / /go/src/github.com/shaowenchen/goproject
    
    WORKDIR /go/src/github.com/shaowenchen/goproject
    RUN CGO_ENABLED=0 GO111MODULE=on GOOS=linux GOARCH=amd64 GOFLAGS=-mod=vendor go build -i -ldflags '-w -s' -o myserver cmd/myserver/apiserver.go
    
    FROM alpine:3.9
    RUN apk add --update ca-certificates && update-ca-certificates
    COPY --from=builder /go/src/github.com/shaowenchen/goproject/myserver /usr/local/bin/
    CMD ["sh"]
    

    上面是一个编译 Go 工程镜像的 Dockerfile 文件。很多项目选择 alpine 作为基础镜像。但是,如果项目使用到系统的某些库,基础镜像不能随意选择。

    2. 利用缓存构建

    Docker 镜像是分层的结构,最多 127 层。除了 FROM 命令,Dockerfile 中其他命令都会生成一个新的镜像层。在构建过程中,如果发现命令将产生的镜像层与之前的一样,则会使用缓存复用。

    为了利用缓存加速构建过程,可以将静态和配置命令放在前面,而将经常变化的内容放在后面。

    FROM stackaero/nodejs-pm2-slim:1.1.5
    WORKDIR /app
    COPY package.json /app/
    RUN npm install
    COPY . /app/
    CMD pm2 start ./index.js --no-daemon >> /dev/null
    

    由于项目工程代码每次构建时,总会发生变化,应该尽量放在底部;依赖包不会经常发生变化,放在上面可以充分利用缓存。

    使用下面的构建命令,可以禁用缓存:

    docker build --no-cache
    

    3. 使用 S2I 打包应用

    相对于使用缓存优化构建速度,更加简单的方式是,使用 S2I 打包应用,增加一层镜像即可。

    参考链接:使用 S2I 构建云原生应用

    没有被 S2I 支持的语言或框架也没关系,我们可以将应用所需的基础环境打包成基础镜像,然后再进行构建。

    4. .dockerignore 文件

    Docker 以 C/S 模型进行工作,在执行构建时,会将所需的文件发送到 Docker Daemon 。有些很大、构建用不上的文件,会占用传输时间,我们可以定义 .dockerignore 忽略这些文件,就像 .gitignore 一样。

    .dockerignore 文件

    .git
    

    Dockerfile 文件

    FROM golang:1.12 as builder
    
    COPY / /go/src/github.com/shaowenchen/goproject
    

    上面的例子,COPY 时会忽略 .git 目录。

    5. 将容器保存为镜像

    在学习 Docker 时,经常会被教育不要在容器中做任何修改。这句话没错,遵循不可变的基础设施。

    除了打包镜像,我们会直接进入容器进行调试。有时因为历史原因,找不到镜像或 Dockerfile 文件,需要将容器保存为镜像。

    执行 docker commit 命令,可以将 ContainerID 保存为 shaowenchen/myimage:latest 镜像。

    docker commit ContainerID  shaowenchen/myimage:latest