Docker镜像
Docker 的镜像概念类似虚拟机的镜像。是一个只读的模板,一个独立的文件系统,包括运行容器所需的数据,可以用来创建新的容器。Docker镜像实际上是由一层一层的系统文件组成,这种层级的文件系统被称为UnionFS( Union file system 统一文件系统),镜像可以基于dockerfile构建,dockerfile(后面会详写)是一个描述文件,里面包含了若干条密令,每条命令都会对基础文件系统创建新的层次结构。
- 获取镜像命令
docker pull [Docker Registry 地址[:端口号]/]仓库名[:标签]
- 正常情况下Docker 镜像仓库地址在/etc/docker/daemon.json里面可以配置,配置好之后可省略此参数。没有配置的话默认地址是 Docker Hub(docker.io)。
- 仓库名:仓库名是两段式名称,即 用户名/软件名,默认为 library,也就是官方镜像。
例如下图所示:
从图中我们发现,此命令下载的不是一个单一的文件,而是一层层的下载的,充分证明了镜像是由多层存储所构成。
- 查看本地已经下载的镜像信息
docker image ls
- REPOSITORY代表镜像名,TAG代表镜像的标签,ID是镜像的唯一标识,CREATED代表镜像创建时间,SIZE为镜像所占的空间。
- 在该命令后加 --digests参数可以查看到DIGEST即为镜像摘要
- 删除本地镜像
docker image rm image
- 参数image可以是镜像的ID,也可以是镜像名或者标签名或者镜像摘要,最精确的方法是使用 镜像摘要 删除镜像。
- Untagged 和 Deleted:
当一个镜像对应多个不同标签时,删除的信息是Untagged,此时不执行Deleted操作,只是取消镜像对应的某个标签。
当该镜像所有的标签都被取消了,该镜像很可能会失去了存在的意义,因此会触发删除行为。镜像是多层存储结构,因此在删除的时候也是从上层向基础层方向依次进行判断删除。镜像的多层结构让镜像复用变得非常容易,因此很有可能某个其它镜像正依赖于当前镜像的某一层。这种情况,依旧不会触发删除该层的行为。直到没有任何层依赖当前层时,才会真实的删除当前层。这就是为什么,有时候会奇怪,为什么明明没有别的标签指向这个镜像,但是它还是存在的原因,也是为什么有时候会发现所删除的层数和自己 docker pull 看到的层数不一样的原因。
同样,容器是基于镜像创建的, 即容器中的进程依赖于镜像中的文件,在基于此镜像的容器没有全部删除前,不要进行删除镜像操作。
- Dockerfile制作镜像
Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。
下面以定制一个 nginx 镜像(构建好的镜像内会有一个 /usr/share/nginx/html/index.html 文件)为例:
- 在一个空目录下,新建一个名为 Dockerfile 文件,并在文件内添加以下内容:
FROM nginx
RUN echo '这是一个本地构建的nginx镜像' > /usr/share/nginx/html/index.html
FROM 和 RUN 指令的作用:
FROM:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。
RUN:用于执行后面跟着的命令行命令。有以下俩种格式:
- shell 格式:
RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。
- exec 格式:
RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline
Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大,不仅仅增加了构建部署的时间,也很容易出错。 这是很多初学 Docker 的人常犯的一个错误。Union FS 是有最大层数限制的,现在是不得超过 127 层。
- 在Dockerfile所在目录下进行镜像的构建,使用如下命令:
docker build -t nginx:v3 .
注意: 后面的 . 不能省略,代表在当前目录下构建image
- 从输出来看,Step1/2 PULL 了library下的nginx镜像,Step2/2启动了一个容器a52919099cc9运行了命令,随后删除了所用到的这个容器a52919099cc9,最后提交了这一层1261c6c3b384 。
- 构建image的命令格式为:
docker build [选项] <上下文路径/URL/->
在上面命令里,我们通过参数-t,指定了镜像的名称和标签
Docker容器
容器是由镜像实例化而来,容器是基于镜像创建的, 即容器中的进程依赖于镜像中的文件, 这里的文件包括进程运行所需要的可执行文件, 依赖软件, 库文件, 配置文件等等…
- 新建并启动容器
docker run image
例如下图所示,下面的命令输出一个 “Hello World”,之后终止容器:
下面的命令则启动一个 bash 终端,允许用户进行交互,-t
选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上,-i
则让容器的标准输入保持打开。我们可以通过创建的终端来输入命令。
当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从registry下载
- 利用镜像创建并启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个 ip 地址给容器
- 执行用户指定的应用程序或命令
- 执行完毕后容器被终止
- 启动已终止容器
docker container start containerID
- 停止运行的容器
docker stop containerID
想要快速停止容器可以使用kill命令:
docker kill containerID
- 查看容器
docker ps
此命令默认只列出运行的容器,如果要查看全部容器,需添加参数-a
5. 重启容器
docker start containerID
docker start会保留容器的第一次启动时的所有参数。docker restart可以重启容器,其作用就是依次执行docker stop和docker start。容器可能因某种错误而停止运行。容器可能因某种错误而停止运行。对于服务类容器,通常希望它能够自动重启。启动容器时设置–restart就可以达到效果。--restart=always
意味着无论容器因何种原因退出(包括正常退出),都立即重启.
6. 后台运行容器
更多的时候,需要让 Docker 在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时,可以通过添加 -d 参数来实现:
- 使用-d启动容器后,会回到host终端;此时如果想要获取容器的输出信息,可以通过
docker container logs containerID
命令。
- 进入容器
在使用 -d 参数时,容器启动后会进入后台,启动完容器之后会停在host端;某些时候需要进入容器进行操作,可以使用docker exec
命令,该命令有多个参数,当只用 -i 参数时,由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回。
当 -i -t 参数一起使用时,则可以看到我们熟悉的 Linux 命令提示符。
当然,也可以使用docker attach
命令,但是当使用docker attach命令时,如果从这个 stdin 中 exit回到host端,会导致容器停止,docker exec命令则不会导致容器停止。
- attach和exec的区别:
(1)attach直接进入容器启动命令的终端,不会启动新的进程;
(2)exec则是在容器中打开新的终端,并且可以启动新的进程;
(3)如果想直接在终端中查看命令的输出,用attach,其他情况使用exec;
- 暂停容器
docker pause containerID
- 删除容器
docker container rm containerID
10. 清理所有处于终止状态的容器
docker container prune
- 批量删除所有已经退出的容器
docker rm -v $(docker ps -aq -f status=exited)
- 导出容器
docker export containerID > ubuntu.tar
- 导入容器快照
可以使用docker import
从容器快照文件中再导入为镜像
cat ubuntu.tar | docker import - test/ubuntu:v1.0
也可以通过指定 URL 或者某个目录来导入,例如:
docker import http://example.com/exampleimage.tgz example/imagerepo
注意: 用户既可以使用 docker load 来导入镜像存储文件到本地镜像库,也可以使用 docker import 来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。