Docker——容器深入理解


整体说明

  • TLDR:容器的本质是封装了指定命令的进程

容器生命周期管理

  • 启动容器:
    • docker run [OPTIONS] IMAGE [COMMAND] [ARG...]:该命令用于从镜像创建并启动一个新的容器
      • [COMMAND] 是希望在容器启动时执行的程序或脚本,而 [ARG…] 就是这个程序或脚本运行所需的额外信息,比如 ls -l /
    • docker start [OPTIONS] CONTAINER [CONTAINER...]:该命令用于启动一个或多个已经停止的容器
    • 常用选项:
      • -d:后台运行容器
      • -p:端口映射,如 -p 8080:80 将宿主机的 8080 端口映射到容器的 80 端口
      • -v:数据卷挂载,如 -v /host/data:/container/data 将宿主机的目录挂载到容器内,可多次使用 -v 参数挂在多个目录
      • --name:给容器指定一个名称,如 --name my-web-app
      • -it:交互式终端,i 保持标准输入打开,t 分配一个伪终端
  • 停止容器:
    • docker stop [OPTIONS] CONTAINER [CONTAINER...]:优雅地停止一个或多个运行中的容器
    • docker kill [OPTIONS] CONTAINER [CONTAINER...]:强制停止一个或多个容器,不进行任何清理
    • docker restart [OPTIONS] CONTAINER [CONTAINER...]:重启一个或多个容器
  • 删除容器:
    • docker rm [OPTIONS] CONTAINER [CONTAINER...]:删除一个或多个已停止的容器
    • docker rm -f CONTAINER:强制删除一个正在运行的容器

查看容器信息

  • 查看容器:
    • docker ps [OPTIONS]:列出所有正在运行的容器
    • 常用选项:
      • -a:列出所有容器,包括已停止的
      • -s:显示总文件大小
      • -l:显示最新创建的容器
  • 查看容器日志:
    • docker logs [OPTIONS] CONTAINER:获取容器的日志
    • 常用选项:
      • -f:实时跟踪日志输出
      • --tail N:仅显示最新的 N 行日志
  • 查看容器详细信息:
    • docker inspect [OPTIONS] CONTAINER [CONTAINER...]:获取容器的详细配置和状态信息,以 JSON 格式输出
  • 查看容器资源使用情况:
    • docker stats [OPTIONS] [CONTAINER...]:实时显示一个或多个容器的 CPU、内存、网络 I/O 和块 I/O 使用情况

容器内部操作

  • 进入容器内部:
    • docker exec [OPTIONS] CONTAINER COMMAND [ARG...]:在运行中的容器内执行命令。这是最常用的方式,因为它不会启动新的进程
    • 常用例子:
      • docker exec -it my-container bash:在名为 my-container 的容器中启动一个 bash 终端
      • docker exec my-container ls -l /:在容器中执行 ls -l / 命令
  • 复制文件到容器或从容器复制文件:
    • docker cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH:从宿主机复制文件到容器
    • docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH:从容器复制文件到宿主机

容器进阶管理

  • 暂停/恢复容器:
    • docker pause CONTAINER [CONTAINER...]:暂停容器内的所有进程。容器状态变为 paused,资源仍然被占用
    • docker unpause CONTAINER [CONTAINER...]:恢复被暂停的容器
  • 清理无用容器:
    • docker container prune:删除所有已停止的容器
  • 批量管理:
    • docker stop $(docker ps -a -q):停止所有容器
    • docker rm $(docker ps -a -q):删除所有容器
    • 注意docker ps -a -q 会列出所有容器的 ID

docker create 和 docker run 的区别

  • TLDR:docker run = docker create + docker start

docker create

  • docker create 命令只负责从一个镜像创建一个容器
  • docker create 它会为容器分配一个 ID,设置好配置(如端口映射、数据卷等),但不会启动容器
  • 总结 docker create 命令:
    • 只创建,不启动 :容器处于“已创建”(Created)状态
    • 分步操作 :您需要先使用 docker create 创建容器,然后再使用 docker start 来启动它
    • 适用场景 :当你需要先配置好容器,但暂时不希望它运行,或者需要对容器进行额外的配置或检查后才启动时,这个命令很有用
      • 例如,在自动化脚本中,您可以先批量创建容器,然后再按需启动

docker run

  • docker run 命令是 docker createdocker start 的组合
  • docker run 它从一个镜像创建一个新的容器,并立即启动
  • 总结 docker run 命令:
    • 创建并启动 :这是最常用的方式,一步到位
    • 一步到位 :大部分情况下,你希望容器创建后立即运行,所以 docker run 更方便快捷
    • 适用场景 :这是日常开发和部署中最常见的命令,因为它简化了操作流程

示例

  • 如果想创建一个 Nginx 容器并让它在后台运行,可以使用:

    1
    docker run -d --name my-nginx nginx
  • 这一个命令就完成了创建和启动

  • 但如果你想分步操作,可以这么做:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 只创建容器,容器不会运行,注意,容器启动命令在这里传入
    docker create --name my-nginx-created nginx

    # 检查容器是否已创建(状态为 "Created")
    docker ps -a

    # 手动启动这个已创建的容器
    docker start my-nginx-created

    # 检查容器是否已启动(状态为 "Up")
    docker ps

附录:一个 docker 容器创建和启动的实例

  • 容器创建:

    1
    docker create --runtime=nvidia --gpus all --net=host --shm-size="10g" --cap-add=SYS_ADMIN -v .:/workspace/python_demo --name python_demo <image:tag> sleep infinity
    • --runtime=nvidia:使用 NVIDIA 容器运行时,支持 GPU 加速
    • --gpus all:允许容器使用所有可用 GPU
    • --net=host:使用主机网络模式,容器与主机共享网络栈
    • --shm-size="10g":设置共享内存大小为 10GB,提升进程间通信效率
    • --cap-add=SYS_ADMIN:添加系统管理员权限,允许容器内执行更多系统操作
    • -v .:/workspace/python_demo:将当前目录挂载到容器内的 /workspace/python_demo 目录
    • --name python_demo:给容器命名为 “python_demo”
    • <image:tag>:指定要使用的 Docker 镜像及标签
    • sleep infinity:容器启动后执行无限休眠命令,保持容器运行
  • 启动容器:

    1
    docker start python_demo
    • 启动名为 “python_demo” 的容器
    • 执行此命令后,之前创建的容器将开始运行
  • 进入容器终端与容器交互:

    1
    docker exec -it python_demo bash
    • 进入 “python_demo” 容器的 bash 交互终端
    • -it:以交互式终端模式进入容器
    • python_demo:目标容器名称
    • bash:在容器内启动 bash shell
  • 以上所有命令也可以使用一个 docker run 命令来实现


附录:Linux 中的 sleep infinity 命令常用于 docker 容器

  • 在 Linux 系统中,sleep infinity 命令会让进程进入无限期休眠状态
    • sleep 命令的作用是让当前进程暂停指定的时间
    • 当使用 infinity 作为参数时,它表示”无限长的时间”
    • 这会导致执行该命令的进程一直处于休眠状态,不会自动退出
    • 要终止这个进程,需要手动干预(通常使用 Ctrl+C 快捷键或 kill 命令)
  • 这种命令常用于需要保持容器运行的场景(如 Docker 容器),或者作为一种简单的方式让进程在后台持续运行而不占用过多系统资源
  • 由于进程处于休眠状态,它只会占用极少的系统资源(主要是进程表项)

终端于进程的关系

  • TLDR:终端存在是进程持续运行的一个条件(避免被 SIGHUP 终止),但进程本身还需要有“不主动退出”的逻辑(如无限循环、sleep infinity 等)才能一直运行
    • sleep infinity 是实现这种“不退出”的简单高效方式
  • 前台进程与终端的关系
    • 如果进程是在终端中直接启动的前台进程(比如直接执行 python script.py),那么当终端关闭时,该进程会收到 SIGHUP(挂断信号),通常会随之终止=
    • 这种情况下,即使不关闭终端,进程也可能因为自身逻辑结束(比如脚本执行完毕)而退出,并非“一直运行”
  • 后台进程的特殊性
    • 如果用 & 将进程放到后台(如 python script.py &),终端关闭时它仍可能被 SIGHUP 终止(取决于 shell 配置,如 huponexit 选项)
    • 即使终端保持打开,后台进程若自身逻辑执行完毕(比如循环结束),也会自动退出
  • sleep infinity 的作用
    • sleep infinity 的核心是让进程进入“无限等待”状态,自身不会主动结束,且几乎不消耗资源
    • sleep infinity 与普通进程的区别在于:
      • 普通进程需要自身逻辑(如无限循环)来维持运行,可能消耗 CPU 或内存;
      • sleep infinity 是利用系统调用让进程进入休眠,本质上是“挂起等待”,资源占用极低
  • 终端存在≠进程持续运行
    • 终端存在只是避免了 SIGHUP 导致的终止,但进程是否持续运行仍取决于其自身是否会主动退出
    • 比如执行 echo "hello" 后,终端还在,但进程已经结束;
    • sleep infinity 无论终端是否关闭(若处理了 SIGHUP),都会一直休眠