第4章 Docker容器
4.1 容器基础
4.1.1 容器启动流程
通过 docker run 命令可以启动运行一个容器。该命令在执行时首先会在本地查找指定的镜像,如果找到了,则直接启动,否则会到镜像中心查找。如果镜像中心存在该镜像,则会下载到本地并启动,如果镜像中心也没有,则直接报错。

如果再与多架构镜像原理相整合,则就形成了完整的容器启动流程。

4.1.2 容器运行本质
Docker 容器存在的意义就是为了运行容器中的应用,对外提供服务,所以启动容器的目的就是启动运行该容器中的应用。容器中的应用运行完毕后,容器就会自动终止。所以,如果不想让容器启动后立即终止运行,则就需要使容器应用不能立即结束。通常采用的方式有两种,使应用处于与用户交互的状态或等待状态。
4.2 容器创建并启动命令
对于容器的运行,有两种运行模式:交互模式与分离模式。下面通过运行 ubuntu 与tomcat 来演示这两种运行模式的不同。
4.2.1 以交互模式运行 ubuntu
首先下载ubantu,然后再进行启动
shell
docker pull ubantu
docker run --name myubuntu -i -t ubuntu /bin/bash
命令解析
- name 自定义容器名称
- -i -t / -it 两个参数分别指定以交互模式运行容器,并且为容器分配一个伪终端
- 后面的/bin/bash 用于指定容器启动后需要运行的命令为/bin 下的 bash 命令,而该命令会启动一个 bash 终端

我们在这里运行了一个 ubuntu 系统的容器,并为其取名为 myubuntu。另外我们可以注意到,命令行前面提示部分内容发生了变化:原来显示的是[root@docker ~],而现在变为了root@f12fae5fd8ea:/# ,这个就是 docker 生成的伪客户端,而数字 f12fae5fd8ea 表示的是docker 容器的 ID。
此时就可以通过 Linux 命令对该 ubuntu 系统进行操作了。不过,由于容器中的该系统是一个精简的系统,有很多常用命令是没有安装的,所以如果要使用这些命令,就需要安装。
使用exit退出,退出后容器则也进行退出,容器本质为处理用户交互的状态或等待状态

4.2.2 以交互模式运行 tomcat
我们现在使用的都是8.5.49之前的版本,包含8.5.49,之后的版本webapps内容修改到其他目录(webapps.dist),需要修改回webapp才能正常访问
shell
docker run --name mytomcat8 -it tomcat:8.5.32 /bin/bash

通过 ls --l 命令可查看 tomcat 根目录下的文件。注意,不支持 ll 命令,查看运行容器,发现没有tomcat,这是因为bin/bash不会启动tomcat
下面也是以交互模式运行 tomcat 容器,不同的是,该命令后没有/bin/bash,此时会真正启动 tomcat。
shell
docker run --name tomcat8081 -it -p 8081:8080 tomcat:8.5.32

通过路径访问 192.168.138.129:8081,-p 代表端口映射,其中8081是宿主机端口,8080是容器内tomcat启动端口,且 tomcat 的日志输出占居了命令行。

4.2.3 以分离模式运行 tomcat
下面是以分离模式运行的 tomcat,返回的是容器 ID,其中-d 选项表示以分离模式(detached mode)运行容器,即命令在后台运行,命令的运行与宿主机的运行分离开来。
shell
docker run --name mytomcat03 -d -p 8083:8080 tomcat:8.5.32

使用docker ps 进行查看,发现三个服务都还在与运行状态

可以看到,已经启动了三个 tomcat 容器。且无论是 IPv4 还是 IPv6,端口映射关系都很明确。此时通过 window 系统中的浏览器访问 docker 主机中映射的三个 tomcat 端口号就可以访问到 tomcat。
通过该访问可以知道为什么要做端口映射的原因了:为了使相同的客户端主机可以访问同一宿主机上相同端口号的不同容器
如果使用大写的 -P,则是使用系统自动分配的端口号映射到容器内的自定义端口
shell
docker run --name mytomcat03 -d -P tomcat:8.5.32
4.2.4 以分离模式运行 **ubuntu **-d
该运行方式存在一个问题:容器使用命令启动了,但通过 docker ps 命令查看不到。再通过 docker ps --a 命令可以发现该容器,只不过其已经退出。docker ps 查看的就是 up状态的容器,由于其已经退出,所以 docker ps 查看不到。
shell
docker run -d ubuntu:latest

4.3 容器创建命令 create
docker create 命令仅创建容器但不启动,其用法与 docker run 非常相似。注意,其没有-d 选项。
shell
docker create --name mytom -p 8084:8080 tomcat:8.5.32

4.4 容器退出命令
退出容器指的是退出以交互模式运行的容器。分为两种退出方式:
4.4.1 退出并停止容器 exit
shell
docker run --name myubuntu01 -it ubuntu:latest
在容器命令行中再运行 exit 命令后,通过 docker ps --a 可以查看到该容器已经退出了。

4.4.2 退出不停止容器 Ctrl + P + Q
使用快捷键 Ctrl + P + Q 能够返回到了宿主机命令行。再通过 docker ps 可以查看到其是 UP 状态,说明容器退出了但并没有停止。

注:先按下 Ctrl + P,然后再按下 Q。
4.5 容器状态查看命令
4.5.1 查看所有正在运行的容器
docker ps 命令本身查看的是所有处于运行状态的容器信息。

4.5.2 查看所有容器 ps -a
docker ps --a 用于查看所有容器,无论是否处于运行状态

4.5.3 查看所有容器的 ID -q
docker ps -q
docker ps -a -q

4.5.4 查看最后创建的容器
docker ps --l 用于查看最后创建的容器,无论该容器是否处于运行状态。
shell
docker ps -l

4.5.5 查看最后创建的 n 个容器
docker ps --n 3 用于查看最后创建的指定个数的容器,无论该容器是否处于运行状态。
shell
docker ps -n 1

4.6 容器再进命令
当我们以分离模式运行了一个容器,或以交互模式运行了一个容器,但容器内部执行的命令占用了交互命令行,而此时我们又想进入到容器中对容器内部进行一些操作,此时就需要用到 exec/attach 命令了。
注意,它们只能对正在运行的容器进行操作
4.6.1 新建进程进入容器 exec
该命令也用于进入到了运行状态的容器中。对于该命令的测试,首先以分离模式运行 tomcat8 容器。此时想进入该 mytomcat 容器,就可以使用 exec 命令。
docker exec -i -t mytomcat01 /bin/bash

此时查看正在运行的容器,发现 mytomcat 容器并未退出。说明 exec 命令会创建一个新的独立于容器的进程,而 exit 命令仅用于结束该新建进程。同样,以交互模式运行 tomcat 容器,仍是无法使用命令行的,因为 tomcat 日志输出占用了命令行
4.6.2 外部操作容器 exec
前两种都是在进入到容器后才对容器进行操作的,我们也可以不进入容器直接对容器内部进行操作。例如仅想查看 tomcat 容器中工作目录中所包含的文件,直接在 exec 命令后紧跟要执行的命令即可直接看到其结果
shell
docker exec -i -t mytomcat01 ls -l

4.6.3 容器附加标准输入
对于该命令的测试,首先以交互方式运行一个 ubuntu 容器,然后使用 Ctrl + P + Q 命令退出但不停止容器。

然后使用 attach 命令进入容器命令行。此时,再使用 exit 命令退出容器。然后会发现容器也停止了。由于 exit 命令的作用是,结束当前进程,所以说明 **attach **命令并没有另外再创建新的进程,而是使用了容器进程,exit 命令退出了当前进程,也就退出了容器

4.6.4 容器附加标准输出
启动一个 tomcat 容器与其中的 tomcat,指定容器名称为 mytom。然后通过 docker attach命令则可看到如下场景:占用了命令行,且没有任何输出,即使通过浏览器访问该 tomcat也没有任何输出。此时的 mytom 容器已经附加了标准输出,只不过,其输出的是 tomcat 的启停日志信息。

通过 Ctrl + C 可结束 tomcat,此时可看到停止日志显示了出来。但由于此时的 tomcat已经停止,tomcat 容器已经退出,所以该 docker attach 命令也就随之结束了。

4.7 容器内进程查看命令 top
docker top 命令用于查看指定的正在运行的容器中正在运行的进程详情,这个详情包括当前这个进程正在运行的命令。当然,如果容器中运行的进程较多,也可以通过 grep 对结果进行过滤。
shell
docker top mytomcat01

4.8 容器日志查看命令
docker logs [容器]可以查看指定容器中应用的运行日志,无论该容器是运行还是停止状态
4.8.1 查看所有日志 logs
docker logs 查看的是所有容器中应用的运行日志。这个日志对于不同的容器来说,其日志内容是不同的。由 docker run 命令的[command]决定(如果没有则由 Dockerfile 中的 CMD指令决定)
对启动了 tomcat 的 tomcat 容器来说,这个日志是 tomcat 启停日志。

对于没有启动 tomcat 的 tomcat 容器来说,这个日志是/bin/bash 的运行历史记录。对于 ubuntu 容器来说,这个日志是/bin/bash 的运行历史记录。

4.8.2 查看最后的日志 -n
通过添加选项-n 或--tail 可以指定要显示的最后几条日志
shell
docker logs -n 5 mytomcat01

4.8.3 查看指定时间内的日志 --since
通过添加选项--since 可以指定要显示自从指定时间以来的日志。这个时间可以是一个绝对时间,也可以是一个相对时长。
-
下面使用的是绝对时间:显示自从 2024 年 7 月 8 日后产生日志的最后 3 条
shelldocker logs --since="2024-07-08" --tail=3 mytomcat01
-
下面使用的是相对时长:显示自从 50 分钟之前产生日志中的最后 3 条。其中 m 表示分,可以使用 s 表示秒,h 表示小时
shelldocker logs --since="50m" --tail=3 mytomcat01
4.8.4 查看指定时间外的日志 --until
通过添加选项--until 可以指定要显示截止到指定时间之前的日志。这个时间可以是一个绝对时间,也可以是一个相对时长。下面使用的是绝对时间:显示截止到 2024 年 7 月 9 日前产生日志的最后 3 条。
shell
docker logs --until="2024-07-09" --tail=3 mytomcat01

下面使用的是相对时长:显示截止到 20 分钟之前产生日志中的最后 3 条。
shell
docker logs --until=20m --tail=3 mytomcat01

4.8.5 查看日志时间戳 -t
如果要查看某日志的详细时间戳,可以使用-t 选项。下面的命令查看的是最后 3 条日志的时间戳,并与不添加-t 的输出进行了对比。

4.8.6 查看动态日志 tail=3
shell
docker logs -f --tail=3 mytomcat01
通过添加选项-f 可以查看运行中容器的动态日志,以下命令用于查看 mytomcat 的最后三条动态日志。其会占用命令行,一直等待日志的输出。

4.9 容器启停命令
4.9.1 启动 start
通过 docker start 命令可以启动已经停止的指定容器,这个容器可以通过容器名称指定,也可以通过容器 ID 指定
docker start mytomcat01

4.9.2 重启 restart
通过 docker restart 命令可以重启处于运行状态的指定容器。
shell
docker restart mytomcat03

4.9.3 优雅停止 stop
通过 docker stop 命令可以优雅停止指定容器。所谓优雅停止是指,若当前容器正在被其它进程访问,则在访问结束后再停止。
shell
docker stop mytomcat03

4.9.4 强制停止 kill
通过 docker kill 命令可以强制停止指定容器。所谓强制停止是指,无论容器当前是否被其它进程访问都直接停止。
shell
docker kill mytomcat03

4.9.5 **停止所有容器 **ps -qa
无论是 docker kill 还是 docker stop,都可使用下面方式停止所有容器。因为这两个命令的参数都可以是容器 ID。

4.9.6 暂停 pause
通过 docker pause 命令可以暂停容器对外提供服务。本身容器是没有被影响的

4.9.7 解除暂停 unpause
通过 docker unpause 命令可解除容器的暂停服务状态
shell
docker unpause mytomcat01

4.10 容器删除命令
4.10.1 正常删除 rm
docker rm 命令在默认情况下,要删除的容器必须是已经停止的容器。当然,这个容器可以使用容器名或容器 ID 指定。
shell
docker rm ubuntu02

4.10.2 强制删除 rm -f
在 docker rm 命令中添加-f 可实现强制删除容器。即,无论容器是否停止都会删除。
shell
docker rm -f ubuntu01

4.10.3 删除所有容器
docker rm -f $(docker ps -aq)

4.11 文件传递 docker cp
docker cp 命令可以完成容器与宿主机中文件/目录的相互复制,无论该容器是否处于运行状态。
4.11.1 容器文件复制宿主机 cp
将docker 中的export.tar文件拷贝到宿主机的/usr/local目录中
shell
docker cp mytomcat01:/usr/local/tomcat/export.tar /usr/local

4.11.2 将宿主机文件复制到容器中
以下命令用于将宿主机中当前目录下的 export.tar 文件复制到 mytomcat01 容器的/usr/local/tomcat 目录中。若要查看容器中是否已经存在了 export.tar 文件,需要首先启动该容器。
shell
docker cp export.tar mytomcat01:/usr/local/tomcat

4.11.3 不支持容器间的 cp
docker cp 命令不支持容器间的文件传递。
shell
docker cp mytomcat01:/usr/local/tomcat/export.tar mytomcat02:/usr

4.12 提交容器为镜像
通过 docker commit 命令可以将一个容器文件系统的当前快照生成为一个新的镜像。
需求:这里要在一个 Ubuntu 容器或 Centos 容器中安装 net-tools工具包。为了方便演示,这里选择 CentOS 容器,直接使用 yum 安装。当然,如果使用 Ubuntu 容器也可以,要么直接使用 apt-get 安装 net-tools,要么先安装 yum 后再安装 net-tools。
首先下载centos7
shell
docker pull centos:7

4.12.1 修改容器层
首先创建并启动一个容器,例如 centos:7 镜像的容器。然后发现该容器中是没有安装ifconfig 命令的
shell
docker run --name centos01 -it centos:7

使用ifconfig查看ip发现无此命令,安装 net-tools 网络工具命令包。如果下载提示无法解析路径,则可以先配置yum源
shell
# 1、备份备份官方的原yum源的配置
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
# 2、下载Centos-7.repo文件
# wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
# 注意:部分小伙伴可能没有安装wget,需要先安装wget,或者用下面的命令下载repo文件
curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
# 执行下载工具
yum install -y net-tools


4.12.2 生成镜像docker commit
下面要将已经安装了 ifconfig 命令的容器生成为一个镜像,以方便后期自己或他人使用
shell
docker commit -a "lxc<lixuchun@git.com.cn>" -m "add net-tools" centos01 centos7:net-tools
这里指定生成的镜像的<repository>为 centos7,<tag>为 net-tools。

4.12.3 使用新镜像
下面是使用新生成的镜像创建并启动一个容器,发现其中的 ifconfig 命令是可以使用的。
shell
docker run --name mycentos7 -it centos7:net-tools

4.12.4 生成悬虚镜像
悬虚镜像,即没有<repository>与<tag>的镜像。悬虚镜像一般都是由于某些失误操作或其它一些操作而生成的副产物,一般是要被清除掉的。如果非要使用悬虚镜像,那只能通过其 ImageID 来使用了。
下面要将已经安装了 ifconfig 命令的容器生成为一个悬虚镜像,即没有指定<repository>与<tag>

4.13 导入/导出容器
在上一章中学习了 docker save 与 docker load 命令,分别用于导出/导入镜像。这里要学习的 docker export 与 docker import 命令分别用于导出/导入容器。
4.13.1 导出容器 export
docker export 命令用于将一个容器的文件系统导出为 tar 文件。
例如,下面的命令是将tomcat:8.5.32 镜像的容器 tomcat01 导出到当前/root 目录的 tomcat8.tar 文件中
shell
docker export -o tomcat8.tar tomcat01

4.13.2 导入容器 import
docker import 命令用于根据指定的 tar 文件构建新的镜像。下面的命令是将当前目录下的 tomcat8.tar 导出为镜像 mytomcat:1.0。
shell
docker import tomcat8.tar tomcat02:1.0

4.13.3 与 save/load 命令的对比
-
export 与 save
export 作用于容器,save 作用于镜像,但它们导出的结果都为 tar 文件
export 一次只能对一个容器进行导出,save 一次可以对多个镜像进行导出
export 只是对当前容器的文件系统快照进行导出,其会丢弃原镜像的所有历史记录与元数据信息,save 则是保存了原镜像的完整记录
-
import 与 load
import 导入的是容器包,load 加载的是镜像包,但最终都会恢复为镜像
import 恢复的镜像只包含当前镜像一层,load 恢复的镜像与原镜像的分层是完全相同的
import 恢复的镜像就是新构建的镜像,与原镜像的 ImageID 不同;load 恢复的镜像与原镜像是同一个镜像,即 ImageID 相同
import 可以为导入的镜像指定<repository>与<tag>,load 加载的镜像不能指定<repository>与<tag>,与原镜像的相同
4.13.4 与 docker commit 的对比
- 相同点:docker export + docker import 会将一个容器变为一个镜像,docker commit 也可以将一个容器变一个镜像。
- 不同点:docker export + docker import 恢复的镜像仅包含原容器生成的一层分层,docker commit 生成的镜像中包含容器的原镜像的所有分层信息。
4.14 docker system 命令集
docker system 是一个命令集,其有四个子命令
sh
docker system --help

4.14.1 docker 磁盘占用数据 df
docker system df 用于查看 docker 各部分占用情况。
shell
docker system df
# 如果要获取更为详细的占用情况,可添加-v 选项。
docker system df -v

4.14.2 docker发生过的事件 events
docker system events 命令等价于 docker events 命令,可查看指定日间之内(--since)或之外(--until)在 docker 上所发生的所有事件。这些事件包含运行过的命令有 docker 内部执行的一些操作。
shell
docker system events --since="2024-07-09"

4.14.3 查看 docker 详情 info
docker system info命令等价于docker info,用于查看当前docker的详情。包括dockerClient与 docker Server 详情。其中 docker server 包含镜像、容器情况,docker 所在系统的软硬件情况等
shell
docker info

4.14.4 删除docker中无用数据 prune
docker system prune 命令用于删除 docker 中的无用数据,这些无用数据包含已经停止的容器、没有任何连接容器的网络、悬空镜像,及悬空镜像的构建缓存。
shell
docker system prune
