Dockfile

发布时间:2024年01月20日

1 常用指令

以Tomcat 的dockerfile 为例

#
# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh"
#
# PLEASE DO NOT EDIT IT DIRECTLY.
#

FROM eclipse-temurin:8-jre-focal

ENV CATALINA_HOME /usr/local/tomcat
ENV PATH $CATALINA_HOME/bin:$PATH
RUN mkdir -p "$CATALINA_HOME"
WORKDIR $CATALINA_HOME

# let "Tomcat Native" live somewhere isolated
ENV TOMCAT_NATIVE_LIBDIR $CATALINA_HOME/native-jni-lib
ENV LD_LIBRARY_PATH ${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$TOMCAT_NATIVE_LIBDIR

# see https://www.apache.org/dist/tomcat/tomcat-8/KEYS
# see also "versions.sh" (https://github.com/docker-library/tomcat/blob/master/versions.sh)
ENV GPG_KEYS 05AB33110949707C93A279E3D3EFE6B686867BA6 07E48665A34DCAFAE522E5E6266191C37C037D42 47309207D818FFD8DCD3F83F1931D684307A10A5 541FBE7D8F78B25E055DDEE13C370389288584E7 5C3C5F3E314C866292F359A8F3AD5C94A67F707E 765908099ACF92702C7D949BFA0C35EA8AA299F1 79F7026C690BAA50B92CD8B66A3AD3F4F22C4FED 9BA44C2621385CB966EBA586F72C284D731FABEE A27677289986DB50844682F8ACB77FC2E86E29AC A9C5DF4D22E99998D9875A5110C01C5A2F6059E7 DCFD35E0BF8CA7344752DE8B6FB21E8933C60243 F3A04C595DB5B6A5F1ECA43E3B7BBB100D811BBE F7DA48BB64BCB84ECBA7EE6935CD23C10D498E23

ENV TOMCAT_MAJOR 8
ENV TOMCAT_VERSION 8.5.98
ENV TOMCAT_SHA512 12f58114fe608fdc5f06e99a4ba01852396169f89d08e1ecf96ace36dd685c439519433e7750bfa7523f12c14788a3b5cb9ee3835dd1cce37e2cee121d69625e

COPY --from=tomcat:8.5.98-jdk8-temurin-focal $CATALINA_HOME $CATALINA_HOME
RUN set -eux; \
	apt-get update; \
	xargs -rt apt-get install -y --no-install-recommends < "$TOMCAT_NATIVE_LIBDIR/.dependencies.txt"; \
	rm -rf /var/lib/apt/lists/*

# verify Tomcat Native is working properly
RUN set -eux; \
	nativeLines="$(catalina.sh configtest 2>&1)"; \
	nativeLines="$(echo "$nativeLines" | grep 'Apache Tomcat Native')"; \
	nativeLines="$(echo "$nativeLines" | sort -u)"; \
	if ! echo "$nativeLines" | grep -E 'INFO: Loaded( APR based)? Apache Tomcat Native library' >&2; then \
		echo >&2 "$nativeLines"; \
		exit 1; \
	fi

EXPOSE 8080

# upstream eclipse-temurin-provided entrypoint script caused https://github.com/docker-library/tomcat/issues/77 to come back as https://github.com/docker-library/tomcat/issues/302; use "/entrypoint.sh" at your own risk
ENTRYPOINT []

CMD ["catalina.sh", "run"]

1.1 FROM

基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from

1.2 MAINTAINER镜像维护者的姓名和邮箱地址

格式 MAINTAINER name<邮箱地址>

1.3 RUN

容器构建时需要运行的命令 即执行docker build 构建容器时执行
两种模式

  • shell模式 ,RUN command param1 param2…,这种格式是基于 shell 实现的, 通常称为shell模式。当使用shell模式时,Docker 会以 /bin/sh -c command 的方式执行命令。
  • exec 模式, [“command” , “param1”, “param2” …] 这种格式是使用 Linux 的exec实现的, 一般称为exec模式,这种书写格式为RUN 后边加 []

1.4 EXPOSE

当前容器对外暴露出的端口

1.5 WORKDIR

指定在创建容器后,终端默认登陆的进来工作目录
如创建tomcat 容器后,进入容器时的当前目录 即为WORKDIR指定的目录

$ docker run -d tomcat:latest
#容器内部
$ pwd
/usr/local/tomcat

1.6 USER

指定该镜像以什么样的用户去执行,如果都不指定,默认是root,一般不需要指定

1.7 ENV

用来在构建镜像过程中设置环境变量
这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样
也可以在其它指令中直接使用这些环境变量,
注意引起环境变量前加$
-参考TOMCAT的环境变量定义

ENV CATALINA_HOME /usr/local/tomcat
ENV PATH $CATALINA_HOME/bin:$PATH
RUN mkdir -p "$CATALINA_HOME"
WORKDIR $CATALINA_HOME

1.8 VOLUME

容器数据卷,用于数据保存和持久化工作, 相当于 docker run -v

1.9 ADD COPY

ADD和COPY指令功能类似,都是从外部往容器内添加文件

  • ADD 将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
  • COPY 类似ADD,拷贝文件和目录到镜像中。COPY指令只支持基本的文件和文件夹拷贝功能.
    将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置

更推荐使用COPY指令,因为COPY指令更加透明,仅支持本地文件向容器拷贝,而且使用COPY指令可以更好地利用构建缓存,有效减小镜像体积。
当你想要使用ADD向容器中添加 URL 文件时,请尽量考虑使用其他方式替代。例如你想要在容器中安装 memtester(一种内存压测工具),你应该避免使用以下格式:

ADD http://pyropus.ca/software/memtester/old-versions/memtester-4.3.0.tar.gz /tmp/
RUN tar -xvf /tmp/memtester-4.3.0.tar.gz -C /tmp
RUN make -C /tmp/memtester-4.3.0 && make -C /tmp/memtester-4.3.0 install

下面是推荐写法:

RUN wget -O /tmp/memtester-4.3.0.tar.gz http://pyropus.ca/software/memtester/old-versions/memtester-4.3.0.tar.gz \
&& tar -xvf /tmp/memtester-4.3.0.tar.gz -C /tmp \
&& make -C /tmp/memtester-4.3.0 && make -C /tmp/memtester-4.3.0 install

1.10 CMD 和 ENTRYPOINT

CMD和ENTRYPOINT指令都是容器启动后需要运行的指令。

  1. 这两个指令的相同之处,CMD和ENTRYPOINT的基本使用格式分为两种。
  • 第一种为CMD/ENTRYPOINT [“command” , “param1”, “param2” …] 这种格式是使用 Linux 的exec实现的, 一般称为exec模式,这种书写格式为CMD/ENTRYPOINT 后边加 [],也是Docker 推荐的使用格式。
  • 另外一种格式为CMD/ENTRYPOINT command param1 param2…,这种格式是基于 shell 实现的, 通常称为shell模式。当使用shell模式时,Docker 会以 /bin/sh -c command 的方式执行命令。

使用 exec 模式启动容器时,容器的 1 号进程就是 CMD/ENTRYPOINT 中指定的命令,而使用 shell模式启动容器时相当于我们把启动命令放在了 shell 进程中执行,等效于执行 /bin/sh -c “task command” 命令。因此 shell 模式启动的进程在容器中实际上并不是 1 号进程。

  1. 两个指令的区别
  • CMD
    Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
    tomcat 的Dockerfile为例,其最后一个指令 “CMD [“catalina.sh”, “run”]”,如果在启动容器是这样写“docker run -it -p 8080:8080 tomcat:8.5 /bin/bash”,此时 最后一个CMD 变为了 容器启动时的 “/bin/bash” (相当于 “CMD [“/bin/bash”,“run”]),此时你会发现容器虽然启动了,但里边的tomcat并没有启动,因为指令 “CMD [“catalina.sh”, “run”]”并没有执行,而是执行了 启动时设置的指令
  • ENTRYPOINT 不会被docker run 后面的命令覆盖
  • 如果既有ENTRYPOINT 也有CMD(包括docker run 后边的命令),CMD命令行参数会被当作 ENTRYPOINT 指令的参数,即相当于 ENTRYPOINT [entrypoint参数,CMD带的参数]
    假设已通过 Dockerfile 构建了 nginx:test 镜像:

FROM nginx
ENTRYPOINT [nginx",“-c”] # 定参
CMD [”/etc/nginx/nginx.conf"] # 变参

是否传参按照dockerfile编写执行dokcer run 传参运行
Docker命令docker run nginx:testdocker run nginx:test -c /etc/nginx/new.conf
衍生出的实际命令nginx -c /etc/nginx/nginx.confnginx -c /etc/nginx/new.conf(docker run 带的参数new.conf 替换 docker file 中的 nginx.conf)

2 Dockerfile 书写原则

  1. 单一职责
    由于容器的本质是进程,一个容器代表一个进程,因此不同功能的应用应该尽量拆分为不同的容器,每个容器只负责单一业务进程。
  2. 提供注释信息
    Dockerfile 也是一种代码,我们应该保持良好的代码编写习惯,晦涩难懂的代码尽量添加注释,让协作者可以一目了然地知道每一行代码的作用,并且方便扩展和使用。
  3. 保持容器最小化
    应该避免安装无用的软件包,比如在一个 nginx 镜像中,我并不需要安装 vim 、gcc 等开发编译工具。这样不仅可以加快容器构建速度,而且可以避免镜像体积过大。
  4. 合理选择基础镜像
    容器的核心是应用,因此只要基础镜像能够满足应用的运行环境即可。例如一个Java类型的应用运行时只需要JRE,并不需要JDK,因此我们的基础镜像只需要安装JRE环境即可。
  5. 使用 .dockerignore 文件
    在使用git时,我们可以使用.gitignore文件忽略一些不需要做版本管理的文件。同理,使用.dockerignore文件允许我们在构建时,忽略一些不需要参与构建的文件,从而提升构建效率。.dockerignore的定义类似于.gitignore。
    .dockerignore的本质是文本文件,Docker 构建时可以使用换行符来解析文件定义,每一行可以忽略一些文件或者文件夹。具体使用方式如下:
规则含义
## 开头的表示注释,# 后面所有内容将会被忽略
/tmp匹配当前目录下任何以 tmp 开头的文件或者文件夹
*.md匹配以 .md 为后缀的任意文件
tem?匹配以 tem 开头并且以任意字符结尾的文件,?代表任意一个字符
!README.md !表示排除忽略。例如 .dockerignore 定义如下:*.md!README.md表示除了 README.md 文件外所有以 .md 结尾的文件。
  1. 尽量使用构建缓存
    Docker 构建过程中,每一条 Dockerfile 指令都会提交为一个镜像层,下一条指令都是基于上一条指令构建的。如果构建时发现要构建的镜像层的父镜像层已经存在,并且下一条命令使用了相同的指令,即可命中构建缓存。

Docker 构建时判断是否需要使用缓存的规则如下:

  • 从当前构建层开始,比较所有的子镜像,检查所有的构建指令是否与当前完全一致,如果不一致,则不使用缓存;
  • 一般情况下,只需要比较构建指令即可判断是否需要使用缓存,但是有些指令除外(例如ADD和COPY);
  • 对于ADD和COPY指令不仅要校验命令是否一致,还要为即将拷贝到容器的文件计算校验和(根据文件内容计算出的一个数值,如果两个文件计算的数值一致,表示两个文件内容一致 ),命令和校验和完全一致,才认为命中缓存。

因此,基于 Docker 构建时的缓存特性,我们可以把不轻易改变的指令放到 Dockerfile 前面(例如安装软件包),而可能经常发生改变的指令放在 Dockerfile 末尾(例如编译应用程序)。

例如,我们想要定义一些环境变量并且安装一些软件包,可以按照如下顺序编写 Dockerfile:

FROM centos:7
# 设置环境变量指令放前面
ENV PATH /usr/local/bin:$PATH
# 安装软件指令放前面
RUN yum install -y make
# 把业务软件的配置,版本等经常变动的步骤放最后
...

按照上面原则编写的 Dockerfile 在构建镜像时,前面步骤命中缓存的概率会增加,可以大大缩短镜像构建时间。

  1. 单一职责正确设置时区
    我们从 Docker Hub 拉取的官方操作系统镜像大多数都是 UTC 时间(世界标准时间)。如果你想要在容器中使用中国区标准时间(东八区),请根据使用的操作系统修改相应的时区信息,下面我介绍几种常用操作系统的修改方式:
  • Ubuntu 和Debian 系统
    Ubuntu 和Debian 系统可以向 Dockerfile 中添加以下指令:
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo "Asia/Shanghai" >> /etc/timezone
  • CentOS系统
    CentOS 系统则向 Dockerfile 中添加以下指令:
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
  1. 使用国内软件源加快镜像构建速度
    由于我们常用的官方操作系统镜像基本都是国外的,软件服务器大部分也在国外,所以我们构建镜像的时候想要安装一些软件包可能会非常慢。

这里我以 CentOS 7 为例,介绍一下如何使用 163 软件源(国内有很多大厂,例如阿里、腾讯、网易等公司都免费提供的软件加速源)加快镜像构建。

首先在容器构建目录创建文件 CentOS7-Base-163.repo,文件内容如下:

# CentOS-Base.repo
#
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client.  You should use this for CentOS updates
# unless you are manually picking other mirrors.
#
# If the mirrorlist= does not work for you, as a fall back you can try the 
# remarked out baseurl= line instead.
#
#
[base]
name=CentOS-$releasever - Base - 163.com
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os
baseurl=http://mirrors.163.com/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=http://mirrors.163.com/centos/RPM-GPG-KEY-CentOS-7
#released updates
[updates]
name=CentOS-$releasever - Updates - 163.com
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates
baseurl=http://mirrors.163.com/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=http://mirrors.163.com/centos/RPM-GPG-KEY-CentOS-7
#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras - 163.com
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras
baseurl=http://mirrors.163.com/centos/$releasever/extras/$basearch/
gpgcheck=1
gpgkey=http://mirrors.163.com/centos/RPM-GPG-KEY-CentOS-7
#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus - 163.com
baseurl=http://mirrors.163.com/centos/$releasever/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.163.com/centos/RPM-GPG-KEY-CentOS-7

然后在 Dockerfile 中添加如下指令:

COPY CentOS7-Base-163.repo /etc/yum.repos.d/CentOS7-Base.repo

执行完上述步骤后,再使用yum install命令安装软件时就会默认从 163 获取软件包,这样可以大大提升构建速度。

  1. 最小化镜像层数
    在构建镜像时尽可能地减少 Dockerfile 指令行数。例如我们要在 CentOS 系统中安装make和net-tools两个软件包,应该在 Dockerfile 中使用以下指令:
RUN yum install -y make net-tools

而不应该写成这样:

RUN yum install -y make
RUN yum install -y net-tools

3 build镜像

格式:

docker build -t 新镜像名字:TAG .

注意后边有个 点

文章来源:https://blog.csdn.net/prcyang/article/details/135638218
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。