Software Development

Docker Compose Keep Container Running Example

This article begins by examining why Docker containers exit, followed by techniques to ensure they remain running when orchestrated with Docker Compose. One of the initial challenges we encounter with Docker Compose is that containers often exit immediately after starting. This can be confusing if you are new to Docker and expect containers to persist like virtual machines. However, Docker containers are designed to run a single main process, and when that process finishes, the container exits.

1. Why Docker Containers Exit

Docker containers exit because they are designed to run a single primary process, which is specified either by the CMD or ENTRYPOINT in the Dockerfile, or by the command provided at runtime. Once this process finishes, the container stops automatically.

Unlike virtual machines, which provide a continually running operating environment, containers are optimized for workload isolation and efficiency. As soon as the designated task or service completes, or if no valid foreground process is running, the container transitions to the exited state.

Below are several reasons why a Docker container might exit right after launch, and they all relate to the state and behavior of the container’s main process:

  • Main Process Completion: Each container has a main process, defined either in the CMD or ENTRYPOINT instruction in the Dockerfile, or via the command specified in docker run or in the command: section of a docker-compose.yml. When this main process finishes naturally, the container exits.
  • Health Checks: If a container’s health check fails (if defined), Docker might stop the container.
  • Process Termination: If the main process is forcefully terminated, either by a user via commands like docker stop or docker kill, or due to an external interrupt signal, the container will stop as well. The container’s lifecycle is directly tied to that process.
  • Empty or Invalid Command: If a container starts without a valid command or is misconfigured to run an invalid or empty command, Docker cannot initiate the main process. As a result, the container starts and then exits immediately, often with an error status code.
  • No Foreground Process: In cases where a container starts a background process (like a daemon) and exits the shell or script that launched it, Docker sees that no foreground process is active and terminates the container. To keep a container running, it needs a process in the foreground to “hold” the container open.
  • Container State: Once the main process ends, regardless of the reason, the container transitions from the running state to the exited state. You can verify this with docker ps -a, which shows containers that are no longer active but haven’t been removed.

Example: Container That Exits Immediately

Here is an example that demonstrates this behavior using a minimal docker-compose.yml file configured to run an Alpine Linux container without a persistent command or service.

services:
  demo:
    image: alpine
    container_name: quick-exit-container

Run the container with:

docker compose up

You will likely see a message indicating that the container quick-exit-container exited with code 0. And checking the status:

docker ps -a

Will reveal:

Screenshot showing the container exit status in the Docker Compose keep container running example.

This happens because Alpine’s default shell (sh) launches and exits immediately if not attached to a terminal or given a long-running command.

2. Using an Infinite Loop in the Docker Container

A straightforward method to keep a container alive is to run a shell script that loops forever. This ensures the container stays active.

services:
  demo:
    image: alpine
    container_name: quick-exit-container
    command: /bin/sh -c "while true; do sleep 1; done"

In this configuration, the command section overrides the default behavior of the Alpine container by running an infinite loop. It executes a shell command that continuously sleeps for one second in a while true loop. This ensures that the container remains running, as the loop keeps the main process active indefinitely.

3. Using the tail Command

Another way to keep a container alive is to use the tail -f command on a file such as /dev/null. This simulates a process that never completes.

services:
  demo:
    image: alpine
    container_name: quick-exit-container
    command: tail -f /dev/null

In this configuration, the command: tail -f /dev/null is used to keep the container running by executing a simple, long-lived foreground process. The tail -f command is typically used to follow updates to a file in real time. However, when applied to /dev/null, a special file that discards all data written to it and never changes, the command effectively does nothing but remain active. This keeps the container alive without consuming significant system resources.

4. Allocating a TTY

Allocating a pseudo-TTY (teletypewriter) keeps a container running by simulating an interactive session.

services:
  demo:
    image: alpine
    container_name: quick-exit-container
    tty: true
    stdin_open: true

This method doesn’t define a long-running command, but keeps the container alive by simulating a terminal session. In this setup:

  • tty: true allocates a TTY.
  • stdin_open: true keeps the standard input open even if not attached.

These settings together simulate an interactive terminal, which prevents the container from shutting down immediately after startup.

5. Using the sleep infinity command

Another effective way to keep a container running is by using the sleep infinity command. This command tells the container to enter an indefinite sleep state, effectively keeping the main process alive without doing any actual work.

services:
  demo:
    image: alpine
    container_name: quick-exit-container
    command: sleep infinity

In this configuration, the Alpine container starts and immediately executes sleep infinity, which causes the container to remain running indefinitely.

6. Verifying Container Status

Once you have started your Docker Compose service using any of the above strategies, you can verify that the containers are still running with:

docker ps

And to view the logs of a specific container:

docker logs <container_name>

To enter the container for inspection or running additional commands:

docker exec -it <container_name> /bin/sh

These commands help monitor and interact with your long-running containers.

7. Conclusion

In this article, we explored why Docker containers often exit immediately and demonstrated several effective methods to keep them running when using Docker Compose. We covered techniques such as allocating a TTY, using tail -f /dev/null, running an infinite loop, and utilizing sleep infinity, all of which help maintain container uptime in scenarios where no long-running service is present.

These strategies are useful in development environments, debugging sessions, or for containers that need to remain active without executing a service continuously.

This article covered how to keep a container running using Docker Compose.

Download
You can download the full source code of this example here: docker compose keep container running

Omozegie Aziegbe

Omos Aziegbe is a technical writer and web/application developer with a BSc in Computer Science and Software Engineering from the University of Bedfordshire. Specializing in Java enterprise applications with the Jakarta EE framework, Omos also works with HTML5, CSS, and JavaScript for web development. As a freelance web developer, Omos combines technical expertise with research and writing on topics such as software engineering, programming, web application development, computer science, and technology.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button