Dockerfile 是一个文本文件包含了构建一个镜像的所有命令。
FROM
指令,用来指定 Base Image.dockerignore
文件中定义的文件将不会被打包至镜像中""
FROM 指令是最重要的一个并且必须为 Dockerfile 文件的第一个非注释行指令,用于为镜像文件构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境。
实践中,基准镜像可以是任何可用镜像文件,默认情况下,Dockerfile 会在 docker 主机上查找指定的镜像文件,当镜像文件不存在时,从 Docker Hub Registry 上拉取所需的镜像文件。如果找不到指定的镜像文件,docker build 会返回一个错误信息。
FROM <repository>[:<tag>] 或
FROM <repository>@<digest>
用于让 Dockerfile 制作者提供制作者本人的详细信息。Dockerfile 并不限制 MAINTAINER 指令可出现的位置,但推荐其放置于 FROM 指令之后
MAINTAINER <author's detail>
参数说明
<author's detail>:任何文本信息,约定俗成地使用作者名称及邮件地址
LABEL 指令可以对镜像添加相关的元数据。
LABEL <key>=<value> <key>=<value> <key>=<value> ...
用于从 Docker 主机复制文件至创建的新镜像文件中。
COPY <src> ... <dest> 或
COPY ["<src>",..."<dest>"]
参数说明
文件复制准则
/
**结尾**;示例
复制单个文件
# Description:myimage
FROM busybox:latest
MAINTAINER "Manson <chrisma1209@gmail.com>"
# LABEL maintainer="Manson <chrisma1209@gmail.com>"
COPY index.html /data/web/html/
docker build -t tinyhttpd:v0.1-1 /root/myimage
docker image ls
docker run --rm --name tinyweb1 tinyhttpd:v0.1-1 cat /data/web/html/index.html
此命令用于测试制作的镜像是否已成功拷贝文件,并且修改容器启动运行的默认命令,修改为 cat 命令,cat 命令执行结束,容器结束并删除。这是测试容器时的常用方法。
复制目录
# Description:myimage
FROM busybox:latest
MAINTAINER "Manson <chrisma1209@gmail.com>"
# LABEL maintainer="Manson <chrisma1209@gmail.com>"
COPY index.html /data/web/html/
COPY yum.repos.d /etc/yum.repos.d/ #仅实验用,因为每一条指令都会生成一个新的文件系统层
cp -r /etc/yum.repos.d/ /root/myimage
tree -L 2
.
├── Dockerfile
├── index.html
└── yum.repos.d
├── CentOS-Base.repo
├── CentOS-CR.repo
├── CentOS-Debuginfo.repo
├── CentOS-fasttrack.repo
├── CentOS-Media.repo
├── CentOS-Sources.repo
├── CentOS-Vault.repo
├── docker-ce.repo
├── epel.repo
├── epel-testing.repo
└── google-cloud.repo
docker build -t tinyhttpd:v0.1-2 /root/myimage
docker image ls
docker run --rm --name tinyweb1 tinyhttpd:v0.1-2 ls /etc/yum.repos.d
ADD 指令类似于 COPY指令,ADD 支持使用 TAR 文件和 URL 路径
ADD <src> ... <dest> 或
ADD ["<src>",..."<dest>"]
说明
tar -x
命令,通过 URL 获取的 TAR 文件不会被自动展开;示例
# Description:myimage
FROM busybox:latest
MAINTAINER "Manson <chrisma1209@gmail.com>"
# LABEL maintainer="Manson <chrisma1209@gmail.com>"
COPY index.html /data/web/html/
COPY yum.repos.d /etc/yum.repos.d/
#ADD http://nginx.org/download/nginx-1.15.2.tar.gz /usr/local/src/ #URL 下载不会展开
ADD nginx-1.15.2.tar.gz /usr/local/src/ #宿主机上先下载好,在镜像文件系统中会自动展开
# 使用 URL 下载 tar 文件包不会被自动解压
docker build -t tinyhttpd:v0.1-3 /root/myimage/
docker run --rm --name tinyweb1 tinyhttpd:v0.1-3 ls /usr/local/src
# 使用本地的 tar 文件包,会被自动展开
wget http://nginx.org/download/nginx-1.15.2.tar.gz
docker build -t tinyhttpd:v0.1-4 /root/myimage/
docker run --rm --name tinyweb1 tinyhttpd:v0.1-4 ls /usr/local/src/nginx-1.15.2
用于为 Dockerfile 中所有的 RUN、CMD、ENTERPOINT、COPY和 ADD 指令设定工作目录
WORKDIR <dirpath>
在 Dockerfile 文件中,WORKDIR 指令可出现多次,其路径也可以为相对路径,不过相对此前一个 WORKDIR 指令指定的路径。
另外,WORKDIR 也可以调用由 ENV 指定定义个变量,如 WORKDIR $STATEPATH
示例
...
WORKDIR /usr/local/
ADD nginx-1.15.2 ./src/ #./目录就使用的WORKDIR 定义个目录
...
用于在 image 中创建一个挂载点目录,以挂载 Docker host 上的卷或其他容器上的卷。
VOLUME <mountpoint> 或
VOLUME ["<mountpoint>"]
如果挂载点目录路径下此前有文件存在,docker run命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中。
**示例**
FROM busybox:latest
ADD nginx-1.15.2.tar.gz /usr/local/src/
VOLUME /data/mysql/
docker build -t tinyhttpd:v0.1-5 /root/myimage/
docker run --rm --name tinyweb1 tinyhttpd:v0.1-5 mount 或
docker run --rm --name tinyweb1 tinyhttpd:v0.1-5 sleep 60
docker inspect
用于为容器打开指定要监听的端口实现与外部通信
EXPOSE <port>[/<protocol>] [<port>[/<protocol>]...]
参数说明
EXPOSE 指令可以一次指定多个端口,如 EXPOSE 11211/udp 11211/tcp
需要注意的是,EXPOSE 指定是待暴露的端口,运行容器默认不会暴露端口,使用 docker run 命令-P 选项后,会暴露 Dockerfile 中指定的暴露端口。
示例
# Description:myimage
FROM busybox:latest
MAINTAINER "Manson <chrisma1209@gmail.com>"
# LABEL maintainer="Manson <chrisma1209@gmail.com>"
COPY index.html /data/web/html/
COPY yum.repos.d /etc/yum.repos.d/
#ADD http://nginx.org/download/nginx-1.15.2.tar.gz /usr/local/src/
ADD nginx-1.15.2.tar.gz /usr/local/src/
VOLUME /data/mysql/
EXPOSE 80/tcp
docker run --name tinyweb1 --rm tinyhttpd:v0.1-6 /bin/httpd -f -h /data/web/html #前台运行 docker 容器
docker inspect tinyweb1 #查看当前容器的 IP地址
curl 容器的 IP地址 #验证端口是否暴露,可以访问网页因为容器和宿主机在一个桥上,默认不会暴露端口
docker port tinyweb1
docker kill tinyweb1 #停止前台运行的容器
docker run --name tinyweb1 --rm -P tinyhttpd:v0.1-6 /bin/httpd -f -h /data/web/html #-P 选项表示暴露应该暴露的端口
docker port tinyweb1
用于为镜像定义所需的环境变量,并可被 Dockerfile 文件中**位于其后**的其他指令如 ENV、ADD、COPY 等所调用。调用格式为 $variable\_name
或 ${variable\_name}
使用环境变量替换 (Environment replacement) 引用变量 $variable_name 或${variable_name} ${variable:-word}:变量默认值,如果 variable 值为空或未设置,就使用 word 作为变量值。 ${variable:+word}:变量有值就显示为 word,变量无值,就显示无值。
ENV <key><value>或
ENV <key>=<value>...
说明
示例
FROM busybox:latest
ENV DOC\_ROOT /data/web/html/ \
WEB\_SERVER\_PACKAGE="nginx-1.15.2"
COPY index.html ${DOC\_ROOT:-/data/web/html/}
ADD ${WEB\_SERVER\_PACKAGE}.tar.gz /usr/local/src/
...
变量值生效的阶段
在容器启动时,可以修改 ENV 的值,但是有些 ENV 的值是不会影响 Dockerfile 中定义的 ENV值,这里要区分 ENV 值的生效阶段,在第一阶段docker build生效的 ENV 值在容器启动前操作,不会被影响。
RUN 指令运行于第一阶段 docker build(镜像文件构建过程)。RUN命令可执行的操作取决于基础镜像支持的命令数量。
RUN <command> 或
RUN ["<executable>","<param1>", "<param2>"]
说明
/bin/sh -c
来运行它,这意味着此进程在容器中的 PID 不为 1,不能接收 Unix 信号,因此,当使用 docker stop <container> 命令停止容器时,此进程接收不到 SIGTERM 信号;/bin/sh -c
来发起,因此常见的 shell 操作如变量替换以及通配符(?,*等)替换不会进行;不过,如果要运行的命令依赖于此类 shell 特性时,可以将其替换为类似下面的格式: RUN ["/bin/sh","-c","executable","paramN"]
...
ENV WEB\_SERVER\_PACKAGE=nginx-1.15.2
ADD http://nginx.org/download/nginx-1.15.2 /usr/local/src/
RUN cd /usr/local/src/ && tar -xf ${WEB\_SERVER\_PACKAGE}.tar.gz && mv nginx-\* webserve
...
类似于 RUN 指令,运行于第二阶段 docker run(基于 Dockerfile 构建出的新镜像文件启动的容器),需要结合 ENTRYPOINT 使用。
在 Dockerfile 中CMD建议只出现一次,如果出现多次,那么只有最后一个 CMD 有效。
CMD 指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;不过,CMD 指令的命令可以被 docker run 的命令行参数所覆盖。
CMD <command> 或
CMD <"<executable>","<param1>","<param2>"> 或
CMD <"<param1>","<param2>">
参数说明
示例
FROM busybox:latest
LABEL maintainer="Manson <chrisma1209@gmail.com>" app="httpd"
ENV WEB\_DOC\_ROOT="/data/web/html/"
RUN mkdir -p $WEB\_DOC\_ROOT && echo '<h1>Busybox httpd server.</h1>' > ${WEB\_DOC\_ROOT}/index.html
CMD /bin/httpd -f -h ${WEB\_DOC\_ROOT}
2.创建镜像
docker build -t tinyhttpd:v0.2-1 /root/img2
3.查看镜像信息
docker image inspect tinyhttpd:v0.2-1
...
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"/bin/sh\" \"-c\" \"/bin/httpd -f -h ${WEB\_DOC\_ROOT}\"]"
...
这里可以看到,容器先启动了/bin/sh,然后在运行 /bin/httpd,就就是说 httpd 是 shell 的子进程
4.运行容器
docker run --name tinyweb2 -it --rm -P tinyhttpd:v0.2-1
即使使用了-it 选项,但是因为没有进入交互式环境,因为 httpd 根本不提供交互式接口
5.进入容器查看进程
docker exec -it tinyweb2 /bin/sh
/ # ps
PID USER TIME COMMAND
1 root 0:00 /bin/httpd -f -h /data/web/html/
11 root 0:00 /bin/sh
16 root 0:00 ps
/ # printenv
WEB\_DOC\_ROOT=/data/web/html/
HOSTNAME=aa6643a0ceaf
SHLVL=1
HOME=/root
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
这里有一个问题,不是应该/bin/sh 的 PID是 1 ,而目前 httpd 的进程号为 1,可以接收 docker stop 发送的信号,因为 docker 进行过转换,通过 docker image inspect tinyhttpd:v0.2-1
可以查看。
6.修改 Dockerfile
...
CMD ["/bin/httpd","-f","-h ${WEB\_DOC\_ROOT}"]
这样构建镜像并启动容器,由于并没有创建 sh 子进程,所以也获取不到shell变量的值,因此会报错,找不到路径。所以要修改为:
FROM busybox:latest
LABEL maintainer="Manson <chrisma1209@gmail.com>" app="httpd"
ENV WEB\_DOC\_ROOT="/data/web/html/"
RUN mkdir -p $WEB\_DOC\_ROOT && echo '<h1>Busybox httpd server.</h1>' > ${WEB\_DOC\_ROOT}/index.html
#CMD /bin/httpd -f -h ${WEB\_DOC\_ROOT}
CMD ["/bin/sh","-c","/bin/httpd -f -h ${WEB\_DOC\_ROOT}"]
注意的是-c 后面的参数是一个参数只需要一个对引号,分开写会报错。
类似 CMD命令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序。与 CMD 不同的是,由 ENTRYPOINT 启动的程序不会被 docker run 命令行指定的参数所覆盖,而且,这些命令行参数会被当做参数传递给 ENTRYPOINT指定的程序。【参数追加】
docker run 命令句的 --entrypoint
选项可以覆盖 ENTRYPOINT 指令指定的程序
ENTRYPOINT <command>
ENTRYPOINT ["<executable>","<param1>","param2"]
说明
示例 1
FROM busybox:latest
LABEL maintainer="Manson <chrisma1209@gmail.com>" app="httpd"
ENV WEB\_DOC\_ROOT="/data/web/html/"
RUN mkdir -p $WEB\_DOC\_ROOT && echo '<h1>Busybox httpd server.</h1>' > ${WEB\_DOC\_ROOT}/index.html
ENTRYPOINT /bin/httpd -f -h ${WEB\_DOC\_ROOT}
docker build -t tinyhttpd:v0.2-5 /root/img2/
#正常运行
docker run --name tinyweb -it --rm -P tinyhttpd:v0.2-5
##正常运行,没有执行 ls 命令,ls 命令作为参数追加到 ENTRYPOINT 指令指定的程序之后
docker run --name tinyweb -it --rm -P tinyhttpd:v0.2-5 ls /data/web/html
示例 2
FROM nginx:1.14-alpine
LABEL maintainer="Simon <chrisma1209@gmail.com>"
ENV NGX\_DOC\_ROOT='/data/web/html/'
ADD index.html ${NGX\_DOC\_ROOT}
ADD entrypoint.sh /bin/
CMD ["/usr/sbin/nginx","-g","daemon off;"]
#先运行/bin/entrypoint.sh 脚本,然后引用 CMD 指定的参数,并替换/bin/entrypoint.sh 进程
#ENTRYPOINT ["/bin/sh","-c","/bin/entrypoint.sh"]
#ENTRYPOINT ["/bin/sh","-c","/bin/entrypoint.sh"]
#ENTRYPOINT ["/bin/sh","-c","ls /bin"]
ENTRYPOINT ["/bin/entrypoint.sh"]
entrypoint.sh
#!/bin/sh
#filenname entrypoint.sh
#
cat > /etc/nginx/conf.d/www.conf << EOF
server {
server\_name $HOSTNAME;
listen ${IP:-0.0.0.0}:${PORT:-80};
root ${NGX\_DOC\_ROOT};
}
EOF
exec "$@" #替换当前进程
index.html
<h1>mynginx in docker</h1>
docker build -t myweb:v0.1-12 /root/mynginx/
docker run --name myweb -it --rm -P myweb:v0.1-12
如果容器运行失败,提示 permission denied,在构建镜像前手动赋予entrypoint.sh执行权限
docker exec -it myweb /bin/sh
进入容器,查看监听的端口,查看进程,获取网页 wget -O - -q ab04ddac4745
docker run --name myweb -it --rm -P -e "PORT=8080" myweb:v0.1-12
为了在不同的环境中使用相同的镜像,通常都是使用 entrypoint 脚本启动,当传入不同的参数来区分在不同环境中使用容器,如区分开发环境、测试环境、生产环境。Dockerfile 中 entrypoint 脚本的作用、意义和参数的传递方式是一个难点,可以在github 上 docker 仓库中多多学习其他镜像Dockerfile 的写法。
用于指定运行 image 时或运行 Dockerfile 中任何 RUN、CMD或 ENTRYPOINT 指令指定程序时的用户名或 UID。
默认情况下,container 的运行用户是 root 用户。
USER <UID>|<USERNAME>
说明
<UID>可以为任意数字,但实践中必须为/etc/passwd 中某用户的有效 UID,否则,docker run 命令将运行失败
用于指定一个命令检查主进程的工作状态
HEALTHCHECK [OPTIONS] CMD command
HEALTHCHECK NONE
OPTIONS
响应值
示例
HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/|| exit 1
指定默认 shell
STOPSIGNAL signal
定义变量,在 docker build 过程中使用的变量。而 ENV 的变量是可以在 docker run 时进行传值的。
用于在 Dockerfile 中定义一个触发器。Dockerfile 用于 build 镜像文件,此镜像文件亦可作为base image 被另外一个 Dockerfile 用作 FROM 指令的参数,并以之构建的镜像文件。
在后面的这个 Dockerfile 中的 FROM 指令在 build 过程中被执行,将会“触发”创建其 base image 的 Dockerfile 文件中的 ONBUILD 指令定义的触发器。
ONBUILD <INSTRUCTION>
说明
尽管任何指令都可注册成为触发器指令,但 ONBUILD 不能自我嵌套,且不会触发 FROM 和 MAINTAINER 指令。
使用包含 ONBUILD 指令的 Dockerfile 构建的镜像应该使用特殊的标签,如 ruby:2.0-onbuild。
在 ONBUILD 指令中使用的 ADD 或 COPY 指令应该格外小心,因为构建过程中的上下文在缺少指定的源文件时会失败。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有