WARNING: Este script cria um loop infinito no seu CI, certifique-se de ter um timeout.

Inicialmente eu pensei em usar o wait-for-it.sh, mas adicionar um script novo (ou seja dependência) só para isso, além do mais o wait-for-it não funcionou como eu esperava.

Eu esperava que o script entrasse num loop infinito (ou que pelo menos tivesse opção de tentar novamente) até que a conexão com o banco de dados fosse funcional.

Para o MySQL:

#!/bin/bash

while ! mysql -h db -D app_test -e "select 1"
do
  echo "waiting for MySQL"
  sleep 5
done

Para o PostgreSQL:

#!/bin/bash

export PGPASSWORD=postgres

while ! echo "select 1" | psql -U postgres -h db postgres
do
  echo "waiting for PostgreSQL"
  sleep 2
done

Eu coloco esse script justamente ante de eu precisar me conectar no banco de dados, por exemplo:

      - run: docker-compose up -d db
      - run: docker-compose run --rm -e RAILS_ENV=test app bundle install --path=vendor/bundle --jobs=4 --retry=3
      - run: docker-compose run db /app/.github/wait-for-db.sh
      - run: docker-compose run --rm -e RAILS_ENV=test app bundle exec rake db:migrate

Isso é o que acontece no CI:

Exemplo CI

P. S.: Não esqueça de fazer esse script executávem com o chmod +x.