Suggestion: add docker-compose-wait to LSIO containers

TL;DR: Can all the LSIO images include docker-compose-wait? Pretty please?


LSIO containers have some nice quality-of-life features, such as a predictable and unified way to set UID and GID and the timezone. That’s great. I’m here suggesting one more quality-of-life improvement:

Problem 1

I run a few containers at my home network with some volumes mounted from a network-attached storage. However, due to different startup times, sometimes the network mount points are only available after the docker container already started, which means it starts in a degraded/broken state.

Problem 2

Some people may run a database server (e.g. MariaDB) on a separate host, and it may take a while for it to start up. Starting up a container before the database is ready may not work well, so it would be better to only start up afterwards. However, we can’t declare it as a dependency in docker-compose.yml, because this database server is managed outside docker or in another host.

Proposed solution

docker-compose-wait is a small tool written in Rust and available for x86_64, aarch64 and arm7 systems. It’s purpose is simple:

  1. Given a list of host:port pairs, check if they are available.
  2. Given a list of paths (files or directories), check if they are available.
  3. If they are not available, sleep for short moment (1 second by default) and try again.
  4. If they are not available after enough time (half minute by default), exit with an error code. (Which means docker will certainly restart the container.)
  5. If they are available, exit cleanly, and proceed to execute the desired entrypoint from the container.

All the configuration can be done via environment variables, so it’s easy to integrate with docker-compose.yml.

Thus, I propose including /wait as the ENTRYPOINT or the CMD of all LSIO docker images. If the user doesn’t configure anything, then nothing exceptional happens and all the images continue working as they are.

However, by having that tool in the images, it gives the power to the users to add some wait-for-it checks in their docker-compose.yml configuration.

  1. this is a host issue not a container issue, you should configure your systemd or bsd style init to ensure remote mounts are up prior to starting the docker service

  2. most of our containers with a dep on an external db do a check for connectivity to the external db before proceeding (for example, https://github.com/linuxserver/docker-unifi-network-application/blob/8987376951b710531fdfe8092009bd542fed94a7/root/etc/s6-overlay/s6-rc.d/init-unifi-network-application-config/run#L22-L39. you would need to provide more detail on how problem 2 is a problem for us to do anything

1 Like

I… Agree… I guess.

But I spent so much time already and I couldn’t figure out how to make systemd wait for the CIFS mounts before starting docker. Can you (or someone) please help me and point me to the right direction?

The best I’ve got so far was x-systemd.automount and some file check for /mnt/Foobar/.is_mounted inside docker-compose.yml. But it’s still not reliable, and looks like I’m adding too much boilerplate inside the docker-compose files. That’s why I thought docker-compose-wait could be a solution. (I also understand that further help with this issue should probably be done in a different forum category.)

Problem 2 was more hypothetical, because I haven’t (yet) faced it.

i would recommend seeking best-effort help in #other-support on our discord. This is a common issue that is relatively easy to resolve (applies to users with usb drives too)

Mostly problems can be solved in this way:

services:
  nextcloud:
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    volumes:
      - data:/var/www/html
    restart: unless-stopped

  redis:
    image: docker.io/redis:7
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 10s
      retries: 10
    restart: unless-stopped

  db:
    image: mariadb:10.6
    healthcheck:
      test: [
        "CMD", 
        "mysqladmin",
        "ping", 
        "-h", "localhost",
        '-u', 'root', 
        '-p$$MYSQL_ROOT_PASSWORD'
      ]
      interval: 10s
      timeout: 10s
      retries: 10
    restart: unless-stopped

service_healthy

The downside of a healthcheck in this case is… The container already started. In other words, if there are two volumes, one local and one remote (i.e. mounted on a remote filesystem on the host), but the remote is not yet ready; then the container process already started and already had a chance to modify the local volume despite the remote volume being unavailable. I’d rather prevent it from starting at all until both are ready.

Sure, we can argue this is a problem on the application, as the application shouldn’t screw up things in this case. And this is still a theoretical problem as I haven’t yet lost nor corrupted any data, but it still sounds risky.

I have already tried this:

services:
  nascheck:
    image: ghcr.io/ufoscout/docker-compose-wait
    restart: on-failure
    volumes:
      - /mnt/nas/foobar:/mnt1
    command: [ "/wait" ]
    environment:
      - WAIT_PATHS=/mnt1/.is_mounted

  the_main_application_here:
    ...
    depends_on:
      nascheck:
        condition: service_completed_successfully
        restart: true

And it works when starting it up once through docker compose up. But after rebooting, the main application container starts disregarding the dependency (certainly because it’s handled by docker itself instead of being orchestrated by docker-compose).

And that’s why I suggested adding docker-compose-wait inside the container image.