【问题标题】:Supervisord only starts with Docker-ComposeSupervisord 仅从 Docker-Compose 开始
【发布时间】:2021-11-28 06:52:24
【问题描述】:

我有以下 Dockerfile,对 Nginx 服务器进行了一些自定义。我使用docker build -t nginx-custom:1.21.1 . 命令构建图像,完成时没有错误。但是,当我想使用docker run -it -d nginx-custom:1.21.1 /bin/bash 命令从此图像创建容器时,也不会出现任何错误。但是当我使用docker exec 命令进入容器并使用ps -ef 检查正在运行的进程时,结果只包含bash 进程。

FROM nginx:1.21.1 AS nginx-base

RUN set -x \
    && apt-get update \
    && apt-get install --no-install-recommends --no-install-suggests -y man nano procps ca-certificates wget gnupg gnupg2 iputils-ping net-tools supervisor \
    && apt-get clean autoclean \
    && apt-get autoremove --yes \
    && rm -rf /var/lib/{apt,dpkg,cache,log}/

EXPOSE  80 443

WORKDIR /var/www

COPY config/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
CMD ["service supervisor restart"]

FROM nginx-base AS nginx-config

# Replace the original Nginx config file
COPY config/nginx.conf /etc/nginx/nginx.conf

# Test HTML file
COPY scripts/index.html /var/www/html/index.html

在一些失败之后,我创建了一个包含以下内容的 compose 文件并运行了下一个命令:docker-compose up -d --build 然后一切正常。所有必要的进程都在运行。

version: '3.8'

services:
  nginx-custom:
    tty: true
    build:
      context: .
      dockerfile: Dockerfile
    image: nginx-custom:1.21.1
    container_name: nginx-custom
    networks:
      devnet:
        ipv4_address: 172.18.0.4
    restart: unless-stopped

networks:
  devnet:
    external: true

有人知道为什么主管只能这样工作吗?

【问题讨论】:

    标签: docker nginx docker-compose supervisord


    【解决方案1】:

    一个 Docker 容器只运行一个进程。如果您需要在单个容器中运行多个进程,则需要像 supervisord 这样的进程管理器,但这通常被认为是一种反模式。标准的 Docker Hub 镜像大致分为三种:基本操作系统镜像(alpineubuntu);语言工具链和运行时(pythonnodegolang);以及运行一些实际程序的东西(postgresqlnginx)。在最后一种情况下,基本映像已经配置为将程序作为单个主容器进程运行。

    这意味着您可以将 Dockerfile 缩减为仅

    FROM nginx:1.21.1
    COPY config/nginx.conf /etc/nginx/nginx.conf
    COPY scripts/index.html /var/www/html/index.html
    

    并且基础镜像已经有一个正确的CMD。您不需要文本编辑器、手册页或低级网络调试工具,因为这个容器唯一要做的就是提供网页服务。


    一个 Docker 容器只运行一个进程。有几种方法可以指定它。 Dockerfile CMD 是默认值,但它可以被 Compose command: 或通过在 docker run 图像名称之后放置命令来覆盖。这意味着,如果您 docker run --rm -it your-image /bin/bash,交互式 shell 将运行 而不是 Dockerfile 中的 CMD

    这里最简单的答案是不用担心运行交互式 shell。 docker run 没有命令的图像。 docker exec 谨慎;这是一个非常有用的调试工具,但通常不是您与容器交互的主要方式。

    # do not override the command at the end
    docker run -d -p 8080:80 nginx-custom:1.21.1
    

    一个 Docker 容器只运行一个进程。当该过程完成时,容器退出。这意味着主容器进程需要是一个长时间运行的前台进程;它不能是启动后台进程然后完成的脚本,也不能是“服务”类型的命令。

    基础nginx 图像会显示类似

    CMD ["nginx", "-g", "daemon off;"]
    

    将 Nginx 服务器作为前台进程启动。

    如果你真的需要run supervisord,那么主CMD需要运行supervisord而不是service命令,它需要一个-n选项来运行它在前台。如果您使用 CMD 的 JSON 数组形式,那么您有责任自己将命令分解为单词。如果有嵌入的空格(如我的示例中的 daemon off; 或问题中的 CMD),它们将被视为包含空格的单个单词,就像您在 shell 中引用它一样。

    CMD ["supervisord", "-n"]
    

    一般来说,像service 这样的命令在 Docker 中不起作用,原因有几个。由于它们会执行一些操作并立即返回,因此它们不适合作为主容器命令。如果您像在问题中那样说“重新启动”,则该服务以前不会运行。如果环境依赖于某个 init 守护进程,它也不会运行,servicesystemctl 将无法与之对话。不要尝试引入init系统,直接作为单个前台主容器进程运行命令即可。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-11
      • 2019-04-22
      • 1970-01-01
      • 2020-11-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多