不要安装无效软件包。
应简化镜像中同时运行的进程数,理想状况下,每个镜像应该只有一个进程。
当无法避免同一镜像运行多进程时,应选择合理的初始化进程(initprocess)。
最小化层级数
把多行参数按字母排序,可以减少可能出现的重复参数,并且提高可读性。
编写dockerfile的时候,应该把变更频率低的编译指令优先构建以便放在镜像底层以有效利用buildcache。
复制文件时,每个文件应独立复制,这确保某个文件变更时,只影响改文件对应的缓存。
Dockerfile 可以看成构建镜像的一条条指令, 结合 docker 镜像打包理解, 一条指令大多对应一层, 追求共用层
层的概念:
$ docker build [选项] <上下文路径/URL/->
通过 docker build 构建镜像会自动扫描 Dockerfile 及其目录下的子目录, 通常将 Dockerfile 置于项目根目录, 如果文件文件过多, 镜像过程也会变慢
指定镜像, 默认从 docker hub 上拉去
用于为镜像添加元数据
格式: LABEL <key>=<value> <key>=<value> <key>=<value> ...
配合 label filter 进行过滤
$ docker images -f label=multi.label1="value1"
注:
使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据
之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。
设置环境变量
构建镜像时执行的命令
格式:
RUN ["executable", "param1", "param2"]
示例:
RUN ["executable", "param1", "param2"]
RUN apk update
RUN ["/etc/execfile", "arg1", "arg1"]
注:RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,
可以在构建时指定–no-cache参数,如:docker build --no-cache
构建镜像后调用,也就是在容器启动时才进行调用。
格式:
CMD ["executable","param1","param2"] (执行可执行文件,优先)
CMD ["param1","param2"] (设置了ENTRYPOINT,则直接调用ENTRYPOINT添加参数)
CMD command param1 param2 (执行shell内部命令)
示例:
CMD echo "This is a test." | wc -l
CMD ["/usr/bin/wc","--help"]
注:CMD不同于RUN,CMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。
镜像的第一个进程
格式:
ENTRYPOINT ["executable", "param1", "param2"] (可执行文件, 优先)
ENTRYPOINT command param1 param2 (shell内部命令)
示例:
FROM ubuntu
ENTRYPOINT ["ls", "/usr/local"]
CMD ["/usr/local/tomcat"]
之后,docker run 传递的参数,都会先覆盖cmd,然后由cmd 传递给entrypoint ,做到灵活应用
注:ENTRYPOINT与CMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,
而docker run命令中指定的任何参数,都会被当做参数再次传递给CMD。
Dockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,
而只执行最后的ENTRYPOINT指令。
通常情况下, ENTRYPOINT 与CMD一起使用,ENTRYPOINT 写默认命令,当需要参数时候 使用CMD传参
工作目录,类似于cd命令
将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget
格式:
ADD <src>... <dest>
ADD ["<src>",... "<dest>"] 用于支持包含空格的路径
示例:
ADD hom* /mydir/ # 添加所有以"hom"开头的文件
ADD hom?.txt /mydir/ # ? 替代一个单字符,例如:"home.txt"
ADD test relativeDir/ # 添加 "test" 到 `WORKDIR`/relativeDir/
ADD test /absoluteDir/ # 添加 "test" 到 /absoluteDir/
与 ADD 相似, 但不能访问网络资源, 也不能解压, 以 ADD 相比, 行为简单, 因此可控, 推荐使用
挂载
VOLUME ["/path/to/dir"]
示例:
VOLUME ["/data"]
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"
注:一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
暴露端口
EXPOSE <port> [<port>...]
注:EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口
如果没有暴露端口,后期也可以通过-p 8080:80方式映射端口,但是不能通过-P形式映射
指定运行容器的用户/组, 不指定默认 root, 指定的 Dockerfile 中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户, 增强容器的安全性考虑, 做到 POLP(最小特权原则)。
注: 镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。
用于指定传递给构建运行时的变量(给dockerfile传参),相当于构建镜像时可以在外部为里面传参
From centos:7
ARG parameter
VOLUME /usr/share/nginx
RUN yum -y install $parameter
EXPOSE 80 443
CMD nginx -g "daemon off;"
# 可以这如下这样灵活传参
docker build --build-arg=parameter=net-tools -t nginx:01 .
# Base images 基础镜像
FROM centos
#MAINTAINER 维护者信息
MAINTAINER Ai-feier
#ENV 设置环境变量
ENV PATH /usr/local/nginx/sbin:$PATH
#ADD 文件放在当前目录下,拷过去会自动解压
ADD nginx-1.8.0.tar.gz /usr/local/
ADD epel-release-latest-7.noarch.rpm /usr/local/
#RUN 执行以下命令
RUN rpm -ivh /usr/local/epel-release-latest-7.noarch.rpm
RUN yum install -y wget lftp gcc gcc-c++ make openssl-devel pcre-devel pcre && yum clean all
RUN useradd -s /sbin/nologin -M www
#WORKDIR 相当于cd
WORKDIR /usr/local/nginx-1.8.0
RUN ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-pcre && make && make install
RUN echo "daemon off;" >> /etc/nginx.conf
#EXPOSE 映射端口
EXPOSE 80
#CMD 运行以下命令
CMD ["nginx"]
# Base images 基础镜像
FROM ubuntu
RUN apt-get update && apt-get install nginx -y && apt-get clean
CMD ["nginx"]
FROM openjdk:8-jre # jar包基于jdk ,war包基于tomcat
WORKDIR /app
ADD demo-0.0.1-SNAPSHOT.jar app.jar # 将上下文中 jar包复制到 /app目录下,并且重命名为app.jar
EXPOSE 8081 # 暴露端口
ENTRYPOINT[ "java" , "-jar" ] # 启动应用固定命令
CMD ["app.jar"] # 动态传递jar包名
# CMD ["/bin/sh","-c","java -jar app.jar"]
在 k8s 优雅终止时, 会发送 terminal 信号, 给应用进行优雅终止, 但是, /bin/sh 会无视这个信号, 最后直接被 kill 掉
目的: 将项目编译, 依赖等, 放到 Dockerfile 的早期构建, 最后留下一个干净的镜像, 有效减少镜像层级
示例:
FROM golang:1.16-alpine AS build
RUN apkadd --no-cache git
RUN go get github.com/golang/dep/cmd/dep
COPY Gopkg.lock Gopkg.toml /go/src/project/
WORKDIR /go/src/project/
RUN dep ensure -vendor-only
COPY . /go/src/project/
RUN go build -o /bin/project(只有这个二进制文件是产线需要的,其他都是waste)
FROM scratch
# 直接把镜像编译的包拷贝下来
COPY --from=build /bin/project /bin/project
ENTRYPOINT ["/bin/project"]
CMD ["--help"]