创建Docker Hub账号
- Docker Hub:https://hub.docker.com/
- 我们可以自己注册一个Docker Hub账号,然后将构建好的镜像推送到Docker Hub或者用户自己的私有Registry中
- 创建账号之后,可以输入下面的命令登录到Docker Hub
sudo docker login
- 个人认证信息配置文件:登录完成之后会将认证信息保存起来以供以后使用,信息会保存到$HOME/.dockercfg文件中。从Docker 1.7.0开始,该文件变为了$HOME/.docker/config.json
- 退出登录的命令如下:
sudo docker logout
演示案例
- 第一步:运行一个带有ubuntu镜像的容器
sudo docker run -i -t ubuntu /bin/bash
- 第二步:然后我们在该ubuntu镜像系统中安装Apache软件包
# 更新,-yqq忽略所有提示信息 apt-get -yqq update # 安装apache2服务器 apt-get -y install apache2
- 第三步:现在我们在这个镜像中安装了Apache2的服务器,我们想把这个镜像的当前状态保存下来,这样就不必每次都创建一个新容器并在此安装了。可以执行下面的命令来提交指定的容器:
# 查看刚才那个容器的ID sudo docker ps -a # 提交定制容器,需要指定容器ID、镜像名 sudo docker commit f3f694f1fc97 jamtur01/apache2
- 第四步:查看一下新创建的镜像
sudo docker images jamtur01/apache2
- 第五步:可以通过dcoker inspect命令查看新创建的镜像的详细信息
sudo docker inspect jamtur01/apache2
- 可以尝试着以上面创建的新镜像运行一个容器
sudo docker run -i -t jamtur01/apache2
演示案例
- 在提交新定制的镜像时还可以指定更定的信息选项,例如:
- -m:用来指定提交时的备注信息
- -a:列出该镜像的作者信息
- 并且下面的镜像还给其指定了一个webserver标签
sudo docker commit -m"A new custom image" -a"dongyusheng" f3f694f1fc97 jamtur01/apache2:webserver
- 查看一下新创建的镜像
sudo docker images jamtur01/apache2:webserver
- 可以通过dcoker inspect命令查看新创建的镜像的信息(作者和备注)
sudo docker inspect --format='{{ .Author }} {{ .Comment }}' jamtur01/apache2:webserver
- 可以尝试着以上面创建的新镜像运行一个容器
sudo docker run -i -t jamtur01/apache2:webserver /bin/bash
- 现在我们本机一共有下面这些容器,图中圈出来的是新创建的镜像的名称
sudo docker ps -a
第一步:创建一个Dockfile文件
- 第一步:自己建立一个目录(取名随意),然后进入目录创建一个文件名为Dockfile的文件(必须名为Dockerfile)
mkdir ~/static_web cd ~/static_web touch Dockerfile
- 此处我们创建了一个名为static_web的目录来保存Dockfile,这个目录就是我们的构建环境,Docker称此环境为上下文或者构建上下文。Docker会在构建镜像时将构建上下文和该上下文的文件和目录上传到Docker守护进程。这样Docker守护进程就能直接访问用户想在镜像中存储的任何代码、文件或者其他数据
- 第二步:编写上面创建的Dockfile文件,内容如下:
# Version: 0.0.1 FROM ubuntu:16.04 MAINTAINER dongyusheng "[email protected]" RUN apt-get update && apt-get install -y nginx RUN echo 'Hi, I am in your container' > /usr/share/nginx/html/index.html EXPOSE 80
- 下面介绍上面Dockerfile文件使用到的指令
- FROM指令:
- 每个Dockerfile的第一条指令必须是FROM
- 该指令指定了一个已经存在的镜像,后续指令都将基于该镜像进行,这个镜像备被称为基础镜像。在此演示案例中,我们以ubuntu:16.04作为基础镜像
- MAINTRINER指令:该指令告诉Docker该镜像的作者是谁,以及作者的电子邮箱地址
- RUN指令:
- RUN指令就是来指定在镜像中执行的命令。例如在这个演示案例中,我们执行了两条命令
- 备注:默认情况下,RUN指令会在shell里使用命令包装器/bin/sh -c来执行。如果在一个不支持shell的平台上运行或者不希望在shell中运行(比如避免shell字符串篡改),也可以使用exec格式的RUN指令。演示案例如下:
# 用一个数组来指定要运行的命令和传递给该命令的每个参数 RUN { "apt-get", " install", "-y", "nginx" }
- EXPOSE指令:
- 该指令告诉Docker该容器内的应用程序将会使用容器的指定端口
- 这并不意味着可以自动访问任意容器运行中的服务的端口(这里为80)
- 处于安全的原因,Docker并不会自动打开该端口,而是需要用户在使用docker run运行容器时来指定需要打开哪些端口。下面我们会看到如何从这一镜像创建一个新容器
- 可以指定多个EXPOSE指令来向外部公开多个端口
- 备注:Docker也可以使用EXPOSE指令来帮助将多个容器链接,我们可以在“在测试中使用Docker”看到相关内容。用户可以在运行时以docker run命令通过--expose选项来指定对外部公开的端口
第二步:基于Dockerfile构建新镜像
- 上面我们的Dockerfile已经书写好了,现在执行下面的命令来构建一个新镜像:
- -t:新镜像的名称
- .:表示Dockerfile文件的路径,此处我们在当前目录,因此就用了.表示
sudo docker build -t="jamtur01/static_web" .
- 结果分析:
- 从上图可以看到命令输入之后,会将构建上下文传到Docker守护进程中(第一行)。如果在构建上下文的根目录存在以.dockerignore命令的文件的话,那么该文件内容会按行进行分割,每一行都是一条文件过滤匹配模式。这非常像.gitignore文件,该文件用来设置哪些文件不会被当做构建上下文的一部分,因此可以防止它们被上传到Docker守护进程中去。该文件中的匹配模式的匹配规则采用了Go语言中的filepath(http://golang.org/pkg/path/filepath/#Match)
- Dockerfile中的每条指令都会被顺序执行,每一条指令对应一条“Step”,然后返回该指令的新镜像的ID,最后所有指令都执行完成之后,最终镜像的ID为b22dcf7f0505
- 附加:如果不设置标签,那么Docker会自动为镜像设置一个latest标签。我们也可以为镜像设置标签,例如下面将其标签设置为v1
sudo docker build -t="jamtur01/static_web":v1 .
- 附加:docker build最后一个参数为Dockerfile文件的路径,除了在本地目录中查找,还可以指定一个Git仓库的源地址来告诉Dockerfile文件的位置。例如:
sudo docker build -t="jamtur01/static_web":v1 [email protected]:jamtur01/docker-static_web
- -f选项:自Docker 1.5.0开始,可以通过-f选项指定一个区别于标准Dockerfile的构建源的位置。例如,下面的命令将当前路径下的file文件作为Dockerfile文件
sudo docker build -t="jamtur01/static_web":v1 ./file
第三步:查看新镜像
- 现在可以看一下新构建的新镜像,可以使用以前介绍过的docker images命令来查看,如下所示:可以看到镜像ID与上面最后生成的镜像ID相同
sudo docker images jamtur01/static_web
- 如果想要深入镜像是如何构建出来的,可以使用docker history命令,如下所示:
- 从下面的结果可以看到新构建的jamtur01/static_web镜像的每一层,以及创建这些曾的Dockerfile指令
sudo docker history jamtur01/static_web
第四步:从新镜像启动容器
- 我们在镜像中安装了Nginx,现在我们可以用该镜像来运行一个容器,命令如下:
- -d:这个参数在前面文章已经介绍过了,让该容器以守护进程的方式在宿主机中运行
- -p:运行容器时,将容器的80端口映射到宿主机的一个随机端口上
- 最后我们运行了nginx程序,并且将其配置文件的daemon参数改为了off,让Nginx在容器中已非守护进程的方式运行程序
sudo docker run -d -p 80 --name static_web jamtur01/static_web nginx -g "daemon off;"
- 运行一个容器时,Docker可以通过两种方法来在宿主机上分配端口:
- Docker可以在宿主机上随机选择一个位于32768~61000的一个比较大的端口号来映射到容器中的80端口上(上面的演示案例就是的,宿主机随意选择一个端口映射到Docker容器的80端口上)
- 可以在Docker宿主机中指定一个具体的端口号来映射到容器的80端口上(下面有演示案例)
- 现在我们可以来查看容器的端口分配情况,如下所示,宿主机的32768端口映射到了Docker容器的80端口上
sudo docker ps -l
- 现在我们可以该地址和端口来访问容器内部的nginx服务器。例如:
curl localhost:32768
- 我们也可以docker port命令来查看容器的端口的映射情况,例如下面查看容器80端口的映射情况:
# 通过容器ID sudo docker port 5c194f6d65b8 80 # 或者通过容器名称查看 sudo docker port static_web 80
附加:映射指定地址和端口
- 在第四步中,我们将宿主机的随机端口映射到了容器的80端口上,我们还可以将容器的端口映射到主机的指定端口上
- 例如,下面是将容器的80端口映射到本地宿主机的8080端口上:
sudo docker run -d -p 8080:80 --name static_web jamtur01/static_web nginx -g "daemon off;"
- 也可以将容器的端口映射到宿主机指定的地址和端口上,例如下面将容器的80端口映射到本地宿主机127.0.0.1接口的80端口上
sudo docker run -d -p 127.0.0.1:80:80 --name static_web jamtur01/static_web nginx -g "daemon off;"
- 还可以将容器的端口映射到宿主机指定接口的随机端口上,例如下面将容器的80端口映射到本地宿主机127.0.0.1接口的随机端口上
sudo docker run -d -p 127.0.0.1:80 --name static_web jamtur01/static_web nginx -g "daemon off;"
- 也可以在端口绑定时使用/udp后缀来指定UDP端口
- -P选项:
- 该选项可以用来对外公开在Dockerfile中通过EXPOSE指令公开的所有端口
- 例如,下面容器运行时,会将"jamtur01/static_web"镜像的Dockerfile中EXPOSE公开的端口映射到映射到宿主机的一个随机端口上
sudo docker run -d -P --name static_web jamtur01/static_web nginx -g "daemon off;"
演示案例
- 例如上面我们将构建好的镜像推送到Docker Hub上,命令如下:
sudo docker push jamtur01/static_web
- 可以看到发生了错误,推送失败了,原因是:jamtur01/static_web仓库已经存在了
- 解决方法:更改仓库名和镜像名,改为自己的Docker Hub账号,例如我的Docker Hub账号为dongyusheng,因此就更改为dongyusheng/static_web
# 更改镜像名 docker tag jamtur01/static_web dongyusheng/static_web
- 接着重新进行推送,成功:
sudo docker push dongyusheng/static_web
- 推送完成之后,在自己的Docker Hub中可以看到该仓库和镜像
演示案例
- 待续,具体参阅《第一本Docker书》P90
sudo docker rmi dongyusheng/static_web
附加:删除多个/全部镜像
- 删除多个镜像,如下所示:
sudo docker rmi dongyusheng/static_web dongyusheng/apache2
- 删除全部镜像,与docker rm一样,Docker不支持全部删除的命令,因此可以按照下面的形式进行删除、
sudo docker rmi 'docker images -a -q'
演示案例
- 第一步:更改当前路径下的Dockerfile文件,将第一个RUN指令中的“nginx”误写为“ngix”,如下所示
# Version: 0.0.2 FROM ubuntu:16.04 MAINTAINER dongyusheng "[email protected]" RUN apt-get update && apt-get install -y ngin RUN echo 'Hi, I am in your container' > /usr/share/nginx/html/index.html EXPOSE 80
- 第二步:接着构建镜像,查看结果
sudo docker build -t="dongyusheng/static_web" .
- 第三步:可以看到在构建第三步的时候出错了,因为没有“ngin”这个软件
- 第四步:我们说过,Dockerfile每执行一条指令就会构造一个新的镜像,构建的时候虽然第3步出错了,但是前2步没有出错,前2不最后构造的镜像的ID为e6a19e1529ce
- 然后通过docker images和docker ps -a查看,虽然镜像没有构建成功,但是构建了一个容器,容器ID为“e63cb83ef973”,镜像名为“e6a19e1529ce”
- 第五步:我们可以尝试运行新创建的那个容器
sudo docker run -t -i e6a19e1529ce /bin/bash
- 第六步:输入nginx命令,可以看到没有安装成功,因为上面“docker build”的第3步出错了,只执行成功了前2步
sudo docker build --no-cache -t="dongshao/static_web" .
# Version: 0.0.3
FROM ubuntu:16.04
MAINTAINER dongyusheng "[email protected]"
ENV PEFRESHED_AT 2020-07-16
RUN apt-get -qq update
# Version: 0.0.3
FROM ubuntu:16.04
MAINTAINER dongyusheng "[email protected]"
ENV PEFRESHED_AT 2020-07-18
RUN apt-get -qq update
FROM fedora:20
MAINTAINER dongyusheng "[email protected]"
ENV PEFRESHED_AT 2020-07-16
RUN yum -q makecache
CMD指令
介绍
- CMD指令用于指定一个容器启动时要运行的命令
Dockerfile中只能有一条CMD指令
- Dockerfile中只能有一条CMD指令
- 如果指定了多条CMD指令,那么只有最后一条CMD指令会被使用
- 如果想要在启动容器时运行多个进程或者多条命令,可以考虑使用类似Supervisor这样的服务管理工具
与RUN指令的区别
- RUN指令是在使用"docker build"命令构建镜像时,让镜像执行的命令
- CMD指令是使用该镜像运行容器时,让容器运行的命令
CMD指令与"docker run"的关系
- 我们知道,在执行"docker run"让容器运行时,可以在"docker run"命令的最后加上命令让容器去运行
- CMD指令与上面的功能是一样的
演示案例
- 下面是Dockerfile中的1条CMD指令,其让容器运行时执行/bin/bash命令启动一个shell
CMD ["/bin/bash"]
- 上面的命令的功能等同于:
sudo docker run -i -t dongshao/images /bin/bash
- 当然,也可以为要运行的命令指定相关的参数与选项
- 备注:这种运行的方式是把要运行的命令存放在一个数组结构中,这告诉Docker按指定的原样来运行该命令。当然也可以不使用数组而是指定CMD指令,这时候Docker会在执行的命令前加上/bin/sh -c。这在执行该命令的时候可能会导致意料之外的行为,所以当命令有选项和参数时建议使用数组形式来存放要执行的命令
CMD ["bin/bash", "-l"]
"docker run"会覆盖CMD指令
- 概念:如果我们在Dockerfile中设置了CMD命令,但是同时执行"docker run"运行容器时指定了容器要运行的命令,那么"docker run"的命令会覆盖Dockerfile中的CMD指令,从而只执行"docker run"指定的命令
- 例如:下面的Dockerfile设置了一条CMD指令,让容器运行时运行/bin/bash
CMD ["/bin/bash"]
- 但是,我们在使用"docker run"运行容器时指定了容器要运行的命令"/bin/ps",那么CMD的/bin/bash命令就不会执行,只执行/bin/ps
sudo docker run -i -t dongshao/images /bin/ps
与ENTRYPOINT指令之间的相互关系
- CMD指令与ENTRYPOINT指令之间有相互配合的关系,见下面ENTRYPOINT指令的介绍
ENTRYPOINT指令
介绍
- ENTRYPOINT指令与CMD指令非常类似,也是用来在运行容器时执行命令,但是与CMD有许多不同的地方,看下面的一一介绍
演示案例
- 例如,我们在Dockerfile中设置下面的ENTRYPOINT指令,那么容器在运行时就会执行/usr/sbin/nginx,从而运行nginx服务器
ENTRYPOINY ["/usr/sbin/nginx"]
- 与CMD一样,当命令有参数和选项时,也可以以数组的形式设置命令。例如,下面让容器运行时执行"/usr/sbin/nginx -g daemon off"命令
ENTRYPOINY ["/usr/sbin/nginx", "-g", "daemon off;"]
"docker run"不会覆盖ENTRYPOINT指令,反而是传递给ENTRYPOINT使用
- "docker run"不会覆盖ENTRYPOINT指令,反而会将"docker run"最后的命令传递给ENTRYPOINT使用
- 例如:下面我们在Dockerfile中设置了如下的ENTRYPOINT指令,让其运行Nginx
ENTRYPOINY ["/usr/sbin/nginx"]
- 我们在启动一个容器时,在最后执行了-g "daemon off;",那么:
- "docker run"最后的一些参数与选项会传递给ENTRYPOINT指令
- 因此整个容器执行的命令是/usr/sbin/nginx -g daemon off
sudo docker run -i -t dongshao/images -g "daemon off;
但是"docker run"的--entrypoint选项会覆盖ENTRYPOINT指令
- 如果"docker run"命令带有--entrypoint选项,那么"docker run"也会覆盖Dockerfile中的ENTRYPOINT指令
ENTRYPOINT指令与RUN指令的使用
- 我们知道RUN指令与"docker run"最后输入的命令作用是相同的,因此RUN指定的命令也会接在ENRRYPOINT的命令后面
- 例如,下面的Dockerfile指定了ENTRYPOINT指令和CMD指令,那么容器运行时最终运行的命令是/usr/sbin/nginx -h
ENTRYPOINY ["/usr/sbin/nginx"] CMD ["-h"]
- RUN指令有时是作为ENTRYPOINT的默认参数使用的。例如,下面我们的Dockerfile执行了下面的命令
ENTRYPOINY ["/usr/sbin/nginx"] CMD ["-h"]
- 但是"docker run"时的命令是下面这样的
sudo docker run -i -t dongshao/images -g "daemon off;
- 那么运行容器时的意思就是,如果"docker run"最后没有指定命令,那么容器就执行/usr/sbin/nginx -h命令,如果"docker run"最后指定了命令,那么容器运行时执行的命令就是/usr/sbin/nginx -g daemon off
WORKDIR指令
介绍
- WORKDIR指令用来执行容器运行时,执行容器运行时的工作目录,ENTRYPOINT指令和/和CMD指令运行的命令就是在这个指令所指定的工作目录下执行的
演示案例
- 一个Dockerfile如下所示,其将容器的工作路径切换到/opt/webapp/db目录下,然后执行了RUN指令
WORKDIR /opt/webapp/db RUN bundle install
- 例如下面是使用多个WORKDIR:先将工作目录切换到/opt/webapp/db执行RUN指令,然后再将工作目录切换到/opt/webapp执行rackup命令
WORKDIR /opt/webapp/db RUN bundle install WORKDIR /opt/webapp/ ENTRYPOINT [ "rackup" ]
-w选项会覆盖WORKDIR指令
- "docker run"命令中的-w选项会覆盖Dockerfile中的WORKDIR指令
- 例如,下面设置了当前的工作路径为/var/log
sudo docker run -it -w /var/log dongshao/images pwd
ENV指令
介绍
- ENV指令用来在镜像构建中设置环境变量
演示案例
- 例如下面设置了一个环境变量RVM_PATH,其值为/home/rmv
ENV RVM_PATH /home/rmv
- 从Docker 1.4开始,可以指定多个环境变量。例如,下面设置了两个环境变量
ENV RVM_PATH=/home/rmv RVM_ARCHFLAGS="-arch i386"
一些注意点
- 当设置了环境变量之后,后面的任何RUN指令等操作都是基于这个环境变量进行操作
- 如果需要,可以通过在环境变量前加上一个反斜线来进行转义
- 该指令设置的环境变量,会在镜像中永久保存,因此基于该镜像创建的任何容器都会使用这个环境变量
-e选项
- ENV设置的环境变量是在镜像中永久保存的,因此每次创建容器,进入系统之后变量都会在系统中
- "docker run"的-e选项可以指定:只在本次创建的容器运行时有效,容器退出或删除后环境变量失效
- 例如,下面启动时指定容器的WEN_PORT环境变量为8080,当该容器退出后变量失效
sudo docker run -it -e "WEB_PORT=8080" dongshao/images
USER指令
介绍
- USER指令可以用来指定该镜像会以什么样的用户去运行
- 如果没有指定USER指令,默认的用户为root,因此容器运行时很多命令都不需要加上sudo
演示案例
- 例如的Dockerfile指定容器运行时,以nginx的身份去运行容器
USER nginx
还可以指定UID以及组或GID
- USER指令还可以指定用户名或UID以及组或GID,甚至是两者的组合
- 例如:
USER user USER user:group USER uid USER uid:gid USER user:gid USER uid:group
VOLUME指令
介绍
- USER指令用来向基于镜像创建的容器添加卷。一个卷是可以存在于一个或者多个容器内的特定的目录,这个目录可以绕过联合文件系统,并提供如下共享数据或者对数据进行持久化的功能:
- 卷可以在容器间共享和重用
- 一个容器可以不是必须和其他容器共享卷
- 对卷的修改是立即生效的
- 对卷的修改不会对更新镜像产生影响
- 卷会一直存在直到没有任何容器再使用它
- 卷功能让我们可以将数据(如源代码)、数据库或者其他内容添加到镜像中而不是将这些内容提交到镜像中,并且允许我们在多个容器间共享这些内容。我们可以利用此功能来测试容器和内部的应用程序代码,管理日志,或者处理容器内部的数据库
演示案例
- 下面这条指令会为基于此镜像创建的任何容器创建一个名为/opt/project的挂载点
VOLUME ["/opt/project"]
- 也可以以数组的形式指定多个卷。例如:
VOLUME ["/opt/project", "/data"]
docker cp命令
- docker cp和VOLUME指令相关并且也是很实用的命令。该命令允许从容器复制文件和复制文件到容器上。可以从Docker命令行文档中获取更多信息:http://docs.docker.com/engine/reference/commandline/cp
相关说明与演示案例
- 卷的介绍:https://blog.csdn.net/qq_41453285/article/details/107397371
- 卷的备份:https://blog.csdn.net/qq_41453285/article/details/107609836
ADD指令
介绍
- ADD指令用来将Dockerfile构建环境下的文件和目录复制到镜像中
演示案例
- 下面的Dockerfile中有如下的ADD指令,当基于该镜像的容器运行时,会将与当前Dockerfile同一路径中的softwarte.lic文件(宿主机中的)复制到容器的/opt/application/目录下,名为software.lic(名字其实可以自己指定的)
ADD software.lic /opt/application/software.lic
格式说明
- 在ADD文件时,Docker通过目的地址(后面的路径)参数末尾的字符来判断文件源(前面的路径)是目录还是文件
- 如果目标地址以/结尾,那么Docker就认为源位置指向的是一个目录
- 如果目标地址不是以/结尾,那么Docker就认为源位置指向的是文件
文件源也可以是URL格式的
- 例如,下面将一个网页中的文件下载到/root/目录下,名为wordpress.zip
ADD http://wordpress.org/latest.zip /root/wordpress.zip
对归档文件有特殊处理
- 如果文件源是本地归档文件(tar archive)时有特殊的处理,如果将一个归档文件(合法的归档文件包括gzip、bzip2、xz)复制到容器中,那么Docker会自动将归档文件解压
- 如果目的位置已经存在了归档文件同名的文件或者目录,那么目录位置中的文件或者目录不会被覆盖
- 目前Docker还不支持以URL方式制定的源位置中使用归档文件。这种行为稍显有点儿不统一,在以后的版本中应该会有所变化
- 例如,一个Dockerfile中的ADD指令如下
- 下面将当前构建目录下的latest.tar.gz文件解压之后复制到容器的/var/ww/wordpress/目录下
- 行为等同于带-x选项的tar命令一样
ADD latest.tar.gz /var/ww/wordpress/
如果目的位置不存在会怎么样?
- 如果目的位置不存在的话,Docker将会为我们在容器中创建这个全路径,包括路径中的任何目录
- 新创建的文件和目录的模式为0775,并且UID和GID都是0
ADD指令会使Dockerfile缓存失效
- 如果通过ADD指令向镜像添加一个文件或者目录,那么这将使Dockerfile中的后续指令都不能继续使用之前的构建缓存
COPY指令
介绍
- COPY指令非常类似于ADD指令,它们本根的不同是COPY只关心在构建上下文中复制本地文件,而不会去做文件提取(extraction)和解压(decomposition)的工作
演示案例
- 例如,下面是将宿主机当前构建目录下的conf.d/目录拷贝到镜像的/etc/apache2/目录下
COPY conf.d/ /etc/apache2/
相关说明
- 文件源路径必须是一个与当前构建环境相对的文件或者目录,本地文件都放到和Dockerfile同一个目录下。不能复制该目录之外的任何文件,因为构建环境将会上传到Docker守护进程,而复制是在Docker守护进程中运行的。任何位于构建环境之外的东西都是不可用的
- COPY指令的目的位置必须是容器内部的一个绝对路径
- 与ADD指令一样,如果目的位置不存在,那么也会进行创建,任何由该指令创建的文件或者目录的UID和GID都会设置为0
- 如果源路径是一个目录,那么这个目录将整个复制到容器中,包括文件系统元数据
- 如果源路径是一个文件,则该文件会随同元数据一起被复制
LABEL指令
介绍
- LABEL指令用于为Docker镜像添加元数据。元数据以键值对的形式展现
- LABEL指令是在Docker 1.6版本中加入的
演示案例
- 例如下面构建镜像时,会添加一个元数据version
LABEL version="1.0"
- 当然,你也可以在一条指令中指定多个元数据,不同的元数据用空格分隔
LABEL location="New York" type="Data Center" role="Web Server"
- 我们建议所有的元数据都放到一条LABEL指令中,以防止不同的元数据指令创建过多镜像层
查看镜像标签
- 通过docker inspect令来查看某个Docker镜像的标签信息。例如:
sudo docker inspect --format='{{ .ContainerConfig.Labels }}' dongshao/consul
STOPSIGNAL指令
- STOPSIGNAL指令用来设置停止容器时发送什么系统调用信号给容器。这个信号必须是内核系统调用表中合法的数,比如9,或者SIGNAME格式中的信号名称,如SIGKILL
- STOPSIGNAL指令是在Docker 1.9版本中引入的
ARG指令
介绍
- ARG指令用来定义可以在docker build构建镜像时传递构建运行时的变量,定义之后在执行"docker build"时使用--build-arg就可以使用该变量了
- ARG指令是在Docker 1.9版本中引入的,可以在Docker文档阅读详细的说明:https://docs.docker.com/engine/reference/builder/#arg
演示案例
- 例如,下面定义了两个变量,其中第二个变量拥有默认值
ARG build ARG webapp_user=user
- 当我们基于该Dockerfile构建镜像时,就可以输入下面的命令:
- 其中将build变量设置为1234
- 因为webapp_user有默认值了,因此下面就没有再指定
sudo docker build --build-arg build=1234 -t dongshao/webapp .
不要传递证书或者秘钥
- 有些人可能会使用ARG来传递证书或者秘钥之类的信息,但是千万别这么做,因为机密信息会在构建过程中以及镜像的构建历史中被暴露出来
预定义的ARG变量
- Dockerfile预定义了一组ARG变量,可以在构建时直接使用,而不必再到Dockerfile中自行定义了
- 预定义的ARG变量如下
HTTP_PROXY http_proxy HTTPS_PROXY https_proxy FTP_PROXY ftp_proxy NO_PROXY no_proxy
- 想要使用这些预定义的变量,在"docker build"命令中用--build-arg
= 来指定就可以了
ONBUILD指令
介绍
- ONBUILD指令能为镜像添加触发器
- 当一个镜像被用作其他镜像的基础镜像时(比如用户的镜像需要从某未准备好的位置添加源代码,或者用户需要执行特定于构建镜像的环境的构建脚本),该镜像中的触发器将会被执行
- 触发器会在构建过程中插入新指令,我们可以认为这些指令是紧跟在FROM之后指定的
- 触发器可以是任何构建指令
- 例如,下面的Dockerfile定义了2条ONBUILD指令
ONBUILD ADD . /app/src ONBUILD RUN cd /app/src && make
- 当然,可以在使用"docker inspect"来查看镜像或者容器的ONBUILD指令
- 有几条指令不能用在ONBUILD中,包括:FROM、MAINTRINER和ONBUILD本身。这么做的原因是为了防止Dockerfile构建过程中产生递归调用的问题
演示案例
- 下面创建一个apache2目录,然后进入创建一个Dockerfile文件
- Dockerfile内容如下,其中安装了apache2服务器
FROM ubuntu:16.04 MAINTAINER dongshao "https://blog.csdn.net/qq_41453285" RUN apt-get update && apt-get install -y apache2 ENV APACHE_RUN_USER www-data ENV APACHE_RUN_GROUP www-data ENV APACHE_LOG_DIR /var/log/apache2 ONBUILD ADD . /var/www/ EXPOSE 80 ENTRYPOINT ["/usr/sbin/apache2"] CMD ["-D", "FOREGROUND"]
- 我们使用上面的Dockerfile来构建一个镜像
sudo docker build -t="dongshao/apache2" .
- 查看创建好的镜像
sudo docker images dongshao/apache2
- 现在我们创建好了一个镜像,这个镜像中创建了apache2服务器,因此我们可以把这个镜像当做一个Web应用程序的模板,其他镜像可以以这个镜像为基础镜像来构建自己的Web应用程序
- 现在我们准备以上面的镜像为基础镜像来创建一个属于自己的镜像(添加自己想要的功能)。首先回到前一目录,创建一个自己Webapp的目录,然后创建一个Dockerfile
cd .. mkdir webapp cd webapp touch Dockerfile
- Dockerfile的内容如下
FROM dongshao/apache2 MAINTAINER dongshao "https://blog.csdn.net/qq_41453285" ENV APPLICATION_NAME webapp ENV ENVIRONMENT development
- 上面的Dockerfile使用了我们之前的dongshao/apche2镜像,又因为dongshao/apche2镜像的Dockerfile中设置了一条“ONBUILD ADD . /var/www/”指令,因此当我们构建镜像时就会执行这条命
- 因此,下面来构建看看,如下所示:
- 因为该镜像依赖于dongshao/apache2镜像,因此Step第一步的时候执行了dongshao/apache2镜像Dockerfile中的ONBUILD指令
sudo docker build -t="dongshao/webapp" .
总结
- 这种机制使得我们每次构建镜像时都会执行ONBUILD所指定的命令,因此可以将这种之前的镜像作为一种镜像模板
- ONBILD触发器会按照在父镜像中指定的顺序执行,并且只能被继承一次(也就是说只能在子镜像中执行,而不会在孙子镜像中执行)。例如,如果我们基于上面的"dongshao/webapp"再构建一个镜像,那么"dongshao/apache2"中的ONBUILD指令是不会在"dongshao/webapp"的子镜像中执行的