Dockerfile是一个文本文件,其中包含了一系列指令,用于自动化构建Docker镜像。这些指令描述了如何从一个基础镜像开始,安装所需的软件包、复制文件、设置环境变量等,最终生成一个自定义的Docker镜像。Dockerfile使得构建过程可重复、可移植,并且方便在不同环境中共享和使用。
Dockerfile通常位于项目的根目录下,通过执行docker build
命令,Docker会读取Dockerfile中的指令,按照顺序执行,并构建出一个新的Docker镜像。这个镜像可以被推送到Docker仓库中,供其他人使用,或者在本地运行容器实例。
Dockerfile中的指令通常包括指定基础镜像、设置工作目录、复制文件、安装软件包、设置环境变量等。例如,你可以使用FROM
指令指定一个基础镜像,COPY
指令将项目文件复制到镜像中,RUN
指令执行一些命令(如安装软件包),以及CMD
或ENTRYPOINT
指令指定容器启动时运行的命令。
使用Dockerfile的好处是,你可以将构建镜像的过程以文本形式记录下来,这样其他人可以轻松地按照相同的步骤构建出相同的镜像。此外,Dockerfile还可以作为项目的一部分进行版本控制,方便团队之间的协作和代码审查。
总的来说,Dockerfile是Docker镜像构建的核心文件,它描述了如何从基础镜像构建出一个自定义的Docker镜像,使得构建过程更加自动化、可重复和可移植。
Dockerfile命令执行规则
-
每条
保留字指令
都必须为大写
且后面要跟随至少一个参数 -
指令按照从上到下,顺序执行
-
#代表注释
-
每条指令都会创建一个新的镜像层,并对镜像进行提交
1、应用程序运行流程
2、三者之间的关系
Dockerfile 是软件的原材料,Docker 镜像是软件的交付品,而 Docker 容器则可以认为是软件的运行态。从应用软件的角度来看,Dockerfile、Docker 镜像与 Docker 容器分别代表软件的三个不同阶段,Dockerfile 面向开发,Docker 镜像成为交付标准,Docker 容器则涉及部署与运维,综上所述,Dockerfile、Docker镜像和Docker容器三者共同协作,使得应用程序的打包、分发、部署和运行变得更加简单、高效和安全。Dockerfile定义了如何构建镜像,Docker镜像作为模板用于创建容器实例,而Docker容器则负责在隔离的环境中运行应用程序。这种协同工作的方式使得Docker成为了一个强大的应用容器引擎,为开发人员和运维人员提供了极大的便利。
3、Dockerfile命令
Dockerfile 指令 | 说明 |
---|---|
FROM | 指定基础镜像,用于后续的指令构建。 |
MAINTAINER | 指定Dockerfile的作者/维护者。(已弃用,推荐使用LABEL指令) |
LABEL | 添加镜像的元数据,使用键值对的形式。 |
RUN | 在构建过程中在镜像中执行命令。 |
CMD | 指定容器创建时的默认命令。(可以被覆盖) |
ENTRYPOINT | 设置容器创建时的主要命令。(不可被覆盖) |
EXPOSE | 声明容器运行时监听的特定网络端口。 |
ENV | 在容器内部设置环境变量。 |
ADD | 将文件、目录或远程URL复制到镜像中。 |
COPY | 将文件或目录复制到镜像中。 |
VOLUME | 为容器创建挂载点或声明卷。 |
WORKDIR | 设置后续指令的工作目录。 |
USER | 指定后续指令的用户上下文。 |
ARG | 定义在构建过程中传递给构建器的变量,可使用 "docker build" 命令设置。 |
ONBUILD | 当该镜像被用作另一个构建过程的基础时,添加触发器。 |
STOPSIGNAL | 设置发送给容器以退出的系统调用信号。 |
HEALTHCHECK | 定义周期性检查容器健康状态的命令。 |
SHELL | 覆盖Docker中默认的shell,用于RUN、CMD和ENTRYPOINT指令。 |
1 FROM 指定构建镜像的基础镜像,必须为Dockerfile中的第一个命令
FROM
:基础镜像,当前镜像是基于哪个镜像的,必须为 Dockerfile 的第一个指令
bash
# 格式
FROM image
FROM image[:tag]
# 示例
FROM nginx
# tag不填,默认使用latest版本
2 MAINTAINER 镜像作者信息 (已过时,推荐使用LABEL
)
# 格式
MAINTAINER <name>
# 示例:
MAINTAINER wuzhibin
MAINTAINER name wuzhibin
3 LABEL:为镜像指定标签
bash
# 格式
LABEL key1=value1 key2=value2
# 示例:
LABEL maintainer="wuzhibin
4 RUN:容器构建时需要运行的指令
bash
# 格式
RUN <命令行命令>
RUN ["可执行文件", "参数1", "参数2"]
# 示例:
RUN ./test.php dev offline
RUN ["./test.php", "dev", "offline"]
# Dockerfile 的指令每执行一次都会在 docker上新建一层会镜像空间增大
FROM centos
RUN yum -y install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz
# 如上使用了三层通过 && 在一层中执行
FROM centos
RUN yum -y install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz
5 CMD类似于 RUN 指令,用于运行程序,但二者运行的时间点不同CMD 在docker run 时运行,RUN 是在 docker build。为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。
bash
# 格式:
CMD <shell 命令>
CMD ["<可执行文件或命令>","<param1>","<param2>",...]
CMD ["<param1>","<param2>",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数
# 示例:
CMD echo "hello world."
CMD ["python","manager.py", "runserver"]
ENTRYPOINT ["/usr/local/bin/my_command"]
# 设置CMD,为ENTRYPOINT指定的程序提供默认参数
CMD ["arg1", "arg2"]
# 如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效
6 ENTRYPOINT类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 ENTRYPOINT 指令指定的程序。
bash
# 格式:
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
# 示例:
ENTRYPOINT ["ps", "-aux"]
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参
docker run nginx:test # 执行默认CMD的命令nginx -c /etc/nginx/nginx.conf
docker run nginx:test -c /etc/nginx/new.conf # 覆盖CMD命令 docker run nginx:test -c /etc/nginx/new.conf
# 如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。
7 EXPOSE仅仅只是声明端口
bash
# 格式:
EXPOSE <端口1> [<端口2>...]
# 示例:
EXPOSE 80 443
EXPOSE 8080
EXPOSE 11211/tcp 11211/udp
# 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口
8 ENV设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
bash
# 格式:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...进行转义,也可以通过""来进行标示;另外,反斜线\也可以用于续行
# 示例:
ENV MYPATH /usr/local
ENV MYPATH1=/usr1/local MYPATH2=/usr2/local \
MYPATH3=/usr3/local
# 在后续的指令中可以通过 $NODE_VERSION 引用前面设置的环境变量值
9 ADD 将本地文件添加到容器中,ADD 指令和 COPY 的使用格类似,ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>; 访问网络资源时能自动下载。ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。
bash
# 格式:
ADD src...dest
ADD ["src",... "dest"] 用于支持包含空格的路径
# 示例:
ADD hom* /mydir/ # 添加所有以"hom"开头的文件 到 /mydir/
ADD hom?.txt /mydir/ # ? 替代一个单字符,例如:"home.txt"
ADD test.tar /mydir/ # 自动解压缩test.tar,并添加到 /mydir/
10 COPY 将从构建上下文目录中 <源路径> 的文件 / 目录复制到新的一层的镜像内的 < 目标路径 > 位置
bash
# 格式
COPY [--chown=<user>:<group>] <源路径1>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
# 示例
COPY hom* /mydir/
COPY hom?.txt /mydir/
# COPY 不会自动解压文件,也不能访问网络资源
11 VOLUME 定义匿名数据卷,用于数据保存和持久化工作
bash
# 格式:
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
# 示例:
VOLUME ["/data1"]
VOLUME ["/data1", "/data2", "/data3"]
# 在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
12 WORKDIR 指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。
bash
# 格式:
WORKDIR <工作目录路径>
# 示例:
WORKDIR /home # 指定工作目录并进入这个目录
# 通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。和RUN cd /home的区别时这个命令只在本层有效,WORKDIR的命令在以后各层都有效
13 USER 用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)
bash
# 格式:
USER <用户名>[:<用户组>]
# 示例:
USER myuser
USER myuser:mygroup
# 可以通过-u参数来覆盖所指定的用户。
14 ARG 构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。
bash
# 格式:
ARG <参数名>[=<默认值>]
# 示例
ARG age=20
# 构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。
15 ONBUILD 用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令
bash
# 格式:
ONBUILD [INSTRUCTION]
# 示例:
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
# 当所构建的镜像被用做其它镜像当作基础镜像时,该镜像中的触发器将会被触发
16 STOPSIGNAL 指令用于设置容器接收到的停止信号。当您执行 docker stop
命令来停止容器时,该命令默认会发送一个 SIGTERM
信号给容器。STOPSIGNAL
允许您改变这个默认行为,指定一个不同的信号来停止容器。
bash
# 格式:
STOPSIGNAL signal
# 示例:
STOPSIGNAL SIGKILL
STOPSIGNAL 9
# 用于设置容器内进程停止信号,在docker stop时如果没有设置**STOPSIGNAL** docker默认会使用SIGTERM信号发送
STOPSIGNAL示例
bash
# sotp_niganl.py
import sys
import time
import signal
sys.stdout = open("output.txt", "a")
def cleanup(signum, frame):
print("Cleaning up resources....", flush=True)
print(signum, frame)
time.sleep(2)
print("Cleanup complte!", flush=True)
exit()
signal.signal(signal.SIGTERM, cleanup)
while True:
print("Running....", flush=True)
time.sleep(1)
Dockerfile文件
bash
FROM python:latest
COPY stop_signal.py /stop_signal.py
STOPSIGNAL SIGQUIT
CMD ["python3", "/stop_signal.py"]
bash
# 编译
docker build . -t my_signal
# 运行
docker run -ti -d --name=my_contain my_signal
17 HEALTHCHECK 用于指定某个程序或者指令来监控 docker 容器服务的运行状态。
bash
# 格式:
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令
HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。
18 SHELL 指令允许覆盖用于 shell 形式的命令的默认 shell。在 Linux 上,默认 shell 是 ["/bin/sh", "-c"]
,而在 Windows 上,默认 shell 是 ["cmd", "/S", "/C"]
。 SHELL
指令必须以 JSON 格式写入 Dockerfile 中。SHELL
指令在 Windows 上特别有用,在 Windows 上有两个常用且完全不同的本机shell:cmd
和 powershell
,以及可用的替代 shell,包括 sh
。SHELL
指令可以出现多次。每条 SHELL
指令都将覆盖所有先前的 SHELL
指令,并影响所有后续指令。
bash
FROM microsoft/windowsservercore
# Executed as cmd /S /C echo default
RUN echo default
# Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default
# Executed as powershell -command Write-Host hello
SHELL ["powershell", "-command"] # 执行之后后续的命令不需要添加powershell -command
RUN Write-Host hello
# Executed as cmd /S /C echo hello
SHELL ["cmd", "/S", "/C"]
RUN echo hello
# 当它们的 shell 形式在 Dockerfile 中使用时,以下指令可能会受到 SHELL 指令的影响:RUN,CMD 和 ENTRYPOINT。
4 Dockerfile 示例
centos 构建一个nginx镜像
bash
#基准镜像
FROM centos:7
#作者信息
MAINTAINER "nginx"
#工作目录
WORKDIR /usr/local/src/
#定义环境变量
ENV NG_VERSION nginx-1.21.0
#安装epel仓库
RUN yum -y install epel-release
#安装wget
RUN yum -y install wget
#下载nginx文件并解压
RUN wget http://nginx.org/download/$NG_VERSION.tar.gz && tar xzvf $NG_VERSION.tar.gz
#安装编译依赖包
RUN yum install -y gcc gcc-c++ glibc make autoconf openssl openssl-devel && yum install -y pcre-devel libxslt-devel gd-devel GeoIP GeoIP-devel GeoIP-data
#清理仓库
RUN yum clean all
#创建nginx用户
RUN useradd -M -s /sbin/nologin nginx
#切换工作目录
WORKDIR /usr/local/src/$NG_VERSION
#编译安装nginx
RUN ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-file-aio --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module --with-http_image_filter_module --with-http_geoip_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_auth_request_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_stub_status_module && make && make install
#复制测试页面到容器中
ADD index.html /usr/local/nginx/html
#设置容器中要挂在到宿主机的目录
VOLUME /usr/local/nginx/html
#设置sbin环境变量
ENV PATH /usr/local/nginx/sbin:$PATH
#暴露80端口
EXPOSE 80/tcp
ENTRYPOINT ["nginx"]
CMD ["-g","daemon off;"]
#当ENTRYPOINT和CMD连用时,CMD的命令是ENTRYPOINT命令的参数,两者连用相当于nginx -g "daemon off;"而当一起连用的时候命令格式最好一致(这里选择的都是json格式的是成功的,如果都是sh模式可以试一下)
bash
mkdir nginx
cd nginx/
vim index.html
<h1> docker nginx build successful</h1>
# 将上面的内容复制到Dokcerfile中
# 构建镜像
docker build ./ -t centos7_nginx
# 运行容器
docker run --name mynginx -d -p 8123:80 centos7_nginx
访问 ip: 8123