Home > database >  Supervisord only starts with Docker-Compose
Supervisord only starts with Docker-Compose

Time:10-08

I have the following Dockerfile with a bit of customization for Nginx server. I build the image with docker build -t nginx-custom:1.21.1 . command finished without errors. But when I want to create a container from this image with docker run -it -d nginx-custom:1.21.1 /bin/bash command also not appears any errors. But when I enter to container with docker exec command and check running processes with ps -ef the result contains only the bash process.

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

After some failures I create a compose file with the following content and ran the next command: docker-compose up -d --build then everything is OK. All necessary processes are running.

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

Does anyone know why the Supervisor only works this way?

CodePudding user response:

A Docker container only runs a single process. You need some process manager like supervisord if you need to run multiple processes in a single container, but that's usually considered an anti-pattern. The standard Docker Hub images roughly break into three varieties: base OS images (alpine, ubuntu); language toolchains and runtimes (python, node, golang); and things that run some actual program (postgresql, nginx). In the last case the base image is already configured to run the program as the single main container process.

This means you can reduce the Dockerfile to just

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

and the base image already has a correct CMD. You don't need a text editor, man pages, or low-level network debugging tools, since the only thing this container is going to do is serve Web pages.


A Docker container only runs a single process. There are a couple of ways to specify it. The Dockerfile CMD is a default, but it can be overridden by Compose command: or by putting a command after the docker run image name. That means, if you docker run --rm -it your-image /bin/bash, the interactive shell runs instead of the CMD in the Dockerfile.

The simplest answer here is to just not worry about running an interactive shell. docker run the image without a command. docker exec sparingly; it's a really useful debugging tool, but not generally the primary way you'll interact with your container.

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

A Docker container only runs a single process. When that process completes, the container exits. This means the main container process needs to be a long-running foreground process; it can't be a script that launches background processes and then completes, or a "service"-type command.

The base nginx image will say something like

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

which launches the Nginx server as a foreground process.

If you really need to run supervisord, then the main CMD needs to run supervisord and not a service command, and it needs a -n option to run it in the foreground. If you use the JSON-array form of CMD then you are responsible for breaking the command into words yourself. If there are embedded spaces (as in daemon off; in my example, or the CMD in the question) they are treated as a single word with spaces include, like if you quoted it in the shell.

CMD ["supervisord", "-n"]

Generally commands like service don't work in Docker, for a couple of reasons. Since they do some action and return immediately they're not suitable as the main container command. If you say "restart" as you do in the question, the service won't have previously been running. If the environment depends on some init daemon, that won't be running either, and service or systemctl won't be able to talk to it. Don't try to introduce an init system, just run the command directly as the single foreground main container process.

  • Related