dockershelldocker-composesh

Docker compose run capturing output freezes terminal from .sh script


I have server in Ubuntu. On the server I have docker compose installed (v2.29.7). I created the script ssl-renew.sh to periodically renew certbot certs via crontab. Certbot is run through the docker the same way as my nginx, they are in the same docker-compose.yml

I DON'T have "docker-compose" because it gives me this error: DockerException: Error while fetching server API version: HTTPConnection.request(), and the fix is clearly stated here - just move to newest 'docker compose' without the dash

The problem is that "docker compose" version just does not work when I try to capture the output.

The failing part of the script:

#!/bin/bash

set -x

DOCKER_COMPOSE_FILE="/services/nginx/docker-compose.yml"

echo "starting renewal"

output=$(/usr/bin/docker compose -f $DOCKER_COMPOSE_FILE run --rm certbot renew --force-renewal 2>&1)

echo "docker script has run"

The output is always the same:

+ DOCKER_COMPOSE_FILE=/services/nginx/docker-compose.yml
+ echo 'starting renewal'
starting renewal
++ /usr/bin/docker compose -f /services/nginx/docker-compose.yml run --rm certbot renew --force-renewal

It never reaches echo "docker script has run". The command is not interactive, when I remove the line in script to this one:

#output=$(/usr/bin/docker compose -f $DOCKER_COMPOSE_FILE run --rm certbot renew --force-renewal 2>&1)
/usr/bin/docker compose -f $DOCKER_COMPOSE_FILE run --rm certbot renew --force-renewal

It is working:

+ DOCKER_COMPOSE_FILE=/services/nginx/docker-compose.yml
+ echo 'starting renewal'
starting renewal
+ /usr/bin/docker compose -f /services/nginx/docker-compose.yml run --rm certbot renew --force-renewal
WARN[0000] /services/nginx/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Renewing an existing certificate for example.com
Failed to renew certificate example.com with error: urn:ietf:params:acme:error:rateLimited :: There were too many requests of a given type :: Error creating new order :: too many certificates (5) already issued for this exact set of domains in the last 168 hours: example.com, retry after 2024-10-02T07:04:55Z: see https://letsencrypt.org/docs/duplicate-certificate-limit/

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
All renewals failed. The following certificates could not be renewed:
  /etc/letsencrypt/live/example.com/fullchain.pem (failure)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 renew failure(s), 0 parse failure(s)
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.
+ echo 'docker script has run'

Now it run the command and terminal didn't freeze, but I want to capture the output and send it via API to logging provider. I tried everything in Google and GPT at the moment, nothing helped. Please, if you have any advices - I would appreciate.


Solution

  • The problem was simple I was missing -t argument:

    Not working one: output=$(/usr/bin/docker compose -f $DOCKER_COMPOSE_FILE run --rm certbot renew --force-renewal 2>&1)

    Working one: output=$(/usr/bin/docker compose -f $DOCKER_COMPOSE_FILE run -t --rm certbot renew --force-renewal 2>&1)