Docker 系列 | 03 - Docker 核心概念:容器 (Container) 详解与实战

引言

在之前的文章中,我们了解了 Docker 的核心概念之一——镜像(Image),它是容器的静态蓝图。本篇文章将聚焦于 Docker 的另一个核心——**容器 (Container)**。容器是镜像的运行实例,是真正承载应用程序运行的独立、隔离的环境。

理解容器的生命周期、运行方式以及如何与容器进行交互,是您开始使用 Docker 部署应用程序的关键。我们将通过理论讲解和实际操作,带您全面掌握容器。

什么是 Docker 容器?

Docker 容器是 Docker 镜像的一个可运行实例。它是一个轻量级、独立的、可执行的软件包,包含应用程序运行所需的所有组件:代码、运行时、系统工具、系统库以及配置文件。

与虚拟机不同,容器不是模拟完整的操作系统,而是利用宿主机的操作系统内核,通过 Linux 内核的 命名空间 (Namespaces)控制组 (Control Groups, cgroups) 技术,实现资源隔离和限制。

容器的特点:

  • 隔离性:每个容器都有自己独立的文件系统、进程空间、网络接口和用户空间,相互之间不会干扰。
  • 可写层:容器在镜像的只读层之上添加了一个可写的“容器层”,所有运行时产生的数据变化都只发生在此层。
  • 生命周期:容器可以被创建、启动、停止、重启、删除。
  • 可移植性:容器可以在任何支持 Docker 的宿主机上运行,无论宿主机的操作系统是什么(只要 Docker 引擎支持)。

容器的生命周期

容器的生命周期相对简单,主要包括以下几个阶段:

  • **创建 (Created)**:使用 docker create 命令创建容器,但它尚未启动。
  • **运行 (Running)**:使用 docker start 命令启动已创建的容器,或使用 docker run 命令直接创建并启动容器。
  • **暂停 (Paused)**:使用 docker pause 命令暂停容器的所有进程。
  • **停止 (Stopped)**:使用 docker stop 命令优雅地停止容器中的主进程。
  • **删除 (Deleted)**:使用 docker rm 命令删除已停止的容器。

容器操作:核心命令实战

我们将通过一些常用的 Docker 命令来演示容器的创建、运行和管理。

1. 运行容器:docker run

docker run 命令是使用 Docker 最常用的命令,它集成了创建、启动和运行容器的功能。

基本语法:

1
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

示例 1:运行一个简单的 Nginx Web 服务器

1
2
3
4
5
6
# 运行 Nginx 容器,并将容器的 80 端口映射到主机的 8080 端口
# -d: 后台运行容器(detached mode)
# -p 8080:80: 端口映射,将主机 8080 端口映射到容器 80 端口
# --name my-nginx: 为容器指定一个名称
# nginx:latest: 使用 Nginx 的最新镜像
docker run -d -p 8080:80 --name my-nginx nginx:latest

运行后,您可以在浏览器中访问 http://localhost:8080,看到 Nginx 的欢迎页面。

示例 2:运行一个临时容器并执行命令

1
2
3
4
5
# 运行一个 Ubuntu 容器,并在其中执行 `echo "Hello from Docker!"` 命令
# --rm: 容器退出后自动删除
# ubuntu:latest: 使用 Ubuntu 最新镜像
# echo "Hello from Docker!": 在容器中执行的命令
docker run --rm ubuntu:latest echo "Hello from Docker!"

这个命令会打印 Hello from Docker!,然后容器会自动退出并删除。

2. 查看运行中的容器:docker ps

docker ps 命令用于列出当前正在运行的容器。

1
2
3
4
5
# 列出所有正在运行的容器
docker ps

# 列出所有容器(包括已停止的)
docker ps -a

3. 查看容器日志:docker logs

docker logs 命令用于查看容器的输出日志。

1
2
3
4
5
6
7
8
# 查看名为 my-nginx 容器的所有日志
docker logs my-nginx

# 实时查看日志(类似 tail -f)
docker logs -f my-nginx

# 查看最近 N 行日志
docker logs --tail 10 my-nginx

4. 进入容器内部:docker exec

docker exec 命令用于在运行中的容器内执行命令。这对于调试或手动配置容器非常有用。

1
2
3
4
5
6
7
# 进入 my-nginx 容器的 bash 终端
# -it: -i 保持标准输入打开,-t 分配一个伪TTY
docker exec -it my-nginx bash

# 进入容器后,你可以像在普通的 Linux 系统中一样操作
# 例如:ls -l /etc/nginx/conf.d/
# 退出容器终端:exit

5. 停止和启动容器:docker stop / docker start

  • docker stop 命令会向容器发送一个 SIGTERM 信号,等待一段时间(默认 10 秒)后如果容器仍未停止,则发送 SIGKILL 强制终止。
  • docker start 命令会启动一个或多个已停止的容器。
1
2
3
4
5
# 停止名为 my-nginx 的容器
docker stop my-nginx

# 启动名为 my-nginx 的容器
docker start my-nginx

6. 重启容器:docker restart

docker restart 命令用于重启一个或多个容器。

1
2
# 重启名为 my-nginx 的容器
docker restart my-nginx

7. 删除容器:docker rm

docker rm 命令用于删除一个或多个已停止的容器。不能删除正在运行的容器,除非使用 -f (force) 选项。

1
2
3
4
5
6
7
8
9
# 删除名为 my-nginx 的容器(确保已停止)
docker rm my-nginx

# 强制删除正在运行的容器
# 注意:这会立即终止容器进程,可能导致数据丢失
docker rm -f my-nginx

# 删除所有已停止的容器
docker rm $(docker ps -aq)

容器的隔离性:命名空间 (Namespaces) 和控制组 (cgroups)

Docker 容器的隔离性是其核心优势之一。这主要归功于 Linux 内核的两种技术:

  1. 命名空间 (Namespaces):

    • 为每个容器提供独立的系统资源视图。
    • 例如,PID 命名空间让每个容器有自己的进程ID空间(容器内部的第一个进程ID通常是1)。
    • NET 命名空间让每个容器有自己的网络接口、IP 地址和路由表。
    • MNT 命名空间让每个容器有自己的文件系统挂载点。
    • UTS 命名空间让每个容器有自己的主机名和域名。
    • USER 命名空间让每个容器有自己的用户和组ID映射。
  2. 控制组 (Control Groups, cgroups):

    • 用于限制、衡量和隔离进程组的资源使用(CPU、内存、磁盘 I/O、网络带宽等)。
    • Docker 利用 cgroups 来确保每个容器只能使用分配给它的资源,避免资源争抢,保证容器运行的稳定性。

这些内核技术共同协作,为每个容器提供了一个看似独立的、完整的操作环境,而实际上它们共享着宿主机的内核,从而实现了轻量且高效的隔离。

结语

本篇文章详细讲解了 Docker 容器的概念、生命周期以及常用的操作命令。通过 docker rundocker psdocker logsdocker execdocker stopdocker startdocker rm 等命令,您已经可以自如地管理容器了。我们也初步了解了容器隔离性的底层技术。

在下一篇文章中,我们将回到镜像的构建,深入学习如何编写 Dockerfile,通过代码定义我们自己的镜像,从而实现应用程序的标准化打包。