You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker Entrypoint脚本trap函数内echo输出无法在docker-compose中显示

Docker-Compose中SIGINT陷阱函数输出无法实时显示的问题及解决方案

问题背景

使用docker-compose管理Postgres容器时,自定义Entrypoint脚本通过trap捕获SIGINT信号,执行数据库备份后再停止容器。实际测试中,备份操作正常执行,但shutdown函数中的echo输出无法在docker-compose up的附加模式下实时显示,仅能通过docker logs查看。

相关代码

自定义Entrypoint脚本

#!/bin/bash

backup_dir="/backup"

# Define a function to handle the SIGINT signal (graceful shutdown)
echo "[+] Postgres customer_entrypoint ran."

shutdown() {
    echo "[+] Backing up database before shutdown."
    pg_dumpall --on-conflict-do-nothing --column-inserts -U "$POSTGRES_USER" > "/backups/backup_$(date +%Y-%m-%d_%H-%M-%S).sql"
    pg_ctl -D "$PGDATA" -m fast -w stop
}

trap shutdown SIGINT

/usr/local/bin/docker-entrypoint.sh postgres &

wait $!

docker-compose配置

version: '3.3'
services:
  postgres:
    container_name: postgres
    build:
      context: ./postgres
      dockerfile: Dockerfile-postgres.dev
    image: postgres-my:latest
    restart: always
    env_file:
      - ./.env.dev.db
    ports:
        - '127.0.0.1:5432:5432'
    volumes:
      - ./postgres/backups:/backups
      - postgres_data_dev:/var/lib/postgresql/data
    stop_signal: SIGINT

volumes:
    postgres_data_dev:

执行命令

sudo docker-compose -f docker-compose.dev up --build

原因分析

  1. 输出缓冲问题:bash默认会对stdout进行缓冲,脚本处理信号时,缓冲的输出可能无法及时刷新到终端,直到进程退出后才写入日志。
  2. docker-compose输出流关闭时机:按下Ctrl+C后,docker-compose触发容器停止流程,可能提前关闭与容器的输出流连接,导致陷阱函数的输出无法传输到前端终端。
  3. 进程结构影响:脚本将官方postgres入口脚本放在后台运行,主进程处于wait状态,信号处理过程中的输出转发机制受限。

解决方案

1. 将陷阱函数输出定向到stderr

docker-compose附加模式下,stderr通常无缓冲实时转发,修改shutdown函数的echo语句,将输出发送到stderr:

shutdown() {
    echo "[+] Backing up database before shutdown." >&2
    pg_dumpall --on-conflict-do-nothing --column-inserts -U "$POSTGRES_USER" > "/backups/backup_$(date +%Y-%m-%d_%H-%M-%S).sql"
    pg_ctl -D "$PGDATA" -m fast -w stop
}

2. 增加优雅停止超时时间

在docker-compose.yml中添加stop_grace_period,给陷阱函数足够的执行和输出时间,避免docker-compose提前关闭输出流:

services:
  postgres:
    # ... 原有配置
    stop_signal: SIGINT
    stop_grace_period: 30s

3. 禁用脚本输出缓冲

在自定义Entrypoint脚本开头添加以下语句,强制关闭stdout和stderr的缓冲:

#!/bin/bash
# 禁用输出缓冲
exec 1>&0
exec 2>&0

backup_dir="/backup"
# ... 后续脚本内容

4. 调整后台进程的启动方式

使用stdbuf命令启动postgres入口脚本,强制其输出无缓冲:

# 替换原有的后台启动命令
stdbuf -i0 -o0 -e0 /usr/local/bin/docker-entrypoint.sh postgres &

验证效果

修改后重新执行docker-compose up --build,按下Ctrl+C后,即可在终端实时看到shutdown函数的输出信息,同时备份操作正常执行。

内容的提问来源于stack exchange,提问作者Dave

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 14:53:14