【Docker学习笔记(三)】Dockerfile解析
【Docker 学习笔记目录】
1 Dockerfile 概述
Dockerfile 是用来构建 Docker 镜像的构建文件,其是由一系列指令和参数构成的脚本
构建三步骤:
- 1、编写 Dockerfile 文件
- 2、docker build
- 3、docker run
Dockerfile 指令:
- 1、大小写不敏感,但是建议全部使用大写
- 2、指令按照从上到下顺序执行
- 3、每条指令都会创建一个新的镜像层,并对镜像进行提交
Dockerfile 构建过程解析:
- 1、Docker 从基础镜像运行一个容器
- 2、执行一条指令并对容器作出修改
- 3、执行类似 docker commit 的操作提交一个新的镜像层
- 4、Docker 再基于刚提交的镜像运行一个新容器
- 5、执行 Dockerfile 中的下一条指令直到所有指令都执行完成
2 Dockerfile 指令
1、FROM
- 必须放在 Dockerfile 的第一行,表示从哪个 baseimage 开始构建
2、MAINTAINER
- 可选的,用来标识镜像作者的姓名和邮箱地址
3、RUN
- 容器构建时需要运行的命令
4、EXPOSE
- 当前容器对外暴露出的端口
5、WORKDIR
- 指定在创建容器后终端默认登录进来的工作目录,一个落脚点
6、ENV
- 用来在构建镜像过程中设置环境变量
- 这个环境变量可以在后续的指令中使用
- eg:
- ENV MY_PATH /usr/mytest
- WORKDIR $MY_PATH
7、ADD
- 将宿主机目录下的文件拷贝进镜像且 ADD 命令会自动处理 URL 和解压 tar 压缩包
8、COPY
- 类似 ADD,拷贝文件或目录到镜像中
- COPY SRC DEST
- COPY ["SRC", "DEST"]
9、VOLUME
- 容器数据卷,用于数据保存和持久化
10、CMD
- 指定容器启动时要运行的命令
- shell 格式:CMD <命令>
- exec 格式:CMD ["可执行文件", "参数1", "参数2" ...]
- Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
11、ENTRYPOINT
- 指定容器启动时要运行的命令
- exec 格式:ENTRYPOINT ["COMMAND","arg1" ...]
- Dockerfile 中可以有多个 ENTRYPOINT 指令,但只有最后一个生效,ENTRYPOINT 不会被 docker run 之后的参数替换
- 不过,docker run的--entrypoint可以覆盖Dockerfile中ENTRYPOINT设置的命令
12、ONBUILD
- 当构建一个被继承的 Dockerfile 时运行命令,父镜像在被子继承后,父镜像的 ONBUILD 会被触发
3 案例
3.1 Base镜像(scratch)
Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的,即 FROM scratch
。
3.2 自定义镜像 mycentos
(1)编写 Dockerfile。因为默认 centos 镜像不包含 vim 和 ifconfig,且默认路径为根目录。所以我们自定义 mycentos 镜像具备功能:vim编辑器、查看网络配置 ifconfig、登录后的默认路径
FROM centos
MAINTAINER haha<haha@163.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "SUCCESS----------------OK"
CMD /bin/bash
(2)构建镜像。执行命令 docker build -f <DockerfilePath> -t <新镜像名>[:TAG] .
[root@localhost mydocker]# docker build -f /mydocker/Dockerfile -t mycentos:1.3 .
Sending build context to Docker daemon 2.048kB
Step 1/10 : FROM centos
---> 49f7960eb7e4
Step 2/10 : MAINTAINER haha<haha@163.com>
---> Running in abba9b25097a
Removing intermediate container abba9b25097a
---> 6b31565e745c
...
...
...
Step 9/10 : CMD echo "SUCCESS----------------OK"
---> Running in ec3732fd9697
Removing intermediate container ec3732fd9697
---> f85df2928359
Step 10/10 : CMD /bin/bash
---> Running in 8c690565ae88
Removing intermediate container 8c690565ae88
---> 9fa354c5af84
Successfully built 9fa354c5af84
Successfully tagged mycentos:1.3
[root@localhost mydocker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos 1.3 9fa354c5af84 3 minutes ago 429MB
(3)运行。执行命令 docker run -it mycentos:1.3
,并测试 vim 和 ifconfig
[root@localhost mydocker]# docker run -it mycentos:1.3
[root@c4c9780e9bd2 local]# vim hi.txt
[root@c4c9780e9bd2 local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet *********** netmask *********** broadcast ***********
ether *********** txqueuelen 0 (Ethernet)
RX packets 8 bytes 648 (648.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet *********** netmask ***********
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
(4)查看镜像变更历史,使用命令 docker history <镜像ID>
[root@localhost mydocker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos 1.3 769456b1e3b6 5 minutes ago 429MB
[root@localhost mydocker]# docker history 769456b1e3b6
IMAGE CREATED CREATED BY SIZE COMMENT
769456b1e3b6 5 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/bin… 0B
9d471d49e890 5 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "echo… 0B
d8af111f35dc 5 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "echo… 0B
478098996ebd 5 minutes ago /bin/sh -c #(nop) EXPOSE 80 0B
5e4dd31fa027 5 minutes ago /bin/sh -c yum -y install net-tools 87.2MB
bea7db715bc2 6 minutes ago /bin/sh -c yum -y install vim 142MB
5fd476dce352 8 minutes ago /bin/sh -c #(nop) WORKDIR /usr/local 0B
c1463e67e0b3 16 minutes ago /bin/sh -c #(nop) ENV MYPATH=/usr/local 0B
6b31565e745c 16 minutes ago /bin/sh -c #(nop) MAINTAINER haha<haha@163.… 0B
49f7960eb7e4 8 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 8 weeks ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 8 weeks ago /bin/sh -c #(nop) ADD file:8f4b3be0c1427b158… 200MB
3.3 CMD/ENTRYPOINT 镜像
CMD:Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
我们可以查看到官方 tomcat 的 Dockerfile 中最后一个 CMD 命令为:CMD ["catalina.sh", "run"]
,则表示直接 docker run tomcat
会输出 tomcat 运行日志
[root@localhost mydocker]# docker run tomcat
31-Jul-2018 13:15:09.738 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server version: Apache Tomcat/8.5.32
31-Jul-2018 13:15:09.741 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server built: Jun 20 2018 19:50:35 UTC
31-Jul-2018 13:15:09.741 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Server number: 8.5.32.0
31-Jul-2018 13:15:09.746 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Name: Linux
31-Jul-2018 13:15:09.746 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log OS Version: 3.10.0-862.9.1.el7.x86_64
31-Jul-2018 13:15:09.746 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Architecture: amd64
31-Jul-2018 13:15:09.746 INFO [main] org.apache.catalina.startup.VersionLoggerListener.log Java Home: /usr/lib/jvm/java-8-openjdk-amd64/jre
当我们执行命令 docker run -it -p 7777:8080 tomcat ls -l
,可以注意到,CMD 被 docker run 后面的参数替换了
[root@localhost mydocker]# docker run -it -p 7777:8080 tomcat ls -l
total 92
-rw-r-----. 1 root root 57092 Jun 20 19:53 LICENSE
-rw-r-----. 1 root root 1723 Jun 20 19:53 NOTICE
-rw-r-----. 1 root root 7138 Jun 20 19:53 RELEASE-NOTES
-rw-r-----. 1 root root 16246 Jun 20 19:53 RUNNING.txt
drwxr-x---. 2 root root 4096 Jul 17 18:16 bin
drwx--S---. 2 root root 238 Jun 20 19:53 conf
drwxr-sr-x. 3 root staff 19 Jul 17 18:16 include
drwxr-x---. 2 root root 4096 Jul 17 18:15 lib
drwxr-x---. 2 root root 6 Jun 20 19:50 logs
drwxr-sr-x. 3 root staff 151 Jul 17 18:16 native-jni-lib
drwxr-x---. 2 root root 30 Jul 17 18:15 temp
drwxr-x---. 7 root root 81 Jun 20 19:51 webapps
drwxr-x---. 2 root root 6 Jun 20 19:50 work
ENTRYPOINT:docker run 之后的参数会被当做参数传递给 ENTRYPOINT ,之后形成新的命令组合
首先创建一个新的镜像 myip,其 Dockerfile 如下:
FROM centos
RUN yum install -y curl
CMD "curl", "-s", "https://ip.cn"
[root@localhost mydocker]# vim Dockerfile2
[root@localhost mydocker]# docker build -f /mydocker/Dockerfile2 -t myip .
Sending build context to Docker daemon 3.072kB
Step 1/3 : FROM centos
---> 49f7960eb7e4
Step 2/3 : RUN yum install -y curl
---> Using cache
---> 8e148a68fc86
Step 3/3 : CMD ["curl", "-s", "https://ip.cn"]
---> Running in 7be857257291
Removing intermediate container 7be857257291
---> 6a341f6d2b42
Successfully built 6a341f6d2b42
Successfully tagged myip:latest
[root@localhost mydocker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
myip latest 036adbaf59cb 13 seconds ago 286MB
接着执行命令 docker run -it myip
[root@localhost mydocker]# docker run -it myip
当前 IP:********* 来自:***省***市 ***
[root@localhost mydocker]#
如果我们想显示更多的信息,比如 HTTP 头信息,则需要加上参数 -i (即 curl -s -i https://ip.cn
)。那么是不是执行 docker run myip -i
呢?我们可以试试
[root@localhost mydocker]# docker run myip -i
docker: Error response from daemon: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: \"-i\": executable file not found in $PATH": unknown.
可以看到 executable file not found
。因为跟在镜像名后面的是 command ,运行时会替换 CMD 的默认值。在这里的 -i 替换了原来的 CMD ,而不是添加在原来的 curl -s https://ip.cn 后面。而 -i 根本不是命令,所以自然找不到啦
那么要如何加这个 -i 参数才能运行呢?答案就是 docker run myip curl -s https:ip.cn -i
[root@localhost lycai]# docker run myip curl -s https://ip.cn -i
HTTP/1.1 200 OK
Date: Tue, 31 Jul 2018 13:50:12 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=************************; expires=Wed, 31-Jul-19 13:50:11 GMT; path=/; domain=.ip.cn; HttpOnly
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
CF-RAY: 4430885bdd39aa50-SIN
当前 IP:******** 来自:***省***市 ***
现在我们再编写一个 Dockerfile3,制作 ENTRYPOINT 版查询 IP 信息的镜像 myip_new
FROM centos
RUN yum install -y curl
ENTRYPOINT ["curl", "-s", "https://ip.cn"]
最后就可以用 docker run myip_new -i
啦
[root@localhost mydocker]# docker run myip_new -i
HTTP/1.1 200 OK
Date: Tue, 31 Jul 2018 13:55:06 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=************************; expires=Wed, 31-Jul-19 13:55:05 GMT; path=/; domain=.ip.cn; HttpOnly
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
CF-RAY: 44308f897c6831ec-SIN
当前 IP:********* 来自:***省***市 ***
其相当于原来的 myip 镜像的 Dockerfile 中最后一行变成了 CMD ["curl", "-s", "-i", "https://ip.cn"]
,而这个 -i 是作为参数传进去的