Здесь — куда Docker подключил оба контейнера и как они видят друг друга.
У каждого контейнера свой сетевой интерфейс и свой адрес — своё сетевое пространство имён. Контейнер без ключа --network Docker подключает к сети bridge. На хосте это виртуальный коммутатор docker0, а каждый контейнер соединён с ним парой veth. Адреса в этой сети — из 172.17.0.0/16.
Сети Docker показывает docker network ls: кроме bridge в списке всегда есть host (контейнер прямо в сети хоста) и none (без сети). Кто подключён к сети и с какими адресами, показывает docker network inspect.
Подключись к базе по адресу
Посмотри, кто подключён к сети bridge и с какими адресами, подключись из app к db по адресу и прочитай /etc/resolv.conf в app.
Адрес по имени программа спрашивает у DNS-серверов из /etc/resolv.conf (разрешение имён). В сети по умолчанию Docker кладёт в контейнер серверы хоста. У нашего хоста своих нет, поэтому стоят запасные 8.8.8.8 и 8.8.4.4 — об этом строка # Used default nameservers. Имя db знает только Docker, в интернете такого имени нет. Строку options добавила подготовка: сети у машины нет, и без неё nc ждал бы ответа этих серверов 10 секунд.