前言:
很抱歉,该篇文章拖延的时间有些长了。今天我们学入戏 docker 的 Dockerfile 指令详解,相信大家学完理论片后,对这个学习应该不会有太大的难度了。
下面开始学习:
copy 指令,指令格式:
copy 文件存放路径 目标路径
举例:将 home 目录下的 inde.html 文件复制到 /usr/local/tomcat/webapps/Root 目录下
cpoy /home/index.html /usr/local/tomcat/webapps/Root
WORKDIR 指令,指令格式:
WORKDIR 目录
例如:进入到 /usr/local/tomcat/ 目录,和 cd 命令及其类似,不过这是docker的指令
WORKDIR /usr/local/tomcat/
注意:WORKDIR 指令时候后,各层工作目录都将变成我们指定的路径,这个指令的使用会影响后面的几个指令,比如:ADD , RUN 等。
RUN 指令,指令格式有 shell 格式和 exec 格式:
RUN 命令 # shell 格式
RUN ["可执行文件", "参数1", "参数2"] # exec 格式
此命令和 Linux 命令及其类似,可以像 shell 一样执行每一步操作,但是有个注意点-- RUN 指令每一个指令都会创建一层,如果指令多,创建的层数也多。然后我们搞笑的是结束了,提交之后,明明修改了,怎么没变化。如果不懂请看 docker 理论篇,理解完在回来看 Dockerfile。
ADD 指令,指令格式:
ADD 文件或文件夹 指定目录下
例如:将 home 目录下的 inde.html 文复制到 /usr/local/tomcat/webapps/Root 目录下
ADD /home/index.html /usr/local/tomcat/webapps/Root
注意:ADD命令很牛逼,他可以自己解压缩,什么意思?就是假设我们将一个 tar.gz 复制到指定目标路径下,它会自动解压缩包将内容放到指定目录。但是也有点鸡肋,谁没事打个压缩包是吧?所以能用 copy 就用 copy 吧,当然特殊场景就特殊对待即可。
补充:ADD 指令还支持通配符,匹配将使用Go的 filepath.Match 规则完成,例如:
ADD hom* /mydir/ #将包含 hom 开头的文件全部复制到 mydir 目录下
ADD hom?.txt /mydir/ # ? 是一个占位符,占位符可以是任何一个字符 例如: home.txt
CMD 指令,指令格式有 shell 格式和 exec 格式和参数列表格式:
CMD 命令 # shell 格式
CMD ["可执行文件", "参数1", "参数2"] # exec 格式
CMD ["参数1", "参数2"...] #参数列表格式
这个指令和 RUN 指令真的太像了。就不做太多解释,先看看下面的例子:
CMD echo $HOME #输出环境变量
上面那句命令,会转换成 shell 的执行,转换后如下:
CMD [ "sh", "-c", "echo $HOME" ]
就是执行 shell 命令呀,牛掰。这就是为什么我们可以使用环境变量的原因,因为这些环境变量会被 shell 进行解析处理。
注意:① 只能有一条 CMD 多条 CMD 只有最后一条 CMD 才生效,其他都是无效的。
② 记住一点容器不是虚拟机,是一个进程,进程,进程
举个栗子:
我执行一个命令:
CMD service nginx start
上面好像很常见,我们在真机或虚拟机上面就是这么启动服务的。可是你拿到容器里执行,发现确实启动了,可是启动完就立即退出了。what? 什么情况?
解释如下:
① 容器里没有后台进程的概念,容器本身就是一个进程,里面执行的应用应该以前台的方式运行。前台后台概念就是我们之前直接执行 docker run tomcat 启动tomcat ,我们要按 Ctrl + C 结束那种就是前台,后面们学了在后面加个 -d 守护进程模式执行,就是后台,这就是简单理解吧。
② 我们执行的 CMD service nginx start 会被解释为 CMD [ "sh", "-c", "service nginx start"] 的,主进程是 sh,执行完 sh 就是结束掉主进程了,主进程都退出了,容器不应该也退出吗?
EXPOSE 指令,指令格式如下:
EXPOSE <port> [<port>/<protocol>...]
主要是暴露端口,例子:
EXPOSE 80/udp
无论是否在Dockerfile中写过该指令,都可以用如下覆盖:
docker run -p 80:80/tcp #暴露80 端口,很方便快捷
注意:docker的暴露的端口只是将对应端口服务公开给外界访问,并不会在宿主机上进行端口映射。
VOLUME 指令,指令格式如下:
VOLUME ["<路径1>", "<路径2>"...]
我们在将应用发布到容器后,尽量不要在容器层进行存储操作,应该讲数据放到宿主机的某个位置。这就要使用到数据卷的概念了。当然是用也很简单,如下:
VOLUME /var/log
ENV 指令,指令格式:
ENV <key> <value>
该命令只要是设置环境变量,例如:
ENV VERSION=1.0 DEBUG=on
ENTRYPOINT 指令,指令格式:
<ENTRYPOINT> "<CMD>"
这个东西怎么和 CMD 有关系呀?这个命令可以说是 CMD 的补充吧,CMD 不是万能,不能加参数得到不通的结果,而 ENTRYPOINT 让镜像变成像命令一样使用。
举个例子:
CMD [ "curl", "-s", "http://域名" ] #从某地下载东西
但是假设我们想看看请求的信息,我们家一个 -i ,如下?
docker run 域名 -i
结果是报错,找不到 -i 这个参数,因为镜像后面跟的是命令,命令。而 -i 是个参数,参数不是命令,所以会报错。这时们引用 ENTRYPOINT 可以很好的解决这个问题。我们修改成如下:
ENTRYPOINT [ "curl", "-s", "http://域名" ]
然后我们在执行
docker run 名字 -i
就可以查出请求信息了。CMD
的内容将会作为参数传给 ENTRYPOINT
,而这里 -i
就是新的 CMD
,因此会作为参数传给 curl
,从而达到了我们预期的效果。
常用命令就是这么多了,理解起来还真的有点难,耐心看看应该还是可以看懂的,如果不懂请参考 官方文档 我也是结合官方文档 + 各位大佬博客进行学习的。可能理解有误,欢迎批评指正。
接下来会补充 Dockerfile 定制镜像的内容,就在该篇写。
2 月 10 日补充。
Dockerfile 定制镜像
随便找个地方创建一个文件夹,然后在该文件夹下创建一个 Dockerfile 文件。
sudo touch Dockerfile
创建一个 index.html 文件,随便往里面写点内容。
如下:
编辑 Docokerfile 文件,添加如下内容:
FROM tomcat #基于什么镜像,Dockerfile 文件需要有 FROM 开头
WORKDIR /usr/local/tomcat/webapps/ROOT #切换到工作目录下
RUN rm -rf * #移除 /usr/local/tomcat/webapps/ROOT 目录下的所有东西
COPY index.html . #将我们写的 index.html 复制到 /usr/local/tomcat/webapps/ROOT 目录下,后 #面有个点,表示当前工作目录,就是 WORKDIR 目录
WORKDIR /usr/local/tomcat #切换 tomcat 默认工作目录下
上面的命令不懂得往上看,简单介绍就是 COPY 命令就类似我们 shell 里的 cd 。而 COPY 就类似的是 cp 了,很简单容易理解。
上面做完,保存退出吧。然后执行如下命令:构建我们定制的镜像
docker build -t tomcat:test1 .
构建完毕后,我们可以查看一下:
docker image ls
最后,我们可以启动镜像来查看是否成功:
docker run -p 8080:8080 4851ce85d6f3 #记得更换为自己镜像 ID
启动成功后,我们访问尝试:
定制镜像基本完成,难度也不大,看懂上面的 + 了解下理论基本就学会了,和 shell 命令类似,只是学下语法即可。最后祝大家新年快乐。