【网络运维】Docker镜像:概念和使用
Docker镜像使用
镜像是 Docker 容器的基石,容器是镜像的运行实例,有了镜像才能启动容器。
hello-world - 最小的镜像
hello-world 是 Docker 官方提供的一个镜像,通常用来验证 Docker 是否安装成功。
通过 docker pull 从 Docker Hub 下载。
[root@docker ~]# docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
Digest: sha256:91fb4b041da273d5a3273b6d587d62d518300a6ad268b28628f74997b93171b2
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest
用 docker images 命令查看镜像的信息。
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d2c94e258dcb 16 months ago 13.3kB
通过 docker run 运行。
[root@docker ~]# docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
Dockerfile 是镜像的描述文件,定义了如何构建 Docker 镜像,Dockerfile 的语法简洁且可读性强。
后续会说明如何创建自己的dockerfile。
hello-world 的 Dockerfile 内容如下:
dockerhub hello-word网页:hello-world - Official Image | Docker Hub
github hello-wrold网页:hello-world/amd64/hello-world at master · docker-library/hello-world · GitHub

- FROM scratch
此镜像从 0 开始构建。 - COPY hello /
将文件“hello”复制到镜像的根目录。 - CMD [“/hello”]
容器启动时,执行 /hello
镜像 hello-world 中就只有一个可执行文件 “hello”,其功能就是打印出 “Hello from Docker …” 等信息。
hello-world 虽然是一个完整的镜像,但它并没有什么实际用途。通常来说,我们希望镜像能提供一个基本的操作系统环境,用户可以根据需要安装和配置软件。这样的镜像我们称作 base 镜像。
base镜像
base 镜像有两层含义:
- 不依赖其他镜像,从 scratch 构建。
- 其他镜像可以之为基础进行扩展。
所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ubuntu, Debian, CentOS 等。
接下来以 CentOS 为例考察 base 镜像包含哪些内容。
下载镜像:
docker pull centos:7
查看镜像信息:
[root@docker ~]# docker images centos:7
REPOSITORY TAG IMAGE ID CREATED SIZE
centos 7 eeb6ee3f44bd 3 years ago 204MB
下面是 CentOS 镜像的 Dockerfile 的内容:

第二行 ADD 指令添加到镜像的 tar 包就是 CentOS 7 的 rootfs。在制作镜像时,这个 tar 包会自动解压到 / 目录下,生成 /dev, /porc, /bin 等目录。
什么是 rootfs

如图所示,Linux 的内核空间是 kernel,Linux 刚启动时会加载 bootfs 文件系统,之后 bootfs 会被卸载掉。
用户空间的文件系统是 rootfs,包含我们熟悉的 /dev, /proc, /bin 等目录。
对于 base 镜像来说,底层直接用 Host 的 kernel,自己只需要提供 rootfs 就行了。
Docker 支持运行多种 Linux OS
不同 Linux 发行版的区别主要就是 rootfs。
比如 Ubuntu 14.04 使用 upstart 管理服务,apt 管理软件包;而 CentOS 7 使用 systemd 和 yum。这些都是用户空间上的区别,Linux kernel 差别不大。
所以 Docker 可以同时支持多种 Linux 镜像,模拟出多种操作系统环境。

上图 Debian 和 BusyBox(一种嵌入式 Linux)上层提供各自的 rootfs,底层共用 Docker Host 的 kernel。
镜像的分层结构
Docker 支持通过扩展现有镜像,创建新的镜像。
实际上,Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。
以debian镜像为例,其Dockerfile 如下:

① 新镜像不再是从 scratch 开始,而是直接在 Debian base 镜像上构建。
② 安装 emacs 编辑器。
③ 安装 apache2。
④ 容器启动时运行 bash。
构建过程如下图所示:
可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。
可写的容器层
当容器启动时,一个新的可写层被加载到镜像的顶部。
这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。

所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。
只有容器层是可写的,容器层下面的所有镜像层都是只读的。
镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。
如果不同层中有一个相同路径的文件,比如 /a,上层的 /a 会覆盖下层的 /a,也就是说用户只能访问到上层中的文件 /a。在容器层中,用户看到的是一个叠加之后的文件系统。
对容器增删改查操作如下:
| 操作 | 具体执行 |
|---|---|
| 创建文件 | 新文件只能被添加在容器层中。 |
| 删除文件 | 依据容器分层结构由上往下依次查找。找到后,在容器层中记录该删除操作。 具体实现是,UnionFS会在容器层创建一个”whiteout”文件,将被删除的文件“遮挡”起来。 |
| 修改文件 | 依据容器分层结构由上往下依次查找。找到后,将镜像层中的数据复制到容器层进行修改,修改后的数据保存在容器层中。(copy-on-write) |
| 读取文件 | 依据容器分层结构由上往下依次查找。 |
只有当需要修改时才复制一份数据,这种特性被称作 Copy-on-Write。可见,容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改,而所有镜像层都是只读的,不会被容器修改,所以镜像可以被多个容器共享。
构建镜像
本节将介绍构建镜像的方法。同时分析构建镜像的过程。
Docker 容器文件系统
Docker 提供了两种构建镜像的方法:
- docker commit 命令
- Dockerfile 构建文件
docker commit
docker commit 命令是创建新镜像最直观的方法,其过程包含三个步骤:
- 运行容器
- 修改容器
- 将容器保存为新的镜像
举例演示:在 ubuntu base 镜像中安装 vim并保存为新镜像。
-
第一步, 运行容器
[root@docker ~]# docker run -it ubuntu root@8dbdff6d3d88:/#-it参数的作用是以交互模式进入容器,并打开终端。8dbdff6d3d88是容器的内部 ID。 -
安装 vim
确认 vim 没有安装。
root@8dbdff6d3d88:/# vim bash: vim: command not found安装 vim。
root@8dbdff6d3d88:/# apt-get update root@8dbdff6d3d8:/# apt-get install -y vim 1. Africa 2. America 3. Antarctica 4. Arctic 5. Asia 6. Atlantic 7. Australia 8. Europe 9. Indian 10. Pacific 11. Etc Geographic area: 5 Please select the city or region corresponding to your time zone. 1. Aden 12. Bangkok 23. Dili 34. Istanbul 45. Krasnoyarsk 56. Novosibirsk 67. Samarkand 78. Tokyo 2. Almaty 13. Barnaul 24. Dubai 35. Jakarta 46. Kuala_Lumpur 57. Omsk 68. Seoul 79. Tomsk 3. Amman 14. Beirut 25. Dushanbe 36. Jayapura 47. Kuching 58. Oral 69. Shanghai 80. Ulaanbaatar 4. Anadyr 15. Bishkek 26. Famagusta 37. Jerusalem 48. Kuwait 59. Phnom_Penh 70. Singapore 81. Urumqi 5. Aqtau 16. Brunei 27. Gaza 38. Kabul 49. Macau 60. Pontianak 71. Srednekolymsk 82. Ust-Nera 6. Aqtobe 17. Chita 28. Harbin 39. Kamchatka 50. Magadan 61. Pyongyang 72. Taipei 83. Vientiane 7. Ashgabat 18. Choibalsan 29. Hebron 40. Karachi 51. Makassar 62. Qatar 73. Tashkent 84. Vladivostok 8. Atyrau 19. Chongqing 30. Ho_Chi_Minh 41. Kashgar 52. Manila 63. Qostanay 74. Tbilisi 85. Yakutsk 9. Baghdad 20. Colombo 31. Hong_Kong 42. Kathmandu 53. Muscat 64. Qyzylorda 75. Tehran 86. Yangon 10. Bahrain 21. Damascus 32. Hovd 43. Khandyga 54. Nicosia 65. Riyadh 76. Tel_Aviv 87. Yekaterinburg 11. Baku 22. Dhaka 33. Irkutsk 44. Kolkata 55. Novokuznetsk 66. Sakhalin 77. Thimphu 88. Yerevan Time zone: 69 -
保存为新镜像
打开一个新窗口,查看当前运行的容器。
[root@docker ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8dbdff6d3d88 ubuntu "/bin/bash" 2 minutes ago Up 2 minutes cool_darwin
上面查看结果的解释如下:
8dbdff6d3d88 是新创建容器的ID
cool_darwin 是 Docker 为我们的容器随机分配的名字。
执行 docker commit 命令将容器保存为镜像。
[root@docker ~]# docker commit cool_darwin ubuntu-with-vim #cool_darwin是容器名,ubuntu-with-vim是新建的镜像名
sha256:ba18ae460c068f9bdba060350e64dcec4bc4af05b9918602ee34e6350d0369a4
新镜像命名为 ubuntu-with-vim。
查看新镜像的属性。
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu-with-vim latest acefd029083b 27 minutes ago 189MB
ubuntu latest edbfe74c41f8 5 weeks ago 78.1MB
从 SIZE 上看到镜像因为安装了软件而变大了。
从新镜像启动容器,验证 vim 已经可以使用。
[root@docker ~]# docker run -it ubuntu-with-vim #ubuntu-with-vim是新创建的镜像名
root@4d071cf3014f:/# which vim
/usr/bin/vim
root@4d071cf3014f:/# vim file1
以上演示了如何用 docker commit 创建新镜像。然而,Docker 并不建议用户通过这种方式构建镜像。原因如下:
- 这是一种手工创建镜像的方式,容易出错,效率低且可重复性弱。比如要在 debian base 镜像中也加入 vim,还得重复前面的所有步骤。
- 更重要的:使用者并不知道镜像是如何创建出来的,里面是否有恶意程序。也就是说无法对镜像进行审计,存在安全隐患。
接下来学习如何通过 Dockerfile 构建镜像。
Dockerfile构建镜像
Dockerfile 是一个文本文件,记录了镜像构建的所有步骤。
Dockerfile基本说明:
- 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
- 指令按照从上到下,顺序执行
- #表示注释
- 每条指令都会创建一个新的镜像层并对镜像进行提交
常用参数:
docker build -f [Dockerfile路径] [构建上下文路径]
| 参数 | 作用 |
|---|---|
-f 或 --file | 标志符,声明要使用自定义 Dockerfile |
[Dockerfile路径] | 绝对路径或相对于构建上下文的路径(如 subdir/Dockerfile.dev) |
[构建上下文路径] | Docker 打包发送给守护进程的目录(通常用 . 表示当前目录) |
第一个 Dockerfile
用 Dockerfile 创建上节的 ubuntu-with-vim,其内容为:

运行 docker build 命令构建镜像。
[root@docker ~]# cd /root
[root@docker ~]# vim Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y vim
[root@docker ~]# docker build -t ubuntu-with-vim-dockerfile .
通过 docker images 查看镜像信息。
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu-with-vim-dockerfile latest bbc08145d011 10 minutes ago 189MB
ubuntu-with-vim latest acefd029083b 27 minutes ago 189MB
ubuntu latest edbfe74c41f8 5 weeks ago 78.1MB
镜像 ID 为 bbc08145d011,与构建时的输出一致。
调试Dockerfile
包括 Dockerfile 在内的任何脚本和程序都会出错,因此,本节讨论如何 debug Dockerfile。
先回顾一下通过 Dockerfile 构建镜像的过程:
- 从 base 镜像运行一个容器。
- 执行一条指令,对容器做修改。
- 执行类似 docker commit 的操作,生成一个新的镜像层。
- Docker 再基于刚刚提交的镜像运行一个新容器。
- 重复 2-4 步,直到 Dockerfile 中的所有指令执行完毕。
从这个过程可以看出,就算 Dockerfile 由于某种原因执行到某个指令失败了,也能够得到由前一个指令成功执行构建出的镜像,这对调试 Dockerfile 非常有帮助。
构建一个dockerfile为例。Dockerfile 内容如下:

执行 docker build:
[root@docker ~]# ls #查看有没有Dockerfile和testfile
Dockerfile testfile
[root@docker ~]# vim Dockerfile #编辑Dockerfile,写入上图的内容
FROM busybox
RUN touch tmpfile
RUN /bin/bash -c "echo continue to build..."
COPY testfile /
[root@docker ~]# docker build -t image-debug . #基于刚才写的Dockerfile构建镜像image-debug

Dockerfile 在执行第三步 RUN 指令时失败。我们可以利用busybox的镜像进行调试,方式是通过 docker run -it 启动镜像的一个容器。

手工执行 RUN 指令很容易定位失败的原因是 busybox 镜像中没有 bash,busybox中使用的是sh。
# 找出错误原因,修改错误
[root@docker ~]# vim Dockerfile
FROM busybox
RUN touch tmpfile
RUN /bin/sh -c "echo continue to builld..." #将错误的/bin/bash修改为正确的/bin/sh
COPY testfile /
[root@docker ~]# docker build -t image-debug . #基于刚才写的Dockerfile构建镜像image-debug

这次执行成功了。
Dockerfile常用指令
下面列出了 Dockerfile 中最常用的指令,完整列表和说明可参看官方文档。
FROM
指定 base 镜像。第一条必须是FROM
MAINTAINER
设置镜像的作者,可以是任意字符串。
COPY
将文件从 build context 复制到镜像。
COPY 支持两种形式:
- COPY src dest
- COPY [“src”, “dest”]
注意:src 只能指定 build context 中的文件或目录。
ADD
与 COPY 类似,从 build context 复制文件到镜像。不同的是,如果 src 是归档文件(tar, zip, tgz, xz 等),文件会被自动解压到 dest。
ENV
设置环境变量,环境变量可被后面的指令使用。例如:
...
ENV MY_VERSION 1.3
RUN apt-get install -y mypackage=$MY_VERSION
...
EXPOSE
指定容器中的进程会监听某个端口,Docker 可以将该端口暴露出来。
VOLUME
将文件或目录声明为 volume。
WORKDIR
为后面的 RUN, CMD, ENTRYPOINT, ADD 或 COPY 指令设置镜像中的当前工作目录。
RUN
在容器中运行指定的命令。
CMD
容器启动时运行指定的命令。
Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效。CMD 可以被 docker run 之后的参数替换。
ENTRYPOINT
设置容器启动时运行的命令。
Dockerfile 中可以有多个 ENTRYPOINT 指令,但只有最后一个生效。CMD 或 docker run 之后的参数会被当做参数传递给 ENTRYPOINT。
示例:一个较为完整的 Dockerfile
# my dockerfile
FROM busybox #从busybox开始构建
MAINTAINER frw #声明作者信息
WORKDIR /testdir #设置工作目录为/testdir
RUN touch tmpfile1 #在新镜像中创建tmpfille1
COPY ["tmpfile2","."] #将Dockerfile文件所在目录中的tmpfile2文件拷贝到新镜像中
ADD ["passwd.tar.gz","."] #将Dockerfile文件所在目录中的passwd.tar.gz拷贝到新镜像中并解压缩
ENV WELCOME "You are in my container,welcome!" #设置环境变量WELOCME
完整的操作步骤如下:
[root@docker ~]# pwd #确定Dockerfile工作目录
/root
[root@docker ~]# ls #当前/root目录下空的
[root@docker ~]# touch tmpfile2 #创建空文档tmpfile2
[root@docker ~]# cp /etc/passwd . #将/etc/passwd文件拷贝到/root
[root@docker ~]# tar -cvzf passwd.tar.gz passwd #将passwd文件做出归档文件passwd.tar.gz
passwd
[root@docker ~]# rm passwd #删除passwd文件
rm: remove regular file 'passwd'? y
[root@docker ~]# vim Dockerfile #编辑Dockerfile写入如下内容
# my dockerfile
FROM busybox
MAINTAINER frw
WORKDIR /testdir
RUN touch tmpfile1
COPY ["tmpfile2","."]
ADD ["passwd.tar.gz","."]
ENV WELCOME "You are in my container,welcome!"
[root@docker ~]# ls #最后目录中有三个文件
Dockerfile passwd.tar.gz tmpfile2
[root@docker ~]# docker build -t my-image . #构建新镜像my-image
RUN / CMD / ENTRYPOINT
RUN、CMD 和 ENTRYPOINT 这三个 Dockerfile 指令看上去很类似,很容易混淆。本节将通过实践详细讨论它们的区别。
简单来说:
- RUN 执行命令并创建新的镜像层,RUN 经常用于安装软件包。
- CMD 设置容器启动后默认执行的命令及其参数,但 CMD 能够被
docker run后面跟的命令行参数替换。 - ENTRYPOINT 配置容器启动时运行的命令。
Shell 和 Exec 格式
可以用两种方式指定 RUN、CMD 和 ENTRYPOINT 要运行的命令:Shell 格式和 Exec 格式,二者在使用上有细微的区别。
Shell 格式
<instruction> <command>
例如:
RUN apt-get install python3
CMD echo "Hello world"
ENTRYPOINT echo "Hello world"
当指令执行时,shell 格式底层会调用 /bin/sh -c 。
例如下面的 Dockerfile :
[root@docker ~]# vim Dockerfile
FROM busybox
ENV name frw
ENTRYPOINT echo "Hello, $name"
用上面的Dockerfile创建镜像dockerfile1用于测试
[root@docker ~]# docker build -t dockerfile1 .
执行 docker run dockerfile1:
[root@docker ~]# docker run dockerfile1
Hello, frw
注意环境变量 name 已经被值 frw 替换。
下面来看 Exec 格式。
Exec 格式
<instruction> ["executable", "param1", "param2", ...]
例如:
RUN ["apt-get", "install", "python3"]
CMD ["/bin/echo", "Hello world"]
ENTRYPOINT ["/bin/echo", "Hello world"]
当指令执行时,会直接调用 ,不会被 shell 解析。
例如下面的 Dockerfile :
[root@docker ~]# vim Dockerfile
FROM busybox
ENV name frw
ENTRYPOINT ["/bin/echo", "Hello, $name"]
用上面的Dockerfile创建镜像dockerfile2用于测试
[root@docker ~]# docker build -t dockerfile2 .
执行 docker run dockerfile2:
[root@docker ~]# docker run dockerfile2
hello, $name
注意环境变量“name”没有被替换。
如果希望使用环境变量,照如下修改
[root@docker ~]# vim Dockerfile
FROM busybox
ENV name frw
ENTRYPOINT ["/bin/sh", "-c", "echo Hello, $name"]
用上面的Dockerfile创建镜像dockerfile3用于测试
[root@docker ~]# docker build -t dockerfile3 .
执行 docker run dockerfile3:
[root@docker ~]# docker run dockerfile3
Hello, frw
CMD 和 ENTRYPOINT 推荐使用 Exec 格式,因为指令可读性更强,更容易理解。
RUN 则两种格式都可以。
RUN
RUN 指令通常用于安装应用和软件包。
RUN 在当前镜像的顶部执行命令,并通过创建新的镜像层。Dockerfile 中常常包含多个 RUN 指令。
RUN 有两种格式:
- Shell 格式:RUN
- Exec 格式:RUN [“executable”, “param1”, “param2”]
下面的Dockerfile是使用 RUN 安装多个包的例子:
[root@docker ~]# vim Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
subversion
用上面的Dockerfile创建镜像dockerfile4用于测试
[root@docker ~]# docker build -t dockerfile4 .
执行 docker run -it dockerfile4:
[root@docker ~]# docker run -it dockerfile4
root@43894b9f29db:/# apt list install brz cvs git mercurial subversion
Listing... Done
brz/noble,now 3.3.5-6build2 amd64 [installed,automatic]
cvs/noble,now 2:1.12.13+real-30build1 amd64 [installed]
git/noble-updates,noble-security,now 1:2.43.0-1ubuntu7.3 amd64 [installed]
mercurial/noble-updates,now 6.7.2-1ubuntu2.2 amd64 [installed]
subversion/noble,now 1.14.3-1build4 amd64 [installed]
注意:apt-get update 和 apt-get install 被放在一个 RUN 指令中执行,这样能够保证每次安装的是最新的包。如果 apt-get install 在单独的 RUN 中执行,则会使用 apt-get update 创建的镜像层,而这一层可能是很久以前缓存的。
CMD
CMD 指令允许用户指定容器的默认执行的命令。
此命令会在容器启动且 docker run 没有指定其他命令时运行。
- 如果 docker run 指定了其他命令,CMD 指定的默认命令将被忽略。
- 如果 Dockerfile 中有多个 CMD 指令,只有最后一个 CMD 有效。
CMD 有三种格式:
- Exec 格式:CMD [“executable”,“param1”,“param2”] 这是 CMD 的推荐格式。
- CMD [“param1”,“param2”] 为 ENTRYPOINT 提供额外的参数,此时 ENTRYPOINT 必须使用 Exec 格式。
- Shell 格式:CMD command param1 param2
Exec 和 Shell 格式前面已经介绍过了。
第二种格式 CMD [“param1”,“param2”] 要与 Exec 格式 的 ENTRYPOINT 指令配合使用,其用途是为 ENTRYPOINT 设置默认的参数。我们将在后面讨论 ENTRYPOINT 时举例说明。
下面看看 CMD 是如何工作的。Dockerfile 如下:
[root@docker ~]# vim Dockerfile
FROM busybox
CMD echo "Hello,world"
用上面的Dockerfile创建镜像dockerfile5用于测试
[root@docker ~]# docker build -t dockerfile5 .
运行容器docker run -it dockerfile5将输出:
[root@docker ~]# docker run -it dockerfile5
Hello,world
但当后面加上一个命令,比如docker run -it dockerfile5 /bin/sh,CMD 会被忽略掉,命令 sh 将被执行:
[root@docker ~]# docker run -it dockerfile5 /bin/sh
/ #
ENTRYPOINT
ENTRYPOINT 指令可让容器以应用程序或者服务的形式运行。
ENTRYPOINT 看上去与 CMD 很像,它们都可以指定要执行的命令及其参数。不同的地方在于 ENTRYPOINT 不会被忽略,一定会被执行,即使运行 docker run 时指定了其他命令。
ENTRYPOINT 有两种格式:
- Exec 格式:ENTRYPOINT [“executable”, “param1”, “param2”] 这是 ENTRYPOINT 的推荐格式。
- Shell 格式:ENTRYPOINT command param1 param2
在为 ENTRYPOINT 选择格式时必须小心,因为这两种格式的效果差别很大。
Exec 格式
ENTRYPOINT 的 Exec 格式用于设置要执行的命令及其参数,同时可通过 CMD 提供额外的参数。
ENTRYPOINT 中的参数始终会被使用,而 CMD 的额外参数可以在容器启动时动态替换掉。
比如下面的 Dockerfile :
[root@docker ~]# vim Dockerfile
FROM busybox
ENTRYPOINT ["/bin/echo", "Hello"]
CMD ["world"]
用上面的Dockerfile创建镜像dockerfile6用于测试
[root@docker ~]# docker build -t dockerfile6 .
当容器通过 docker run -it dockerfile6 启动时,输出为:
[root@docker ~]# docker run -it dockerfile6
Hello world
而如果通过 docker run -it dockerfile6 frw 启动,则输出为:
[root@docker ~]# docker run -it dockerfile6 frw
Hello frw
Shell 格式
ENTRYPOINT 的 Shell 格式会忽略任何 CMD 或 docker run 提供的参数。
比如下面的 Dockerfile :
FROM busybox
ENTRYPOINT echo "Hello,"
CMD ["world"]
用上面的Dockerfile创建镜像dockerfile7用于测试
[root@docker ~]# docker build -t dockerfile7 .
当容器通过 docker run -it dockerfile7 启动时,输出为:
[root@docker ~]# docker run -it dockerfile7
Hello,
而如果通过 docker run -it dockerfile7 frw 启动,则输出为:
[root@docker ~]# docker run -it dockerfile7 frw
Hello,
为镜像命名
无论采用何种方式保存和分发镜像,首先都得给镜像命名。
当执行 docker build 命令时已经为镜像取了个名字,例如前面:
docker build -t ubuntu-with-vim
这里的 ubuntu-with-vim 就是镜像的名字。通过 dock images 可以查看镜像的信息。

这里注意到 ubuntu-with-vim 对应的是 REPOSITORY,而且还有一个叫 latest 的 TAG。
实际上一个特定镜像的名字由两部分组成:repository 和 tag。
[image name] = [repository]:[tag]
全称如下:
镜像名称格式:Image hub address/Namespace/Repository:tag即054b8ac70e8010d90f2ac00ef29e6580.mirror.swr.myhuaweicloud.com/library/nginx:latest
如果执行 docker build 时没有指定 tag,会使用默认值 latest。其效果相当于:
docker build -t ubuntu-with-vim:latest
tag 常用于描述镜像的版本信息,比如 httpd 镜像:

当然 tag 可以是任意字符串,比如 ubuntu 镜像:
Docker镜像仓库:Registry
Docker仓库类似于代码仓库,它是Docker集中存放镜像文件的场所。仓库注册服务器存放着很多类镜像,每类镜像包括多个镜像文件,通过不同的标签(tag)来进行区分。
根据所存储的镜像公开分享与否,Docker仓库可以分为:
- 公开仓库(Public)
- 私有仓库(Private)
目前,最大的公开仓库是官方提供的Docker Hub,其中存放了数量庞大的镜像供用户下载。国内不少云服务提供商(如华为、阿里云等)也提供了仓库的本地源,可以提供稳定的国内访问。
保存和分发镜像的最直接方法就是使用 Docker Hub。
Docker Hub 是 Docker 公司维护的公共 Registry。用户可以将自己的镜像保存到 Docker Hub 免费的 repository 中。如果不希望别人访问自己的镜像,也可以购买私有 repository。
国内的公共 Registry 有华为云、阿里云等。
如需要私有镜像仓库,则可以使用Harbor。
Harbor是构建企业级私有docker镜像的仓库的开源解决方案,它是Docker Registry的更高级封装,除了提供友好的Web UI界面,角色和用户权限管理,用户操作审计等功能外,它还整合了K8s的插件(Add-ons)仓库。
harbor下载:https://github.com/goharbor/harbor/releases
导入导出本地镜像文件
保存本地镜像为文件-save
docker默认使用overlay2存储驱动存储镜像。
[root@docker ~]# docker info | grep 'Storage Driver'
Storage Driver: overlay2
镜像存储在本地/var/lib/docker/overlay2,通过文件系统层面拷贝image,操作复杂。可以使用save命令,将本地镜像保存为单个文件,并分享给他人使用。
[root@docker ~]# docker save --help
Usage: docker save [OPTIONS] IMAGE [IMAGE...]
Save one or more images to a tar archive (streamed to STDOUT by default)
Aliases:
docker image save, docker save
Options:
-o, --output string Write to a file, instead of STDOUT
示例:
[root@docker ~]# docker save httpd -o httpd.tar #httpd是镜像名 httpd.tar是要保存的文件名
[root@docker ~]# docker save httpd hello-world -o images.tar #将httpd,hello-world镜像保存为images.tar
[root@docker ~]# ls
httpd.tar images.tar
将本地镜像文件导入本地-load
[root@docker ~]# docker load --help
Usage: docker load [OPTIONS]
Load an image from a tar archive or STDIN
Aliases:
docker image load, docker load
Options:
-i, --input string Read from tar archive file, instead of STDIN
-q, --quiet Suppress the load output
示例:删除本地镜像,并导入本地镜像文件
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd latest 90f191b9781e 11 days ago 148MB
hello-world latest 74cc54e27dc4 6 months ago 10.1kB
[root@docker ~]# docker rmi httpd:latest hello-world:latest
Untagged: httpd:latest
Untagged: httpd@sha256:f84fe51ff5d35124e024f51215b443b16c939b24eae747025a515200e71c7d07
Deleted: sha256:90f191b9781e01f5cd601af7b32d4ebb46770d1a98fa9170c328f9a78458b758
Deleted: sha256:8cbdaf91f3d9b2916bd85a36c608c8b652176b92266a6c51ead6c52f487b9eb5
Deleted: sha256:352b0ea3b9e318a2111200ed85540548a23873ce5ab5e6076b1dcef0110724ce
Deleted: sha256:7810a27010681e9307dae49c3673a021928add80b99e43937d79a3c5322cb862
Deleted: sha256:3c75e1b632ae15a9a14d7527fb134de5d45b2abcf3eef1cfaa057d702b957dba
Deleted: sha256:4eabd365f7baf2356d8d27adb4a182e45fca9dfc1d5533e93832c243135a5aa9
Deleted: sha256:1bb35e8b4de116e84b2ccf614cce4e309b6043bf2cd35543d8394edeaeb587e3
Untagged: hello-world:latest
Untagged: hello-world@sha256:ec153840d1e635ac434fab5e377081f17e0e15afab27beb3f726c3265039cfff
Deleted: sha256:74cc54e27dc41bb10dc4b2226072d469509f2f22f1a3ce74f4a59661a1d44602
Deleted: sha256:63a41026379f4391a306242eb0b9f26dc3550d863b7fdbb97d899f6eb89efe72
[root@docker ~]# docker images #本地没有镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
删除本地正在使用的镜像需要选项-f
导入镜像
[root@docker ~]# docker load -i images.tar
1bb35e8b4de1: Loading layer 77.88MB/77.88MB
6c5ea8a96778: Loading layer 2.56kB/2.56kB
5f70bf18a086: Loading layer 1.024kB/1.024kB
785236f38f5b: Loading layer 11.41MB/11.41MB
5ca968893b91: Loading layer 62.99MB/62.99MB
b4558c4e936a: Loading layer 3.584kB/3.584kB
Loaded image: httpd:latest
63a41026379f: Loading layer 11.78kB/11.78kB
Loaded image: hello-world:latest
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd latest 90f191b9781e 11 days ago 148MB
hello-world latest 74cc54e27dc4 6 months ago 10.1kB
说明:如果本地镜像名与导入的镜像重名,则本地的镜像会被覆盖。
[root@docker ~]# docker rm -f $(docker ps -aq) #删除所有容器 [root@docker ~]# docker rmi -f $(docker images -aq) #删除所有镜像
Docker镜像小结
本文首先讨论了镜像的分层结构,然后学习了如何构建镜像,包括Dockerfile的格式和各种常用指令。
镜像的常用操作子命令如下:
images 显示镜像列表
history 显示镜像构建历史
commit 从容器创建新镜像
build 从 Dockerfile 构建镜像
tag 给镜像打 tag
pull 从 registry 下载镜像
push 将 镜像 上传到 registry
rmi 删除 Docker host 中的镜像
search 搜索 Docker Hub 中的镜像
下面简单讲解前文未提到的子命令 rmi 和 search。
rmi
rmi 只能删除 host 上的镜像,不会删除 registry 的镜像。
如果一个镜像对应了多个 tag,只有当最后一个 tag 被删除时,镜像才被真正删除。例如 host 中 busybox镜像有三个 tag:
[root@docker ~]# docker images busybox
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest 6fd955f66c23 16 months ago 4.26MB
[root@docker ~]# docker tag busybox:latest busybox:v1
[root@docker ~]# docker tag busybox:latest busybox:v2
[root@docker ~]# docker images busybox
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest 6fd955f66c23 16 months ago 4.26MB
busybox v1 6fd955f66c23 16 months ago 4.26MB
busybox v2 6fd955f66c23 16 months ago 4.26MB
删除其中 busybox:latest 只是删除了 latest tag,镜像本身没有删除。

只有当 busybox:v1和busybox:v2也被删除时,整个镜像才会被删除。

search
search 可以直接在命令行中搜索 Docker Hub 中的镜像。

如果想知道镜像都有哪些 tag,还是得访问 Docker Hub。
更多推荐


所有评论(0)