Docker
Docker 是一个开源的应用容器引擎,它通过将应用程序及其依赖项打包到轻量级、可移植的容器中,实现了软件开发、交付和运行环境的一致性。Docker 提供了一种标准化的方式来构建、分发和运行应用程序,极大地简化了 DevOps 流程,促进了微服务架构的发展。以下是对 Docker 的详细说明:
容器化概念:
- 容器:Docker 容器是一种轻量级、独立的运行时环境,其中包含了应用程序及其所有依赖(如库、配置文件、环境变量等)。容器与宿主机共享内核,但每个容器之间相互隔离,各自拥有独立的文件系统、网络空间和进程视图,确保了应用程序的隔离性和可移植性。
- 镜像:Docker 镜像是创建容器的模板,它是一个只读的、包含应用程序及其依赖的文件系统层次结构。镜像通过分层存储和版本控制,实现了高效的空间利用和快速的分发共享。
Docker 架构:
- Docker 客户端与服务器:Docker 采用客户端-服务器(C/S)架构。用户通过 Docker 客户端(命令行工具或 API)发送请求到 Docker 服务器(Docker Daemon),服务器负责执行具体的容器管理操作。
- Registry(仓库):Docker Registry 是存储和分发 Docker 镜像的仓库,如 Docker Hub、GitHub Container Registry 等。用户可以上传自己的镜像到仓库,或者从仓库中拉取所需镜像。
Docker 工作流程:
- 构建镜像:使用
Dockerfile
文件定义应用程序的构建过程,包括基础镜像、依赖安装、文件复制、环境变量设置、启动命令等步骤。通过docker build
命令构建出一个新的 Docker 镜像。 - 运行容器:使用
docker run
命令基于镜像启动一个容器。可以指定容器运行时的各种参数,如端口映射、环境变量、卷挂载等。 - 管理容器:通过
docker start
、docker stop
、docker restart
、docker rm
等命令对容器进行启动、停止、重启、删除等操作。 - 网络与存储管理:Docker 提供了网络驱动(如桥接、overlay)来管理和配置容器间的网络通信。同时,支持使用卷(volume)和绑定挂载(bind mount)实现容器与宿主机或其他容器之间的数据持久化和共享。
- 构建镜像:使用
优势与应用场景:
- 环境一致性:Docker 保证了应用程序在开发、测试、生产环境的一致性,消除了“在我机器上能运行”的问题。
- 敏捷开发与部署:开发者可以快速构建、测试和部署容器化的应用程序,加速迭代周期。
- 资源利用率高:由于容器共享宿主机内核,相比于虚拟机,容器更加轻量级,启动速度快,资源利用率更高。
- 微服务架构支持:Docker 与 Kubernetes 等容器编排工具结合,有力地支撑了微服务架构的实施,便于服务的水平扩展、故障恢复和自动化运维。
总之,Docker 通过提供标准化的容器化解决方案,极大地提升了软件开发、交付和运维的效率与灵活性,已成为现代云原生技术栈中的关键组件。
Docker 数据存储在其他盘上
Docker 默认会把镜像、容器和其他数据保存在系统盘上。如果系统盘空间有限,想要将 Docker 数据存储在其他盘上,需要配置 Docker 的数据目录。以下是如何在 Linux 系统上更改 Docker 存储目录的一般步骤:
1. 停止 Docker 服务:
sudo systemctl stop docker
2. 找到 Docker 的默认数据目录(通常是 /var/lib/docker),并将该目录移到想要的新位置。假设想移到 /new/path/docker,可以使用如下命令:
sudo mv /var/lib/docker /new/path/docker
3. 配置 Docker 的 daemon.json 文件以指定新的数据目录。如果 /etc/docker/daemon.json 文件不存在,请创建它。如果已存在,请编辑它:
sudo nano /etc/docker/daemon.json
在该文件中添加或修改以下内容:
{
"data-root": "/new/path/docker"
}
4. 重启 Docker 服务:
sudo systemctl start docker
确保具备在新盘上写入的权限,并且给 Docker 设置的新路径有足够的空间。
请注意,更改 Docker 数据目录可能带来一些风险,例如数据丢失、权限问题或服务中断。务必在更改操作前备份关键数据。如果在共享主机或有稳定性要求的生产环境中操作,可以先在测试环境中验证步骤。如果是在 Windows 或者 macOS 上,Docker 设置提供了更改数据存储位置的选项,可以通过 Docker Desktop 应用进行配置。
清理未使用的镜像
在使用Docker时,当构建镜像(docker build)并且没有给这些新构建的镜像指定一个标签(tag),这些未标记的镜像将会显示为`<none>`。它们通常是在构建过程中创建的中间层,或者是之前标记的镜像在更新后留下的旧层。
如果曾经给一个镜像添加了标签,然后构建了一个新版本的镜像并再次使用了同样的标签,那个原先的镜像会丢失其标签并被显示为`<none>`。这些无标签的镜像和悬空镜像(dangling images)占据磁盘空间,但是通常不会被使用。
要删除所有悬空的、无标签的镜像,可以使用下面的Docker命令:
docker rmi $(docker images -f "dangling=true" -q)
此命令会找出所有带有`dangling=true`标记的镜像,即无标签的镜像,然后使用`docker rmi`删除它们。`-q`选项告诉Docker只返回镜像的ID,这正是`docker rmi`命令需要的。
如果想清理所有无用的镜像,包括未引用且未标记的镜像以及构建缓存,可以使用以下命令:
docker system prune
该命令会提示你确认,在继续之前确保不会误删还需要的镜像。另外,添加`-a`选项可以清理所有未使用的镜像,而不只是悬空的。
docker system prune -a
进行这些操作前,确保你不会删除任何重要的镜像。这些操作不会清除任何正在使用中或标记的镜像。在执行任何删除操作之前,最好是确认一下Docker环境,并明确哪些镜像是可以安全删除的。
在 Docker 中,`<none>` 标签在仓库名(REPOSITORY)和标签(TAG)列中表示这些是 “悬空镜像”(dangling images)。悬空镜像是指原本由更高一级的镜像生成,随后更高一级的镜像被更新而不再使用当前的层。这通常发生在构建新版本的镜像时,但没有重用所有层。
通常情况下,`docker system prune` 命令应该能够清理不再使用的悬空镜像,但如果镜像是被某个容器所使用,或者被标记为需要保留,那它们将不会被删除。
如果 docker system prune 没有工作,可能是因为这些悬空镜像有特定的关联或者标记。可以尝试以下命令来清理未使用的镜像:
1. 强制删除单个悬空镜像:
sudo docker rmi a3dcb3e6e0f0
在这里,替换 a3dcb3e6e0f0 为想要删除的悬空镜像的 IMAGE ID。
2. 批量删除所有悬空镜像:
sudo docker rmi $(sudo docker images -f "dangling=true" -q)
这个命令会查找所有悬空镜像的 IMAGE ID 并删除它们。
如果认为这些镜像被只是停止而不是删除的容器所使用,确保没有任何正在运行或停止的容器依赖于这些镜像。要删除未使用的容器和所有悬空镜像以及未使用的网络和卷,请执行:
sudo docker system prune -a --volumes
请注意,这将删除未被任何容器使用的所有 Docker 镜像和卷,包括悬空的和未被标记的镜像,因此请仔细操作,确保您不会丢失必要的数据。
如果镜像仍然不被删除,检查是否有任何 Docker 服务或容器可能在使用这些镜像。您可以停止和删除正在使用这些镜像的服务或容器,然后再次尝试清理。
将文件从容器复制到宿主机
在 Docker 容器中,默认情况下是与宿主机隔离的。要将文件从容器复制到宿主机,可以使用 docker cp 命令。这个命令允许在宿主机和容器之间复制文件或者文件夹。
下面是一个如何使用 docker cp 命令的基本示例:
1. 首先,需要知道需要复制文件的容器的ID或名称。可以通过使用 docker ps 来打印当前运行的容器信息。
2. 假设要从名为`container_name`的容器中复制文件`/path/in/container/file.txt`到宿主机当前目录下:
docker cp container_name:/path/in/container/file.txt .
这行命令将会将`container_name`容器中的`/path/in/container/file.txt`文件复制到宿主机的当前工作目录下。
3. 如果想从宿主机复制文件到容器内部,命令的顺序则相反:
docker cp file.txt container_name:/path/in/container
这条命令会将宿主机当前目录下的`file.txt`复制到`container_name`容器的`/path/in/container`目录中。
请注意,对于正在运行的容器来说,直接修改容器内部的文件系统可能不被建议。这样的改动在容器重新启动后通常会丢失,除非将更改的路径挂载为一个持久化卷(Volume)。对于需要常规修改的文件,应该使用卷或绑定挂载,这样修改会被保存在宿主机上,并且容器重启后仍然可用。
查看 Docker 容器的名称
要查看 Docker 容器的名称,可以使用 Docker CLI 提供的 docker ps 命令。这个命令会列出当前所有运行中的容器。如果想查看所有容器(包括停止的容器),可以加上 -a 或 --all 参数。
运行以下命令以列出所有运行中的容器及其名字:
docker ps
或者,列出所有容器(无论它们的状态):
docker ps -a
这两个命令会打印容器的列表,包括容器 ID、创建时间、状态、端口等信息。在这个列表中,将会有一个 "NAMES" 列,展示了每个容器的名字。
如果想要获取容器名字的简洁列表,可以使用以下命令结合 --format 选项来定制输出:
docker ps --format "{{.Names}}"
这将会输出所有运行中容器的名字,每个名字占一行。
如果想要获取所有容器(包括非运行状态的)的名字列表,同样可以使用 --format 连同 -a 参数:
docker ps -a --format "{{.Names}}"
通过这些方法,可以快速地获取当前 Docker 容器的名称。
容器名称
每次使用 docker run 命令运行新的容器时,默认情况下 Docker 都会为该容器自动生成一个随机的名称,该名称是由两个单词组合而成,通常一个形容词和一个名词,例如 nostalgic_morse。这个名称在所有运行中的容器里必须是唯一的。
如果不想使用自动生成的名称,也可以在运行容器的时候使用 --name 选项来手动指定一个名称:
docker run --name my_container_name my_image
使用上述命令,Docker 会为新创建的容器命名为 my_container_name 而不是生成一个随机名称。如果尝试创建名为 my_container_name 的另一个容器,Docker 将会报错,因为容器名称必须是唯一的。
如果容器停止运行,可以重用已停止容器的名称来启动新的容器。 若要删除一个容器,可以使用 docker rm 命令。删除之后,它的名称可以被任何新的容器使用。
查看本地已经拉取(pull)的所有 Docker 镜像
要查看本地已经拉取(pull)的所有 Docker 镜像,可以使用 docker images 命令。这个命令会列出所有已经下载到本地机器的镜像,包括它们的仓库名称、标签、镜像ID、创建时间以及大小等信息。
打开终端或命令提示行,然后输入:
docker images
或者可以使用更加详细的版本:
docker image ls
执行以上任一命令,会看到类似下面格式的输出:
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 4e2eef94cd6b 2 weeks ago 64.2MB
nginx stable b175e7467d66 3 weeks ago 109MB
mysql 5.7 2073e0bcb60f 4 weeks ago 256MB
redis alpine 24f28824ad0e 5 weeks ago 32MB
这个示例展示了输出列表中可能包含的一些常用镜像,以及它们的标签、ID、创建时间和大小。通过这个命令,可以方便地查看所有已经下载到本地的 Docker 镜像。如果想要看到包括未被使用的悬挂镜像在内的所有镜像,可以添加 -a 选项:
docker images -a
这会显示所有镜像,包括中间层镜像,它们通常在构建过程中使用,并不直接赋予标签(TAG)或者仓库名称(REPOSITORY)。
退出容器
在 Docker 中,如果要退出(停止)一个运行的容器,以下是几种常见的方法:
1. 在容器内退出进程:如果正在容器内部交互式地运行一个进程(例如,通过 docker run -it image bash),那么退出容器的进程通常可以通过在该进程终端内部输入退出命令来完成,比如在 Bash 中就是 exit 或者按 Ctrl+D。
2. 关闭容器:如果容器是在后台运行的(通过 -d 标志),可以使用 docker stop 命令来停止它。这个命令需要一个或多个容器的 ID 或名称作为参数。例如:
docker stop container_name_or_id
docker stop 会向容器发送 SIGTERM 信号,并会等待一段时间(默认是 10 秒)以便容器可以正常关闭。如果容器在等待时间内没有正常退出,那么 Docker 会发送 SIGKILL 信号来强制停止容器。
3. 强制停止容器:有时,可能需要立即停止容器,不等待正常关闭的过程。可以使用 docker kill 命令来立即发送 SIGKILL 信号停止容器:
docker kill container_name_or_id
4. 从 Docker 客户端退出并保持容器运行:如果在没有后台模式下运行了一个容器,并且是通过附加到容器上进行操作的(使用 docker attach),那么可以通过按 Ctrl+P Ctrl+Q 的组合键来从容器中断开连接,而容器会继续运行。
请注意,以上所述的退出容器都是指停止容器的运行。如果需要完全删除容器以释放资源,可以在停止容器后使用 docker rm 命令加上容器的 ID 或名称来删除容器。
要从正在交互模式运行的 Docker 容器(即已经附加到容器终端的场合)退出而不关闭容器,可以使用以下快捷键组合:
Ctrl + p, Ctrl + q
这将使脱离容器并返回宿主机的命令行,但不会停止容器本身。
但如果使用的是 docker attach 命令或通过 docker exec -it 进入一个运行中的容器来附加到它的 shell,并希望退出容器并停止它,只需正常地从 shell 退出,比如:
- 输入 exit 命令,或者
- 使用快捷键 Ctrl + d(意即文件结束符EOF)
这样会导致容器停止运行,因为 Docker 容器通常是以 PID 1 的进程(通常是附加到的 shell)作为主进程,当主进程结束时,容器也会停止。
如果希望仅仅退出容器而保持它运行,就需要在启动容器时采用 "detached mode" (即以 -d 选项执行 docker run),这样即使退出容器,它也会继续在后台运行。之后,可以通过 docker exec 来进入一个正在运行的容器进行交互操作,同样使用 exit 命令或 Ctrl + d 快捷键退出,这并不会影响容器的运行状态。
例如:
docker exec -it 容器名或ID /bin/bash
然后退出:
exit
或者按 Ctrl + d。
这样做会退出当前附加的会话,但容器本身将继续运行。如果想停止容器可以使用 docker stop 命令:
docker stop 容器名或ID
记住,如果执行 docker rm 命令并带有 -f (或 --force) 选项,则无论容器是否在运行,它都会被强制停止并删除。
docker rm -f 容器名或ID
Docker 的卷(volume)
Docker 容器可以看做是一个独立的、轻量级的执行环境,它使用 Docker 镜像作为模板创建。当使用 Docker 运行镜像时,实际上是创建了一个或多个容器实例。
容器中进行的修改,例如下载文件、修改配置等,只会在该容器的生命周期内保持有效。默认情况下,当退出(停止)一个容器时,其内部的所有状态和数据都将随之丢失,因为 Docker 的容器是无状态的,它们不会自动将状态保持到下一次运行。
然而,如果希望容器中的某些数据能够持久化或在不同容器间共享,可以使用 Docker 的卷(volume)功能。卷是 Docker 用来实现数据持久化和共享的机制,它是独立于容器生命周期之外的。
以下是使用 Docker 卷的一些常见场景:
1. 数据持久化:比如数据库存储的数据,如果希望数据在容器重启后依然存在,可以将数据存储在卷中。
2. 数据共享:如果希望多个容器访问相同的数据,可以使用卷来共享文件或目录。
3. 数据备份、迁移和恢复:使用卷可以更方便地将数据备份、迁移到其他系统上,或者进行数据的恢复。
要使用 Docker 卷,可以在运行容器时通过 -v 或 --mount 标志来指定。例如:
docker run -v /path/on/host:/path/in/container -d my_image
这里,`/path/on/host` 是宿主机上的路径,`/path/in/container` 是容器内的路径。容器内的 /path/in/container 目录中的数据将会持久化存储在宿主机的 /path/on/host 目录中。
记住,只有显式地指定了一个卷来保持数据,退出 Docker 容器时,与该卷相关联的数据才会被保留。否则,没有指定卷的数据在容器停止或被删除之后,将会丢失。