dockerfile命令详解
from
定义基础镜像,比如你写官方定义的centos ubuntu等等,或者你用其它人的都OK,有基础镜像就是尽力减少基础环境的劳动。
eg
FROM ubuntu
image.png
我们看到命令都是大写的,约定俗成,遵守即可。
copy
复制 ,https://docs.docker.com/engine/reference/builder/#copy
最简单的
COPY src dst
src 是你宿主机路径,dst是这个容器里面的路径。
image.png当然你可以写多个src,复制多个文件到容器。
image.pngADD
和copy差不多,就是更强一点,比如,ADD一个tar.gz文件,不仅它会复制上去,它还会解压了。
FROM alpine
ADD jdk-13.0.2_linux-x64_bin.tar.gz /usr/local
ENV love nini
ENV me=qdc
image.png
不仅解压了,压缩的文件也干掉了,太方便了。
LABEL
定义一些镜像的元数据, 比如维护者是是谁。
ENV
定义环境变量
比如
FROM alpine
ENV love nini
ENV me=qdc
这两种都可以的。
image.png比如将来我们转个JDK,maven,按需解压后,就可以了。
FROM ubuntu
ADD jdk-13.0.2_linux-x64_bin.tar.gz /usr/local
ENV JAVA_HOME /usr/local/jdk-13.0.2
ENV PATH=$PATH:$JAVA_HOME/bin
image.png
现在装个JDK是不是so easy。
CMD
CMD指令指定在启动容器时要运行的命令。它类似于RUN指令,但不是在构建容器时运行命令,而是在启动容器时指定要运行的命令,这与使用docker RUN命令启动容器时指定要运行的命令很相似,例如:
docker run -it xx/yy /bin/bash
等效于
CMD ["/bin/bash"]
你还可以给命令传递参数
CMD ["/bin/bash",'-l']
注意到该命令包含在一个数组中。这告诉Docker以“原样”运行命令。还可以在不使用数组的情况下指定CMD指令,在这种情况下,Docker会在命令前加上/bin/sh -c。这可能会在执行命令时导致意外的行为。因此,建议始终使用数组语法。
最后,重要的是要理解我们可以使用docker run命令重写CMD指令。如果在Dockerfile和docker run命令行中分别指定一个CMD,那么命令行将覆盖Dockerfile的CMD指令。一会我们看ENTRYPOINT,它们也是有区别的。
我们看个案例
FROM alpine
CMD ["/bin/sh"]
如果运行命令里面没有传入其它命令则走 /bin/sh
docker build .
docker run -it 1ca294e5b8d9
如果运行命令是
docker run -it 1ca294e5b8d9 ps
image.png
最后一点主意:
在Dockerfile中只能指定一条CMD指令。如果指定了多条指令,则将使用最后一条CMD指令。如果需要在启动容器时运行多个进程或命令,则应使用诸如Supervisor之类的服务管理工具。
ENTRYPOINT
ENTRYPOINT指令与CMD指令密切相关,常常与之混淆。那么两者有什么区别,为什么两者都需要呢?正如我们刚刚发现的,我们可以重写docker run命令行上的CMD指令。 有时候,当我们希望容器以某种方式运行时,这并不是很好。 ENTRYPOINT指令提供的命令不太容易被覆盖。 相反,我们在docker run命令行上指定的所有参数将作为参数传递给ENTRYPOINT中指定的命令。 我们来看一个ENTRYPOINT指令的示例。
FROM ubuntu:18.04
LABEL maintainer="singkingcho@gmail.com"
ADD sources.list /etc/apt/
RUN apt-get update ; apt-get install -y nginx
RUN echo "Hi,baby " > /var/www/html/index.html
ENTRYPOINT ["/usr/sbin/nginx"]
docker build -t="qiduaozhang/static_web" .
docker run -it -p 80:80 qiduaozhang/static_web -g "daemon off;"
我们重建了我们的镜像,然后启动了一个交互式容器。我们指定了参数-g “daemon off;”。此参数将传递给ENTRYPOINT指令中指定的命令,该命令将成为/usr/sbin/nginx -g "daemon off;"
。这个命令将在前台启动Nginx守护进程,并让容器作为web服务器运行。为了让大家能看到,我们指定了端口映射方便外部访问得到。
你可以使用等价写法。
FROM ubuntu:18.04
LABEL maintainer="singkingcho@gmail.com"
ADD sources.list /etc/apt/
RUN apt-get update ; apt-get install -y nginx
RUN echo "Hi,baby " > /var/www/html/index.html
ENTRYPOINT ["/usr/sbin/nginx","-g","daemon off;"]
docker build -t="qiudaozhang/static_web" .
docker run -it -p 80:80 qiudaozhang/static_web
效果一样。
我们还可以结合ENTRYPOINT和CMD来做一些整洁的事情。例如,我们可能需要在Dockerfile中指定以下内容。
ENTRYPOINT ["/usr/sbin/nginx"]
CMD ["-h"]
现在,当我们启动一个容器时,我们指定的任何选项都将传递给Nginx守护进程;例如,我们可以指定-g“daemon off”;就像我们在前面运行守护进程一样。如果我们没有指定要传递给容器的任何内容,那么-h将由CMD指令传递,并返回Nginx帮助文本/usr/sbin/Nginx -h。
FROM ubuntu:18.04
LABEL maintainer="singkingcho@gmail.com"
ADD sources.list /etc/apt/
RUN apt-get update ; apt-get install -y nginx
RUN echo "Hi,baby " > /var/www/html/index.html
ENTRYPOINT ["/usr/sbin/nginx"]
CMD ["-h"]
# 现在我们传递了参数
docker run -it -p 80:80 qiudaozhang/static_web -g "daemon off;"
依然以前端守护进程的方式跑动。
如果没传递参数,那么 CMD里面的 -h
传递给ENTRYPOINT,就成了nginx的求助命令了。
docker run -it -p 80:80 qiudaozhang/static_web
image.png
这使我们可以构建默认命令,以在容器运行时结合docker run命令行上的可覆盖选项和标志来执行。
如果在运行时需要决定,则可以使用带有--entrypoint标志的docker run命令覆盖ENTRYPOINT指令。
WORKDIR
WORKDIR指令提供了一种方法,用于设置容器的工作目录以及从映像启动容器时要执行的ENTRYPOINT和/或CMD。
我们可以使用它来设置一系列指令或最终容器的工作目录。 例如,要为特定指令设置工作目录,我们可以:
WORKDIR /usr/local
RUN touch love.txt
WORKDIR /opt/
RUN mkdir baby
image.png