docker三大组件
docker镜像
Docker 运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker会从镜像仓库下载该镜像。
获取镜像
Docker Hub 上有大量的高质量的镜像可以用,这里我们就说一下怎么获取这些镜像。
从 Docker 镜像仓库获取镜像的命令是 docker pull。其命令格式为:
docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
具体的选项可以通过 docker pull --help 命令看到,这里我们说一下镜像名称的格式。
- Docker 镜像仓库地址:地址的格式一般是 <域名/IP>[:端口号]。默认地址是 Docker Hub。
- 仓库名:如之前所说,这里的仓库名是两段式名称,即 <用户名>/<软件名>。对于 Docker Hub,如果不给出用户名,则默认为 library,也就是官方镜像。
如:
上面的命令中没有给出 Docker 镜像仓库地址,因此将会从 Docker Hub 获取镜像。而镜像名称是 ubuntu:16.04,因此将会获取官方镜像 library/ubuntu 仓库中标签为 16.04 的镜像。
从下载过程中可以看到我们之前提及的分层存储的概念,镜像是由多层存储所构成。下载也是一层层的去下载,并非单一文件。下载过程中给出了每一层的 ID 的前 12 位。并且下载结束后,给出该镜像完整的 sha256 的摘要,以确保下载一致性。
在使用上面命令的时候,你可能会发现,你所看到的层 ID 以及 sha256 的摘要和这里的不一样。这是因为官方镜像是一直在维护的,有任何新的 bug,或者版本更新,都会进行修复再以原来的标签发布,这样可以确保任何使用这个标签的用户可以获得更安全、更稳定的镜像。
如果从 Docker Hub 下载镜像非常缓慢,可以参照 Docker安装配置镜像加速器。
运行镜像
有了镜像后,我们就能够以这个镜像为基础启动并运行一个容器。以上面的 ubuntu:16.04 为例,如果我们打算启动里面的 bash 并且进行交互式操作的话,可以执行下面的命令。
docker run
就是运行容器的命令,我们这里简要的说明一下上面用到的参数。
- -it:这是两个参数,一个是-i:交互式操作,一个是 -t 终端。我们这里打算进入 bash 执行一些命令并查看返回结果,因此我们需要交互式终端。
- --rm:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 docker rm。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 --rm 可以避免浪费空间。
- ubuntu:16.04:这是指用 ubuntu:16.04 镜像为基础来启动容器。
- bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 bash。
进入容器后,我们可以在 Shell 下操作,执行任何所需的命令。这里,我们执行了 cat /etc/os-release
,这是 Linux 常用的查看当前系统版本的命令,从返回的结果可以看到容器内是 Ubuntu 16.04.4 LTS 系统。
最后我们通过 exit
退出了这个容器。
列出镜像
概述
要想列出已经下载下来的镜像,可以使用 docker image ls
命令。
各个选项说明:
- REPOSITORY:表示镜像的仓库源
- TAG:镜像的标签
- IMAGE ID:镜像ID
- CREATED:镜像创建时间
- SIZE:镜像大小
其中仓库名、标签在之前的基础概念章节已经介绍过了。镜像 ID 则是镜像的唯一标识,一个镜像可以对应多个标签。
镜像体积
如果仔细观察,会注意到,这里标识的所占用空间和在 Docker Hub 上看到的镜像大小不同。比如,ubuntu:16.04 镜像大小,在这里是 127 MB,但是在 Docker Hub 显示的却是 50 MB。这是因为 Docker Hub 中显示的体积是压缩后的体积。在镜像下载和上传过程中镜像是保持着压缩状态的,因此 Docker Hub 所显示的大小是网络传输中更关心的流量大小。而 docker image ls 显示的是镜像下载到本地后,展开的大小,准确说,是展开后的各层所占空间的总和,因为镜像到本地后,查看空间的时候,更关心的是本地磁盘空间占用的大小。
另外一个需要注意的问题是,docker image ls 列表中的镜像体积总和并非是所有镜像实际硬盘消耗。由于 Docker 镜像是多层存储结构,并且可以继承、复用,因此不同镜像可能会因为使用相同的基础镜像,从而拥有共同的层。由于 Docker 使用 Union FS,相同的层只需要保存一份即可,因此实际镜像硬盘占用空间很可能要比这个列表镜像大小的总和要小的多。
你可以通过以下命令来便捷的查看镜像、容器、数据卷所占用的空间。
虚悬镜像
镜像既没有仓库名,也没有标签,均为
镜像原本是有镜像名和标签的,随着官方镜像维护,发布了新版本后,这个镜像名被转移到了新下载的镜像身上,而旧的镜像上的这个名称则被取消,从而成为了
docker image ls -f dangling=true
一般来说,虚悬镜像已经失去了存在的价值,是可以随意删除的,可以用下面的命令删除。
docker image prune
中间层镜像
为了加速镜像构建、重复利用资源,Docker 会利用 中间层镜像。所以在使用一段时间后,可能会看到一些依赖的中间层镜像。默认的 docker image ls 列表中只会显示顶层镜像,如果希望显示包括中间层镜像在内的所有镜像的话,需要加 -a 参数。
docker image ls -a
这样会看到很多无标签的镜像,与之前的虚悬镜像不同,这些无标签的镜像很多都是中间层镜像,是其它镜像所依赖的镜像。这些无标签镜像不应该删除,否则会导致上层镜像因为依赖丢失而出错。实际上,这些镜像也没必要删除,因为之前说过,相同的层只会存一遍,而这些镜像是别的镜像的依赖,因此并不会因为它们被列出来而多存了一份,无论如何你也会需要它们。只要删除那些依赖它们的镜像后,这些依赖的中间层镜像也会被连带删除。
列出部分镜像
不加任何参数的情况下,docker image ls 会列出所有顶级镜像,但是有时候我们只希望列出部分镜像。docker image ls 有好几个参数可以帮助做到这个事情。
- 根据仓库名列出镜像
docker image ls ubuntu
- 列出特定的某个镜像,也就是说指定仓库名和标签
docker image ls ubuntu:16.04
- 除此以外,docker image ls 还支持强大的过滤器参数 --filter,或者简写 -f。之前我们已经看到了使用过滤器来列出虚悬镜像的用法,它还有更多的用法。比如,我们希望看到在 mongo:3.2 之后建立的镜像,可以用下面的命令:
docker image ls -f since=mongo:3.2
- 想查看某个位置之前的镜像也可以,只需要把 since 换成 before 即可。
此外,如果镜像构建时,定义了 LABEL,还可以通过 LABEL 来过滤。
docker image ls -f label=com.example.version=0.1
以特定格式显示
默认情况下,docker image ls
会输出一个完整的表格,但是我们并非所有时候都会需要这些内容。比如,刚才删除虚悬镜像的时候,我们需要利用 docker image ls
把所有的虚悬镜像的 ID 列出来,然后才可以交给 docker image rm
命令作为参数来删除指定的这些镜像,这个时候就用到了 -q
参数。
--filter
配合 -q
产生出指定范围的 ID 列表,然后送给另一个 docker 命令作为参数,从而针对这组实体成批的进行某种操作的做法在 Docker 命令行使用过程中非常常见,不仅仅是镜像,将来我们会在各个命令中看到这类搭配以完成很强大的功能。因此每次在文档看到过滤器后,可以多注意一下它们的用法。
另外一些时候,我们可能只是对表格的结构不满意,希望自己组织列;或者不希望有标题,这样方便其它程序解析结果等,这就用到了 Go 的模板语法。
比如,下面的命令会直接列出镜像结果,并且只包含镜像ID和仓库名:
docker image ls --format "{{.ID}}: {{.Repository}}"
或者打算以表格等距显示,并且有标题行,和默认一样,不过自己定义列:
docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"
删除本地镜像
概述
如果要删除本地的镜像,可以使用 docker image rm
命令,其格式为:
docker image rm [选项] <镜像1> [<镜像2> ...]
用 ID、镜像名、摘要删除镜像
其中,<镜像>
可以是 镜像短 ID
、镜像长 ID
、镜像名
或者 镜像摘要
。
[root@localhost ~]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 16.04 9499db781771 4 days ago 131MB
ubuntu 21.04 de35fa744ddc 4 days ago 79.6MB
nginx latest bc9a0695f571 5 days ago 133MB
mysql 8.0.22 dd7265748b5d 9 days ago 545MB
redis 6.0.9-buster 74d107221092 11 days ago 104MB
hello-world latest bf756fb1ae65 11 months ago 13.3kB
我们可以用镜像的完整 ID,也称为 长 ID
,来删除镜像。使用脚本的时候可能会用长 ID,但是人工输入就太累了,所以更多的时候是用 短 ID
来删除镜像。docker image ls
默认列出的就已经是短 ID 了,一般取前3个字符以上,只要足够区分于别的镜像就可以了。
比如这里,如果我们要删除 ubuntu:21.04
镜像,可以执行:
[root@localhost ~]# docker image rm de3
Untagged: ubuntu:21.04
Untagged: ubuntu@sha256:b6dc45a852dc83fa0e7504e9d68b9b0084eefb8aeb5f295f276bf99f5c033490
Deleted: sha256:de35fa744ddc8e77100c28fb8991d27608844ad7e471326ed065b5fef93cd136
Deleted: sha256:fd65f8aa83950d70250af00da5689928e3f40cd69e698f0759f0378e09c4f8be
Deleted: sha256:0bd7c17bf4b4b2a863a2682022759d5c13409883490a9fd469234894947a33e6
Deleted: sha256:a1420feae655de344314664a83c3509ec59cee20e1b3934a50b5568d7ae95c69
我们也可以用镜像名
,也就是 <仓库名>:<标签>
,来删除镜像。
[root@localhost ~]# docker image rm nginx
Untagged: nginx:latest
Untagged: nginx@sha256:6b1daa9462046581ac15be20277a7c75476283f969cb3a61c8725ec38d3b01c3
Deleted: sha256:bc9a0695f5712dcaaa09a5adc415a3936ccba13fc2587dfd76b1b8aeea3f221c
Deleted: sha256:a6862ade3b91fdde2aa8a3d77fdcc95b1eb6c606be079c11b7f97f249d0e731d
Deleted: sha256:32bcbe3740b68d0625744e774b404140366c0c4a2b2eadf32280d66ba001b4fb
Deleted: sha256:2dc5e43f496e41a18c016904b6665454a53be22eb4dcc1b468d864b4e2d1f311
Deleted: sha256:5fe6a7c579cd9fbcfa604810974c4c0c16893f4c40bc801545607ebd0accea74
当然,更精确的是使用 镜像摘要
删除镜像。
[root@localhost ~]# docker image ls --digests
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
ubuntu 16.04 sha256:3355b6e4ba1b12071ba5fe9742042a2f10b257c908fbdfac81912a16eb463879 9499db781771 4 days ago 131MB
mysql 8.0.22 sha256:4bb2e81a40e9d0d59bd8e3dc2ba5e1f2197696f6de39a91e90798dd27299b093 dd7265748b5d 9 days ago 545MB
redis 6.0.9-buster sha256:5b98e32b58cdbf9f6b6f77072c4915d5ebec43912114031f37fa5fa25b032489 74d107221092 11 days ago 104MB
hello-world latest sha256:e7c70bb24b462baa86c102610182e3efcb12a04854e8c582838d92970a09f323 bf756fb1ae65 11 months ago 13.3kB
[root@localhost ~]# docker image rm redis@sha256:5b98e32b58cdbf9f6b6f77072c4915d5ebec43912114031f37fa5fa25b032489
Untagged: redis@sha256:5b98e32b58cdbf9f6b6f77072c4915d5ebec43912114031f37fa5fa25b032489
用 docker image ls 命令来配合
像其它可以承接多个实体的命令一样,可以使用 docker image ls -q
来配合使用 docker image rm
,这样可以成批的删除希望删除的镜像。我们在“镜像列表”章节介绍过很多过滤镜像列表的方式都可以拿过来使用。
比如,我们需要删除所有仓库名为 redis
的镜像:
docker image rm $(docker image ls -q redis)
或者删除所有在 mongo:3.2
之前的镜像:
docker image rm $(docker image ls -q -f before=mongo:3.2)
充分利用你的想象力和 Linux 命令行的强大,你可以完成很多非常赞的功能。
docker容器
简单的说,容器是独立运行的一个或一组应用,以及它们的运行态环境。对应的,虚拟机可以理解为模拟运行的一整套操作系统(提供了运行态环境和其他系统环境)和跑在上面的应用。
启动容器
1、新建并启动
以下命令使用 ubuntu 镜像启动一个容器,参数为以命令行模式进入该容器:
docker run -itd ubuntu /bin/bash
参数说明:
- -i: 让容器的标准输入保持打开(交互式操作)。
- -t: 分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上。
- -d: 指定容器的运行模式,参数默认不会进入容器(后台运行),想要进入容器需要使用指令 docker exec
- ubuntu: ubuntu 镜像。
- /bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。
要退出终端,直接输入 exit,如下:
当利用 docker run
来创建容器时,Docker 在后台运行的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从公有仓库下载
- 利用镜像创建并启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个 ip 地址给容器
- 执行用户指定的应用程序
- 执行完毕后容器被终止
2、启动已终止容器
查看所有的容器命令如下:
docker ps -a
使用 docker start
启动一个已停止的容器:
docker start <容器 ID>
使用 ps
或 top
再伪终端中来查看进程信息
停止容器
停止容器的命令如下:
docker stop <容器 ID>
停止的容器可以通过 docker restart 重启:
docker restart <容器 ID>
进入容器
在使用 -d 参数时,容器启动后会进入后台。此时想要进入容器,可以通过以下指令进入:
- docker attach
- docker exec:推荐大家使用 docker exec 命令,因为此退出容器终端,不会导致容器的停止。
attach 命令
下面演示了使用 docker attach 命令。
docker attach 0aa2fd00e1ca
注意: 如果从这个容器退出,会导致容器的停止。
exec 命令
下面演示了使用 docker exec 命令。
docker exec -it 0aa2fd00e1ca /bin/bash
注意: 如果从这个容器退出,容器不会停止,这就是为什么推荐大家使用 docker exec 的原因。
更多参数说明请使用 docker exec --help 命令查看。
删除容器
删除容器使用 docker rm 命令:
docker rm -f d4de48672d62
下面的命令可以清理掉所有处于终止状态的容器。
docker container prune
导出和导入容器
导出容器
如果要导出本地某个容器,可以使用 docker export 命令。
docker export 6f16882c8b05 > ubuntu.tar
这样将导出容器快照到本地文件。
导入容器快照
可以使用 docker import 从容器快照文件中再导入为镜像,以下实例将快照文件 ubuntu.tar 导入到镜像 test/ubuntu:v1:
cat docker/ubuntu.tar | docker import - test/ubuntu:v1
此外,也可以通过指定 URL 或者某个目录来导入,例如:
docker import http://example.com/exampleimage.tgz example/imagerepo
docker仓库
仓库(Repository
)是集中存放镜像的地方。
一个容易混淆的概念是注册服务器(Registry
)。实际上注册服务器是管理仓库的具体服务器,每个服务器上可以有多个仓库,而每个仓库下面有多个镜像。从这方面来说,仓库可以被认为是一个具体的项目或目录。例如对于仓库地址 dl.dockerpool.com/ubuntu
来说,dl.dockerpool.com
是注册服务器地址,ubuntu
是仓库名。
大部分时候,并不需要严格区分这两者的概念。
Docker Hub
目前 Docker 官方维护了一个公共仓库 Docker Hub,其中已经包括了数量超过 15,000 的镜像。大部分需求都可以通过在 Docker Hub 中直接下载镜像来实现。
注册
你可以在 https://cloud.docker.com 免费注册一个 Docker 账号。
登录
可以通过执行 docker login
命令交互式的输入用户名及密码来完成在命令行界面登录 Docker Hub。
你可以通过 docker logout
退出登录。
拉取镜像
通过 docker search
命令来查找官方仓库中的镜像,并利用 docker pull
命令来将它下载到本地。
以 centos
为关键词进行搜索:
docker search centos
docker pull centos
推送镜像
用户也可以在登录后通过 docker push
命令来将自己的镜像推送到 Docker Hub。
以下命令中的 username
替换为你的 Docker 账号用户名。
docker hub上效果如下:
docker 删除镜像
Docker 私有仓库
有时候使用 Docker Hub 这样的公共仓库可能不方便,用户可以创建一个本地仓库供私人使用。
本节介绍如何使用本地仓库。
docker-registry
是官方提供的工具,可以用于构建私有的镜像仓库。本文内容基于 docker-registry
v2.x 版本。
服务端安装运行
通过获取官方 registry
镜像来运行
docker run -d -p 5000:5000 --restart=always --name registry registry
这里使用官方的 registry
镜像来启动私有仓库。默认情况下,仓库会被创建在容器的 /var/lib/registry
目录下。你可以通过 -v
参数来将镜像文件存放在本地的指定路径。例如下面的例子将上传的镜像放到本地的 /opt/data/registry
目录。
docker run -d \
-p 5000:5000 \
-v /opt/data/registry:/var/lib/registry \
--restart=always\
--name registry_demo\
registry:latest
参数说明:
-
-d: 后台运行容器,并返回容器ID;
-
-p: 指定端口映射,格式为:主机(宿主)端口:容器端口
-
-v: 指定镜像文件存放路径,格式为:**主机(宿主)路径:容器路径
-
--name: 为容器指定一个名称
-
--restart=always:参数能够使我们在重启docker时,自动启动相关容器
如图:
访问http://ip:5000/v2/ 返回{}
客户端上传、搜索、下载镜像
1、标记镜像
使用 docker tag
将 ubuntu:latest
这个镜像标记为 127.0.0.1:5000/ubuntu:latest
。
格式为 docker tag IMAGE[:TAG] [REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG]
。
docker tag nginx:latest 192.168.147.134:5000/nginx:v1
如图:
2、上传标记镜像
docker push 192.168.147.134:5000/nginx
如图:
注意:上传镜像如果报错如下,意思就是 Docker 默认不允许非 HTTPS
方式推送镜像。
解决办法:
vim /etc/docker/daemon.json
在daemon.json文件下添加"insecure-registries":["ip:5000"],如下:
{
"registry-mirrors": ["https://xx.mirror.aliyuncs.com"],
"insecure-registries":["192.168.0.xx:5000"]
}
刷新配置:
systemctl daemon-reload
systemctl restart docker
3、查看结果
查看仓库中的所有镜像:
http://192.168.147.134:5000/v2/_catalog
查看镜像tags:
http://192.168.147.134:5000/v2/镜像名/tags/list
如下: