从零到一:一份有温度的Docker实战命令手册

你好,我是老陈,一个在容器化浪潮里摸爬滚打了多年的技术老兵。还记得第一次接触Docker时,面对满屏的命令和陌生的概念,那种既兴奋又无从下手的感觉。这些年,我见过太多开发者,从满怀期待地安装Docker,到被复杂的网络配置、镜像拉取慢、容器调试等问题劝退。其实,Docker本身并不复杂,它更像是一套精密的“乐高”工具,关键在于你是否有一份清晰、按场景编排的“搭建说明书”。

今天这份手册,不是冷冰冰的命令罗列,而是我结合无数项目实战,为你梳理的一份从安装到深度运维的“生存指南”。我们不会止步于“这个命令是干什么的”,而是会深入探讨“在什么场景下,为什么要用这个命令,以及如何用得更好”。无论你是刚入门的新手,还是希望系统梳理知识的中级开发者,这份手册都将是你容器化旅程中可靠的伙伴。让我们暂时忘掉那些晦涩的理论,直接从解决实际问题开始。

1. 起航:搭建你的第一个Docker环境

万事开头难,一个稳定、高效的Docker环境是后续所有操作的基础。这一步的核心目标有两个:一是正确安装,二是优化配置,尤其是解决国内开发者最头疼的镜像拉取速度问题。

1.1 安装与验证:跨平台一步到位

Docker的安装过程在不同操作系统上略有差异。对于大多数Linux发行版,最推荐的方式是通过官方提供的便捷脚本或包管理器。

# 对于 Ubuntu/Debian 系统
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

执行上述命令后,脚本会自动完成依赖检测、仓库添加和软件包安装。安装完成后,一个至关重要的步骤是将当前用户加入 docker 用户组,这样可以避免每次执行命令都需要 sudo,提升操作安全性和便捷性。

sudo usermod -aG docker $USER
# 执行后需要退出当前终端并重新登录,用户组变更才会生效

注意:生产环境服务器上,请谨慎评估将用户加入docker组的风险,因为这等同于赋予了该用户root权限。对于个人开发机,这是推荐的便捷做法。

验证安装是否成功,经典的三连击命令可以给你清晰的反馈:

# 检查Docker客户端和服务端版本
docker --version
docker version
# 运行一个测试容器,这是最直观的验证方式
docker run hello-world

如果看到“Hello from Docker!”的欢迎信息,恭喜你,你的Docker引擎已经准备就绪。对于macOS和Windows用户,直接下载并安装 Docker Desktop 是更省心的选择,它集成了图形化管理界面和必要的虚拟化组件。

1.2 镜像加速:告别漫长的等待

默认的Docker Hub镜像仓库位于海外,拉取镜像时速度可能非常缓慢,甚至超时失败。配置国内镜像加速器是提升体验的关键一步。你需要修改Docker守护进程的配置文件。

Linux系统的配置文件通常位于 /etc/docker/daemon.json(如果文件不存在,则创建它)。以下是一个配置示例,你可以添加多个镜像加速器地址,Docker会按顺序尝试。

{
  "registry-mirrors": [
    "https://docker.m.daocloud.io",
    "https://hub.ckyl.me",
    "https://dockerhub.jobcher.com"
  ]
}

提示:不同的镜像加速器在不同网络环境下稳定性各异。建议定期测试,选择当前网络下速度最快的1-2个即可,无需全部添加。

修改配置文件后,必须重启Docker服务使配置生效:

sudo systemctl daemon-reload
sudo systemctl restart docker

重启后,可以通过 docker info 命令查看 Registry Mirrors 一项,确认镜像加速器是否已成功配置。对于Docker Desktop用户,可以在设置界面(Preferences -> Docker Engine)中直接编辑 daemon.json 文件,保存后点击“Apply & Restart”即可。

2. 核心操作:镜像与容器的生命周期管理

掌握了环境的搭建,我们就进入了Docker的核心舞台:镜像和容器。理解它们的关系至关重要——镜像是静态的、不可变的模板,而容器则是这个模板运行起来的一个动态实例。你可以用一个镜像创建无数个容器。

2.1 镜像管理:获取、查看与清理

镜像管理是容器操作的基础。首先,我们从公共仓库拉取镜像。

# 拉取官方的最新版 nginx 镜像
docker pull nginx
# 拉取指定标签的镜像,如 alpine 轻量版
docker pull nginx:alpine
# 拉取特定版本的镜像
docker pull nginx:1.23

拉取镜像后,使用 docker images 或更详细的 docker image ls 来查看本地镜像列表。输出信息包括仓库名、标签、镜像ID、创建时间和大小。镜像ID是镜像的唯一标识。

随着使用,本地会积累很多中间镜像或旧版本镜像,占用大量磁盘空间。定期清理非常必要。

# 删除指定的镜像(可以使用镜像ID或仓库名:标签)
docker rmi nginx:alpine
# 强制删除一个镜像,即使有容器正在使用它(不推荐,可能导致容器异常)
docker rmi -f <image_id>
# 清理所有未被任何容器引用的悬空镜像(非常有用!)
docker image prune
# 交互式地批量删除镜像
docker image prune -a

2.2 容器操作:从创建到交互

容器是真正运行应用的地方。docker run 命令是其中最强大也最常用的命令,它结合了“创建”和“启动”两个动作。

# 基础运行:启动一个nginx容器,前台运行
docker run nginx:alpine
# 后台运行:-d 参数让容器在后台运行
docker run -d --name my-web nginx:alpine
# 端口映射:将容器的80端口映射到宿主机的8080端口
docker run -d -p 8080:80 --name my-web nginx:alpine
# 挂载数据卷:将宿主机的 ./html 目录挂载到容器的 /usr/share/nginx/html
docker run -d -v $(pwd)/html:/usr/share/nginx/html --name my-web nginx:alpine
# 设置环境变量:为容器内的应用传递配置
docker run -d -e “NGINX_HOST=myapp.com” --name my-web nginx:alpine

启动容器后,我们经常需要与之交互,进行调试或执行命令。

# 查看正在运行的容器
docker ps
# 查看所有容器(包括已停止的)
docker ps -a
# 查看容器的详细配置信息(JSON格式)
docker inspect my-web
# 查看容器的实时日志输出
docker logs my-web
# 持续跟踪日志输出(类似 tail -f)
docker logs -f my-web
# 进入一个正在运行的容器的交互式终端(最常用的调试命令)
docker exec -it my-web /bin/sh

注意docker execdocker attach 不同。exec 是开启一个新的终端进程连接到容器,而 attach 是直接连接到容器的主进程(通常是PID 1)。在生产环境中,除非特殊情况,否则应使用 exec 进行调试,避免影响主进程。

容器的停止、启动、重启和删除是日常维护的一部分。

# 优雅停止容器(发送SIGTERM信号,允许应用进行清理)
docker stop my-web
# 强制立即停止容器(发送SIGKILL信号)
docker kill my-web
# 启动一个已停止的容器
docker start my-web
# 重启容器(先stop再start)
docker restart my-web
# 删除一个已停止的容器
docker rm my-web
# 强制删除一个容器(无论运行与否)
docker rm -f my-web

3. 进阶实战:数据、网络与多容器编排

当单个容器无法满足复杂应用的需求时,我们就需要处理数据持久化、容器间通信和多服务协同的问题。这是从“会用Docker”到“用好Docker”的关键跨越。

3.1 数据持久化:告别“失忆”的容器

容器本身是临时性的,其内部文件系统的变更在容器删除后就会丢失。为了持久化数据(如数据库文件、应用日志、上传的文件),我们必须使用数据卷绑定挂载

数据卷是由Docker管理的一种特殊的目录,它独立于容器的生命周期。

# 创建一个名为 `my-data` 的数据卷
docker volume create my-data
# 启动容器并使用这个数据卷
docker run -d -v my-data:/var/lib/mysql --name mysql-db mysql:8
# 查看所有数据卷
docker volume ls
# 查看某个数据卷的详细信息,包括其在宿主机上的实际存储路径
docker volume inspect my-data
# 删除未使用的数据卷
docker volume prune

绑定挂载则是将宿主机的任意目录或文件直接挂载到容器中,更加灵活,常用于挂载配置文件或源代码目录进行开发。

# 将宿主机的当前目录挂载到容器的 /app 目录
docker run -d -v $(pwd):/app --name dev-app some-image
# 挂载单个配置文件
docker run -d -v /宿主机路径/nginx.conf:/etc/nginx/nginx.conf:ro nginx
# `:ro` 表示只读挂载,防止容器内进程误修改宿主机文件

3.2 网络互联:让容器彼此对话

默认情况下,每个容器都运行在独立的网络命名空间中。Docker提供了几种网络模式来满足不同的通信需求。

网络模式命令示例特点与适用场景
Bridge(桥接)docker run --net=bridge ...默认模式。容器通过虚拟网桥与宿主机通信,容器间可通过IP地址互通。适合单机多容器应用。
Host(主机)docker run --net=host ...容器直接使用宿主机的网络栈,没有隔离,性能最好。但端口冲突风险高。
None(无)docker run --net=none ...容器拥有独立的网络命名空间,但不进行任何网络配置。需要用户手动配置,用于高度定制化场景。
自定义网络docker network create my-net推荐用于多容器通信。提供自动的DNS服务发现(容器名即主机名)、更好的隔离性和控制。

创建和使用自定义网络是最佳实践:

# 创建一个名为 backend 的自定义桥接网络
docker network create backend
# 启动两个容器,并连接到同一个网络
docker run -d --name app --network backend my-app-image
docker run -d --name db --network backend mysql:8
# 现在,在 `app` 容器中,可以直接通过主机名 `db` 访问数据库容器
# 例如:ping db 或 mysql -h db -u root -p

3.3 Docker Compose:定义和运行多容器应用

当应用由多个服务(如Web服务器、应用服务器、数据库、缓存)组成时,手动使用 docker run 管理每个容器会变得异常繁琐。Docker Compose 正是为解决这一问题而生。它通过一个YAML文件(docker-compose.yml)来定义和配置所有服务。

下面是一个典型的 docker-compose.yml 示例,定义了一个WordPress应用(包含WordPress容器和MySQL数据库容器):

version: '3.8'
services:
  db:
    image: mysql:8.0
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: some_root_password
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress_password
    networks:
      - wp-network

  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    ports:
      - "8080:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress_password
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wp_data:/var/www/html
    networks:
      - wp-network

volumes:
  db_data:
  wp_data:

networks:
  wp-network:
    driver: bridge

使用Compose命令,你可以用一行指令管理整个应用栈:

# 在包含 docker-compose.yml 的目录下执行
# 启动所有服务(后台运行)
docker-compose up -d
# 查看服务运行状态
docker-compose ps
# 查看服务日志(可以指定服务名,如 `docker-compose logs wordpress`)
docker-compose logs -f
# 停止并移除所有容器、网络(默认保留数据卷)
docker-compose down
# 停止并移除所有容器、网络、数据卷
docker-compose down -v

4. 运维与排错:让容器稳定运行

将应用容器化并运行起来只是第一步,确保其长期稳定、高效、安全地运行,才是真正的挑战。这一部分我们将聚焦于日常运维、监控和常见问题排查。

4.1 系统监控与资源管理

了解Docker宿主机的资源使用情况和容器运行状态是运维的基础。

# 查看Docker系统层面的信息,包括容器/镜像数量、存储驱动、运行时等
docker info
# 实时监控所有容器的资源使用情况(类似Linux的top命令)
docker stats
# 查看指定容器的资源使用详情
docker stats my-web
# 查看容器的进程列表
docker top my-web
# 查看Docker磁盘使用情况(镜像、容器、数据卷、缓存等)
docker system df

docker stats 命令会动态显示每个容器的CPU、内存、网络I/O和块I/O使用率,是快速定位性能瓶颈的利器。

4.2 日志与故障排查

日志是排查问题的第一手资料。Docker将容器的标准输出和标准错误流捕获为日志。

# 查看容器最近日志
docker logs my-web
# 持续跟踪日志输出
docker logs -f my-web
# 查看最近10行日志
docker logs --tail 10 my-web
# 查看特定时间点之后的日志
docker logs --since “2023-10-01T10:00:00” my-web
# 结合时间戳查看日志
docker logs -t my-web

当容器行为异常时,docker inspect 命令能提供容器配置的完整快照,包括网络设置、挂载卷、环境变量、启动命令等,信息以JSON格式呈现,非常详尽。

# 获取容器的所有元数据
docker inspect my-web
# 仅获取容器的IP地址
docker inspect -f ‘{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}’ my-web
# 仅获取容器的状态信息
docker inspect -f ‘{{.State.Status}}’ my-web

4.3 系统清理与最佳实践

长期运行Docker,系统会积累大量停止的容器、未使用的镜像、网络和数据卷,占用宝贵的磁盘空间。定期清理是保持系统健康的好习惯。

# 交互式地清理所有未使用的Docker对象(镜像、容器、网络、构建缓存)
docker system prune
# 强制清理,无需确认
docker system prune -f
# 清理所有内容,包括未使用的数据卷(请谨慎,数据卷通常包含重要数据!)
docker system prune -a --volumes

除了命令,养成一些好的习惯能让你事半功倍:

  • 为容器命名:使用 --name 参数,比使用随机生成的容器ID友好得多。
  • 使用.dockerignore文件:在构建镜像时,忽略不必要的文件(如.git, node_modules, 日志文件),可以显著减少构建上下文大小和构建时间。
  • 理解镜像层缓存:在编写Dockerfile时,将变化频率低的指令(如安装系统包)放在前面,变化频率高的指令(如复制源代码)放在后面,可以充分利用缓存,加速镜像构建。
  • 不要在生产环境容器中存储数据:务必使用数据卷或绑定挂载来实现数据持久化。
  • 保持镜像精简:尽量使用Alpine等小型基础镜像,并在同一RUN指令中执行多个命令并清理缓存,以减小最终镜像体积。

容器化之旅就像学习一门新的手艺,命令是工具,而场景化的理解才是心法。这份手册里的每一个命令,都曾在我真实的项目场景中反复使用和验证。刚开始不必追求记住所有命令,遇到实际问题时,知道该用什么工具去解决,然后回来查阅,这才是最高效的学习方式。真正的熟练,来自于一次又一次的搭建、调试和优化。现在,打开你的终端,从运行第一个 docker run hello-world 开始,亲手去感受容器的魅力吧。如果在实践中遇到了这里没覆盖的“坑”,欢迎随时交流,那或许就是我们下一篇手册的起点。

更多推荐