在上一篇文章写给后端的Docker初级入门教程:实战篇最后咱们有提到用DockerFile来构建和定制属于咱们本身的镜像,由于时间和篇幅问题,上一篇文章对DockerFile只作了一个简单的介绍和使用,并无对DockerFile具体的指令进行详细的介绍和解释,本篇,做为上一篇实战篇的额外补充篇,咱们将从DockerFile基础的命令入手,一步一步的去构建一个属于咱们本身的镜像出来。java
Dockerfile是由一系列命令和参数构成的脚本,一个Dockerfile里面包含了构建整个image的完整命令。Docker经过docker build执行Dockerfile中的一系列命令自动构建image。python
这里咱们仍然选择咱们上一篇使用的在centos基础上定制咱们本身的镜像为本章的代码实例,代码以下:linux
FROM centos //继承至centos
ENV mypath /tmp //设置环境变量
WORKDIR $mypath //指定工做目录
RUN yum -y install vim //执行yum命令安装vim
RUN yum -y install net-tools //执行yum命令安装net-tools
EXPOSE 80 //对外默认暴露的端口是80
CMD /bin/bash //CMD 容器启动命令,在运行容器的时候会自动执行这行命令,好比当咱们 docker run -it centos 的时候,就会直接进入bash
复制代码
以后再经过docker build 命令编译该DockerFile即可以获得一个属于本身的镜像了。nginx
而后编译该镜像
docker build -f ./DockerFile -t mycentos:1.3.
-t 新镜像名字:版本
-f 文件 -d 文件夹
复制代码
运行该镜像会发现vim和net-tools在咱们新的容器中已经能够正常使用了。git
接下来呢,咱们将从FROM命令开始逐行介绍,最终完成对DockerFile经常使用命令的了解和掌握。程序员
既然咱们是在原有的centos镜像的基础上作定制,那么咱们的新镜像也必定是须要以centos这个镜像为基础的,而FROM命令则表明了这个意思,在DockerFile中,基础镜像是必须指定的,FROM指令的做用就是指定基础镜像,所以一个DockerFile中,FROM是必备的指令,并且就像java,python的import关键字同样,在DockerFile中,FROM指令必须放在第一条指令的位置github
固然,这个时候可能有朋友会问了,我要是不想在其余的镜像上定制镜像怎么办呢,没问题啊,Docker 提供了scratch 这个虚拟镜像,若是你选择 FROM scratch 的话,则意味着你不以任何镜像为基础,接下来所写的指令将做为镜像的第一层开始存在,固然,在某些状况下,好比linux下静态编译的程序,运行的时候不须要操做系统提供运行时的支持,这个时候FROM scratch 是没有问题的,反而会大幅下降咱们的镜像体积。sql
功能:设置环境变量docker
一样的,DockerFile也提供了两种格式:shell
这个指令很简单,就是设置环境变量而已,不管是后面的其它指令,如 RUN, 仍是运行时的应用,均可以直接使用这里定义的环境变量。
能够看到咱们示例中使用ENV设置mypath变量以后,在下一行WORKDIR则使用到了mypath这个变量
ENV mypath /tmp //设置环境变量
WORKDIR $mypath //指定工做目录
复制代码
功能,指定工做目录
格式为:WORKDIR 工做目录路径,若是这个目录不存在的话,WORKDIR则会帮助咱们建立这个目录。
设置过工做目录以后,当咱们启动容器,会直接进入该工做目录
[root@8081304919c9 tmp]#
复制代码
RUN 指令是用来执行命令行命令的。因为命令行的强大能力,RUN 指令也是在定制镜像时是较为经常使用的指令之一。
RUN命令的格式一共有两种,分别是:
Shell 格式
RUN 命令,就像直接在命令行中输入命令同样,好比RUN yum -y install vim就是使用的这种格式
exec 格式
RUN["可执行文件","参数1","参数2"],感受就像调用函数同样
就像咱们在上一篇文章中说过的那样,DockerFile中每一条指令都会创建一层,好比咱们上面执行过下面这条命令
RUN yum -y install vim
复制代码
执行结束以后,则调用commit提交这一层的修改,使之构成一个新的镜像,怎么样,是否是豁然开朗了呢。
并无
那好吧
一样的,Dockerfile 支持 Shell 类的行尾添加 \ 的命令换行方式,以 及行首 # 进行注释的格式。良好的格式,好比换行、缩进、注释等,会让维护、排障更为容易,这是一个比较好的习惯。
提示:
若是使用apt方式安装的话,最后不要忘记清理掉额外产生的apt缓存文件,若是不清理的话会让咱们的镜像显得很是臃肿。由于DockerFile生成一层新的镜像的时候,并不会删除上一层镜像所残留的文件。
功能:声明端口
格式: EXPOSE 端口1 端口2
EXPOSE 指令是声明运行时容器提供服务端口,这固然只是一个声明,在运行时并不会由于这个声明应用就会开启这个端口的服务。这样声明主要是为了方便后期咱们配置端口映射。
以前介绍容器的时候曾经说过,Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,须要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主进程的启动命令的。
一样的,DockerFile也为咱们提供了两种格式来使用CMD命令:
示例中,咱们使用的是第一种:
CMD /bin/bash
复制代码
这条指令带来的效果就是,当咱们经过run -it 启动命令的时候,容器会自动执行/bin/bash,centos默认也是CMD /bin/bash,因此当咱们运行centos镜像的时候,会自动进入bash环境里面。
固然,咱们也能够经过运行时指定命令的方式来体换默认的命令,好比:
docker run -it centos cat /etc/os-release
复制代码
这样当咱们运行镜像的时候,cat /etc/os-release就会替代默认的CMD /bin/bash 输出系统的版本信息了。
若是使用 shell 格式的话, 实际的命令会被包装为 sh -c 的参数的形式进行执行。
好比:
CMD echo $HOME
复制代码
在实际执行中,会将其变动为
CMD [ "sh", "-c", "echo $HOME" ]
复制代码
固然还有不少初学者特别容易犯的问题,就是去启动后台服务,好比:
CMD service nginx start
复制代码
这样子去用,会发现容器运行了一会就自动退出了。
因此,?????
咱们以前不止一次的提醒过,容器不是虚拟机,容器就是进程,容器内的应用都应该之前台运行,而不是像虚拟机,物理机那样去运行后台服务,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它须要关心的东西。
怎么理解呢?想一想偶像剧,容器是女主角,主进程是男主角
你走了,我也不活了(撕心裂肺大哭),大概就是这么个意思。
正如咱们前面所提出的,实际上CMD service nginx start 最终会被理解为:
CMD [ "sh", "-c", "service nginx start"]
复制代码
在这里,咱们主进程实际就是sh,当咱们service nginx start执行完毕以后,那么sh天然就会退出了,主进程退出,容器天然就会相应的中止。争取的作法是直接执行nginx可执行文件,而且声明之前台的形式运行:
CMD ["nginx", "-g", "daemon off;"]
复制代码
到这里,咱们示例中所涉及到的命令已经讲完了,固然,这并不够,Docker中仍然有不少命令是咱们使用比较频繁的,下面咱们的部分做为补充,讲一下其余经常使用的DockerFile命令。
功能:复制文件
Docker依旧提供了两种格式供咱们选择:
到这里你们其实会发现,Docker提供的两种格式其实都是差很少的用法,一种相似于命令行,一种则相似于函数调用。
第一种例如(将package.json拷贝到/usr/src/app/目录下):
COPY package.json /usr/src/app/
复制代码
其次,目标路径 能够是容器内的绝对路径,也能够是相对于工做目录的相对路径 ,工做目录能够用 WORKDIR 指令来指定,若是须要改变文件所属的用户或者用户组,能够加上--chown 选项。
须要注意的是,使用 COPY 指 令,源文件的各类元数据都会保留。好比读、写、执行权限、文件变动时间等。这 个特性对于镜像定制颇有用。
ADD命令能够理解为COPY命令的高级版,格式和用法与COPY几乎一致,ADD在COPY的基础上增长了一些功能,好比源路径能够是一个URL连接,当你这么用的时候,Docker会尝试着先将该URL表明的文件下载下来,而后复制到目标目录上去,其余的则是在COPY的基础上增长了解压缩之类的操做,码字码的手疼,须要了解的朋友能够去官网查看相关的文档,这里我就不延申了。
在上一篇中,咱们有讲容器卷这个概念,为了防止运行时用户忘记 将动态文件所保存目录挂载为卷,在 Dockerfile 中,咱们能够事先指定某些 目录挂载为匿名卷,这样在运行时若是用户不指定挂载,其应用也能够正常运 行,不会向容器存储层写入大量数据。
例如:
VOLUME /data
复制代码
运行时经过-v参数便可以覆盖默认的匿名卷设置。
功能:指定当前用户
格式:USER 用户名:用户组
USER 指令和 WORKDIR 类似,都是改变环境状态并影响之后的层。WORKDIR 是改变工做目录,USER 则是改变以后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。固然,和 WORKDIR 同样,USER 只是帮助你切换到指定用户。
固然这个大前提是,你的User用户是事先存在好的。
不知不觉间,Docker系列初级入门教程已经发到了第四篇,篇幅也到了一万多字,前三篇文章加起来在掘金上慢慢有了大概1500左右的阅读量,我知道这点对于不少掘金大佬来讲只是微不足道的一点,但对于现阶段的我来讲已经很是知足了,历来没有想到过有一天本身也能够经过分享去帮助到别人,正如我以前经过别人的技术博客学习那样。
这个系列完结了吗?我想初级篇应该是完结了,可是Nginx的初级入门教程,即将到来的Mysql,Netty等等并无,因为目前还没有毕业,尚未接受过工做的毒打(滑稽),因此只能尽本身的能力去写一些基础的入门教程,因此完结了吗?并无,技术之路永无止境,只要咱们一直在坚持学习,我想,咱们能够一直继续下去。
感谢掘金,你们好,我是韩数,咱们下期文章再见!
最后,相关笔记已经同步开源至Github(欢迎star): github.com/hanshuaikan…
必定要记得给个star哦。
提早祝你们1024程序员节快乐!