查看镜像、容器、数据卷所占用的空间
docker system df虚悬镜像: 个镜像既没有仓库名,也没有标签,均为 <none>
docker image ls -f dangling=true
一般来说,虚悬镜像已经失去了存在的价值,是可以随意删除的,可以用下面的命令删除。docker image prune
中间层镜像
默认的 docker image ls 列表中只会显示顶层镜像,如果希望显示包括中间层镜像在内的所有镜像的话,需要加 -a 参数。
docker image ls -a.
列出部分镜像
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 --format "{{.ID}}: {{.Repository}}"
docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"
如果要删除本地的镜像,可以使用 docker image rm 命令,其格式为:
docker image rm [选项] <镜像1> [<镜像2> ...]用 ID
其中, <镜像> 可以是 镜像短 ID 、 镜像长 ID 、 镜像名 或者 镜像摘要 。
docker image ls --digests
Untagged 和 Deleted:如果观察上面这几个命令的运行输出信息的话,你会注意到删除行为分为两类,一类是 Untagged ,另一类是 Deleted 。我们之前介绍过,镜像的唯一标识是其ID 和摘要,而一个镜像可以有多个标签。因此当我们使用上面命令删除镜像的时候,实际上是在要求删除某个标签的镜像。
所以首先需要做的是将满足我们要求的所有镜像标签都取消,这就是我们看到的Untagged 的信息。因为一个镜像可以对应多个标签,因此当我们删除了所指定的标签后,可能还有别的标签指向了这个镜像,如果是这种情况,那么 Delete行为就不会发生。所以并非所有的 docker image rm
都会产生删除镜像的行为,有可能仅仅是取消了某个标签而已。当该镜像所有的标签都被取消了,该镜像很可能会失去了存在的意义,因此会触发删除行为。镜像是多层存储结构,因此在删除的时候也是从上层向基础层方向依次进行判断删除。镜像的多层结构让镜像复用变动非常容易,因此
很有可能某个其它镜像正依赖于当前镜像的某一层。这种情况,依旧不会触发删除该层的行为。直到没有任何层依赖当前层时,才会真实的删除当前层。这就是为什么,有时候会奇怪,为什么明明没有别的标签指向这个镜像,但是它还是存在的原因,也是为什么有时候会发现所删除的层数和自
己 docker pull 看到的层数不一样的源。除了镜像依赖以外,还需要注意的是容器对镜像的依赖。如果有用这个镜像启动的容器存在(即使容器没有运行),那么同样不可以删除这个镜像。之前讲过,容器是以镜像为基础,再加一层容器存储层,组成这样的多层存储结构去运行的。因此该镜像如果被这个容器所依赖的,那么删除必然会导致故障。如果这些容器是不需要的,应该先将它们删除,然后再来删除镜像。
批量删除: docker image rm $(docker image ls -q redis)
删除所有在 mongo:3.2 之前的镜像:
docker image rm $(docker image ls -q -f before=mongo:3.2)可以通过 docker diff 命令看到具体的改动。
commit 镜像构成
docker commit 的语法格式为:
commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]
docker commit \ --author "Tao Wang <twang2218@gmail.com>" \ --message "修改了默认网页" \ webserver \ nginx:v2
其中 --author 是指定修改的作者,而 --message 则是记录本次修改的内容。这点和 git 版本控制相似,不过这里这些信息可以省略留空
慎用 docker commit
使用 docker commit 命令虽然可以比较直观的帮助理解镜像分层存储的概念,但是实际环境中并不会这样使用。首先,如果仔细观察之前的 docker diff webserver 的结果,你会发现除了真正想要修改的 /usr/share/nginx/html/index.html 文件外,由于命令的执行,还有很多文件被改动或添加了。
这还仅仅是最简单的操作,如果是安装软件包、编译构建,那会有大量的无关内容被添加进来,如果不小心清理,将会导致镜像极为臃肿。此外,使用 docker commit 意味着所有对镜像的操作都是黑箱操作,生成的镜像也被称为黑箱镜像,换句话说,就是除了制作镜像的人知道执行过什么命令、怎
么生成的镜像,别人根本无从得知。而且,即使是这个制作镜像的人,过一段时间后也无法记清具体在操作的。虽然 docker diff 或许可以告诉得到一些线索,但是远远不到可以确保生成一致镜像的地步。这种黑箱镜像的维护工作是非常痛苦的。而且,回顾之前提及的镜像所使用的分层存储的概念,
除当前层外,之前的每一层都是不会发生改变的,换句话说,任何修改的结果仅仅是在当前层进行标记、添加、修改,而不会改动上一层。如果使用 docker commit 制作镜像,以及后期修改的话,每一次修改都会让镜像更加臃肿一次,所删除的上一层的东西并不会丢失,会一直如影随形的跟着这个
镜像,即使根本无法访问到。这会让镜像更加臃肿。
8. 我们还可以用 docker history 具体查看镜像内的历史记录
9. 启动容器
启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态( stopped )的容器重新启动。
新建并启动
docker run
当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:
检查本地是否存在指定的镜像,不存在就从公有仓库下载
利用镜像创建并启动一个容器
分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
从地址池配置一个 ip 地址给容器
执行用户指定的应用程序
执行完毕后容器被终止
启动已终止容器
docker container start
10.后台运行
更多的时候,需要让 Docker 在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时,可以通过添加 -d 参数来实现
注: 容器是否会长久运行,是和 docker run 指定的命令有关,和 -d 参数无关。
11. 要获取容器的输出信息
docker container logs [container ID or NAMES]
12. 终止容器
docker container stop / docker stop
docker container restart /docker restart 命令会将一个运行态的容器终止,然后再重新启动它。
13. 进入容器
exec命令 (推荐) 原因 : exit 命令不会导致容器的停止
docker exec 后边可以跟多个参数,这里主要说明 -i -t 参数。
只用 -i 参数时,由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回
当 -i -t 参数一起使用时,则可以看到我们熟悉的 Linux 命令提示符。
14. 导出和导入容器
1. 导出容器快照
docker export
$ docker container ls -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7691a814370e ubuntu:18.04 "/bin/bash" 36 hours ago Exited (0) 21 hours ago test $ docker export 7691a814370e > ubuntu.tar
这样将导出容器快照到本地文件
2. 导入容器快照
可以使用 docker import 从容器快照文件中再导入为镜像,例如
$ cat ubuntu.tar | docker import - test/ubuntu:v1.0 $ docker image ls REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE test/ubuntu v1.0 9d37a6082e97 About a minute ago 171.3 MB
此外,也可以通过指定 URL 或者某个目录来导入,例如
$ docker import http://example.com/exampleimage.tgz example/imagerepo
3.保存镜像
使用 docker save 命令可以将镜像保存为归档文件。
比如我们希望保存这个 alpine 镜像。
docker save alpine -o filename
这里的 filename 可以为任意名称甚至任意后缀名,但文件的本质都是归档文件
注意:如果同名则会覆盖(没有警告)
若使用 gzip 压缩:
docker save alpine | gzip > alpine-latest.tar.gz
4. 加载镜像
docker load -i alpine-latest.tar.gz
如果我们结合这两个命令以及 ssh 甚至 pv 的话,利用 Linux 强大的管道,我们可以写一个命令完成从一个机器将镜像迁移到另一个机器,并且带进度条的功能:
docker save <镜像名> | bzip2 | pv | ssh <用户名>@<主机名> 'cat | docker load'
注:用户既可以使用 docker load 来导入镜像存储文件到本地镜像库,也可以使用 docker import 来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。
此外,从容器快照文件导入时可以重新指定标签等元数据信息。
15. 删除容器
docker container rm / docker rm 来删除一个处于终止状态的容器。例如
如果要删除一个运行中的容器,可以添加 -f 参数。Docker 会发送 SIGKILL信号给容器。
16. 清理所有处于终止状态的容器
用 docker container ls -a 命令可以查看所有已经创建的包括终止状态的容器,如果数量太多要一个个删除可能会很麻烦,用下面的命令可以清理掉所有处于终止状态的容器。
docker container prune
17. 私有仓库
1. 安装运行 docker-registry
docker run -d \ -p 5000:5000 \ -v /opt/data/registry:/var/lib/registry \ registry
2. 在私有仓库上传、搜索、下载镜像
创建好私有仓库之后,就可以使用 docker tag 来标记一个镜像,然后推送它到仓库。例如私有仓库地址为 127.0.0.1:5000 。先在本机查看已有的镜像。
docker image ls REPOSITORY TAG IMAGE IDCREATED VIRTUAL SIZE ubuntu latest ba5877dc9bec 6 weeks ago 192.7 MB
使用 docker tag 将 ubuntu:latest 这个镜像标记为127.0.0.1:5000/ubuntu:latest 。
格式为 docker tag IMAGE[:TAG][REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG] 。
docker tag ubuntu:latest 127.0.0.1:5000/ubuntu:latest $ docker image ls REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE ubuntu latest ba5877dc9bec 6 weeks ago 192.7 MB 127.0.0.1:5000/ubuntu:latest latest ba5877dc9bec 6 weeks ago 192.7 MB
使用 docker push 上传标记的镜像。
$ docker push 127.0.0.1:5000/ubuntu:latest The push refers to repository [127.0.0.1:5000/ubuntu] 373a30c24545: Pushed a9148f5200b0: Pushed cdd3de0940ab: Pushed fc56279bbb33: Pushed b38367233d37: Pushed 2aebd096e0e2: Pushed latest: digest: sha256:fe4277621f10b5026266932ddf760f5a756d2facd 505a94d2da12f4f52f71f5a size: 1568
用 curl 查看仓库中的镜像。
$ curl 127.0.0.1:5000/v2/_catalog {"repositories":["ubuntu"]}
这里可以看到 {"repositories":["ubuntu"]} ,表明镜像已经被成功上传了。
先删除已有镜像,再尝试从私有仓库中下载这个镜像。
docker image rm 127.0.0.1:5000/ubuntu:latest $ docker pull 127.0.0.1:5000/ubuntu:latest Pulling repository 127.0.0.1:5000/ubuntu:latest ba5877dc9bec: Download complete 511136ea3c5a: Download complete 9bad880da3d2: Download complete 25f11f5fb0cb: Download complete ebc34468f71d: Download complete 2318d26665ef: Download complete $ docker image ls REPOSITORY TAG IMAGE IDCREATED VIRTUAL SIZE 127.0.0.1:5000/ubuntu:latest latest ba5877dc9bec 6 weeks ago 192.7 MB
注意事项
如果你不想使用 127.0.0.1:5000 作为仓库地址,比如想让本网段的其他主机也能把镜像推送到私有仓库。你就得把例如 192.168.199.100:5000 这样的内网地址作为私有仓库地址,这时你会发现无法成功推送镜像。这是因为 Docker 默认不允许非 HTTPS 方式推送镜像。
我们可以通过 Docker 的配置选项来取消这个限制,或者查看下一节配置能够通过 HTTPS 访问的私有仓库。
18. Docker 数据管理
在容器中管理数据主要有两种方式:
数据卷(Volumes)
挂载主机目录 (Bind mounts)
1. 数据卷
数据卷 是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:
数据卷 可以在容器之间共享和重用
对 数据卷 的修改会立马生效
对 数据卷 的更新,不会影响镜像
数据卷 默认会一直存在,即使容器被删除
注意: 数据卷 的使用,类似于 Linux 下对目录或文件进行 mount,镜像中的被指定为挂载点的目录中的文件会隐藏掉,能显示看的是挂载的 数据卷 。
1.1 创建一个数据卷
docker volume create my-vol
1.2 查看所有的 数据卷
docker volume ls
1.3 查看指定 数据卷 的信息
$ docker volume inspect my-vol [ { "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/my-vol/_data", "Name": "my-vol", "Options": {}, "Scope": "local" } ]
1.4 启动一个挂载数据卷的容器
在用 docker run 命令的时候,使用 --mount 标记来将 数据卷 挂载到容器里。在一次 docker run 中可以挂载多个 数据卷 。
下面创建一个名为 web 的容器,并加载一个 数据卷 到容器的 /webapp 目录。
docker run -d -P \ --name web \ # -v my-vol:/wepapp \ --mount source=my-vol,target=/webapp \ training/webapp \ python app.py
1.5 查看 指定容器的信息
$ docker inspect web
数据卷 信息在 "Mounts" Key 下面
1.6 删除数据卷
docker volume rm my-vol
数据卷 是被设计用来持久化数据的,它的生命周期独立于容器,Docker 不会在容器被删除后自动删除 数据卷 ,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的 数据卷 。如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用 docker rm -v 这个命令
无主的数据卷可能会占据很多空间,要清理请使用以下命令
docker volume prune
2. 挂载主机目录
2.1 挂载一个主机目录作为数据卷
使用 --mount 标记可以指定挂载一个本地主机的目录到容器中
$ docker run -d -P \ --name web \ # -v /src/webapp:/opt/webapp \ --mount type=bind,source=/src/webapp,target=/opt/webapp \ training/webapp \ python app.py
上面的命令加载主机的 /src/webapp 目录到容器的 /opt/webapp 目录
使用 -v 参数时如果本地目录不存在 Docker 会自动为你创建一个文件夹,现在使用 --mount 参数时如果本地目录不存在,Docker 会报错。
Docker 挂载主机目录的默认权限是 读写 ,用户也可以通过增加 readonly 指定为 只读
$ docker run -d -P \ --name web \ # -v /src/webapp:/opt/webapp:ro \ --mount type=bind,source=/src/webapp,target=/opt/webapp,read only \ training/webapp \ python app.py
加了 readonly 之后,就挂载为 只读 了。如果你在容器内 /opt/webapp 目录新建文件,会显示如下错误
/opt/webapp # touch new.txt touch: new.txt: Read-only file system
2.2 挂载一个本地主机文件作为数据卷
--mount 标记也可以从主机挂载单个文件到容器中
$ docker run --rm -it \ # -v $HOME/.bash_history:/root/.bash_history \ --mount type=bind,source=$HOME/.bash_history,target=/root/.ba sh_history \ ubuntu:18.04 \ bash root@2affd44b4667:/# history 1 ls 2 diskutil list
这样就可以记录在容器输入过的命令了。
19 Docker 中的网络功能介绍
Docker 允许通过外部访问容器或容器互联的方式来提供网络服务。
1 外部访问容器
容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P 或-p 参数来指定端口映射。
当使用 -P 标记时,Docker 会随机映射一个 49000~49900 的端口到内部容器开放的网络端口。
2. 映射所有接口地址
使用 hostPort:containerPort 格式本地的 5000 端口映射到容器的 5000 端口,可以执行
docker run -d -p 5000:5000 training/webapp python app.py
此时默认会绑定本地所有接口上的所有地址
3. 映射到指定地址的指定端口
-p 127.0.0.1:5000:5000
4. 映射到指定地址的任意端口
使用 ip::containerPort 绑定 localhost 的任意端口到容器的 5000 端口,本地主机会自动分配一个端口。
-d -p 127.0.0.1::5000
还可以使用 udp 标记来指定 udp 端口
-p 127.0.0.1:5000:5000/udp
5. 查看映射端口配置
docker port nostalgic_morse 5000
容器有自己的内部网络和 ip 地址(使用 docker inspect 可以获取所有的变量,Docker 还可以有一个可变的网络配置。)
-p 标记可以多次使用来绑定多个端口
20 容器互联
如果你之前有 Docker 使用经验,你可能已经习惯了使用 --link 参数来使容器互联。随着 Docker 网络的完善,强烈建议大家将容器加入自定义的 Docker 网络来连接多个容器,而不是使用 --link 参数。
1. 新建网络
docker network create -d bridge mynet
-d 参数指定 Docker 网络类型,有 bridge overlay 。其中 overlay 网络类型用于 Swarm mode.
2. 连接容器
运行一个容器并连接到新建的 my-net 网络
docker run -it -d --rm --name test1 --network mynet centos:latest bash docker run -it -d --rm --name test2 --network mynet centos:latest bash
进入到test2 容器进行 ping test1
[root@8a5374553ed0 /]# ping test1 PING test1 (172.18.0.2) 56(84) bytes of data. 64 bytes from 8a5374553ed0 (172.18.0.2): icmp_seq=1 ttl=64 time=0.030 ms 64 bytes from 8a5374553ed0 (172.18.0.2): icmp_seq=2 ttl=64 time=0.047 ms 64 bytes from 8a5374553ed0 (172.18.0.2): icmp_seq=3 ttl=64 time=0.262 ms [root@8a5374553ed0 /]# ping 192.168.123.1 PING 192.168.123.1 (192.168.123.1) 56(84) bytes of data. 64 bytes from 192.168.123.1: icmp_seq=1 ttl=63 time=0.845 ms 64 bytes from 192.168.123.1: icmp_seq=2 ttl=63 time=0.789 ms [root@8a5374553ed0 /]# ping www.baidu.com PING www.a.shifen.com (220.181.111.37) 56(84) bytes of data. 64 bytes from 220.181.111.37 (220.181.111.37): icmp_seq=1 ttl=54 time=6.61 ms 64 bytes from 220.181.111.37 (220.181.111.37): icmp_seq=2 ttl=54 time=7.02 ms
容器之间是可以互相ping通的, 也可以ping通局域网的其他ip, ping百度也正常!
如果你有多个容器之间需要互相连接,推荐使用 Docker Compose。
3. 配置 DNS
如何自定义配置容器的主机名和 DNS 呢?秘诀就是 Docker 利用虚拟文件来挂载容器的 3 个相关配置文件。在容器中使用 mount 命令可以看到挂载信息:
$ mount /dev/disk/by-uuid/1fec...ebdf on /etc/hostname type ext4 ... /dev/disk/by-uuid/1fec...ebdf on /etc/hosts type ext4 ... tmpfs on /etc/resolv.conf type tmpfs ...
这种机制可以让宿主主机 DNS 信息发生更新后,所有 Docker 容器的 DNS 配置通过 /etc/resolv.conf 文件立刻得到更新。配置全部容器的 DNS ,也可以在 /etc/docker/daemon.json 文件中增加以下内容来设置。
{ "dns" : [ "114.114.114.114", "8.8.8.8" ] }
21 .手动指定容器的配置
docker run 命令启动容器时加入如下参数:
1. 设定容器的主机名
-h HOSTNAME 或者 --hostname=HOSTNAME 设定容器的主机名,它会被写到容器内的 /etc/hostname 和 /etc/hosts 。但它在容器外部看不到,既不会在docker container ls 中显示,也不会在其他的容器的 /etc/hosts 看到。
2. 设置DNS
--dns=IP_ADDRESS 添加 DNS 服务器到容器的 /etc/resolv.conf 中,让容器用这个服务器来解析所有不在 /etc/hosts 中的主机名。
3. 设置搜索域
--dns-search=DOMAIN 设定容器的搜索域,当设定搜索域为 .example.com时,在搜索一个名为 host 的主机时,DNS 不仅搜索 host,还会搜索host.example.com 。
注意:如果在容器启动时没有指定最后两个参数,Docker 会默认用主机上的/etc/resolv.conf 来配置容器。
还没有评论,来说两句吧...