一、 核心概念:镜像、容器与仓库
Docker 主要包含三个核心概念,分别是镜像、容器和仓库,理解了这三个概念,就理解了 Docker 的整个生命周期。
镜像: Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
容器: 容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间容器可以被。创建、启动、停止、删除和暂停等等,说到镜像与容器之间的关系,可以类比面向对象程序设计中的类和实例。
仓库: 镜像构建完成后,可以很容易的在当前宿主机上运行,但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。一个 Docker Registry 中可以包含多个仓库;每个仓库可以包含多个标签;每个标签对应一个镜像,其中标签可以理解为镜像的版本号。
1. 镜像(Image)- 一个特殊的文件系统
我们都知道,操作系统分为内核和用户空间。对于 Linux 而言,内核启动后,会挂载 root 文件系统为其提供用户空间支持。而 Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:18.04 就包含了完整的一套 Ubuntu 18.04 最小系统的 root 文件系统。
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。 镜像不包含任何动态数据,其内容在构建之后也不会被改变。
因为镜像包含操作系统完整的 root 文件系统,其体积往往是庞大的,因此在 Docker 设计时,就充分利用 Union FS 的技术,将其设计为分层存储的架构。所以严格来说,镜像并非是像一个 ISO 那样的打包文件,镜像只是一个虚拟的概念,其实际体现并非由一个文件组成,而是由一组文件系统组成,或者说,由多层文件系统联合组成。
Docker 设计时,就充分利用 Union FS的技术,将其设计为 分层存储的架构 。 镜像实际是由多层文件系统联合组成。
镜像构建时,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。因此,在构建镜像的时候,需要额外小心,每一层尽量只包含该层需要添加的东西,任何额外的东西应该在该层构建结束前清理掉。
分层存储的特征还使得镜像的复用、定制变的更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。
总的来说,你最需要记住这点:
在 Dockerfile 中, 每一条指令都会创建一个镜像层,继而会增加整体镜像的大小。
镜像作为 Docker 最突出的创新之一,它变革了软件交付标准。理解镜像,对理解整个 Docker 的生命周期非常重要。
2. 容器(Container) - 镜像运行时的实体
镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的 类 和 实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等 。
Docker容器将应用程序和运行所需的所有内容封装到一个黑色沙箱中。这包括操作系统,应用程序代码,运行时,系统工具,系统库等.Docker容器是基于Docker镜像构建的。由于镜像是只读的,因此Docker在镜像的只读文件系统上添加了一个读写文件系统来创建容器。
容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的 命名空间。前面讲过镜像使用的是分层存储,容器也是如此。
容器存储层的生存周期和容器一样,容器消亡时,容器存储层也随之消亡。因此,任何保存于容器存储层的信息都会随容器删除而丢失。
按照 Docker 最佳实践的要求,容器不应该向其存储层内写入任何数据 ,容器存储层要保持无状态化。所有的文件写入操作,都应该使用数据卷(Volume)、或者绑定宿主目录,在这些位置的读写会跳过容器存储层,直接对宿主(或网络存储)发生读写,其性能和稳定性更高。数据卷的生存周期独立于容器,容器消亡,数据卷不会消亡。因此, 使用数据卷后,容器可以随意删除、重新 run ,数据却不会丢失。
3. 仓库(Repository)- 集中存放镜像文件的地方
Docker 仓库 是集中存放镜像文件的场所。镜像构建完成后,可以很容易的在当前宿主上运行,但是, 如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry就是这样的服务。
一个 Docker Registry
中可以包含多个 仓库(Repository);每个仓库可以包含多个 标签(Tag);每个标签对应一个镜像。所以说:镜像仓库是Docker用来集中存放镜像文件的地方类似于我们之前常用的代码仓库。
通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本 。我们可以通过<仓库名>:<标签>
的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。
仓库又可以分为两种形式:
- public(公有仓库)
- private(私有仓库)
1) 公有仓库
Docker Registry 公开服务 是开放给用户使用、允许用户管理镜像的 Registry 服务。一般这类公开服务允许用户免费上传、下载公开的镜像,并可能提供收费服务供用户管理私有镜像。
最常使用的 Registry 公有仓库是官方的 Docker Hub ,这也是默认的 Registry,并拥有大量的高质量的官方镜像,网址为:hub.docker.com 。在国内访问Docker Hub 可能会比较慢国内也有一些云服务商提供类似于 Docker Hub 的公开服务。比如 网易云镜像服务、DaoCloud 镜像市场、阿里云镜像库等。
2) 私有仓库
除了使用公有仓库外,用户还可以在本地搭建私有仓库 Docker Registry。Docker 官方提供了 Docker Registry 镜像,可以直接使用做为私有 Registry 服务。
开源的 Docker Registry 镜像只提供了 Docker Registry API 的服务端实现,足以支持 docker 命令,不影响使用。但不包含图形界面,以及镜像维护、用户管理、访问控制等高级功能。在官方的商业化版本 Docker Trusted Registry 中,提供了这些高级功能。
除了官方的 Docker Registry 外,还有第三方软件实现了 Docker Registry API,甚至提供了用户界面以及一些高级功能。比如,Harbor 和 Sonatype Nexus。
二、Docker 安装
1. 在macOS系统安装
1.1 使用 Homebrew 安装
Homebrew 的 Cask 已经支持 Docker Desktop for Mac,因此可以很方便的使用 Homebrew Cask 来进行安装:
安装 HomeBrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
安装 Docker
brew cask install docker
1.2 手动下载安装Docker
如果需要手动下载,请点击以下链接下载 Stable 或 Edge 版本的 Docker Desktop for Mac。
如同 macOS 其它软件一样,安装也非常简单,双击下载的 .dmg 文件,然后将那只叫 Moby 的鲸鱼图标拖拽到 Application 文件夹即可(其间需要输入用户密码)。
1.3 运行Docker桌面服务
从应用中找到 Docker 图标并点击运行。
运行之后,会在右上角菜单栏看到多了一个鲸鱼图标,这个图标表明了 Docker 的运行状态。
点击鲸鱼图标会弹出操作菜单
启动终端后,通过命令可以检查安装后的 Docker 版本。
➜ docker --version
Docker version 19.03.8, build afacb8b
~ via ⬢ v12.16.3
➜ docker-compose --version
docker-compose version 1.25.5, build 8a1c60f6
~ via ⬢ v12.16.3
➜ kubectl version
Client Version: version.Info{Major:"1", Minor:"16+", GitVersion:"v1.16.6-beta.0", GitCommit:"e7f962ba86f4ce7033828210ca3556393c377bcc", GitTreeState:"clean", BuildDate:"2020-01-15T08:26:26Z", GoVersion:"go1.13.5", Compiler:"gc", Platform:"darwin/amd64"}
The connection to the server localhost:8080 was refused - did you specify the right host or port?
通过鲸鱼图标弹出菜单的 About Docker Desktop
1.4 镜像加速
当然了,由于某些原因,国内从 Docker Hub 上拉取内容会非常缓慢,这个时候就可以配置一个镜像加速器环境。详情说明可以移步Docker 中国官方镜像加速,对于 macOS 用户,在任务栏点击应用图标 -> Perferences… -> Docker Engine -> configuration file,在文件中填写加速器地址 https://registry.docker-cn.com 即可。修改完成之后,点击 Apply & Restart 即可。
国内很多云服务商都提供了国内加速器服务,例如:
- 网易云加速器 https://hub-mirror.c.163.com
- 百度云加速器 https://mirror.baidubce.com
- 阿里云加速器 https://kfwkfulq.mirror.aliyuncs.com
"registry-mirrors": ["https://registry.docker-cn.com"]
三、 镜像使用
Docker 使用 C/S 结构,即客户端/服务器体系结构。 Docker 客户端与 Docker 服务器进行交互,Docker服务端负责构建、运行和分发 Docker 镜像。 Docker 客户端和服务端可以运行在一台机器上,也可以通过 RESTful 、 stock 或网络接口与远程 Docker 服务端进行通信。
Docker 运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker 会从镜像仓库下载该镜像。
这张图展示了 Docker 客户端、服务端和 Docker 仓库(即 Docker Hub 和 Docker Cloud ),默认情况下Docker 会在 Docker 中央仓库寻找镜像文件,这种利用仓库管理镜像的设计理念类似于 Git ,当然这个仓库是可以通过修改配置来指定的,甚至我们可以创建我们自己的私有仓库。
1. Docker的简单运用—ubuntu:18.04
1) 获取镜像
之前提到过,Docker Hub 上有大量的高质量的镜像可以用,这里我们就说一下怎么获取这些镜像。
从 Docker 镜像仓库获取镜像的命令是 docker pull。其命令格式为:
docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]
具体的选项可以通过 docker pull –help 命令看到,这里我们说一下镜像名称的格式。
- Docker 镜像仓库地址:地址的格式一般是
<域名/IP>[:端口号]
。默认地址是 Docker Hub。 - 仓库名:如之前所说,这里的仓库名是两段式名称,即
<用户名>/<软件名>
。对于 Docker Hub,如果不给出用户名,则默认为library
,也就是官方镜像。
直接运行下面的命令,将名为 ubuntu:18.04
的 image 文件从仓库抓取到本地
docker pull ubuntu:18.04
上面的命令中没有给出 Docker 镜像仓库地址,因此将会从 Docker Hub 获取镜像。而镜像名称是 ubuntu:18.04
,因此将会获取官方镜像 library/ubuntu
仓库中标签为 18.04
的镜像。
运行结果如下
➜ docker pull ubuntu:18.04
18.04: Pulling from library/ubuntu
23884877105a: Pull complete
bc38caa0f5b9: Pull complete
2910811b6c42: Pull complete
36505266dcc6: Pull complete
Digest: sha256:3235326357dfb65f1781dbc4df3b834546d8bf914e82cce58e6e6b676e23ce8f
Status: Downloaded newer image for ubuntu:18.04
docker.io/library/ubuntu:18.04
从下载过程中可以看到我们之前提及的分层存储的概念,镜像是由多层存储所构成。下载也是一层层的去下载,并非单一文件。下载过程中给出了每一层的 ID 的前 12 位。并且下载结束后,给出该镜像完整的 sha256 的摘要,以确保下载一致性。
2) 列出镜像
要想列出已经下载下来的镜像,可以使用 docker image ls 命令。
docker image ls
运行结果如下
➜ docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 18.04 c3c304cb4f22 2 weeks ago 64.2MB
hello-world latest bf756fb1ae65 4 months ago 13.3kB
列表包含了 仓库名
、标签
、镜像 ID
、创建时间
以及 所占用的空间
。
其中仓库名、标签在之前的基础概念章节已经介绍过了。镜像 ID
则是镜像的唯一标识,一个镜像可以对应多个 标签。因此,在上面的例子中,我们可以看到 ubuntu:18.04 和 ubuntu:latest 拥有相同的 ID,因为它们对应的是同一个镜像。
3) 运行镜像
有了镜像后,我们就能够以这个镜像为基础启动并运行一个容器。以上面的 ubuntu:18.04 为例,如果我们打算启动里面的 bash 并且进行交互式操作的话,可以执行下面的命令。
执行以下命令 运行镜像
docker run -it --rm ubuntu:18.04 bash
运行结果如下
➜ docker run -it --rm ubuntu:18.04 bash
root@3a5e608746e1:/# cat /etc/os-release
NAME="Ubuntu"
VERSION="18.04.4 LTS (Bionic Beaver)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 18.04.4 LTS"
VERSION_ID="18.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=bionic
UBUNTU_CODENAME=bionic
root@3a5e608746e1:/#
docker run
就是运行容器的命令,我们这里简要的说明一下上面用到的参数。
- -it:这是两个参数,一个是 -i:交互式操作,一个是 -t 终端。我们这里打算进入 bash 执行一些命令并查看返回结果,因此我们需要交互式终端。
- –rm:这个参数是说容器退出后随之将其删除。默认情况下,为了排障需求,退出的容器并不会立即删除,除非手动 docker rm。我们这里只是随便执行个命令,看看结果,不需要排障和保留结果,因此使用 –rm 可以避免浪费空间。
- ubuntu:18.04:这是指用 ubuntu:18.04 镜像为基础来启动容器。
- bash:放在镜像名后的是 命令,这里我们希望有个交互式 Shell,因此用的是 bash。
进入容器后,我们可以在 Shell 下操作,执行任何所需的命令。这里,我们执行了 cat /etc/os-release
,这是 Linux 常用的查看当前系统版本的命令,从返回的结果可以看到容器内是 Ubuntu 18.04.1 LTS 系统。
最后我们通过 exit 退出了这个容器。
4) 删除本地镜像
如果要删除本地的镜像,可以使用 docker image rm 命令,其格式为:
docker image rm [选项] <镜像1> [<镜像2> ...]
用 ID、镜像名、摘要删除镜像
其中,<镜像>
可以是 镜像短 ID
、镜像长 ID
、镜像名
或者 镜像摘要
。
比如我们有下列镜像:
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu 18.04 c3c304cb4f22 2 weeks ago 64.2MB
hello-world latest bf756fb1ae65 4 months ago 13.3kB
我们可以用镜像的完整 ID,也称为 长 ID
,来删除镜像。使用脚本的时候可能会用长 ID
,但是人工输入就太累了,所以更多的时候是用 短 ID
来删除镜像。docker image ls
默认列出的就已经是短 ID 了,一般取前3个字符以上,只要足够区分于别的镜像就可以了。
比如这里,如果我们要删除 ubuntu 镜像,可以执行:
➜ docker image rm c3c304cb4f22
Untagged: ubuntu:18.04
Untagged: ubuntu@sha256:3235326357dfb65f1781dbc4df3b834546d8bf914e82cce58e6e6b676e23ce8f
Deleted: sha256:c3c304cb4f22ceb8a6fcc29a0cd6d3e4383ba9eb9b5fb552f87de7c0ba99edac
Deleted: sha256:82751c4dcc36265daceeee0abd938806b591eb66700863186377348c96e8aead
Deleted: sha256:24b16cac34768092d57cdb429a12de6c9ee870a3724d70098a189ae0ac344c42
Deleted: sha256:b1daff3b271fede2bec31812c398e28952f792935f608e467271cdfaccab7de2
Deleted: sha256:b7f7d2967507ba709dbd1dd0426a5b0cdbe1ff936c131f8958c8d0f910eea19e
我们也可以用镜像名,也就是 <仓库名>:<标签>,来删除镜像。
➜ docker image rm ubuntu:18.04
Untagged: ubuntu:18.04
Untagged: ubuntu@sha256:3235326357dfb65f1781dbc4df3b834546d8bf914e82cce58e6e6b676e23ce8f
Deleted: sha256:c3c304cb4f22ceb8a6fcc29a0cd6d3e4383ba9eb9b5fb552f87de7c0ba99edac
Deleted: sha256:82751c4dcc36265daceeee0abd938806b591eb66700863186377348c96e8aead
Deleted: sha256:24b16cac34768092d57cdb429a12de6c9ee870a3724d70098a189ae0ac344c42
Deleted: sha256:b1daff3b271fede2bec31812c398e28952f792935f608e467271cdfaccab7de2
Deleted: sha256:b7f7d2967507ba709dbd1dd0426a5b0cdbe1ff936c131f8958c8d0f910eea19e
当然,更精确的是使用 镜像摘要 删除镜像。
➜ docker image ls --digests
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
hello-world latest sha256:6a65f928fb91fcfbc963f7aa6d57c8eeb426ad9a20c7ee045538ef34847f44f1 bf756fb1ae65 4 months ago 13.3kB
➜ docker image rm hello-world:latest@sha256:6a65f928fb91fcfbc963f7aa6d57c8eeb426ad9a20c7ee045538ef34847f44f1
Untagged: hello-world:latest@sha256:6a65f928fb91fcfbc963f7aa6d57c8eeb426ad9a20c7ee045538ef34847f44f1
四、操作容器
1. 查看容器
我们要想知道当前有哪些容器在运行,我们可以用如下命令:
docker ps -a -a
是查看当前所有正在运行的容器
docker ps -a
运行结果如下
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
45448b240593 hello-world "/hello" 9 minutes ago Exited (0) 9 minutes ago keen_pasteur
2. 启动容器
启动容器有两种方式,一种是基于镜像新建一个容器并启动,另外一个是将在终止状态(stopped)的容器重新启动。
2.1 新建并启动
所需要的命令主要为 docker run。
例如,下面的命令输出一个 “Hello World”,之后终止容器。
➜ docker run ubuntu:18.04 /bin/echo 'Hello world'
Hello world
这跟在本地直接执行 /bin/echo ‘hello world’ 几乎感觉不出任何区别。
下面的命令则启动一个 bash 终端,允许用户进行交互。
➜ docker run -t -i ubuntu:18.04 /bin/bash
root@c0a95c27382a:/#
其中,-t 选项让Docker分配一个伪终端(pseudo-tty)并绑定到容器的标准输入上, -i 则让容器的标准输入保持打开。
在交互模式下,用户可以通过所创建的终端来输入命令,例如
➜ docker run -t -i ubuntu:18.04 /bin/bash
root@c0a95c27382a:/# pwd
/
root@c0a95c27382a:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@c0a95c27382a:/#
当利用 docker run 来创建容器时,Docker 在后台运行的标准操作包括:
- 检查本地是否存在指定的镜像,不存在就从公有仓库下载
- 利用镜像创建并启动一个容器
- 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层
- 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
- 从地址池配置一个 ip 地址给容器
- 执行用户指定的应用程序
- 执行完毕后容器被终止
2.2 启动已终止容器
可以利用 docker container start 命令,直接将一个已经终止的容器启动运行。
容器的核心为所执行的应用程序,所需要的资源都是应用程序运行所必需的。除此之外,并没有其它的资源。可以在伪终端中利用 ps 或 top 来查看进程信息。
root@b0f1a106dcdf:/# ps
PID TTY TIME CMD
1 pts/0 00:00:00 bash
11 pts/0 00:00:00 ps
root@b0f1a106dcdf:/#
可见,容器中仅运行了指定的 bash 应用。这种特点使得 Docker 对资源的利用率极高,是货真价实的轻量级虚拟化。
3. 守护态运行
更多的时候,需要让 Docker 在后台运行而不是直接把执行命令的结果输出在当前宿主机下。此时,可以通过添加 -d 参数来实现。
➜ docker run ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
hello world
hello world
hello world
hello world
容器会把输出的结果 (STDOUT) 打印到宿主机上面
如果使用了 -d 参数运行容器。
➜ docker run -d ubuntu:18.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
f8849adf1f3ce58981c95142abc65729da41b3b5a4e89edb2d0a8c5ac967f171
~ via ⬢ v12.16.3
➜
此时容器会在后台运行并不会把输出的结果 (STDOUT) 打印到宿主机上面(输出结果可以用 docker logs 查看)。
注: 容器是否会长久运行,是和 docker run 指定的命令有关,和 -d 参数无关。
使用 -d 参数启动后会返回一个唯一的 id,也可以通过 docker container ls 命令来查看容器信息。
➜ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f8849adf1f3c ubuntu:18.04 "/bin/sh -c 'while t…" About a minute ago Up About a minute funny_matsumoto
c0a95c27382a ubuntu:18.04 "/bin/bash" 9 minutes ago Up 4 minutes musing_margulis
要获取容器的输出信息,可以通过 docker container logs 命令。
➜ docker container logs f8849adf1f3c
hello world
hello world
hello world
hello world
hello world
hello world
...
4. 终止容器
可以使用 docker container stop 来终止一个运行中的容器。
此外,当 Docker 容器中指定的应用终结时,容器也自动终止。
例如对于上一章节中只启动了一个终端的容器,用户通过 exit 命令或 Ctrl+d 来退出终端时,所创建的容器立刻终止。
终止状态的容器可以用 docker container ls -a 命令看到。例如
➜ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f8849adf1f3c ubuntu:18.04 "/bin/sh -c 'while t…" 4 minutes ago Up 4 minutes funny_matsumoto
208d3180e5ca ubuntu:18.04 "/bin/sh -c 'while t…" 5 minutes ago Exited (0) 5 minutes ago hardcore_dubinsky
b0f1a106dcdf ubuntu:18.04 "/bin/bash" 7 minutes ago Exited (0) 5 minutes ago naughty_lumiere
c0a95c27382a ubuntu:18.04 "/bin/bash" 12 minutes ago Up 8 minutes musing_margulis
1b10a73accd8 ubuntu:18.04 "/bin/echo 'Hello wo…" 13 minutes ago Exited (0) 8 minutes ago eager_napier
37c02b640650 ubuntu:18.04 "/bin/echo 'Hello wo…" 13 minutes ago Exited (0) 13 minutes ago confident_leavitt
处于终止状态的容器,可以通过 docker container start 命令来重新启动。
此外,docker container restart 命令会将一个运行态的容器终止,然后再重新启动它。
5. 进入容器
在使用 -d 参数时,容器启动后会进入后台。
某些时候需要进入容器进行操作,包括使用 docker attach 命令或 docker exec 命令,推荐大家使用 docker exec 命令,原因会在下面说明。
5.1 attach 命令
下面示例如何使用 docker attach 命令。
➜ docker run -dit ubuntu
dd8d472bb3b30ba6ab4a230d5734a97c61d0205d8d09ac080c88d3ace0a2fffd
~ via ⬢ v12.16.3
➜ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dd8d472bb3b3 ubuntu "/bin/bash" 7 seconds ago Up 6 seconds optimistic_pasteur
~ via ⬢ v12.16.3
➜ docker attach dd8d472bb3b3
root@dd8d472bb3b3:/#
注意: 如果从这个 stdin 中 exit,会导致容器的停止。
5.2 exec 命令
docker exec 后边可以跟多个参数,这里主要说明 -i -t 参数。
只用 -i 参数时,由于没有分配伪终端,界面没有我们熟悉的 Linux 命令提示符,但命令执行结果仍然可以返回。
当 -i -t 参数一起使用时,则可以看到我们熟悉的 Linux 命令提示符。
➜ docker run -dit ubuntu
c9ca08210d46abaee7228c4541f164908063cbd681c4aa541fe4e060da532d45
~ via ⬢ v12.16.3
➜ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c9ca08210d46 ubuntu "/bin/bash" 6 seconds ago Up 6 seconds pedantic_albattani
~ via ⬢ v12.16.3
➜ docker exec -i c9ca bash
ls
bin
boot
dev
etc
home
lib
lib32
lib64
libx32
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
^C
~ via ⬢ v12.16.3 took 41s
➜ docker exec -it c9ca bash
root@c9ca08210d46:/#
如果从这个 stdin 中 exit,不会导致容器的停止。这就是为什么推荐大家使用 docker exec 的原因。
6. 容器的导出和导入
6.1 导出容器
如果要导出本地某个容器,可以使用 docker export 命令。
➜ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c9ca08210d46 ubuntu "/bin/bash" 5 minutes ago Up 5 minutes pedantic_albattani
dd8d472bb3b3 ubuntu "/bin/bash" 8 minutes ago Exited (127) 6 minutes ago optimistic_pasteur
208d3180e5ca ubuntu:18.04 "/bin/sh -c 'while t…" 17 minutes ago Exited (0) 17 minutes ago hardcore_dubinsky
b0f1a106dcdf ubuntu:18.04 "/bin/bash" 19 minutes ago Exited (0) 17 minutes ago naughty_lumiere
1b10a73accd8 ubuntu:18.04 "/bin/echo 'Hello wo…" 26 minutes ago Exited (0) 20 minutes ago eager_napier
37c02b640650 ubuntu:18.04 "/bin/echo 'Hello wo…" 26 minutes ago Exited (0) 26 minutes ago confident_leavitt
~ via ⬢ v12.16.3
➜ docker export 37c02b640650 > ubuntu.tar
这样将导出容器快照到本地文件。
6.1 导入容器
可以使用 docker import 从容器快照文件中再导入为镜像,例如
➜ cat ubuntu.tar | docker import - test/ubuntu:v1.0
sha256:d21f5263937d78928f78d3c76268783e930a989255fbc5db09453deabd45c537
~ via ⬢ v12.16.3 took 2s
➜ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
test/ubuntu v1.0 d21f5263937d 9 seconds ago 64.2MB
ubuntu latest 1d622ef86b13 2 weeks ago 73.9MB
ubuntu 18.04 c3c304cb4f22 2 weeks ago 64.2MB
hello-world latest bf756fb1ae65 4 months ago 13.3kB
此外,也可以通过指定 URL 或者某个目录来导入,例如
docker import http://example.com/exampleimage.tgz example/imagerepo
注:用户既可以使用 docker load 来导入镜像存储文件到本地镜像库,也可以使用 docker import 来导入一个容器快照到本地镜像库。这两者的区别在于容器快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也要大。此外,从容器快照文件导入时可以重新指定标签等元数据信息。
6. 删除容器
6.1 删除容器
可以使用 docker container rm 来删除一个处于终止状态的容器。例如
➜ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c9ca08210d46 ubuntu "/bin/bash" 10 minutes ago Up 10 minutes pedantic_albattani
dd8d472bb3b3 ubuntu "/bin/bash" 12 minutes ago Exited (127) 10 minutes ago optimistic_pasteur
208d3180e5ca ubuntu:18.04 "/bin/sh -c 'while t…" 22 minutes ago Exited (0) 21 minutes ago hardcore_dubinsky
b0f1a106dcdf ubuntu:18.04 "/bin/bash" 24 minutes ago Exited (0) 22 minutes ago naughty_lumiere
1b10a73accd8 ubuntu:18.04 "/bin/echo 'Hello wo…" 30 minutes ago Exited (0) 24 minutes ago eager_napier
37c02b640650 ubuntu:18.04 "/bin/echo 'Hello wo…" 30 minutes ago Exited (0) 30 minutes ago confident_leavitt
~ via ⬢ v12.16.3
➜ docker container rm 37c02b640650
37c02b640650
如果要删除一个运行中的容器,可以添加 -f 参数。Docker 会发送 SIGKILL 信号给容器。
6.2 清理所有处于终止状态的容器
用 docker container ls -a 命令可以查看所有已经创建的包括终止状态的容器,如果数量太多要一个个删除可能会很麻烦,用下面的命令可以清理掉所有处于终止状态的容器。
➜ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c9ca08210d46 ubuntu "/bin/bash" 12 minutes ago Up 12 minutes pedantic_albattani
dd8d472bb3b3 ubuntu "/bin/bash" 14 minutes ago Exited (127) 12 minutes ago optimistic_pasteur
208d3180e5ca ubuntu:18.04 "/bin/sh -c 'while t…" 23 minutes ago Exited (0) 23 minutes ago hardcore_dubinsky
b0f1a106dcdf ubuntu:18.04 "/bin/bash" 25 minutes ago Exited (0) 23 minutes ago naughty_lumiere
1b10a73accd8 ubuntu:18.04 "/bin/echo 'Hello wo…" 32 minutes ago Exited (0) 26 minutes ago eager_napier
~ via ⬢ v12.16.3
➜ docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
dd8d472bb3b30ba6ab4a230d5734a97c61d0205d8d09ac080c88d3ace0a2fffd
208d3180e5cac70cff44d499951138c968f15921d6e1fcdf1756f8d3c74e890f
b0f1a106dcdf1773985fb601f2292683ed825d483675e695eb2cebd9c26b6e4e
1b10a73accd84fc078433165ce7fa7527509bd3d2c1c2a33172bc64b98b41944
Total reclaimed space: 74B
~ via ⬢ v12.16.3 took 3s
➜ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c9ca08210d46 ubuntu "/bin/bash" 12 minutes ago Up 12 minutes pedantic_albattani