Dockerfile
1.基本结构
Dockerfile由一行行命令语句组成,并支持以#
开头的注释行,如:
# This dockerfile uses the ubuntu image
# base image to use, set as the first line
FROM ubuntu:18.04
# maintainer info, username<email address>
MAINTAINER daviswen<daviswen@docker.com>
# commands to update the image
RUN echo "it's a dockerfile print..."
# if RUN cmd followed by several cmd, please merge to one RUN
# cmd, and seperate with ";" or "&&"
RUN echo "1st print" && echo "2nd print"
# cmds when creating a new container
CMD /usr/sbin/nginx
其中,
- FROM, 开始必须指定基于镜像的名称
- MAINTAINER, 维护者的信息
- RUN, 镜像的操作指令,对镜像执行跟随的命令,每运行RUN,镜像就增加一层,并commit
- CMD, 指定运行容器的操作命令
接下来先来看看来自docker hub上的热门Dockerfile
基于buildpack-deps:jessie-scm基础镜像,制作一个GO语言的运行环境
FROM buildpack-deps:jessie-scm
# gcc fo cgo
RUN apt-get update && apt-get install -y --no-install-recommends g++ gcc libc6-dev make && rm -rf /var/lib/apt/lists*
ENV GOLANG_VERSION 1.6.3
ENV GOLANG_DOWNLOAD_RUL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
ENV GOLANG_DOWNLOAD_SHA256 cdd5e08530c0579255d6153b08fdb3b8e47caabbe717bc7bcd7561275a87aeb
RUN curl -fssL "$GOLANG_DOWNLOAD_RUL" -o golang.tar.gz && \
echo "$GOLANG_DOWNLOAD_SHA256 golang.tar.gz" | sha256sum -c - && tar -C /usr/local -xzf golang.tar.gz && rm golang.tar.gz
ENV GOPATH $GOPATH/bin:/usr/local/go/bin:$PATH
RUN mkdir -p "$GOPATH/bin" && chmod -R 777 "$GOPATH"
WORKDIR $GOPATH
COPY go-wrapper /usr/local/bin
2.指令说明
指令的一般格式为 INSTRUNCTION args, 指令包括FROM,MAINTAINER,RUN等,具体指令说明如下:
2.1 FROM
指定所创建镜像的基础镜像
指定所创建的镜像的基础镜像,如果本地不存在,则默认会去Docker Hub下载指定镜像。
格式为:FROM,或FROM:,或FROM@
任何Dockerfile中的第一条指令必须为FROM指令。并且,如果在同一个Dockerfile文件中创建多个镜像,可以使用多个FROM指令(每个镜像一次)。
2.2 MAINTAINER
指定维护者信息
e.g. MAINTAINER image_creator@docker.com
该信息将会写入生成镜像的Author属性域中。
2.3 RUN
运行命令,尽量合并层级
运行指定命令。
格式为:RUN或RUN [“executable”,“param1”,“param2”]
注意:
后一个指令会被解析为json数组,所以必须使用双引号。
前者默认将在shell终端中运行命令,即/bin/sh -c;后者则使用exec执行,不会启动shell环境。
指定使用其他终端类型可以通过第二种方式实现,例如:
RUN ["/bin/bash","-c",“echo hello”]
每条RUN指令将在当前镜像的基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用\换行。
例如:
RUN apt-get update && apt-get install -y libsnappy-dev zliblg-dev libbz2-dev && rm -rf /var/cache/apt
2.4 CMD
指定启动容器时默认执行的命令,多个CMD只执行最后一个,有多个,可合并
支持三种格式:
1.CMD ["executable","param1","param2"] 使用exec执行,是推荐使用的方式;
2.CMD param1 param2 在/bin/sh中执行,提供给需要交互的应用;
3.CMD ["param1","param2"] 提供给ENTRYPOINT的默认参数。
每个Dockerfile只能有一条CMD命令。如果指定了多条命令,只有最后一条会被执行。入股用户启动容器时指定了运行的命令(作为run的参数),则会覆盖掉CMD指定的命令。
2.5 LABEL
指定生成镜像的元数据标签信息
例如:
LABEL version="1.0"
2.6 EXPOSE
声明镜像内服务所监听的端口
格式为:EXPOSE […]
例如:
EXPOSE 22 80 443 3306
注意:
该命令只是起到声明,并不会自动完成端口映射。
在容器启动时需要使用-P(大写P),Docker主机会自动分配一个宿主机未被使用的临时端口转发到指定的端口;使用-p(小写p),则可以具体指定哪个宿主机的本地端口映射过来。
2.7 ENV
指定环境变量
在镜像生成过程中会被后续RUN指令使用,在镜像启动的容器中也会存在。
格式为:ENV 或ENV=…。
例如:
ENV GOLANG_VERSION 1.6.3
ENV GOLANG_DOWNLOAD_RUL https://golang.org/dl/go$GOLANG_VERSION.linux-amd64.tar.gz
ENV GOLANG_DOWNLOAD_SHA256 cdd5e08530c0579255d6153b08fdb3b8e47caabbe717bc7bcd7561275a87aeb
RUN curl -fssL "$GOLANG_DOWNLOAD_RUL" -o golang.tar.gz
另一种写法:
ENV GOLANG_VERSION=1.6.3
指令指定的环境变量在运行时可以被覆盖掉,如docker run --env = built_image。
2.8 ADD
复制指定的路径下的内容到容器中的路径下,可以为URL;如果为tar文件,会自动解压到路径下
ADD *.c /code/
ADD app.tar.gz /app/app
# ADD <src> <dest>
# src部分是是你Dockerfile的相对路径
2.9 COPY
复制本地主机的路径下的内容到容器中的路径下;一般情况下推荐使用COPY而不是ADD
目标路径不存在时,会自动创建。路径同样支持正则。当使用本地目录为源目录时,推荐使用COPY。
如果COPY的是压缩包不会帮你解压。
2.10 ENTRYPOINT
指定镜像的默认入口
该入口命令会在启动容器时作为根命令执行,所有传入值作为该命令的参数。
支持两种格式:
1.ENTRYPOINT ["executable","param1","param2"] (exec调用执行);
2.ENTRYPOINT command param1 param2(shell中执行)。
此时,CMD指令指定值将作为根命令的参数。
每个Dockerfile中只能有一个ENTRYPOINT,当指定多个时,只有最后一个有效。
在运行时可以被–entrypoint参数覆盖掉,如docker run --entrypoint。
2.11 VOLUME
创建数据挂载点
格式为:
VOLUME ["/data"]
VOLUME ["/data","/data/etc"]
可以从本地主机或者其他容器挂载数据卷,一般用来存放数据库
和需要保存的数据
等。
在启动容器的时候Docker会在/var/lib/docker/
的下一级目录下创建一个卷,以保存你在容器中产生的数据。若没有申明则不会创建。(可以把此指令看成shell中的mkdir)此指令不是独立数据卷,数据会随着容器的停止而消失,如果想数据持久化,请参考docker 简单命令 在run启动容器是加-V 参数!
2.12 USER
指定运行容器时的用户名或UID
后续的RUN等指令也会使用特定的用户身份。
格式为:USER daemon
当服务不需要管理员权限时,可以通过该指令指定运行用户,并且可以在之前创建所需要的用户。例如:
RUN groupadd -r nginx && useradd -r -g nginx nginx
要临时获取管理员权限可以用gosu或者sudo。
2.13 WORKDIR
配置工作目录
为后续的RUN、CMD和ENTRYPOINT指令配置工作目录。
格式为:WORKDIR /path/to/workdir。
可以使用多个WORKDIR指令,后续命令如果参数是相对的,则会基于之前命令指定的路径,可以理解为shell的cd。例如:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
# 最终路径为/a/b/c
2.14 ARG
指定镜像内使用的参数(例如版本号信息等)
这些参数在执行docker build命令时才以–build-arg=格式传入。
格式为:ARG[=]。
则可以用docker build --build-arg=来指定参数值。
2.15 ONBUILD
配置当前所创建的镜像作为其他镜像的基础镜像时,所执行的创建操作的命令
格式为:ONBUILD [INSTRUCTION]。
例如Dockerfile使用如下的内容创建了镜像image-A:
[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]
如果基于image-A镜像创建新的镜像时,新的Dockerfile中使用FROM image-A指定基础镜像,会自动执行ONBUILD指令的内容,等价于在后面添加了两条指令:
FROM image-A
# Automatically run the following
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
使用ONBUILD指令的镜像,推荐在标签中注明,例如:ruby:1.9-onbuild。
2.16 STOPSIGNAL
容器退出的信号
例如:
STOPSIGNAL singnal
2.17 HEALTHCHECK
如何进行健康检查
格式有两种:
1.HEALTHCHECK [OPTIONS] CMD command :根据所执行命令返回值是否为0判断;
2.HEALTHCHECK NONE :禁止基础镜像中的健康检查。
2.18 SHELL
指定使用SHELL时的默认SHELL类型
格式为: SHELL [“executable”,“parameters”]
默认值为 [“bin/sh”,"-c"]。
3.创建镜像
编写Dockerfile之后,可以通过docker build
命令来创建镜像。
基本的docker build [选项] 内容路径
,该命令将读取指定路径下(包括子目录)的Dockerfile,并将该路径下的所有内容发送给Docker服务端,由服务端来创建镜像。因此除非生成镜像需要,否则一般建议放置Dockerfile的目录为空目录。
1.如果使用非内容路径下的Dockerfile,可以通过-f选项来指定其路径;
2.要指定生成镜像的标签信息,可以使用-t选项。
例如:指定Dockerfile所在路径为 /tmp/docker_builder/,并且希望生成镜像标签为build_repo/first_image,可以使用下面的命令:
docker build -t build_repo/first_image /tmp/docker_builder
4.其他tips
4.1 使用 .dockerignore文件
以通过 .dockeringore文件(每一行添加一条匹配模式)来让Docker忽略匹配模式路径下的目录和文件。例如:
# comment
*/tmp*
*/*/tmp*
tmp?
~*
4.2 Dockerfile编写小结
从需求出发,定制适合自己需求、高效方便的镜像,可以参考他人优秀的Dockerfile文件,在构建中慢慢优化Dockerfile文件:
1.精简镜像用途: 尽量让每个镜像的用途都比较集中、单一,避免构造大而复杂、多功能的镜像;
2.选用合适的基础镜像: 过大的基础镜像会造成构建出臃肿的镜像,一般推荐比较小巧的镜像作为基础镜像;
3.提供详细的注释和维护者信息: Dockerfile也是一种代码,需要考虑方便后续扩展和他人使用;
4.正确使用版本号: 使用明确的具体数字信息的版本号信息,而非latest,可以避免无法确认具体版本号,统一环境;
5.减少镜像层数: 减少镜像层数建议尽量合并RUN指令,可以将多条RUN指令的内容通过&&连接;
6.及时删除临时和缓存文件: 这样可以避免构造的镜像过于臃肿,并且这些缓存文件并没有实际用途;
7.提高生产速度: 合理使用缓存、减少目录下的使用文件,使用.dockeringore文件等;
8.调整合理的指令顺序: 在开启缓存的情况下,内容不变的指令尽量放在前面,这样可以提高指令的复用性;
9.减少外部源的干扰: 如果确实要从外部引入数据,需要制定持久的地址,并带有版本信息,让他人可以重复使用而不出错
5.启动Dockerfile创建新镜像
在编写好Dockerfile
文件后,我们可以通过docker build
命令来创建新的镜像。通常我们在某个文件夹下放置 Dockerfile
文件,进入当前的文件夹:
# docker build .
# "."表示在当前目录下读取Dockerfile文件信息
或者,我们也可以指定新镜像及tag标签信息,使用 -t 参数
# docker build -t newImage:tag dockerfile_path
# 指定绝对或相对路径
以我用Dockerfile创建镜像为例:
整理自:https://blog.csdn.net/weixin_43551152/article/details/85702315