Verifique se o contêiner / serviço está sendo executado com docker-compose

Estou usando o docker-compose.

Alguns comandos como up -d service_name ou start service_name estão retornando imediatamente e isso é muito útil se você não quiser que os contêineres em execução dependam do Estado do shell, como fazem com o normal up service_name. O único caso de uso é executá-lo a partir de algum tipo de servidor de integração/entrega contínuo.

Mas essa maneira de executar/iniciar serviços não fornece nenhum feedback sobre o estado real do serviço posteriormente.

O Docker Compose CLI referência para up comando menciona a opção relevante, mas, quanto à versão 1.7.1, é mutuamente exclusivo com -d:

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

Posso de alguma forma verificar manualmente se o contêiner está realmente funcionando e não parou por causa de algum erro?

  • docker-compose ps -q <service_name> exibirá o ID do contêiner, independentemente de estar em execução ou não, desde que tenha sido criado.
  • docker ps mostra apenas aqueles que estão realmente funcionando.

Vamos combinar esses dois comandos:

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 mostra a versão curta dos IDs por padrão, portanto, precisamos especificar --no-trunc bandeira.

ACTUALIZACAO: Ele jogou "uso grep" aviso se o serviço não estava em execução. Graças a @ Dzhuneyt, aqui está a resposta atualizada.

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

Quanto à versão 1.7.1, não existem tais comandos embutidos.

Em vez disso, o exec pode ser usado de maneira semelhante.

Quando você executá-lo para o serviço que tem alguns contêineres, ele será executado ok:

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

Mas quando você executá-lo para o serviço que não tem execução servico contêineres, ele mostrará um erro:

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

Portanto, ele pode ser usado para verificar se há algum contêiner "vivo" para determinado serviço.

Ver todo serviços em execução:

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

Para ver se seu-serviço está em execução:

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

Notar --filter deve ser usado com --services por alguma razão estrangeira.

Você pode correr:

docker-compose ps -q service-name

E você obterá o id do contêiner se service-name está a correr. Algo como:

18a04e61240d8ffaf4dc3f021effe9e951572ef0cb31da7ce6118f681f585c7f

Se o serviço não estiver executando, a saída estará vazia, portanto, se você quiser usar isso em um script, poderá fazer algo como:

IS_RUNNING=`docker-compose ps -q service-name`if [[ "$IS_RUNNING" != "" ]]; then    echo "The service is running!!!"fi

Eu tinha uma necessidade semelhante. No entanto, eu tenho um restart: always no meu ambiente. Portanto, pode ser um pouco complicado detectar se algo está travando e reiniciando em um loop.

Fiz uma verificação Icinga / Nagios para também comparar os horários de criação e início. Talvez seja útil para outra pessoa no futuro:

#!/usr/bin/env pythonfrom __future__ import print_functionimport argparsefrom datetime import timedeltafrom datetime import datetimeimport sysfrom dateutil.parser import parse as parse_dateimport dockerimport pytzparser = 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_atif 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)

Aqui está um forro simples que retorna o status atual do serviço:

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

Isso está retornando apenas o status do contêiner docker. Se você quiser verificar o estado real do seu aplicativo, adicione HEALTHCHECK ao seu Dockerfile (https://docs.docker.com/engine/reference/builder/#healthcheck). Depois, você pode inspecioná-lo com:

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

Que tal isto?

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

você lista os processos, seleciona as linhas em que" Up " está na coluna 4 e filtra para obter uma correspondência no nome do serviço.

Se você assumir esse cenário:

  • os contêineres iniciam e são executados indefinidamente ou param imediatamente com um código de erro (ou seja, para configuração ausente)
  • você faz a verificação apenas uma vez após o docker-compose up-d retornar

você pode verificar se há algum contêiner parado devido a um erro com:docker ps -a | grep 'Exited (255)'.

Essa verificação funciona corretamente, mesmo no caso de contêineres que devem parar imediatamente sem erro (ou seja, contêineres de dados), como seu status (de docker ps -a) é marcado como Exited (0).

Por exemplo, em nosso docker-compose.yml, começamos nossos contêineres com:

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

Para php-fpm, usamos um comando semelhante:

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

O dotenv_check.js e dotenv_check.php são scripts que saem com um código de erro caso uma variável env necessária esteja faltando.

O set -e comando, diz ao script para parar no erro, que, por sua vez, irá parar imediatamente o contêiner. Sobre set-e

Você pode grep para (healthy) ou / e (unhealthy) imagens para agir corretamente.

Neste exemplo, estou sondando docker-compose a cada 5 segundos para executar o serviço com (healthy) status.Se o script encontrar esse serviço, ele interromperá a execução.Se o script exceder 300 segundos, ele sairá com o código de erro.

#!/bin/bashSECONDS=0LIMIT=300x=$(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    fidone

Aqui está um one-liner simplificado baseado na resposta de almquista:

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

Nós usamos grep's -q sinalize para que um código de saída diferente de zero indique que o serviço não está sendo executado. Por exemplo:

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