Docker-Compose启动自定义镜像容器自动退出,手动运行正常的解决求助
解决Docker Compose中自定义构建容器启动后直接退出的问题
问题场景
现有如下docker-compose.yml文件:
version: "3.9" services: # Database db: image: mysql:5.7 volumes: - db_data:/var/lib/mysql - ./schemas/mysql.sql:/data/application/init.sql restart: always ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: 123 MYSQL_ROOT_HOST: 10.5.0.1 MYSQL_DATABASE: forgottenserver MYSQL_PASSWORD: 123 command: --init-file /data/application/init.sql networks: tibia: ipv4_address: 10.5.0.5 # phpmyadmin phpmyadmin: depends_on: - db image: phpmyadmin restart: always ports: - "8090:80" environment: PMA_HOST: db MYSQL_ROOT_PASSWORD: 123 networks: tibia: ipv4_address: 10.5.0.3 networks: tibia: driver: bridge ipam: config: - subnet: 10.5.0.0/16 gateway: 10.5.0.1 volumes: db_data:
以及用于构建可执行程序的Dockerfile:
FROM ubuntu:20.04@sha256:bffb6799d706144f263f4b91e1226745ffb5643ea0ea89c2f709208e8d70c999 ENV TZ=America/Sao_Paulo ENV WD=/home/tibia/server ARG DEBIAN_FRONTEND=noninteractive RUN useradd --system --create-home --shell /bin/bash --gid root --groups sudo --uid 1001 tibia RUN apt-get update -y && \ apt-get upgrade -y && \ apt-get install --no-install-recommends -y tzdata \ autoconf automake pkg-config build-essential cmake \ liblua5.1-0-dev libsqlite3-dev libmysqlclient-dev \ libxml2-dev libgmp3-dev libboost-filesystem-dev \ libboost-regex-dev libboost-thread-dev USER tibia WORKDIR $WD COPY . . RUN mv config.lua.dist config.lua && \ mkdir build && \ cd build && \ cmake .. && \ make -j$(grep processor /proc/cpuinfo | wc -l) EXPOSE 7171 7172 CMD ["/bin/bash"]
将以下server服务配置加入compose文件后,执行docker-compose up启动所有服务时,该自定义构建的容器会直接退出且不会重启:
# ... services: server: build: . ports: - "7171:7171" - "7172:7172" networks: tibia: ipv4_address: 10.5.0.4
但仅启动compose中的db和phpMyAdmin服务后,通过以下docker run命令手动启动镜像,容器却能正常运行:
docker run -itd --network=3777_tibia --ip 10.5.0.4 -p 7171:7171 -p 7172:7172 3777_server
问题原因
问题出在Dockerfile的CMD配置以及compose的启动参数上:
- Dockerfile中指定的
CMD ["/bin/bash"]会启动bash终端,但在Docker Compose默认启动模式下,没有分配TTY终端和标准输入,bash启动后没有可交互的输入源,会立即退出。 - 手动执行
docker run时使用了-it参数,其中-i开启标准输入,-t分配TTY终端,这让bash能保持运行状态。
解决方案
方法一:在Compose配置中添加终端支持
修改compose中的server服务配置,添加tty: true和stdin_open: true,模拟交互式终端环境:
services: server: build: . ports: - "7171:7171" - "7172:7172" networks: tibia: ipv4_address: 10.5.0.4 tty: true stdin_open: true
方法二:修改Dockerfile,直接启动服务程序
既然该Dockerfile是用来构建可执行程序的,应该直接运行编译后的服务程序而非bash。假设编译后的可执行文件位于build/forgottenserver(需根据实际编译产物调整路径和文件名),修改Dockerfile的CMD:
# 替换原CMD行 CMD ["./build/forgottenserver"]
这种方式更符合Docker容器的设计理念——容器应专注运行单一服务进程,而非交互式终端,也能避免容器因终端问题退出。
内容的提问来源于stack exchange,提问作者João Casarin
相关产品推荐
相关产品推荐

