47

I am using the docker-compose.

Some commands like up -d service_name or start service_name are returning right away and this is pretty useful if you don't want the containers running to depend on the state of the shell, like they do with regular up service_name. The one use-case is running it from some kind of continious integration/delivery server.

But this way of running/starting services does not provide any feedback about the actual state of the service afterwards.

The Docker Compose CLI reference for up command does mention the relevant option, but, as for version 1.7.1, it is mutually exclusive with -d:

--abort-on-container-exit  Stops all containers if any container was stopped.
                           *Incompatible with -d.*

Can I somehow manually check that the container is indeed working and haven't stopped because of some error?

12 Answers 12

41
  • docker-compose ps -q <service_name> will display the container ID no matter it's running or not, as long as it was created.
  • docker ps shows only those that are actually running.

Let's combine these two commands:

if [ -z `docker ps -q --no-trunc | grep $(docker-compose ps -q <service_name>)` ]; then
  echo "No, it's not running."
else
  echo "Yes, it's running."
fi

docker ps shows short version of IDs by default, so we need to specify --no-trunc flag.

UPDATE: It threw "grep usage" warning if the service was not running. Thanks to @Dzhuneyt, here's the updated answer.

if [ -z `docker-compose ps -q <service_name>` ] || [ -z `docker ps -q --no-trunc | grep $(docker-compose ps -q <service_name>)` ]; then
  echo "No, it's not running."
else
  echo "Yes, it's running."
fi
8
  • Nice one, and it also addresses problem with current answer that was stated in comments. Marking this as a new answer. Oct 16, 2018 at 6:01
  • 3
    If you are using a restart policy you also need to filter it to only include running containers (rather than ones in a restarting state): docker ps -q -f "status=running" --no-trunc | grep $(docker-compose ps -q <service_name>)
    – Max
    Oct 20, 2018 at 21:58
  • 1
    This works but throws a "grep usage" warning if the service isn't running, in other words, when the grep .... part ends up with an empty string.
    – Dzhuneyt
    Jul 12, 2019 at 8:25
  • 2
    @elquimista Yes, I solved it using the OR operator: if [ -z `docker-compose ps -q mysql` ] || [ -z `docker ps -q --no-trunc | grep $(docker-compose ps -q mysql)` ]; then. What this does is: it first checks if the service exists at all (even if it's stopped) and the second part checks if the existing service is actually running. You might want to include this in your example for future readers that glance over the accepted answer only. I think it's useful.
    – Dzhuneyt
    Jul 15, 2019 at 8:49
  • 1
    You can do it all in a single command without an error from grep if the input is quoted, if [ -z "$( docker ps -q --no-trunc | grep "$( docker-compose ps -q <service_name> )" )" ].
    – chawkinsuf
    May 16, 2020 at 20:46
19

To see all services running:

docker-compose ps --services --filter "status=running"

To see if your-service is running:

docker-compose ps --services --filter "status=running" | grep <your-service>

Note that --filter must be used with --services for some foreign reason.

2
  • Looks like docker changed the flags, using docker-compose ps --status running | grep <your-service> worked for me (v20.10.7)
    – tharkay
    Jul 21, 2021 at 9:11
  • | grep -Fxe <your-service> in case the service you're checking for also has another service with that name in, e.g. app and console-app, grep app would match both
    – Andy
    May 13, 2022 at 10:57
16

As for version 1.7.1, there are no such commands built-in.

Instead, the exec can be used in similar way.

When you run it for the service which has some containers up it will run ok:

~/apperture-science $ docker-compose exec chell echo 'Still alive!'
Still alive!
~/apperture-science $ echo $?
0

But when you run it for the service which has no running service containers, it will show an error:

~/apperture-science $ docker-compose exec glados echo "Still alive!"
ERROR: No container found for apperture-science-glados_1
~/apperture-science $ echo $?
1

So, it can be used in order to check, is there any "alive" containers for given service.

5

You can run:

docker-compose ps -q service-name

And you will get the id of the container if service-name is running. Something like:

18a04e61240d8ffaf4dc3f021effe9e951572ef0cb31da7ce6118f681f585c7f

If the service is not running the output is empty, so if you want to use this in a script you can do something like:

IS_RUNNING=`docker-compose ps -q service-name`
if [[ "$IS_RUNNING" != "" ]]; then
    echo "The service is running!!!"
fi
2
  • Yes, that works too. Marked this as answer now. Feb 5, 2018 at 13:06
  • 19
    This doesn't tell you if the container is running or not, just if it exists or not. Try doing docker-compose up then Ctrl-C. docker-compose ps should then show that the container states are not "Up", but docker-compose ps -q service-name still gives you an id.
    – djanderson
    Feb 22, 2018 at 22:13
3

Here is a simple one liner that returns the current status of the service:

docker inspect --format "{{.State.Status}}" $(docker-compose ps -q your_service_name)

This is returning only the status of docker container. If you want to check for the actual state of your application you should add HEALTHCHECK to your Dockerfile (https://docs.docker.com/engine/reference/builder/#healthcheck). Afterwards you can inspect it with:

docker inspect --format "{{.State.Health.Status}}" $(docker-compose ps -q your_service_name)
3
  • but how do you ensure its really running and not crashed as in the original question?
    – djdomi
    Jul 21, 2021 at 13:23
  • For the actual state of your application add HEALTHCHECK to your Dockerfile. Afterwards you can inspect it with: docker inspect --format "{{.State.Health.Status}}" $(docker-compose ps -q your_service_name)
    – Elembivios
    Jul 22, 2021 at 9:12
  • i suggest to add the fact to your answer
    – djdomi
    Jul 22, 2021 at 10:08
2

I had a similar need. However, I have a restart: always in my environment. So it can be a bit tricky to detect if something is crashing and restarting in a loop.

I made an Icinga/Nagios check to also compare the created and start times. Maybe it's useful to someone else down the line:

#!/usr/bin/env python
from __future__ import print_function
import argparse
from datetime import timedelta
from datetime import datetime
import sys

from dateutil.parser import parse as parse_date
import docker
import pytz
parser = argparse.ArgumentParser()
parser.add_argument("compose_project",
                    help="The name of the docker-compose project")
parser.add_argument("compose_service",
                    help="The name of the docker-compose service")
args = vars(parser.parse_args())

client = docker.from_env()
service_containers = client.containers.list(filters={
    "label": [
        "com.docker.compose.oneoff=False",
        "com.docker.compose.project={}".format(args["compose_project"]),
        "com.docker.compose.service={}".format(args["compose_service"])
    ]})

if len(service_containers) == 0:
    print("CRITICAL: project({})/service({}) doesn't exist!".format(
        args["compose_project"], args["compose_service"]))
    sys.exit(2)
elif len(service_containers) > 1:
    print("CRITICAL: project({})/service({}) has more than 1 "
          "container!".format(
              args["compose_project"], args["compose_service"]))
    sys.exit(2)

service_container = service_containers[0]
created_at = parse_date(service_container.attrs['Created'])
status = service_container.attrs['State']['Status']
started_at = parse_date(service_container.attrs['State']['StartedAt'])
now = datetime.utcnow().replace(tzinfo=pytz.utc)
uptime = now - started_at

if status in ['stopped', 'exited', 'dead']:
    print("CRITICAL: project({})/service({}) is status={}".format(
        args["compose_project"], args["compose_service"], status))
    sys.exit(2)

if (started_at - created_at) > timedelta(minutes=5):
    if uptime < timedelta(seconds=5):
        print("CRITICAL: project({})/service({}) appears to be "
              "crash-looping".format(
                  args["compose_project"], args["compose_service"]))
        sys.exit(2)

if status == "restarting":
    print("WARNING: project({})/service({}) is restarting".format(
        args["compose_project"], args["compose_service"]))
    sys.exit(1)

print ("OK: project({})/service({}) is up for {}".format(
    args["compose_project"], args["compose_service"], uptime
))
sys.exit(0)
2

How about this?

docker-compose ps | awk '$4 == "Up" {print $1}' | grep <service-name>

you list the processes, select the lines where "Up" is in column 4 and filter through for a match on the service name.

1
  • I had to change $4 to either $5 or $6 depending on if the command had any spaces in it.
    – Andy
    Aug 9, 2022 at 0:14
2

You could use filters, for example:

docker ps \
    --filter label=com.docker.compose.project.working_dir=/my_projects/project1
    --filter label=com.docker.compose.project.config_files=docker-compose.yml
    --filter status=running
    --format '{{.Names}}'

--filter label=com.docker.compose.project=project1 is valid as well, yet for automation I prefer more specific project.working_dir.

That would return all container names related to the the compose file.

0

If you assume this scenario:

  • containers either start and run indefinitely or stop immediately with an error code (i.e. for missing configuration)
  • you do the check only once after docker-compose up -d returns

you can check if there is any stopped container due to an error with: docker ps -a | grep 'Exited (255)'.

This check works correctly even in case of containers which are expected to stop immediately with no error (i.e. data containers), as their status (from docker ps -a) is marked as Exited (0).

For example, in our docker-compose.yml, we start our containers with:

command: sh -c 'node dotenv_check.js && pm2 start --no-daemon src/worker.js --watch'

For php-fpm, we use a similar command:

command: >-
  sh -c '
  set -e;
  for PROJECT in frontend backend; do
    cd /var/www/$${PROJECT};
    php dotenv_check.php;
  done;
  php-fpm
  '

The dotenv_check.js and dotenv_check.php are scripts which exit with an error code in case a required env variable is missing.

The set -e command, tells the script to stop on error, which, in turns, will immediately stop the container. About set-e

0

Here's a simplified one-liner based on almquista's answer:

docker ps -q --no-trunc | grep -q "^$(docker-compose ps -q app-service)$"

We use grep's -q flag so a non-zero exit code indicates the service is not running. For example:

if docker ps -q --no-trunc | grep -q "^$(dc-audo-dev ps -q app-service)$"; then
    echo "Container is still running..."
fi
0

You can grep for (healthy) or/and (unhealthy) images to act properly.

In this example, i'm probing docker-compose each 5 seconds for running service with (healthy) status. If script will find such service, it will break execution. If script will exceed 300 seconds, it will exit with error code.

#!/bin/bash
SECONDS=0
LIMIT=300
x=$(docker-compose -f /mnt/<service>/docker-compose.yaml ps <service> | grep -c '(healthy)')
while [[ $x == "0" ]]; do
    echo "Please wait until <service> becomes healthy"
    sleep 5
    x=$(docker-compose -f /mnt/<service>/docker-compose.yaml ps <service> | grep -c '(healthy)')
    EXPIRED=$SECONDS
    if [[ $x == "1" ]]; then
      echo "<service> is healthy..."
      break
    elif [[ $LIMIT -lt $EXPIRED ]]; then
      echo "<service> startup has exceeded 5m timeout, exiting!"
      exit 1
    fi
done
0

I think I can improve on everything that's been written so far, using a regex test:

CONTAINER_NAME=my-favourite-container

# Start Compose if necessary
RUNNING_SERVICES=$(docker-compose ps --services --filter "status=running")
if [[ ! $RUNNING_SERVICES =~ "${CONTAINER_NAME}" ]]; then
  echo "Starting Docker Compose"
  docker-compose up -d
fi

There's obviously some edge cases here, where you've got some other Compose service whose name is a superset of the name you're checking for, but since Compose services tend to start and end at the same time, you can probably write some cleverer regex as a one-off to defend against this if it happens.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .