Диагностика недоступного сервиса: от DNS до процесса и логов
Фраза «сайт не работает» объединяет разные сбои: имя не разрешается, TCP недоступен, TLS не подтверждён, proxy возвращает ошибку, процесс упал или dependency отвечает медленно. Надёжная диагностика проверяет слои по порядку и сохраняет наблюдения до перезапуска.
Сначала сформулируйте симптом
Зафиксируйте URL/host, время с timezone, точку наблюдения, ожидаемый status и фактическую ошибку. Один клиент может использовать VPN, IPv6, cache или proxy, которого нет у другого. Повторять запрос нужно из той же среды пользователя и отдельно с сервера.
Минимальный маршрут проверки
- getent/dig: какое имя и address получил клиент.
- ss/lsof на сервере: есть ли listener на ожидаемом address/port и кто owner.
- curl с timeout: дошли ли TCP, TLS и HTTP; какой status/body.
- systemctl/container status: жив ли управляемый экземпляр и не перезапускается ли он.
- journal/application logs в узком окне.
- Dependency probes: БД, очередь, диск, DNS и внешние API.
target=https://example.com/
body_file=$(mktemp)
trap 'rm -f -- "$body_file"' EXIT
date -Is
getent ahosts example.com
curl --silent --show-error --fail-with-body \
--connect-timeout 3 --max-time 10 \
--output "$body_file" \
--write-out 'http=%{http_code} remote=%{remote_ip} total=%{time_total}\n' \
"$target"
status=$?
printf 'curl_status=%s body_bytes=%s\n' \
"$status" "$(wc -c <"$body_file")"
rm -f -- "$body_file"
trap - EXITКоманда создаёт отдельный приватный временный файл, очищает его через trap и не смешивает HTTP-status с curl exit status. Поскольку mktemp каждый раз создаёт пустой уникальный файл, неуспешное соединение не оставит в расчёте body от предыдущего запуска. Не сохраняйте чувствительный ответ дольше расследования.
Локальная воспроизводимая модель
log=$(mktemp)
python3 -m http.server 18080 --bind 127.0.0.1 >"$log" 2>&1 &
pid=$!
trap 'kill "$pid" 2>/dev/null || true' EXIT
ss -ltnp | grep ':18080'
curl --fail --silent --show-error http://127.0.0.1:18080/ >/dev/null
kill -TERM "$pid"
wait "$pid"
trap - EXITЭтот fixture позволяет наблюдать PID, listener, request и корректное завершение. Если порт занят, это тоже полезный заранее диагностируемый результат: найдите owner, не завершайте его автоматически.
Ошибка и диагностика
Самая дорогая ошибка — начать с restart. Он уничтожает состояние, очищает временный симптом и может сделать incident невоспроизводимым. Сначала соберите status, PID, listener, health response, последние logs и ресурсные ограничения. Restart допустим как контролируемое восстановление после evidence, но не заменяет root cause.
Также не проверяйте только localhost, если жалоба приходит извне: локальный curl обходит DNS, firewall, TLS termination и proxy. И наоборот, внешний 502 не доказывает падение backend — proxy мог иметь неверный upstream.
Практика
Запустите локальную модель, подтвердите каждый слой и сохраните короткий incident note. Затем измените curl port на соседний и объясните отличие Connection refused от timeout. После этого завершите процесс, повторите ss/curl и укажите, какое наблюдение локализует сбой раньше логов.
Что важно запомнить
- Диагностика идёт от конкретного client symptom через DNS, transport и protocol к process/dependencies.
- Каждая команда отвечает на один вопрос; успешный нижний слой не гарантирует верхний.
- Собирайте evidence до restart и всегда фиксируйте namespace и время.