赞
踩
Dockerfile 是用于构建Docker镜像的脚本文件,由一系列指令构成。通过 docker build
命令构建镜像时,Dockerfile 中的指令会由上到下依次执行,每条指令都将会构建出一个镜像。这就是镜像的分层,因此,指令越多,层次数就越多,创建的镜像就越多,效率就越低。所以在定义Dockerfile
时,能在一个指令完成的动作就不要分为两条。
FORM
MAINTAINER
LABLE
docker inspect
可查看到 LABEL 与 MAINTAINER 的内容。ENV
WORKDIR
docker run
运行容器时,可以通过 -w
参数覆盖构建时所设置的工作目录。RUN
docker build
执行过程中,会使用 shell 运行指定的 command。docker build
执行过程中,会调用第一个参数"EXECUTABLE"指定的应用程序运行,并使用后面第二、三等参数作为应用程序的运行参数。CMD
docker run
后会立即调用执行"EXECUTABLE"指定的可执行文件,并使用后面第二、三等参数作为应用程序的运行参数。ENTRYPOINT
docker run
时,会调用执行"EXECUTABLE"指定的应用程序,并使用后面第二、三等参数作为应用程序的运行参数。docker run
时,会运行指定的 shell 命令。EXPOSE
docker run
命令时使用-p(小 p)
来指定说要真正暴露出的端口号。ARG
ADD
docker build
命令所指定的路径的。src 指定的文件可以是一个压缩文件,压缩文件复制到容器后会自动解压为目录;src 也可以是一个 URL,此时的 ADD 指令相当于 wget 命令;src 最好不要是目录,其会将该目录中所有内容复制到容器的指定目录中。dest 是一个绝对路径,其最后面的路径必须要加上斜杠,否则系统会将最后的目录名称当做是文件名的。COPY
ONBUILD
VOLUME
(1)scratch境像
在构建自己的镜像之前,首先要了解一个特殊的镜像 scratch。
scratch 镜像是一个空镜像,是所有镜像的 Base lmage(相当于面向类).对象编程中的Object类)。scratch 镜像只能在 Dockerfile 中被继承,不能通过 pull 命令拉取,不能 run,也没有 tag。不并且它也不会生成镜像中的文件系统层。在 Docker 中,scratch 是一个保留字,用户不能作为自己的镜像名称使用。
(2)安装编译器
yum install -y gcc gcc-c++
由于下面要编写、编译一段c语言代码,所以要先安装一下c语言的编译器。
由于后面在编译时要使用c的静态库,所以要再安装 glibc-static。·
yum install -y glibc-static
注意:
在CentOS 8上安装glibc-static时可能会遇到以下错误:No package glibc-static available。这是因为在CentOS 8中,glibc-static软件包已被移除。glibc-static软件包包含了glibc库的静态版本,用于编译和链接需要静态库的程序。然而,由于静态库的使用逐渐减少,CentOS 8决定将glibc-static软件包从默认仓库中删除。
如果您确实需要安装glibc-static,有几种解决方法可供选择:
使用其他发行版:如果您需要使用glibc-static,可以考虑使用其他发行版,如CentOS 7或Ubuntu等,它们可能仍然提供glibc-static软件包。
手动编译安装:您可以手动从源代码编译和安装glibc-static。首先,您需要下载glibc的源代码,并按照编译和安装指南进行操作。请注意,这是一项复杂的任务,需要一定的技术知识和经验。
寻找第三方仓库:您可以尝试寻找第三方仓库,这些仓库可能提供了glibc-static软件包。但请注意,使用第三方仓库存在一定的风险,请确保您从可信任的来源获取软件包。
(3)创建hello.c
在宿主机任意目录创建一个名称为 hello.c 的文件。这里在/root 下 mkdir 一个目录 hw,然后将 hello.c 文件创建在这里。文件内容如下:
# 创建目录
mkdir hw
# 进入目录
cd ./hw
# 编辑文件
vim hello.c
#include<stdio.h>
int main()
{
printf("hello my docker world\n");
return 0;
}
(4)编译测试hello.c
使用 gcc 编译 hello.c 文件。
(5)创建Dockerfile
在 hw 目录中新建 Dockerfile,内容如下:
FROM scratch
ADD hello /
CMD ["/hello"]
(6)构建镜像
-t 用于指定要生成的镜像的<repository>与<tag>。若省略 tag,则默认为 latest。
最后的点(.)是一个宿主机的 URL 路径,构建镜像时会从该路径中查找 Dockerfile 文件。同时该路径也是在 Dockerfile 中 ADD、COPY 指令中,若使用的是相对路径,那个相对路径就相对的这个路径。不过需要注意,即使 ADD、COPY 指令中使用绝对路径来指定源文件,该源文件所在路径也必须要在这个 URL 指定目录或子目录内,否则将无法找到该文件。
通过 docker images
查看本地镜像,可以看到新构建的 hello-my-world 镜像。
(7)运行新镜像
(8)为镜像重打标签
某镜像被指定为 latest 后,后期又出现了更新的版本需要被指定为 latest,那么原 latest 镜像就应被重打<tag>标签,否则,当最新版被发布为 latest 后,原镜像就会变为悬虚镜像。
通过 docker tag
命令可对镜像重打标签。所谓重打标签,实际是复制了一份原镜像,并为新的镜像指定新的<tag>。当然,重新指定<repository>也是可以的。所以,新镜像的 ImageID、Digest 都与原镜像的相同。
查看镜像,发现增加了一个新的镜像。
从镜像中心拉取来的 centos:7 镜像中是没有 vim、ifconfig、wget 等常用命令的,这里要构建一个自己的 centos7 镜像,使这些命令都可以使用。
(1)创建 Dockerfile
在宿主机任意目录创建一个文件,并命名为 Dockerfile。这里在/root 下 mkdir 一个目录 dfs。然后将如下内容复制到该文件中:
FROM centos:7
MAINTAINER zhangsan zs@163.com
LABEL version="1.0" description="this is a custom centos image"
ENV WORKPATH /usr/local
WORKDIR $WORKPATH
RUN yum -y install vim net-tools wget
CMD /bin/bash
(2)构建镜像 build
当看到下面的日志时说明构建完成。
此时通过 docker images
命令可以查看到刚刚生成的新的镜像。并且还发现,新镜像的大小要大于原镜像的,因为新镜像安装了新软件。
(3)运行新建镜像
运行了新镜像后,发现默认路径是 /usr/local 了,ifconfig、vim 命令可以使用了。
悬虚镜像是指既没有 Repository 又没有 Tag 的镜像。当新建了一个镜像后,为该镜像指定了一个已经存在的 TAG,那么原来的镜像就会变为悬空镜像。
为了演示悬虚镜像的生成过程,这里先修改前面定义的 Dockerfile,然后再生成镜像,且生成的新的镜像与前面构建的镜像的名称与 Tag 均相同。
(1)修改 Dockerfile
修改 /root/dfs 中的 Dockerfile。修改任意内容均可。这里仅将原来的 LABEL 中的 version 值由 1.0 修改为了 2.0,其它没变。
FROM centos:7
MAINTAINER zhangsan zs@163.com
LABEL version="2.0" description="this is a custom centos image"
ENV WORKPATH /usr/local
WORKDIR $WORKPATH
RUN yum -y install vim net-tools wget
CMD /bin/bash
(2)构建镜像 build
在构建镜像之前,先查看前面构建的 cucentos:1.0 镜像的 ID,以备在后面进行对比。
构建镜像时仍然指定镜像为 cucentos:1.0,与前面的镜像完全重名。
构建完毕后,再次查看镜像,发现原来 cucentos:1.0 镜像的名称与 Tag 均变为了<none>,即变为了悬虚镜像。
(3)删除悬虚镜像
悬虚镜像是一种“无用”镜像,其存在只能是浪费存储空间,所以一般都是要删除的。对于悬虚镜像的删除,除了可以通过 docker rmi <imageID>
进行删除外,还有专门的删除命令 docker image prune
,该命令能够一次性删除本地全部的悬空镜像。不过有个前提,就是这些悬虚镜像不能是已经启动了容器的,无论容器是否是退出状态。当然,如果再加上-a
选项,则会同时再将没有被任何容器使用的镜像也删除。
另外,还有一个命令 docker system prune
也可以删除悬虚镜像。只不过,其不仅删除的是悬虚镜像,还有其它系统“无用”内容。
在删除这个悬虚镜像之前,首先查看其是否启动了容器。如果启动了,则先将容器删除。
在删除了相关容器后再运行 docker image prune
。
此时再查看就发现悬虚镜像已经被删除了。
使用 docker system prune
命令可删除系统中的四类“无用”内容,其中就包含悬虚镜像 dangling images。
这两个指令都用于指定容器启动时要执行的命令,无论哪个指令,每个 Dockerfile 中都只能有一个 CMD/ENTERYPOINT 指令,多个 CMD/ENTERYPOINT 指令只会执行最后一个。不同的是,CMD 指定的是容器启动时默认的命令,而 ENTRYPOINT 指定的是容器启动时一定会执行的命令。即 docker run
时若指定了要运行的命令,Dockerfile 中的 CMD 指令指定的命令是不会执行的,而 ENTERYPOINT 中指定的命令是一定会执行的。
在 dfs 目录中新建文件 Dockerfile2,并定义内容如下。
FROM centos:7
CMD cal
说明:-f 用于指定本次构建所要使用的 Dockerfile 文件。如果文件名不是 docker build 默认加载的 Dockerfile 这个名称。
运行后可以查看到当前月份的日历。
在 docker run 命令中指定要执行的命令,Dockerfile 中通过 CMD 指定的默认的命令就不会在执行。
这种方式无法为 CMD 中指定的默认的命令指定选项。
在 dfs 目录中新建文件 Dockerfile3,并将如下内容复制到文件中。
FROM centos:7
CMD ["/bin/bash", "-c", "cal"]
使用 Dockerfile3 构建镜像 mycal:2.0。
运行结果与 shell 方式的相同。
运行结果与 shell 方式的相同,也可以被覆盖。
虽然在 CMD 中指定可以从命令行接收选项,但运行结果与 shell 方式的相同,也不能添加命令选项。这是由 CMD 命令本身决定的。
在 dfs 目录中新建文件 Dockerfile4,并将如下内容复制到文件中。
FROM centos:7
ENTRYPOINT cal
使用 Dockerfile4 构建镜像 mycal:3.0。
ENTRYPOINT 指定的命令是不会被 docker run 中指定的命令给覆盖掉的。
在 docker run 中添加的命令选项,对于 ENTRYPOINT 中指定的命令是无效的。在这点上不像 CMD 指令一样报错。
在 dfs 目录中新建文件 Dockerfile5,并将如下内容复制到文件中。
FROM centos:7
ENTRYPOINT ["cal"]
使用 Dockerfile5 构建镜像 mycal:4.0。
运行结果与 shell 方式的相同。
运行结果会报错,系统认为 date 是 cal 的非法参数。
与之前不同的是,这种情况下在 docker run 中添加的命令选项是有效的。
在 dfs 目录中新建文件 Dockerfile6,并将如下内容复制到文件中。此时的 CMD 中给出的就是 ENTRYPOINT 的参数,注意不能是选项。
FROM centos:7
CMD ["hello world"]
ENTRYPOINT ["echo"]
使用 Dockerfile6 构建镜像 myecho:latest。
在 docker run -it myecho
命令后添加选项 > hello.log
,用于将输出的内容重定向写入到 hello.log 文件中。选项生效。
在 docker run -it myecho
命令后指定新的参数,用于覆盖 CMD 中的参数,生效。
Dockerfile 中的 [command] 或 [“EXECUTABLE”] 如果是通过 CMD 指定的,则该镜像的启动命令 docker run
中是不能添加参数 [ARG] 的。因为 Dockerfile 中的 CMD 是可以被命令中的 [COMMAND] 替代的。如果命令中的 IMAGE 后仍有内容,此时对于 docker daemon 来说,其首先认为是替代用的 [COMMAND],如果有两个或两个以上的内容,后面的内容才会认为是 [ARG]。所以,添加的 -y 会报错,因为没有-y 这样的[COMMAND]。
Dockerfile 中的 [command] 或 [“EXECUTABLE”] 如果是通过ENTRYPOINT 指定的,则该镜像的启动命令 docker run
中是可以添加参数 [ARG] 的。因为 Dockerfile 中的 ENTRYPOINT 是不能被命令中的 [COMMAND] 替代的。如果命令中的 IMAGE 后仍有内容,此时对于 docker daemon 来说,其只能是 [ARG]。
不过,docker daemon 对于 ENTRYPOINT 指定的 [command] 与 [“EXECUTABLE”] 的处理方式是不同的。如果是 [command] 指定的 shell,daemon 会直接运行,而不会与 docker run
中的 [ARG] 进行拼接后运行;如果是 [“EXECUTABLE”] 指定的命令,daemon 则会先与 docker run
中的[ARG]进行拼接,然后再运行拼接后的结果。
结论:无论是 CMD 还是 ENTRYPOINT,使用[“EXECUTABLE”]方式的通用性会更强些。
在宿主机/root 目录中 mkdir 一个目录 ac。将事先下载好的任意某 tar.gz 包上传到 /root/ac 目录。本例在 zookeeper 官网
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。