Docker专题(七)-DockerFile详解
1.DockerFile是什么
当我们从docker镜像仓库中下载的镜像不能满足我们的需求时,我们可以通过以下两种方式对镜像进行更改。
1.从已经创建的容器中更新镜像,并且提交这个镜像
2.使用 Dockerfile 指令来创建一个新的镜像Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。DockerFile是描述镜像的一种文件!
DockerFile是镜像的说明书,里面有一系列的执行,告诉Docker如何构建镜像!
Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。
-
Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
-
在Docker中创建镜像最常用的方式,就是使用Dockerfile。Dockerfile是一个Docker镜像的描述文件,我们可以理解成火箭发射的A、B、C、D…的步骤。Dockerfile其内部包含了一条条的指令,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
-
Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时,会真正开始提供服务;
-
Docker容器,容器是直接提供服务的。
-
构建三步骤
编写Dockerfile文件 -----> 编写DockerFile文件 docker build -----> 构建镜像 docker run -----> 使用镜像启动容器 DockerFile就是镜像的描述文件!
2.DockerFile文件什么样
2.1.以我们熟悉的CentOS为例
网站:https://hub.docker.com/_/centos/
2.2.一个Dockerfile的示例如下所示
#基于centos镜像 FROM centos #维护人的信息 MAINTAINER The CentOS Project <303323496@qq.com> #安装httpd软件包 RUN yum -y update RUN yum -y install httpd #开启80端口 EXPOSE 80 #复制网站首页文件至镜像中web站点下 ADD index.html /var/www/html/index.html #复制该脚本至镜像中,并修改其权限 ADD run.sh /run.sh RUN chmod 775 /run.sh #当启动容器时执行的脚本文件 CMD ["/run.sh"]
由上可知,Dockerfile结构大致分为四个部分: (1)基础镜像信息 (2)维护者信息 (3)镜像操作指令 (4)容器启动时执行指令。 Dockerfile每行支持一条指令,每条指令可带多个参数,支持使用以#号开头的注释。下面会对上面使用到的一些常用指令做一些介绍。
2.3.DockerFile构建过程解析
-
Dockerfile内容基础知识
1:每条保留字指令都必须为大写字母且后面要跟随至少一个参数
2:指令按照从上到下,顺序执行
3:#表示注释
4:每条指令都会创建一个新的镜像层,并对镜像进行提交 -
Dockerfile内容基础知识
1:docker从基础镜像运行一个容器
2:执行一条指令并对容器作出修改
3:执行类似docker commit的操作提交一个新的镜像层
4:docker再基于刚提交的镜像运行一个新容器
5:执行dockerfile中的下一条指令直到所有指令都执行完成 -
小结
从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段:
1:Dockerfile是软件的原材料
2:Docker镜像是软件的交付品
3**:Docker容器**则可以认为是软件的运行态。
3.Dockerfile常用指令
3.1.FROM
指明构建的新镜像是来自于哪个基础镜像,例如:
FROM centos:6
基础镜像不存在会在Docker Hub上拉去(一般会是文件的第一个指令) 使用格式:
FROM <镜像>:[tag]
3.2.MAINTAINER
指明镜像维护着及其联系方式(一般是邮箱地址),例如
MAINTAINER BRUCELIU<bruceliu9527@163.com>
不过,MAINTAINER并不推荐使用,更推荐使用LABEL来指定镜像作者,例如:
LABEL maintainer="bruceliu.cn"
[逐渐废弃] LABLE --替代MAINTANIER 具体使用: LABLE maintainer=“作者信息”
3.3.RUN
RUN 指令是用来执行命令行命令的。由于命令行的强大能力,RUN 指令在定制镜像时是最常用的指令之一。其格式有两种:
• shell 格式:RUN <命令>,就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的 RUN 指令就是这种格式.
• exec 格式:RUN [“可执行文件”, “参数1”, “参数2”],这更像是函数调用中的格式。
使用格式:
RUN RUN ["","",""]
构建镜像时运行的Shell命令,例如:
RUN ["yum", "install", "httpd"] RUN yum install httpd
RUN 就像 Shell 脚本一样可以执行命令,那么我们是否就可以像 Shell 脚本一样把每个命令对应一个 RUN 呢?比如
这样:
RUN apt-get update RUN apt-get install -y gcc libc6-dev make RUN wget http://download.redis.io/releases/redis-4.0.1.tar.gz RUN tar xzf redis-4.0.1.tar.gz RUN cd redis-4.0.1
Dockerfile 中每一个指令都会建立一层,RUN 也不例外。每一个 RUN 的行为,和刚才我们手工建立镜像的过程一样:新建立一层,在其上执行这些命令,执行结束后,commit 这一层的修改,构成新的镜像。 而上面的这种写法,创建了 多 层镜像。这是完全没有意义的,而且很多运行时不需要的东西,都被装进了镜像里,比如编译环境、更新的软件包等等。结果就是产生非常臃肿、非常多层的镜像,不仅仅增加了构建部署的时间,也很容易出错。 这是很多初学 Docker 的人常犯的一个错误。
Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过 127 层。上面的Dockerfile 正确的写法应该是这样
FROM centos RUN apt-get update \ && apt-get install -y gcc libc6-dev make \ && wget http://download.redis.io/releases/redis-4.0.1.tar.gz \ && tar xzf redis-4.0.1.tar.gz \ && cd redis-4.0.1
首先,之前所有的命令只有一个目的,就是编译、安装 redis 可执行文件。因此没有必要建立很多层,这只是一层的事情。因此,这里没有使用很多个 RUN 对一一对应不同的命令,而是仅仅使用一个 RUN 指令,并使用 && 将各个所需命令串联起来。将之前的 7 层,简化为了 1 层。
在撰写 Dockerfile 的时候,要经常提醒自己,这并不是在写Shell 脚本,而是在定义每一层该如何构建且,这里为了格式化还进行了换行。Dockerfile 支持 Shell 类的行尾添加 \ 的命令换行方式,以及行首 # 进行注释的格式。良好的格式,比如换行、缩进、注释等,会让维护、排障更为容易,这是一个比较好的习惯。
3.4.CMD
启动容器时执行的Shell命令,例如:
CMD ["-C", "/start.sh"] CMD ["/usr/sbin/sshd", "-D"] CMD /usr/sbin/sshd -D
3.5.EXPOSE
声明容器运行的服务端口,为容器打开指定要监听的端口以实现与外部通信,例如:
EXPOSE 80 443
3.6.ENV
ENV指令可以用于为docker容器设置环境变量 ENV设置的环境变量,可以使用 docker inspect命令来查看。同时还可以使用docker run --env =来修改环境变量。
具体用法: ENV JAVA_HOME /usr/local/jdk ENV JRE_HOME $JAVA_HOME/jre ENV CLASSPATH $JAVA_HOME/lib/:$JRE_HOME/lib/ ENV PATH $PATH:$JAVA_HOME/bin/
3.7.ADD
类似COPY命令,拷贝文件或目录到镜像中,例如:
ADD <src>...<dest> ADD html.tar.gz /var/www/html ADD https://xxx.com/html.tar.gz /var/www/html
3.8.COPY
拷贝文件或目录到镜像中,用法同ADD,只是不支持自动下载和解压,例如:
COPY ./start.sh /start.sh
3.9.ENTRYPOINT
启动容器时执行的Shell命令,同CMD类似,只是由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且,这些命令行参数会被当作参数传递给ENTRYPOINT指定指定的程序,例如:
ENTRYPOINT ["/bin/bash", "-C", "/start.sh"] ENTRYPOINT /bin/bash -C '/start.sh'
PS:Dockerfile文件中也可以存在多个ENTRYPOINT指令,但仅有最后一个会生效。
3.10. VOLUME
创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。例如:
VOLUME ["/var/lib/mysql"]
只能定义docker管理的卷: VOLUME /data/mysql运行的时候会随机在宿主机的目录下生成一个卷目录!
一般不会在Dockerfile中用到,更常见的还是在docker run的时候指定-v数据卷。
3.11 USER
为RUN、CMD和ENTRYPOINT执行Shell命令指定运行用户,例如:
USER <user>[:<usergroup>] USER <UID>[:<UID>] USER bruceliu
3.12 WORKDIR
Docker 默认的工作目录是/,只有 RUN 能执行 cd 命令切换目录,而且还只作用在当下下的 RUN,也就是说每一个 RUN 都是独立进行的。
如果想让其他指令在指定的目录下执行,就得靠 WORKDIR。WORKDIR 动作的目录改变是持久的,不用每个指令前都使用一次 WORKDIR。
WORKDIR /usr/local/tomcat/
3.13.小总结
4.DockerFile案例
4.1.Base镜像(scratch)
Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的
4.2.自定义镜像mycentos
Docker Hub默认CentOS镜像什么情况??
- 准备编写DockerFile文件
[root@localhost myfile]# pwd /root/myfile [root@localhost myfile]# vi mycentos_dockerfile
- myCentOS内容DockerFile
FROM centos MAINTAINER bruceliu<bruceliu167@126.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
- 构建
命令:
docker build -t 新镜像名字:TAG .
会看到 docker build 命令最后有一个 .
. 表示当前目录
[root@localhost myfile]# docker build -f /root/myfile/mycentos_dockerfile -t mycentos:1.3 . Sending build context to Docker daemon 2.048 kB Step 1/10 : FROM centos ---> 9f38484d220f Step 2/10 : MAINTAINER bruceliu<bruceliu167@126.com> ---> Using cache ---> 281446cb753d Step 3/10 : ENV MYPATH /usr/local ---> Using cache ---> 2e09cdb61576 Step 4/10 : WORKDIR $MYPATH ---> Using cache ---> 4aa136d65f26 Step 5/10 : RUN yum -y install vim ---> Using cache ---> 585392f09407 Step 6/10 : RUN yum -y install net-tools ---> Using cache ---> 9c7971b08e59 Step 7/10 : EXPOSE 80 ---> Using cache ---> 6741c0b61390 Step 8/10 : CMD echo $MYPATH ---> Using cache ---> fb1b4b72ba02 Step 9/10 : CMD echo "success--------------ok" ---> Using cache ---> 3d636347cc9a Step 10/10 : CMD /bin/bash ---> Using cache ---> 720d4eb5c5f0 Successfully built 720d4eb5c5f0
- 运行
docker run -it 新镜像名字:TAG
可以看到,我们自己的新镜像已经支持vim/ifconfig命令,扩展成功了。
[root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE docker.io/mongo latest 9c02a5a12c52 Less than a second ago 413 MB mycentos 1.3 720d4eb5c5f0 50 minutes ago 480 MB bruceliu/centos9527 latest 071e944a589b 8 hours ago 202 MB bruceliu/tomcat 7-jre7 a66f9aba334d 13 hours ago 359 MB docker.io/tomcat 7-jre7 47c156f4d4e3 5 weeks ago 359 MB docker.io/mysql latest 7bb2586065cd 2 months ago 477 MB docker.io/centos 7 9f38484d220f 3 months ago 202 MB docker.io/centos latest 9f38484d220f 3 months ago 202 MB [root@localhost ~]# docker run -it mycentos:1.3 [root@50784a17d114 local]# pwd /usr/local [root@50784a17d114 local]# vi 1.txt [root@50784a17d114 local]# ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.17.0.3 netmask 255.255.0.0 broadcast 0.0.0.0 inet6 fe80::42:acff:fe11:3 prefixlen 64 scopeid 0x20<link> ether 02:42:ac:11:00:03 txqueuelen 0 (Ethernet) RX packets 8 bytes 656 (656.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 8 bytes 656 (656.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> 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
- 列出镜像的变更历史
命令:
docker history 镜像名
[root@localhost ~]# docker history 720d4eb5c5f0 IMAGE CREATED CREATED BY SIZE COMMENT 720d4eb5c5f0 53 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "/b... 0 B 3d636347cc9a 53 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "ec... 0 B fb1b4b72ba02 53 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "ec... 0 B 6741c0b61390 53 minutes ago /bin/sh -c #(nop) EXPOSE 80/tcp 0 B 9c7971b08e59 53 minutes ago /bin/sh -c yum -y install net-tools 112 MB 585392f09407 54 minutes ago /bin/sh -c yum -y install vim 167 MB 4aa136d65f26 About an hour ago /bin/sh -c #(nop) WORKDIR /usr/local 0 B 2e09cdb61576 About an hour ago /bin/sh -c #(nop) ENV MYPATH=/usr/local 0 B 281446cb753d About an hour ago /bin/sh -c #(nop) MAINTAINER bruceliu<bru... 0 B 9f38484d220f 3 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B <missing> 3 months ago /bin/sh -c #(nop) LABEL org.label-schema.... 0 B <missing> 3 months ago /bin/sh -c #(nop) ADD file:074f2c974463ab3... 202 MB
5.小结
- Dockerfile指令用法详解【18年新版】-罗洋-专题视频课程
- Docker Dockerfile详解
- Docker入门与实践之 Dockerfile 语法详解
- Dockerfile HEALTHCHECK详解
- DockerFile 参数详解
- Docker学习(3):Dockerfile文件详解与构建缓存
- Docker基础教程之Dockerfile语法详解
- Dockerfile中的ARG指令详解
- dockerfile详解
- Docker--Dockerfile详解
- Docker Dockerfile详解
- docker Dockerfile详解
- DockerFile详解
- 详解docker中Dockerfile指令创建镜像
- Dockerfile详解(附录如何构建一个Dockerfile)
- dockerfile命令详解
- Dockerfile详解
- 【转载】Dockerfile文件详解
- Docker Dockerfile详解
- Docker学习之路(二)DockerFile详解