Docker 快速上手指南
约 11281 字大约 38 分钟
Docker
2025-09-29
安装
在 Ubuntu 上用阿里云镜像源安装 Docker CE(稳定版)
sudo apt-get install ca-certificates curl
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get install docker-ce docker-ce-cli containerd.ioDocker 官方推荐的一键安装脚本
apt-get update
apt-get install -y apt-transport-https ca-certificates curl gnupg lsb-release
curl -fsSL https://get.docker.com | sh介绍
Docker 简单来说就是一个 开源的应用容器引擎。
它让开发者可以 将他们的应用程序及其所有依赖项打包到一个标准化的、可移植的容器中。
这个容器可以在任何支持 Docker 的环境中运行,无论是开发者的笔记本电脑、测试服务器还是生产环境的云服务器,都可以保持一致的行为。
通过 Docker,应用程序的部署变得更加快速、可靠和高效,因为它消除了不同运行环境之间的兼容性问题。它使得 开发、测试和生产环境的一致性成为可能,大大简化了软件的交付流程。
拉取镜像
docker pull docker.io/library/nginx:latestdock pull 命令用于从配置的镜像仓库(registry),例如 Docker Hub 或私有镜像仓库中,下载特定的 Docker 镜像到本地系统。
docker.io 是 Docker 仓库的注册表地址,表示这是 docker hub 的官方仓仓库,官方仓库可以省略仓库地址
library 是命名空间,docker hub 是公共仓库,每个人都可以上传自己的镜像,所以要用名称进行区分,library 是 docker 官方仓库的命名空间,如果一个镜像属于是官方的命名空间,那这部分可以省略不写
nginx 是镜像名称,表示要下载的镜像是 nginx
latest 是镜像的标签,表示要下载的镜像是 nginx 的最新版本,标签可以省略,默认就是 latest,也可以指定其他版本的标签,例如 nginx:1.21
简化后的命令为:docker pull nginx,表示从 Docker Hub 上拉取最新版本的 nginx 镜像。
这些镜像包含了运行一个或多个容器实例所需的所有应用程序组件、依赖库、运行时环境、以及相关的代码和配置文件。在用户创建并启动容器之前,必须确保其所依赖的基础或特定应用镜像已通过 pull 操作下载到本地。
该命令是 Docker 工作流中的一个基本且重要的步骤,它保证了用户能够获取到最新版本或特定标签(tag)的镜像,从而为容器的正确部署和运行奠定基础。
docker pull --platform=xxx 命令用于从 Docker 仓库中拉取特定平台的镜像。这个命令允许用户指定所需的操作系统架构和平台类型,以确保拉取到的镜像能够在目标环境中正确运行。
默认情况 Docker 会根据当前系统的架构自动选择合适的镜像,但有时用户可能需要拉取特定平台的镜像,例如在 ARM 架构的设备上运行 x86 架构的镜像,或者在 x86 架构的设备上运行 ARM 架构的镜像。
例如,docker pull --platform=linux/amd64 nginx 将拉取适用于 Linux 操作系统和 AMD64 架构的 Nginx 镜像。
Docker Hub 是 Docker 官方提供的公共镜像仓库,用户可以在其中找到各种开源和官方维护的 Docker 镜像,它提供了一个集中式的平台,允许用户上传、分享和下载 Docker 镜像。其他镜像站:Docker Hub 镜像搜索
在国内的网络环境中执行命令可能会遇到报错,可以通过修改配置文件来使用国内的镜像源。详细资源:https://github.com/tech-shrimp/docker_installer
管理镜像
docker image 命令用于管理本地的 Docker 镜像,包括查看、删除、标记等操作。常用的子命令包括:
docker image ls:列出本地所有的镜像docker image rm:删除一个或多个镜像docker image tag:为镜像添加一个新的标签
docker rmi 命令也可以用于删除一个或多个 Docker 镜像,将需要删除的镜像 ID 或名称作为参数传递给该命令,这个命令可以帮助用户清理不再需要的镜像,释放存储空间。
创建容器
docker run 命令用于创建并启动一个新的容器实例。
这个命令可以接受多个参数,以便在启动容器时进行配置。
将需要运行的镜像名称作为参数传递给该命令,这个命令是 Docker 的核心命令之一,允许用户从指定的镜像创建一个新的容器,并在该容器中运行指定的命令或应用程序。
每次运行 docker run 命令时,Docker 会根据指定的镜像创建一个新的容器实例。容器是镜像的一个运行时实例,它包含了应用程序及其所有依赖项。
docker run -d,其中的 d 表示 detached mode(分离模式),容器将在后台运行,而不是绑定到当前终端,执行后会返回一个容器 ID。这个命令常用于需要长时间运行的服务或应用程序,例如 Web 服务器、数据库等。
当直接使用 docker run 命令时,如果发现本地不存在 指定的镜像,Docker 会自动尝试从默认的 Docker Hub 仓库中拉取该镜像。如果需要从其他仓库拉取镜像,可以使用 docker pull 命令手动拉取。
docker run -p 命令用于将容器的端口映射到宿主机的端口。通过指定 -p 选项,用户可以将容器内部的服务暴露到宿主机上,从而实现外部访问。例如,docker run -p 8080:80 nginx 将容器的 80 端口映射到宿主机的 8080 端口。
-p 参数用于端口映射,其主要作用是将 Docker 容器内部的网络端口与宿主机的网络端口进行关联,从而允许外部访问容器内运行的服务。
核心概念:
- 网络隔离:Docker 容器拥有独立的虚拟网络环境,与宿主机网络默认是隔离的。这意味着,即使容器内运行着一个服务(如 Nginx),在不进行端口映射的情况下,也无法直接通过宿主机的 IP 地址和端口访问到该服务。
- 端口映射的作用: 解决网络隔离问题,实现宿主机与容器之间的通信。通过端口映射,当访问宿主机的特定端口时,流量会被转发到容器内部对应的端口,从而能够访问容器内运行的服务。
使用 -p 参数进行端口映射的格式为:宿主机端口:容器内端口。
冒号前: 宿主机的端口(外部端口)。
冒号后: 容器内部的端口(内部端口)。
示例: docker run -p 80:80 nginx,这个命令会将宿主机的 80 端口映射到 Nginx 容器内部的 80 端口,这样,当在宿主机浏览器中访问 localhost:80 时,实际上就是访问到了 Nginx 容器内的服务,网页因此可以正常显示。
一个容器端口可以映射到多个宿主端口。要实现这一点,你需要在 docker run 命令中使用 -p 参数多次,每个所需的映射使用一次。
例如,要将容器的端口 33 映射到宿主端口 1253 和宿主端口 2313,你可以使用以下命令:
docker run -p 1253:33 -p 2313:33 my_image这允许你从宿主机的两个不同端口访问在容器内部运行在端口 33 上的服务。
在运行的时候可以通过 -name 参数为容器指定一个名称,这样在删除容器时可以使用名称而不是容器 ID。例如:
docker run --rm -d --name mynginx -p 8080:80 nginx并且在后续的操作中可以使用名称而不是容器 ID,从而简化命令,这个名称必须是 唯一 的。
--name mynginx:给容器起一个名字,方便下次用这个名字操作(如 docker stop mynginx)。
--rm:容器一旦停止就自动删除,不会出现在 docker ps -a 中,这个参数可以帮助用户在容器不再需要时自动清理资源,避免积累大量已停止的容器。
docker run -e 命令用于在创建容器时设置环境变量。这个命令允许用户在容器内定义特定的环境变量,以便在运行时使用。
docker run -e MY_ENV_VAR=value nginx可以传递多个环境变量,使用多个 -e 参数:
docker run -e MY_ENV_VAR1=value1 -e MY_ENV_VAR2=value2 nginxdocker run -it 命令用于创建并启动一个新的容器实例,并进入该容器的交互式终端。这个命令常用于需要与容器内的应用程序进行交互的场景,例如调试或测试:
docker run -it --rm alpine sh进入容器后,可以使用 exit 命令退出容器的交互式终端。由于使用了 --rm 参数,容器停止后会自动被删除。
--restart 策略定义了容器在 退出后(无论是因为进程结束、崩溃还是宿主机重启),由 Docker 守护进程自动重新启动的规则。
no - 不自动重启(默认值)
- 行为:容器 永远不会 自动重启。无论容器以何种状态退出(即使是异常退出),它都会保持停止状态。
- 使用场景:临时性的任务、一次性执行的脚本、或者您希望手动控制其生命周期的开发/测试容器。
docker run --restart=no my-app
# 或者直接省略,因为它是默认值
docker run my-appon-failure - 失败时重启
- 行为:只有当容器 以非零状态码退出(即表示失败)时,Docker 才会尝试重启它。如果容器正常退出(状态码为 0),则不会被重启。
- 可以限制最大重启次数:
on-failure:3表示最多尝试重启 3 次。
- 可以限制最大重启次数:
- 使用场景:需要确保在程序崩溃或发生错误时能自动恢复的服务,但任务成功完成后就不需要再运行。例如,一个定时的数据处理任务,如果中途出错,我们希望它重试。
# 在失败时无限次重启
docker run --restart=on-failure my-flaky-app
# 最多重启 5 次
docker run --restart=on-failure:5 my-flaky-appalways - 总是重启
- 行为:无论容器因何原因退出,Docker 都会无条件地重启它。这包括:
- 容器进程正常结束(退出码为 0)。
- 容器进程异常结束(退出码非 0)。
- 容器被
docker stop或docker restart命令正常停止后,当 Docker 守护进程启动时(例如宿主机重启后),它也会被重新启动。
- 注意:如果容器被
docker stop明确停止,在手动再次启动它之前,它不会立即重启。但宿主机重启会触发它的重启。 - 使用场景:需要持续运行、保持高可用的长期服务,如 Web 服务器(Nginx)、API 后端等。
docker run -d --restart=always --name nginx nginxunless-stopped - 除非被停止,否则总是重启
- 行为:与
always类似,但有一个 关键区别:- 如果容器是 被
docker stop命令明确停止的,那么即使 Docker 守护进程重启(或宿主机重启),该容器也不会被自动启动。 - 除此之外的其他退出情况(进程自己退出、系统崩溃等),它都会在守护进程启动时被重启。
- 如果容器是 被
- 使用场景:这是最常用和最智能的策略。适用于那些您希望默认一直运行,但有时可能需要手动停止并使其保持停止状态的服务。它比
always更尊重用户的意图。
docker run -d --restart=unless-stopped --name database mysql:8.0策略对比总结
为了更直观地理解,请看下表:
| 重启策略 | 容器正常退出 (exit 0) | 容器异常退出 (exit 非 0) | 宿主机重启后 | 被 docker stop 停止后,宿主机重启 |
|---|---|---|---|---|
no | ❌ | ❌ | ❌ | ❌ |
on-failure | ❌ | ✅ | ✅ | ❌ |
always | ✅ | ✅ | ✅ | ✅ |
unless-stopped | ✅ | ✅ | ✅ | ❌ |
注:on-failure 在宿主机重启后,只有之前是因为异常退出而停止的容器才会被重启。
查看当前策略:
docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' <container-name>使用 docker update 命令修改运行中容器的策略:
注意:某些更改可能在运行时不生效
docker update --restart=unless-stopped <container-name>如果不想反复的创建和删除容器,可以使用 docker start 和 docker stop 命令来管理已存在的容器。这样可以避免重复的资源开销,提高效率,之前使用 docker run 运行时传入的配置已经被保留,下次启动时会使用相同的配置。
管理容器
docker ps 命令用于列出当前正在运行的容器,ps 就是 process status (进程状态) 的缩写,它显示了容器的基本信息,包括容器 ID、镜像名称、创建时间、状态、端口映射等。
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c710212735c9 mysql:8.0 "docker-entrypoint.s…" 5 seconds ago Up 3 seconds 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp my-mysql-containerCONTAINER ID 是容器的 id,每创建一个容器,Docker 就会分配一个唯一的 ID,用于标识该容器
IMAGE 列显示了容器所基于的镜像名称
COMMAND 列显示了容器启动时执行的命令
CREATED 列显示了容器创建的时间
STATUS 列显示了容器的当前状态(如运行中、已停止等)
PORTS 列显示了容器暴露的端口映射信息
NAMES 列显示了容器的名称
docker rm 容器ID 命令用于删除一个或多个 Docker 容器。
这个命令可以帮助用户清理不再需要的容器,释放系统资源,在删除正在运行的容器可以使用 -f 参数强制删除。
列出所有容器可以使用 docker ps -a 命令,-a 参数表示列出所有容器,包括已停止的容器。
docker ps 命令默认只列出正在运行的容器。
使用 -a 列出的所有容器中,状态为 Exited 的容器表示已经停止运行的容器。可以使用 docker rm 命令删除这些已停止的容器,这些停止运行的容器不会占用系统资源,但如果不删除,它们仍然会占用存储空间。
可以使用 docker start/stop 启动或者停止已有容器,前提是你没有用 --rm
docker start mynginx
docker stop mynginx批量删除所有停止的容器:
docker container prune会提示确认,删除所有“Exited”或“Created”的容器。
删除所有容器 慎用:
docker rm $(docker ps -aq)-q: 只输出容器的 ID,不显示其他信息。
docker inspect 命令用于查看容器或镜像的详细信息,包括其配置、状态、网络设置等信息。
docker inspect mynginxdocker create 命令用于创建一个新的容器实例,但不会立即启动它。这个命令可以用于预先配置容器的设置,然后在需要时手动启动。
docker create --name mynginx -p 8080:80 nginx后续启动使用 docker start 命令
docker logs 容器ID 命令用于查看容器的日志输出。这个命令可以帮助用户调试和监控容器内运行的应用程序。
docker logs mynginx可以加上 -f 参数来实时查看日志输出
docker exec 进程ID 执行的命令 命令用于在运行中的容器内执行命令。这个命令允许用户在容器内运行特定的命令或进入容器的交互式终端。
docker exec b12a3072d8b3 ps -ef其中 ps -ef 命令用于列出容器内的所有进程。
docker exec -it 进程ID /bin/bash 命令用于进入正在运行的容器的交互式终端。这个命令允许用户在容器内执行命令,就像在本地终端一样。
docker exec -it mynginx /bin/bash/bin/bash 是容器内的一个常用 shell,允许用户在容器内执行命令,可以使用 exit 命令退出容器的交互式终端。
容器内部的命令行是一个极简的 Linux 环境,通常只包含最基本的命令和工具。为了在容器内执行更复杂的操作,可能需要安装额外的软件包。
执行命令前先执行 cat /etc/os-release 查看容器的操作系统版本。
比如:
cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
NAME="Debian GNU/Linux"
VERSION_ID="12"
VERSION="12 (bookworm)"
VERSION_CODENAME=bookworm
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"其中显示了容器的操作系统信息,包括名称、版本等。
比如上述的系统的软件的包管理工具是 apt,可以使用以下命令安装软件包:
apt update
apt install [package_name]安装 Vim 编辑器的命令为:
apt install vim镜像位置
在 Windows 上,Docker 镜像的默认下载位置取决于 Docker 的设置:
在 Windows 的 Docker Desktop 上,镜像的物理存储位置取决于其运行后端:
- 当使用 WSL2 后端时(推荐且默认):镜像实际存储在一个名为
docker-desktop-data的 WSL2 发行版内。- 访问路径:在文件资源管理器的地址栏输入
\\wsl$\docker-desktop-data\data\docker\overlay2。 - 在这里,您可以看到所有镜像层和容器读写层的具体文件。
- 访问路径:在文件资源管理器的地址栏输入
- 传统 Hyper-V 后端:镜像存储在一个 Docker Desktop 管理的虚拟硬盘 (VHD) 文件中,默认位于
C:\ProgramData\DockerDesktop。该文件对用户不直接可见或可操作。
请注意,通常通过 Docker CLI 命令与 Docker 镜像交互,而不是直接访问或修改这些文件。
您可以使用 docker info 命令查看 Docker Root Dir,它指示 Docker 存储其数据的位置。
在 Linux 系统中,Docker 的默认数据存储位置通常是 /var/lib/docker 。修改此位置需要配置 Docker 守护进程。
步骤:
停止 Docker 服务: 在修改任何配置前,务必停止 Docker 服务以避免数据损坏。
sudo systemctl stop docker备份(可选但强烈建议): 为了安全起见,可以备份当前的 Docker 数据目录。
sudo cp -rp /var/lib/docker /var/lib/docker_backup创建新的存储目录: 选择一个新的位置来存储 Docker 数据,并创建该目录。例如,在
/mnt/new_docker_data:sudo mkdir -p /mnt/new_docker_data移动现有 Docker 数据到新目录: 将旧目录中的所有内容移动到新创建的目录。这一步 非常重要,因为这将保留你现有的镜像、容器和卷等数据。
sudo mv /var/lib/docker/* /mnt/new_docker_data/注意: 如果新目录是空的,你也可以选择不移动,让 Docker 重新创建一个全新的环境。但如果你有重要的现有数据,那么移动是必须的。
配置 Docker 守护进程: Docker 的配置文件是
/etc/docker/daemon.json。如果文件不存在,则创建它;如果存在,则编辑它。使用你喜欢的文本编辑器打开或创建
daemon.json文件:sudo nano /etc/docker/daemon.json添加或修改
data-root字段指向新的存储路径。如果文件中有其他配置,请确保这是一个有效的 JSON 格式(例如,用逗号分隔多个条目)。{ "data-root": "/mnt/new_docker_data" }保存并关闭文件。
启动 Docker 服务:
sudo systemctl start docker验证: 运行
docker info命令,查找 "Docker Root Dir" 行,确认其指向新的路径。docker info | grep "Docker Root Dir"输出应显示你刚刚配置的新路径。
Docker 的存储位置和行为取决于您使用的是 Docker Desktop(绝大多数用户的选择)还是经典的 Windows Server 版 Docker。以下内容主要针对 Docker Desktop。
Docker Desktop 默认通过 WSL 2(推荐后端)或 Hyper-V 在虚拟机中运行 Linux 内核,因此其数据(包括镜像、容器)存储在专用的虚拟磁盘中,而非 Windows 宿主目录。
- WSL 2 后端:数据存储在一个名为
docker-desktop-data的 WSL 发行版内。其物理文件路径通常为\\wsl$\docker-desktop-data,对用户透明。 - Hyper-V 后端:数据存储在一个 Hyper-V 虚拟硬盘(
.vhdx文件)中,默认位于C:\Users\Public\Documents\Hyper-V\下。
如果您希望将 Docker 数据移动到其他驱动器以释放 C 盘空间,请根据您的后端类型选择以下方法。
对于使用 WSL 2 后端的用户
这是最常见的情况。由于 Docker Desktop 的设置界面可能不直接提供 WSL 发行版的迁移选项,需要通过命令行操作。
步骤如下:
关闭 Docker 与 WSL: 在 PowerShell(以管理员身份运行)中执行以下命令,确保所有相关进程关闭:
wsl --shutdown导出
docker-desktop-data发行版: 将现有数据导出为一个备份文件(例如,导出到 E 盘):wsl --export docker-desktop-data E:\docker-desktop-data.tar注销原有发行版: 此操作会删除当前的数据,请确保上一步导出成功。
wsl --unregister docker-desktop-data在新位置导入发行版: 将备份文件导入到新的目标目录(例如,
E:\Docker\wsl),这将在此目录创建新的虚拟磁盘文件。wsl --import docker-desktop-data E:\Docker\wsl E:\docker-desktop-data.tar --version 2完成后,可手动删除
E:\docker-desktop-data.tar备份文件以节省空间。重启 Docker Desktop: 完成以上步骤后,启动 Docker Desktop。它将自动使用新位置的数据。
对于使用 Hyper-V 后端的用户
此方法更简单,可直接通过 Docker Desktop 图形界面完成。
步骤如下:
- 点击系统托盘中的 Docker Desktop 图标,选择 “Settings”。
- 导航至 “Resources” -> “Advanced” 选项卡。
- 找到 “Disk image location” 设置项。
- 点击 “Browse”,选择一个新的目标文件夹(例如
E:\Docker)。 - 点击 “Apply & Restart”。
Docker Desktop 将自动在后台完成虚拟磁盘文件的迁移工作,并重启服务。
注意事项:
- Docker Desktop 对数据存储的管理比原生 Linux 或 Windows Server 版更集成和自动化。
- 直接在 Windows 文件系统中找到并修改 Docker 数据文件是不可取的,因为它们通常在 WSL 或 Hyper-V 虚拟磁盘内部。
- 如果 Docker Desktop 没有直接的 GUI 选项来移动数据,WSL 版本的解决方案会涉及到 WSL 命令,它移动的是整个 WSL 虚拟磁盘。
Windows Server (原生 Docker Daemon)
如果你在 Windows Server 上手动安装了 Docker 引擎而不是 Docker Desktop,其行为更类似于 Linux 版本。
步骤:
停止 Docker 服务:
Stop-Service docker创建新的存储目录: 选择一个新的位置,例如
D:\DockerData:New-Item -ItemType Directory -Path D:\DockerData移动现有 Docker 数据到新目录: 默认路径通常是
C:\ProgramData\Docker。Move-Item -Path "C:\ProgramData\Docker\daemon.json" -Destination "D:\DockerData" -Force # 移动 daemon.json 如果存在,通常它可能不存在 Move-Item -Path "C:\ProgramData\Docker\containers" -Destination "D:\DockerData" -Force -Recurse -ErrorAction SilentlyContinue # 移动容器数据 Move-Item -Path "C:\ProgramData\Docker\image" -Destination "D:\DockerData" -Force -Recurse -ErrorAction SilentlyContinue # 移动镜像数据 # 根据需要移动其他子目录,如 volumes, swarm, network等- 注意: 确保移动了
C:\ProgramData\Docker下所有重要的子目录。或者,你可以直接将整个C:\ProgramData\Docker文件夹移动到新位置,但请确保在移动前没有任何进程占用这些文件。
- 注意: 确保移动了
配置 Docker 守护进程: 创建一个或编辑
daemon.json文件。在 Windows Server 上,这个文件通常位于C:\ProgramData\Docker\config或C:\ProgramData\Docker。如果文件不存在,你需要创建它。使用记事本或其他文本编辑器打开或创建此文件: 例如,打开
C:\ProgramData\Docker\config\daemon.json。添加或修改
data-root字段指向新的存储路径:{ "data-root": "D:\\DockerData" }请注意 Windows 路径中使用双反斜杠
\\,或者使用正斜杠/。保存并关闭文件。
启动 Docker 服务:
Start-Service docker验证: 运行以下命令并查找 "Docker Root Dir" 行:
docker info | Select-String "Docker Root Dir"输出应显示你配置的新路径。
一般注意事项:
- 权限: 确保新的存储目录具有 Docker 服务账户的读写权限。在 Linux 上,通常是
root或docker组。 - 空间: 确保新的存储位置有足够的磁盘空间来容纳现有的 Docker 数据和未来的增长。
- 重启: 每次修改
daemon.json后,都需要重启 Docker 服务才能使更改生效。 - 数据丢失风险: 在操作前最好进行备份。错误的操作可能导致镜像和容器数据的丢失。
挂载卷
docker run -v 参数用于 挂载卷(Volume Mounting) ,其核心功能是实现宿主机与容器之间文件目录的双向绑定。
核心功能和作用:
- 文件目录绑定:
-v参数将宿主机上的一个文件目录与容器内部的某个指定目录关联起来。 - 双向同步: 一旦绑定建立,对其中任何一端(宿主机或容器)该目录内容的修改,都会实时反映到另一端。宿主机与容器通过这个共享目录紧密联系。
- 数据持久化: 这是挂载卷最重要的作用。当容器被删除时,容器内部的所有数据通常也会被一并删除。然而,如果使用了挂载卷,容器中与宿主机目录绑定的数据实际上是存储在宿主机上的。这意味着,即使容器被删除,这些数据也会安全地保留在宿主机上,从而实现了数据的持久化保存。
比如:
docker run -v /website/html:/usr/share/nginx/html nginx-v 宿主机路径:容器内路径 这种挂载方式被称为绑定挂载
还有一种方式是让 Docker 自动创建一个存储位置,为存储空间提供一个名称,然后在挂载的时候直接使用名称就行了,这种方式叫 命名卷挂载。
docker volume create 卷名称 命令用于创建一个新的 Docker 卷(挂载卷)。卷是 Docker 中用于持久化数据的机制,它允许容器之间共享数据,并在容器删除后保留数据。
创建的挂载卷的位置取决于 Docker 的配置和操作系统。默认情况下,Docker 卷存储在以下位置:
- Linux:
/var/lib/docker/volumes/ - Windows:
C:\ProgramData\Docker\volumes\
docker volume inspect 命令可以查看卷的详细信息,包括其存储位置、创建时间、挂载点等。
在下次 docker run 命令中使用 -v 卷名称:容器内路径 参数来挂载这个卷。例如:
docker run -d -v my_volume_name:/data nginx
docker run -d -p 3000:80 -v nginx_html:/usr/share/nginx/html nginxsudo -i 用于在 Linux 系统中以 root 用户身份运行命令。使用 sudo -i 可以获得一个交互式的 root shell,允许用户执行需要更高权限的操作。在使用 Docker 时,如果需要访问 Docker 的系统目录或执行特权操作,可能需要使用 sudo -i 切换到 root 用户。
注意:命名卷在第一次使用时 Docker 会把容器的文件同步到卷中进行一个初始化,但是绑定挂载不会进行初始化,绑定挂载会直接使用宿主机的文件内容。
docker volume list 命令用于列出所有 Docker 卷。这个命令可以帮助用户查看当前系统中存在的所有卷,包括它们的名称、驱动程序和挂载点等信息。
docker volume rm 卷名称 命令用于删除一个或多个 Docker 卷。这个命令可以帮助用户清理不再需要的卷,释放存储空间。
docker volume prune 命令用于删除所有未使用的 Docker 卷。这个命令可以帮助用户清理不再需要的卷,释放存储空间,可以加上 -a 参数来删除所有未使用的卷,不加 -a 参数只会删除那些没有被任何容器使用的卷。
加 -a 和不加的区别可以简单理解为:
- **不加 **
-a:只会删除那些完全没有被任何容器使用的卷(即“孤立”的卷)。 - **加 **
-a:会删除所有未被容器挂载的卷,无论这些卷是否曾经被容器使用过。这样可以更彻底地清理无用的卷。
一般情况下,建议先不加 -a,以免误删还可能需要的数据卷。
网络模式
Docker 网络默认是桥接模式(bridge),它允许容器之间通过虚拟网络进行通信。Docker 提供了多种网络模式,包括:
- bridge:默认的网络模式,容器通过虚拟网桥连接到宿主机的网络。
- host:容器直接使用宿主机的网络栈,不进行网络隔离。
- none:容器没有网络连接。
- overlay:用于跨多个 Docker 主机的网络连接,通常用于 Swarm 集群。
所有的容器都链接到这个默认的桥接网络上,每个容器内部都分配了一个虚拟 IP 地址。容器之间可以通过这个 IP 地址进行通信。
容器网络和宿主机的网络是隔离的,容器内部的 IP 地址和宿主机的 IP 地址是不同的。容器可以通过端口映射将其服务暴露到宿主机上,从而允许外部访问。
docker network create 命令用于创建一个新的 Docker 子网络。默认也是桥接模式的一种。
可以指定容器加入不同的子网络,以实现容器之间的隔离和通信。
同一个子网络中的容器可以通过容器名称或 IP 地址进行通信,跨子网络则不能。
子网络中的容器可以通过名称互相访问,而不需要使用内部 IP 地址。
docker network create network1docker run -d --name container1 --network network1 nginx--network 参数用于指定容器要加入的网络。
比如同一个子网络中,有两个容器 container1 和 container2,可以在 container2 中通过 ping 命令测试与 container1 的连接:
docker exec -it container2 ping container1
ping container1Docker 子网络内部有一套 DNS 系统,可以通过容器名称进行解析。
host 网络模式允许容器直接使用宿主机的网络栈,不进行网络隔离。在这种模式下,容器将共享宿主机的 IP 地址和端口,在启动时候无需进行端口映射,因为容器的服务直接运行在宿主机的网络上。
在启动的时候使用 --network host 参数来指定容器使用宿主机网络模式。
docker run --network host nginx启动后可以进入容器内查询 IP 地址:
docker exec -it container_id /bin/sh
apt update
apt install iproute2
ip addr showdocker network list 命令用于列出当前 Docker 主机上所有的网络,包括默认的桥接网络和用户创建的自定义网络。
其中列出的以下种网络是不能删除的:
bridge:默认的桥接网络。host:宿主机网络模式。none:无网络模式。
docker network rm [network_name/ID] 命令用于删除用户创建的自定义网络。
镜像构建(DockerFile)
docker file 是一个文本文件,包含了一系列的指令和参数,用于定义如何构建一个 Docker 镜像。Dockerfile 中的每一条指令都会创建一个新的镜像层,这些层会被组合在一起形成最终的镜像。
如果要将一个项目打包成 Docker 镜像,先在项目的根目录下创建一个名为 Dockerfile 的文件。这个文件将包含构建镜像所需的所有指令。
所有的 Dockerfile 文件的第一行都是 FROM 指令,用于指定基础镜像。基础镜像可以是一个操作系统镜像,也可以是一个已经存在的应用程序镜像。
FROM nginx:latestWORKDIR 指令用于设置工作目录。所有后续的指令都会在这个目录下执行。如果目录不存在,Docker 会自动创建它。
WORKDIR appCOPY 指令用于将文件从宿主机复制到镜像中,可以指定源路径和目标路径。
COPY 宿主机路径 镜像路径 指令将宿主机上的文件或目录复制到镜像中的指定路径。
COPY . .上述代码表示将宿主机当前目录下的所有文件和子目录复制到镜像中的工作目录 app 下。
RUN 指令用于在镜像构建过程中执行命令。可以使用 RUN 指令安装软件包、复制文件等。
RUN npm install --productionEXPOSE 指令用于指定容器运行时要暴露的端口。这个指令不会实际打开端口,但它会在镜像的元数据中记录下要暴露的端口。
EXPOSE 8090实际使用还是以 -p 参数来进行端口映射。
CMD 指令用于指定容器启动时要执行的命令。这个指令只能出现一次,如果有多个 CMD 指令,只有最后一个会生效。
CMD ["npm", "run", "start"]ENTRYPOINT 指令用于设置容器启动时的默认命令和参数。与 CMD 不同,ENTRYPOINT 指令指定的命令无法被 docker run 命令的参数覆盖,它的优先级更高。
ENTRYPOINT ["npm", "run", "start"]最后就可以在终端执行
docker build -t [myAppName]:[myAppVersion] .可以在项目的根目录中创建 .dockerignore 文件来指定在构建镜像时要忽略的文件和目录。这个文件的语法与 .gitignore 类似,可以使用通配符来匹配文件和目录。 例如,以下是一个 .dockerignore 文件的示例:
node_modules
.git
Dockerfile
.dockerignore
*.log为了将镜像推送到 Docker Hub,先进行登录操作:
docker login推送到 Docker Hub 的镜像需要有一个唯一的名称。通常镜像名称的格式为 用户名/镜像名:标签,所以在打包的时候需要指定用户名。
docker build -t username/myapp:latest .推送到 Docker Hub 的命令为:
docker push username/myapp:latest推送镜像到 Docker Hub 后,可以在任何地方使用 docker pull username/myapp:latest 命令来拉取这个镜像。
多容器编排(Docker Compose)
Docker compose 是一个用于定义和运行多容器 Docker 应用程序的工具。它使用 YAML 文件来配置应用程序的服务、网络和卷等。
它使用 yaml 文件来管理多个容器,其中配置了容器之间是如何相互连接的,以及它们的环境变量、端口映射等。
Docker 会为每一个 compose 文件创建一个独立的子网络,容器之间可以通过服务名称进行通信。
同一个 Compose 文件中的容器都会自动加入到同一个子网络中,这样它们可以通过服务名称进行互相访问。
Docker compose 还可以自定义启动顺序,确保某些服务在其他服务之前启动。
创建好 docker-compose.yml 文件后,可以使用以下命令来启动所有服务:
docker compose up -dup: 子命令,用于根据 YAML 文件中的定义创建并启动所有服务。
-d: 代表 "detached" mode,即 后台运行。如果不加 -d,所有服务的日志都会在前台终端输出,退出终端可能会导致服务停止。
如果需要停止所有服务并且删除容器,可以使用以下命令:
docker compose down如果只想停止服务而不删除容器,可以使用以下命令:
docker compose stop使用 docker compose start 命令可以重新启动已停止的服务。
如果容器已经在运行了,再次执行 docker compose up 命令不会重新创建容器,而是会根据 docker-compose.yml 文件中的配置更新现有容器。
docker compose up 可以用于更新,但它的行为是“重新创建”容器,而不是“原地更新”容器。
当您对 docker-compose.yml 文件做了修改(例如:更新了镜像标签、改变了环境变量、映射了新的端口等),并在已经运行服务的目录下再次执行 docker compose up -d 时,会发生以下事情:
- 构建/拉取新镜像:如果配置有变更,Compose 会先根据配置拉取新的镜像或重新构建镜像。
- 停止旧容器:Compose 会 停止 当前正在运行的、与服务同名的旧容器。
- 创建新容器:Compose 会 创建一个新的容器,这个新容器应用了
docker-compose.yml中的所有新配置。 - 启动新容器:新的容器被启动。
- 移除旧容器:默认情况下,旧的容器会被移除(除非使用了
--no-recreate参数,但这样更新会不生效)。
所以,这个过程是 “停止 -> 创建新的 -> 启动新的 -> 删除旧的”,我们称之为 “重新创建”。
用于更新的最佳实践命令:为了确保更新过程干净、可靠,推荐在使用 docker compose up 时结合以下参数:
# 最佳实践:拉取最新镜像并重新创建容器
docker compose pull && docker compose up -d
# 或者,强制重新构建镜像并重新创建容器(如果使用 build: 选项)
docker compose up -d --build
# 最严格的更新:即使配置没变,也强制重新创建所有容器
docker compose up -d --force-recreate对于非标准的 yaml 文件名,可以使用 -f 参数指定文件名:
docker compose -f custom-compose.yml up -d在包含 docker-compose.yml 文件的目录下,您可以执行以下命令来管理整个应用的生命周期:
# 1. 启动所有服务(后台运行)
docker compose up -d
# 2. 查看服务运行状态
docker compose ps
# 3. 查看服务的实时日志(所有服务)
docker compose logs -f
# 查看特定服务的日志
docker compose logs -f webapp
# 4. 停止所有服务,但保留容器和数据
docker compose stop
# 5. 停止并移除所有容器、网络(但默认会保留数据卷)
docker compose down
# 6. 停止并移除所有容器、网络、数据卷(彻底清理)
docker compose down -v
# 7. 在运行中重启某个服务(例如,更新了代码后)
docker compose restart webapp文件名称:默认情况下,docker compose 会寻找当前目录下名为 docker-compose.yml 的文件。如果您的文件是其他名称,需要使用 -f 参数指定:
docker compose -f my-compose-file.yml up -d项目名称:默认情况下,Compose 会使用当前目录的名称作为 "项目名",并为所有资源(容器、网络、卷)加上项目名前缀,从而隔离不同项目。您也可以使用 -p 参数自定义项目名:
docker compose -p my-project up -d构建镜像:如果您的 docker-compose.yml 文件中包含 build: 指令(用于从 Dockerfile 构建镜像),docker compose up -d 会在启动服务前自动构建或重新构建镜像。
经典“硬核”工作流:
# 1. 核弹发射井开启(销毁一切)
docker compose down
# 2. 确保灰飞烟灭(加上 -v 删除所有匿名卷,--rmi all 甚至删除所有相关镜像)
docker compose down -v --rmi all
# 3. 在一片净土上重建世界
docker compose up -d适用场景:
- “我不管了” 场景:各种端口冲突、网络问题、容器状态诡异,懒得一点点排查。
- “从头来过” 场景:
docker-compose.yml文件做了大量结构性修改,确保旧容器 100%会影响新配置。 - “求个心安” 场景:虽然可能有些小题大做,但这样操作一遍,心里特别踏实,知道环境绝对是干净的。
- 部署生产前:在最终部署前,用一个绝对干净的环境测试整个编排流程。
注意:
数据丢失警告:如果您的 Compose 项目里定义了 匿名卷(在 docker-compose.yml 里只写了容器路径,没起名字),使用 docker compose down -v 会 一并删除这些卷,导致数据永久丢失。
- 安全做法:如果卷里有重要数据(比如数据库内容),请确保在
docker-compose.yml中使用了 命名卷,这样即使执行down -v,再次up时命名卷的数据通常还在。
最佳实践
容器设计原则
单一职责原则
每个容器应该只运行一个主要进程,保持容器的专注性和可维护性。
反例:
# 一个容器中同时运行Web服务器和数据库
docker run -d my-app-that-runs-nginx-and-mysql正例:
# 使用多个容器,各司其职
docker run -d --name web nginx
docker run -d --name db mysql
docker run -d --name app my-python-app无状态设计
容器应该是无状态的,所有状态数据都应该外部化存储。
实现方式:
# 将状态数据存储在卷中
docker run -d \
-v app-data:/var/lib/app/data \
-v app-logs:/var/log/app \
my-app镜像构建最佳实践
使用多阶段构建
减少最终镜像大小,提高安全性。
# 第一阶段:构建环境
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# 第二阶段:运行环境
FROM node:16-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
USER node
EXPOSE 3000
CMD ["node", "server.js"]优化镜像层缓存
合理安排指令顺序,充分利用Docker的构建缓存。
# 错误的顺序 - 每次代码变更都会导致依赖重新安装
COPY . .
RUN npm install
# 正确的顺序 - 依赖变更时才重新安装
COPY package*.json ./
RUN npm install
COPY . .使用特定版本标签
避免使用 latest 标签,确保构建的可重复性。
# 不推荐
FROM ubuntu:latest
# 推荐
FROM ubuntu:20.04安全最佳实践
使用非root用户运行
FROM node:16-alpine
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
USER nextjs
COPY --chown=nextjs:nodejs . .
CMD ["node", "server.js"]定期更新基础镜像
# 定期检查并更新基础镜像版本
FROM ubuntu:20.04
# 而不是使用旧的、可能存在漏洞的版本扫描镜像漏洞
# 使用Docker Scout或类似工具扫描镜像
docker scout cves my-app:latest资源配置最佳实践
设置资源限制
防止单个容器消耗过多资源。
# docker-compose.yml
services:
web:
image: nginx
deploy:
resources:
limits:
memory: 512M
cpus: '1.0'
reservations:
memory: 256M
cpus: '0.5'配置健康检查
# 在Dockerfile中定义健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1# 或在docker-compose.yml中定义
services:
web:
image: my-app
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s网络最佳实践
使用自定义网络
# docker-compose.yml
version: '3.8'
services:
frontend:
image: nginx
networks:
- frontend-network
backend:
image: node:16
networks:
- frontend-network
- backend-network
database:
image: postgres:13
networks:
- backend-network
networks:
frontend-network:
driver: bridge
backend-network:
driver: bridge避免使用主机网络
# 不推荐 - 安全性差
services:
web:
network_mode: "host"
# 推荐 - 使用端口映射
services:
web:
ports:
- "80:80"数据管理最佳实践
使用命名卷
services:
database:
image: postgres:13
volumes:
- db-data:/var/lib/postgresql/data
- ./backups:/backups # 绑定挂载用于备份
volumes:
db-data:
driver: local定期备份重要数据
# 备份数据库卷
docker run --rm \
-v db-data:/source \
-v /host/backups:/backup \
alpine tar czf /backup/db-$(date +%Y%m%d).tar.gz -C /source .日志管理最佳实践
配置日志轮转
services:
web:
image: nginx
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"使用结构化日志
# 在应用中使用JSON格式日志
CMD ["node", "-r", "pino", "server.js"]编排最佳实践
使用环境变量文件
# docker-compose.yml
services:
web:
image: my-app
env_file:
- .env
environment:
- NODE_ENV=production定义服务依赖关系
services:
web:
image: nginx
depends_on:
database:
condition: service_healthy
backend:
condition: service_started
backend:
image: node:16
depends_on:
database:
condition: service_healthy
database:
image: postgres:13
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5监控与维护
设置监控和告警
# 使用cAdvisor监控容器资源使用
docker run \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:ro \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--publish=8080:8080 \
--detach=true \
--name=cadvisor \
gcr.io/cadvisor/cadvisor:v0.47.0定期清理无用资源
# 清理无用镜像、容器、卷和网络
docker system prune -f
docker volume prune -f
docker network prune -f
# 更激进的清理(谨慎使用)
docker system prune -a -f --volumes开发环境最佳实践
使用开发专用配置
# docker-compose.dev.yml
services:
web:
build: .
volumes:
- .:/app # 开发时挂载源代码
- /app/node_modules # 防止覆盖容器内的node_modules
environment:
- NODE_ENV=development
ports:
- "3000:3000"热重载配置
services:
web:
build: .
develop:
watch:
- action: sync
path: ./
target: /app
- action: rebuild
path: package.json通过遵循这些最佳实践,您可以构建出更安全、更稳定、更易维护的Docker化应用。记住,Docker不仅仅是容器技术,更是一套完整的应用交付方法论。