1. 概述

Docker 容器本质上是运行一个进程、应用或脚本的载体。当容器内没有任何进程或脚本运行时,容器会自动停止并退出。像 MySQL 数据库、Spring Boot 应用或 SMTP 邮件服务器这类容器,默认会持续运行直到用户手动停止。但有时我们需要让容器在完成主要任务后仍保持运行状态,比如 Ubuntu 容器。

本文将介绍在 Docker Compose 中实现这一目标的几种方法。

2. Docker Compose 环境准备

Docker Compose 是用于定义和运行多容器服务的工具。只需在支持的操作系统(本教程使用 Linux Ubuntu)上安装 Docker(包括 Docker Server、Client 和 Compose)即可开始。

3. 运行 Ubuntu 容器

我们使用名为 docker-compose.yml 的配置文件定义服务:

services:
  demo:
    image: ubuntu

3.1. 启动 Docker Compose 服务

使用 -d 选项在后台运行服务容器:

$ docker-compose up -d

命令输出显示容器创建成功:

Creating ubuntu_demo_1 ... done

检查容器运行状态(使用 docker ps -a 列出所有容器):

$ docker ps -a

输出显示容器已退出:

CONTAINER ID   IMAGE     COMMAND          CREATED          STATUS                     PORTS     NAMES
a66cec15e72c   ubuntu    "/bin/bash"      10 seconds ago   Exited (0) 9 seconds ago             ubuntu_demo_1

Docker Compose 创建的 ubuntu_demo_1 容器启动后立即退出。接下来我们通过以下方法保持容器运行:

✅ 分配伪终端(TTY)
✅ 使用 tail 命令
✅ 使用 sleep 命令
✅ 使用无限循环脚本

3.2. 测试间清理环境

在尝试不同方法前,建议清理环境(使用 docker-compose down 移除容器):

$ docker-compose down
Stopping ubuntu_demo_1 ... done
Removing ubuntu_demo_1 ... done
Removing network ubuntu_default

此命令会同时删除关联的网络和卷。

4. 分配伪终端(TTY)

为 Ubuntu 容器分配伪终端可保持其运行。伪终端(pseudo-TTY)通过软件模拟终端会话,无需物理设备驱动。

在配置文件中添加 tty: true

services:
  demo:
    image: ubuntu
    tty: true

启动服务并检查状态:

$ docker-compose up -d
$ docker ps

输出显示容器持续运行:

CONTAINER ID   IMAGE     COMMAND       CREATED          STATUS          PORTS     NAMES
dcc44f90a9eb   ubuntu    "/bin/bash"   16 seconds ago   Up 13 seconds             ubuntu_demo_1

分配 TTY 后,Docker 守护进程会保持主进程运行,从而维持容器状态。

5. 使用 tail 命令

**另一种简单粗暴的方法是使用 tail 命令**:

services:
  demo:
    image: ubuntu
    command: "tail -f /dev/null"

这里利用 tail -f 持续读取输入,/dev/null 作为"永远读不完"的设备,使容器保持运行。

启动服务后验证:

$ docker ps
CONTAINER ID   IMAGE     COMMAND               CREATED          STATUS          PORTS     NAMES
5b293dbf6cc9   ubuntu    "tail -f /dev/null"   18 seconds ago   Up 17 seconds             ubuntu_demo_1

容器成功保持运行状态。

6. 使用 sleep 命令

通过 sleep 命令也能维持容器运行

services:
  demo:
    image: ubuntu
    command: "sleep infinity"

此方法本质是在容器 bash 中创建 TTYinfinity 参数使命令永不结束。

验证容器状态:

$ docker ps
CONTAINER ID   IMAGE     COMMAND               CREATED          STATUS          PORTS     NAMES
c55a8b1f3839   ubuntu    "sleep infinity"      2 minutes ago    Up 2 minutes              ubuntu_demo_1

容器持续运行中。

7. 使用无限循环脚本

结合 whiledo 命令创建无限循环脚本

services:
  demo:
    image: ubuntu
    command: "sh -c 'while true; do sleep 1; done'"

启动服务后检查:

$ docker ps
CONTAINER ID   IMAGE     COMMAND                     CREATED           STATUS          PORTS     NAMES
1f690849f774   ubuntu    "sh -c 'while true; …"      14 seconds ago    Up 12 seconds              ubuntu_demo_1

while true 条件永远成立,容器持续运行。

⚠️ 相比 sleep infinity,无限循环的优势在于可在循环中执行其他任务(如输出日志或检查进程状态)。

8. 为何不适用于 hello-world 镜像?

注意:并非所有容器都能用上述方法保持运行。前述方法的前提是容器内能运行 bash 和 Linux 命令,这对 Ubuntu 等基础镜像有效。

hello-world 镜像无法保持运行,查看其 Dockerfile:

FROM scratch
COPY hello /
CMD ["/hello"]

scratch 是极简基础镜像,不提供 Linux 环境,因此无法执行 bash 或其他命令。

9. 总结

本文介绍了在 Docker Compose 中保持容器运行的四种方法。需注意:并非所有容器都需要显式配置——像数据库或 Web 应用这类容器,其主进程会自然保持运行状态。

同时,某些容器(如 hello-world)因缺乏 Linux 环境,无法通过命令维持运行。选择方法时需根据镜像特性判断。

本文涉及的 Docker 命令脚本可在 GitHub 获取。


原始标题:How to Keep a Container Running in Docker Compose | Baeldung