dockerfile

简介

Dockerfile 是由一系列命令和参数构成的脚本,这些命令应用于操作系统基础镜像并最终创建的一个新镜像;

生产实践中一定优先使用 Dockerfile 的方式构建镜像。

基础镜像体积应该尽量小

尽量减少 Dockerfile 的行数,因为 Dockerfile 的每一条指令都会生成一个镜像层。

Dockerfile 书写原则

  1. 单一职责:由于容器的本质是进程,一个容器代表一个进程,因此不同功能的应用应该尽量拆分为不同的容器,每个容器只负责单一业务进程。

  2. 提供注释信息:Dockerfile 也是一种代码,我们应该保持良好的代码编写习惯,晦涩难懂的代码尽量添加注释,让协作者可以一目了然地知道每一行代码的作用,并且方便扩展和使用。

  3. 保持容器最小化:应该避免安装无用的软件包,可以加快容器构建速度,而且可以避免镜像体积过大。

  4. 合理选择基础镜 :容器的核心是应用,因此只要基础镜像能够满足应用的运行环境即可

  5. 使用 .dockerignore 文件 : 使用 .dockerignore 在构建时,忽略一些不需要参与构建的文件,从而提升构建效率。

  6. 尽量使用构建缓存 :Docker 构建过程中,每一条 Dockerfile 指令都会提交为一个镜像层,下一条指令都是基于上一条指令构建的。如果构建时发现要构建的镜像层的父镜像层已经存在,并且下一条命令使用了相同的指令,即可命中构建缓存。

  1. 正确设置时区: 从 Docker Hub 拉取的官方操作系统镜像大多数都是 UTC 时间 , 也可以运行时指定 -e TZ=Asia/Shanghai
1
2
3
4
5
6
# Debian
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo "Asia/Shanghai" >> /etc/timezone

# centos
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
  1. 使用国内软件源加快镜像构建速度: 最好的方式是换源
  1. 最小化镜像层数

常用命令

FROM image:tag : 使用的基础镜像构建
MAINTAINER user_info : 声明镜像维护者信息
LABEL value : 镜像描述元信息 (可以多条)
ENV key value : 设置环境变量 (可以多条)
RUN command : 构建镜像时需要运行的命令 (可以多条)
WORKDIR path_dir : 设置终端默认登录进来的工作目录
EXPOSE port : 当前容器对外暴露出的端口
ADD source_dir/file dest_dir/file : 宿主机内文件复制到容器,压缩文件会解压,也可以获取远程文件
COPY source_dir/file dest_dir/file : 宿主机内文件复制到容器,不过压缩文件不解压
VOLUME : 创建一个 可以从本机或其他容器挂载的挂载点,一般用来存放数据库和需要保存的数据
CMD : 指定容器启动时要运行的命令,多个CMD,最后一个生效 CMD 或CMD [““,”“,”“,…] CMD [““,”“,…]
ENTRYPOINT : 指定容器启动时要运行的命令,最后一个才有用
ONBUILD : 为子镜像服务

示例

简单实例:父镜像 Dockerfile:

1
2
3
4
5
6
FROM centos
ONBUILD RUN yum -y install vim
CMD /bin/bash

子镜像简单点:
FROM parent

Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM centos
MAINTAINER weilai<[email protected]>

LABEL name="imwl CentOS Image" \
build-date="20180916"

ENV WORKPATH /home/
WORKDIR $WORKPATH

RUN yum -y install net-tools
RUN yum -y install vim

EXPOSE 80
CMD /bin/bash

多阶构建

多阶段构建可以通过一个 Dockerfile 很方便地构建出体积更小的镜像,只需要编写 Dockerfile 文件即可,无须借助外部脚本文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 编译代码
FROM golang:1.13
WORKDIR /go/src/github.com/wilhelmguo/multi-stage-demo/
COPY main.go .
RUN CGO_ENABLED=0 GOOS=linux go build -o http-server .

# 构建运行时镜像
FROM alpine:latest
WORKDIR /root/

# 使用 COPY 指令拷贝编译后的文件到 alpine 镜像中, --from=0 表示从第一阶段构建结果中拷贝文件到当前构建阶段
COPY --from=0 /go/src/github.com/wilhelmguo/multi-stage-demo/http-server .

CMD ["./http-server"]

与上面的效果一样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM golang:1.13 AS builder  # 使用 AS 指令将这个阶段命名为 builder
WORKDIR /go/src/github.com/wilhelmguo/multi-stage-demo/
COPY main.go .
RUN CGO_ENABLED=0 GOOS=linux go build -o http-server .


FROM alpine:latest
WORKDIR /root/

# 可以使用 --from=builder,使得 Dockerfile 更加清晰可读
COPY --from=builder /go/src/github.com/wilhelmguo/multi-stage-demo/http-server .

# COPY --from=nginx:latest /etc/nginx/nginx.conf /etc/local/nginx.conf # 拷贝 nginx 官方镜像的配置文件到我们自己的镜像中时
CMD ["./http-server"]

在执行 docker build 命令时添加 target 参数,可以将构建阶段停止在指定阶段

1
docker build --target builder -t http-server:latest .

补充说明

cmdENTRYPOINT

CMDENTRYPOINT 的基本使用格式分为两种:

第一种为 CMD/ENTRYPOINT["command" , "param"] 。这种格式是使用 Linuxexec 实现的, 一般称为 exec 模式,这种书写格式为CMD/ENTRYPOINT 后面跟 json 数组,也是 Docker 推荐的使用格式。

另外一种格式为 CMD/ENTRYPOINT command param ,这种格式是基于 shell 实现的, 通常称为 shell 模式。当使用 shell 模式时,Docker 会以 /bin/sh -c command 的方式执行命令.

Dockerfile 中如果使用了 ENTRYPOINT 指令,启动 Docker 容器时需要使用 --entrypoint 参数才能覆盖 Dockerfile 中的 ENTRYPOINT 指令 ,而使用 CMD 设置的命令则可以被 docker run 后面的参数直接覆盖。

ENTRYPOINT 指令可以结合 CMD 指令使用,也可以单独使用,而 CMD 指令只能单独使用