Docker 命令 之 镜像(Image)

摘要

docker search : 搜索镜像

1
2
3
4
5
6
7
8
9
10
$ docker search --help
用法: docker search [OPTIONS] TERM

在 Docker Hub 中搜索镜像

选项:
-f, --filter filter 根据提供的条件过滤输出,常见的过滤条件包括:stars(星级)、is-official(是否为官方镜像)
--format string 使用 Go 模板美化输出,不太常用
--limit int 搜索结果的最大数量
--no-trunc 不截断输出内容,显示完整信息(默认输出中某些字段如描述可能被截断)

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 搜索名称中包含 nginx 的镜像
$ docker search nginx

# 搜索名称中包含 nginx 且星级不少于 100 的镜像。
$ docker search -f stars=100 nginx
# 搜索官方镜像
$ docker search -f is-official=true nginx

# 搜索 nginx,按照指定模板格式化输出
$ docker search nginx --format "{{.Name}}: {{.StarCount}} stars: {{.Description}}"

# 搜索nginx镜像,并限制5个结果
$ docker search nginx --limit 5

# 组合使用多个选项
$ docker search -f stars=100 --limit 5 --no-trunc nginx

docker search 命令报错的解决方法

  • 目前国内使用docker search时会出现Error response from daemon: Get "https://index.docker.io/v1/search?q=nginx&n=25": dial tcp 210.56.51.193:443: i/o timeout的错误,即便我们配置了国内的镜像源,这个错误还是会存在。
  • 即便为宿主机和docker都配置上DNS也依然会报错。
  • 不过可以通过第三方镜像仓库进行查询,比如在查询的镜像名称前加上 docker.1ms.run/,比如查询nginx镜像,则输入docker search docker.1ms.run/nginx,这里要注意并不是所有的第三方镜像仓库都支持查询。
  • 可以编写一个脚本docker_search,查询镜像并输出结果,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cat << 'EOF' > docker_search
#!/bin/bash
QUERY=${1} # 查询关键词,这里要注意,第一个参数必须是查询关键词
# 获取除第一个参数外的所有参数
ARGS=${@:2}
echo "查询镜像:docker search docker.1ms.run/$QUERY $ARGS"
docker search docker.1ms.run/$QUERY $ARGS
EOF

# 设置执行权限
chmod +x docker_search
# 将其移动到 /usr/local/bin/
mv docker_search /usr/local/bin/docker_search
# 如果/usr/local/bin/没有在PATH中,请添加到环境变量
echo "export PATH=$PATH:/usr/local/sbin" >> ~/.bashrc
source ~/.bashrc
# 测试
docker_search redis -f stars=100 --limit 5 --no-trunc
## 输出
NAME DESCRIPTION STARS OFFICIAL
redis Redis is the world’s fastest data platform for caching, vector search, and NoSQL databases. 13315 [OK]
redis/redis-stack redis-stack installs a Redis server with additional database capabilities and the RedisInsight. 149
bitnami/redis Bitnami container image for Redis
  • 基于url搜索,支持分页,但不能支持其它search参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
cat << 'EOF' > docker_search_by_url
#!/bin/bash

# 参数处理
QUERY=${1:-nginx} # 默认查询关键词
N=${2:-25} # 默认每页条数
PAGE=${3:-1} # 默认页码

# 镜像源列表:依次尝试访问这些域名,这里要注意,并不是所有的镜像源都支持搜索功能
REGISTRIES=(
"docker.1ms.run"
"register.librax.org"
# 你可以继续添加备用域名
)

# 初始化成功标志
WORKING_URL=""

# 遍历域名,找到第一个可访问的
for REG in "${REGISTRIES[@]}"; do
TEST_URL="https://${REG}/v1/search?q=test&n=1"
if curl -s --connect-timeout 2 "$TEST_URL" | grep -q '"results"'; then
WORKING_URL="https://${REG}/v1/search?q=${QUERY}&n=${N}&page=${PAGE}"
break
fi
done

# 如果都失败,退出
if [ -z "$WORKING_URL" ]; then
echo "❌ 无法连接任何镜像源,请检查网络或备用域名设置。"
exit 1
fi

# 请求数据并格式化输出
curl -s "$WORKING_URL" \
| jq -r '["NAME","STARS","OFFICIAL","DESCRIPTION"],
(.results[] |
[.name,
(.star_count|tostring),
(if .is_official then "[OK]" else "" end),
.description])
| @tsv' \
| column -t -s $'\t'
EOF

docker image : 镜像管理

  • docker image --help

命令 说明 别名(简写)
build 从 Dockerfile 构建一个镜像 docker build
history 显示镜像的历史记录 docker history
import 从 tar 包导入内容以创建文件系统镜像 docker import
inspect 显示一个或多个镜像的详细信息 可以使用 docker inspect
load 从 tar 归档或标准输入中加载镜像 docker load
ls 列出镜像 docker images
prune 移除未使用的镜像
pull 从镜像仓库下载镜像 docker pull
push 上传镜像到镜像仓库 docker push
rm 移除一个或多个镜像 docker rmi
save 将一个或多个镜像保存为 tar 归档(默认输出到标准输出) docker save
tag 创建一个标签 TARGET_IMAGE 指向 SOURCE_IMAGE docker tag
  • 运行 docker image COMMAND --help 可获取某个命令的更多信息。

docker pull : 拉取镜像

  • docker image pull == docker pull

1
2
3
4
5
6
7
8
9
10
11
12
13
# 命令格式,不加tag默认拉取 :latest
$ docker pull <image_name>[:<tag>]

# 拉取nginx镜像,默认拉取最新版本:latest,nginx是官方镜像,完整名称实际上是 library/nginx
$ docker pull nginx == docker pull library/nginx == docker pull nginx:latest
# 拉取指定tag的镜像
$ docker pull nginx:1.28.0

# 拉取非官方镜像,用户上传的
$ docker pull hanqunfeng/alpine-jre8-slim:1.0.0

# 拉取指定平台的镜像,如果不指定 --platform 参数,默认会拉取与你当前 Docker 客户端运行平台匹配的镜像,通过 docker version 查看
$ docker pull --platform=linux/amd64 nginx:latest
  • Linux 安装 Docker 中介绍了如配置国内的镜像加速源来加快镜像的拉取,但是国内镜像源不稳定,随时都有可能不可用,而且每次重新配置镜像源还需要重启Docker,可以编写一个脚本来完成pull,这样每次更新镜像源时只需要修改脚本,而不需要重启Docker了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# 脚本名称:docker_pull
#!/bin/bash

# 用法检查
if [[ -z "$1" ]]; then
echo "用法: $0 <镜像名>,例如:docker_pull redis"
exit 1
fi

# 原始镜像名称,例如 nginx 或 someuser/image
ORIGINAL_IMAGE_NAME="$1"

# 镜像源列表,修改镜像源时只需要修改该列表即可
MIRROR_LIST=(
"docker.1ms.run"
"docker.xuanyuan.me"
"docker.m.daocloud.io"
"docker.1panel.live"
)

# 如果镜像名中不包含 "/",加上 "library/"
if [[ "$ORIGINAL_IMAGE_NAME" != *"/"* ]]; then
IMAGE_NAME="library/$ORIGINAL_IMAGE_NAME"
else
IMAGE_NAME="$ORIGINAL_IMAGE_NAME"
fi

# 遍历镜像源
for MIRROR in "${MIRROR_LIST[@]}"; do
FULL_IMAGE="$MIRROR/$IMAGE_NAME"
echo "尝试从 $FULL_IMAGE 拉取镜像..."
if docker pull "$FULL_IMAGE"; then
echo "成功拉取镜像:$FULL_IMAGE"

# 将镜像重命名为去除镜像源前缀的版本
docker tag "$FULL_IMAGE" "$ORIGINAL_IMAGE_NAME"
echo "镜像重命名为:$ORIGINAL_IMAGE_NAME"

# 可选:删除带镜像源前缀的镜像
docker rmi "$FULL_IMAGE" >/dev/null 2>&1

exit 0
else
echo "从 $MIRROR 拉取失败,尝试下一个镜像源..."
fi
done

echo "所有镜像源尝试失败,无法拉取镜像:$ORIGINAL_IMAGE_NAME"
exit 1

如何获取镜像tag

  • docker 命令中没有提供直接获取镜像tag的命令,如果不想到dockerhub上查看,可以通过如下方式获取(需要科学上网):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 只显示tag名称,官方镜像替换 nginx,非官方镜像替换 libryary/nginx,page_size=5表示每页5条数据,page=1表示第一页(默认为1)
curl -s "https://registry.hub.docker.com/v2/repositories/library/nginx/tags?page_size=5&page=1" | jq '.results[].name'

## 也可以使用如下url,两者效果相同
## https://hub.docker.com/v2/namespaces/{namespace}/repositories/{repository}/tags?page_size=5&page=1
## 示例:https://hub.docker.com/v2/namespaces/library/repositories/nginx/tags?page_size=1&page=1

# 输出json格式,并显示最后更新时间和镜像大小
curl -s "https://registry.hub.docker.com/v2/repositories/library/nginx/tags?page_size=5&page=1" | jq '.results[] | {name,last_updated,full_size}'

# 输出表格格式,并格式化输出
curl -s "https://registry.hub.docker.com/v2/repositories/library/nginx/tags?page_size=5&page=1" \
| jq -r '.results[] |
"\(.name)\t\t\(.last_updated | sub("T"; " ") | sub("\\..*"; ""))\t\t\(((.full_size / 1024 / 1024 * 100 | round)/100) | tostring) MB"' \
| awk '{printf "%-30s %-20s %8.2f MB\n", $1, $2" "$3, $4}'

docker images : 列出镜像

  • docker image ls == docker images

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 列出所有镜像,不包括悬空镜像,(dangling images:没有 tag 的镜像,通常是构建中间产物,例如:<none>:<none> 形式。)
$ docker images
# 列出所有镜像,包括悬空镜像
$ docker images -a

# 列出所有镜像,并显示镜像的摘要信息
$ docker images --digests

# 列出所有镜像,并输出为json格式
$ docker images --format json
# 只显示镜像名称和标签
$ docker images --format "{{.Repository}}:{{.Tag}}"

# 只显示镜像ID
$ docker images -q

docker inspect : 查看镜像的详细信息

  • docker image inspect == docker inspect

  • 这里要注意,docker inspect如果基于名称查找会优先查找容器

1
2
3
4
5
6
7
8
9
10
11
# 命令格式
$ docker inspect [OPTIONS] NAME|ID [NAME|ID...]

# 显示镜像的详细信息,镜像名称
$ docker inspect nginx

# 显示镜像的详细信息,镜像ID
$ docker inspect 9f0c0d0a0f0f

# 显示镜像的Labels信息,获取json中指定的字段
$ docker image inspect --format='{{json .Config.Labels}}' nginx

docker image prune : 删除未使用的镜像

1
2
3
4
5
6
# 删除悬空镜像,(dangling images:没有 tag 的镜像,通常是构建中间产物,例如:<none>:<none> 形式。)
$ docker image prune
# 删除全部未使用镜像(未被任何一个容器引用),包括悬空镜像
$ docker image prune -a
# 不进行确认提示,直接执行
$ docker image prune -f

docker rmi : 删除镜像

  • docker image rm == docker rmi

1
2
3
4
5
6
7
8
9
10
11
12
13
# 命令格式
$ docker rmi [OPTIONS] IMAGE [IMAGE...]

# 删除镜像,镜像名称
$ docker rmi nginx
# 删除多个镜像,空格分隔
$ docker rmi nginx mysql
# 删除镜像,镜像ID
$ docker rmi 9f0c0d0a0f0f
# 强制删除镜像,当镜像被容器引用时,会报错,需要使用-f参数进行强制删除
$ docker rmi -f nginx
# 删除全部镜像
$ docker rmi $(docker images -q)

docker history : 查看镜像的构建历史

  • docker image history == docker history

1
2
3
4
5
6
7
8
9
10
# 命令格式
$ docker history [OPTIONS] IMAGE
# 查看镜像的历史记录,镜像名称
$ docker history nginx
# 查看镜像的历史记录,镜像ID
$ docker history 9f0c0d0a0f0f
# 显示完整的镜像历史记录,默认`CREATED BY`中的信息太长会被截断
$ docker history --no-trunc nginx
# 显示为json格式
$ docker history --format=json nginx
  • docker history 显示的是构建历史,会将每一个 Dockerfile 指令都算一层,而不是物理镜像层(layer)数量,若要查看镜像的物理层数,可以通过如下命令查看

1
$ docker image inspect --format '{{ len .RootFS.Layers }}' nginx

docker tag : 创建一个标签

  • docker image tag == docker tag

1
2
3
4
5
6
7
8
9
10
11
12
# 命令格式
$ docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
# 创建一个标签
$ docker tag nginx:latest hanqunfeng/nginx:latest
# 查看镜像,可以看到两个镜像的 IMAGE ID 一致
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hanqunfeng/nginx latest be69f2940aaf 5 weeks ago 192MB
nginx latest be69f2940aaf 5 weeks ago 192MB
# 此时若通过 IMAGE ID 删除镜像,会报错,提示被多个 REPOSITORY 关联,需要使用 -f 参数进行强制删除
$ docker rmi be69f2940aaf
Error response from daemon: conflict: unable to delete be69f2940aaf (must be forced) - image is referenced in multiple repositories

docker save : 将镜像保存为 tar 归档

  • docker image save == docker save

1
2
3
4
5
6
# 命令格式
$ docker save [OPTIONS] IMAGE [IMAGE...]
# 将镜像保存为 tar 归档,-o 指定输出文件,文件名称任意,甚至都不需要以 .tar 结尾
$ docker save -o nginx.tar nginx
# 或者
$ docker save nginx > nginx.tar

docker load : 从 tar 归档中加载镜像

  • docker image load == docker load

1
2
3
4
5
6
# 命令格式
$ docker load [OPTIONS]
# 从 tar 归档中加载镜像,导出tar归档时的镜像名称就是加载后的镜像名称
$ docker load -i nginx.tar
# -q 参数表示不显示进度条
$ docker load -q -i nginx.tar

docker import : 从文件创建镜像

  • docker image import == docker import

1
2
3
4
5
6
7
8
9
10
11
12
13
# 命令格式
$ docker import [OPTIONS] FILE|URL|- [REPOSITORY[:TAG]]
## 参数说明
file 本地 tar 文件,例如 rootfs.tar
URL 网络地址(http/https)
- 从标准输入读取(比如通过管道)

# 输出镜像名称与标签
REPOSITORY[:TAG] 导入后镜像的名称与标签

# OPTIONS
--change 在导入镜像时设置 Dockerfile 指令,如 CMD、ENV、EXPOSE 等
--message, -m 添加导入说明(commit message)
  • docker importdocker load 的区别

命令 用途 格式 是否保留历史
docker import 导入文件系统,创建镜像(由 docker export 生成) 纯文件系统 tar 包 ❌ 不保留历史、标签等元数据
docker load 加载镜像(通常由 docker save 生成) Docker 镜像 tar(含元数据) ✅ 保留 tag、层、历史等
  • 示例: 从容器导出再导入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 启动一个容器
$ docker run -d -p 8080:80 --name nginx nginx

# 导出容器文件系统,此时 nginx 容器中的所有文件都保存在 my_nginx.tar 文件中
$ docker export -o my_nginx.tar nginx

# 导入文件系统,导入时指定 启动命令,因为 my_nginx.tar 只是文件,并不包含任何启动命令
$ docker import --change='CMD ["nginx", "-g", "daemon off;"]' my_nginx.tar nginx:my_tag

# 查看镜像,镜像ID不一致
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx my_tag 4ab42de31bac 4 seconds ago 191MB
nginx latest be69f2940aaf 5 weeks ago 192MB

docker build : 从指定目录或URL中的 Dockerfile 构建 Docker 镜像

  • docker image build == docker build

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 命令格式
docker build [OPTIONS] PATH | URL | -
# 参数说明
PATH Dockerfile 所在的目录
URL Git 仓库的 URL
- 从标准输入读取 Dockerfile


# 构建镜像,-t: 指定镜像名称,.: 表示从当前目录查找Dockerfile,默认文件名称为 Dockerfile
docker build -t myimage:latest .
# 构建镜像,-f: 指定 Dockerfile 的相对路径,.: 表示基于当前目录,实际的 Dockerfile 路径就是 ./path/MyDockerfile
docker build -t myimage:latest -f path/MyDockerfile .
# 实际的 Dockerfile 路径就是 /usr/local/path/MyDockerfile
docker build -t myimage:latest -f path/MyDockerfile /usr/local

# 构建镜像,从 Git 仓库中构建,git 仓库的 Dockerfile 必须在根目录下
docker build https://github.com/hanqunfeng/docker_test.git -t abc:1.0.0
# 构建镜像,从 Git 仓库中构建,指定 Dockerfile 的相对路径
docker build -f docker/Dockerfile https://github.com/hanqunfeng/docker_test.git -t abc:1.0.1
# 构建镜像,从 Git 仓库中构建,指定分支或 tag
docker build -f docker/Dockerfile https://github.com/hanqunfeng/docker_test.git#release -t abc:1.0.2

# 构建镜像,--no-cache 表示不使用缓存,每次构建都会重新构建,但会非常慢,一般没有导致某一个层发生变化时不需要加上这个参数
docker build --no-cache -t app:latest .

docker push : 推送本地镜像到远程仓库

  • docker image push == docker push

  • 这里介绍如何将镜像推送到docker hub远程仓库

  • 需要先在docker hub网站上创建一个账号,比如我的用户名是hanqunfeng

  • 然后就可以使用下面的命令将本地镜像推送到远程仓库了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 查看本地镜像
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest e573c6323878 18 hours ago 191MB

# 对nginx镜像打tag,前缀必须与用户名一致
$ docker tag nginx hanqunfeng/nginx:1.0.0
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hanqunfeng/nginx 1.0.0 be69f2940aaf 5 weeks ago 192MB
nginx latest be69f2940aaf 5 weeks ago 192MB

# 登录 loghup
$ docker login -u hanqunfeng

i Info → A Personal Access Token (PAT) can be used instead.
To create a PAT, visit https://app.docker.com/settings


Password: # 输入密码
Login Succeeded

# 登录同时输入密码
# docker login -u hanqunfeng -p 12345678
# 登录其它仓库
# docker login -u username -p password registry.orther.com

# 推送到docker hub,此后就可以通过 docker pull hanqunfeng/nginx:1.0.0 获取了
$ docker push hanqunfeng/nginx:1.0.0