Имеется AWS EC2 инстанс, на котором запущен
dnsmasq
.
Имеется AWS RDS-инстанс, для которого разрешён публичный доступ, и у домена которого, соответственно, есть два IP — публичный, если запрашивать публичные DNS, и приватный, который отдаётся DNS самого Amazon, с DNS VPC, в котором запущены инстансы. См начало поста AWS: php_network_getaddresses: getaddrinfo failed: Temporary failure in name resolution и dnsmasq.
Но возникает проблема — иногда dnsmasq
локальным клиентам отдаёт публичный адрес, а иногда — приватный.
Т.е иногда ответ выглядит так:
А иногда — так:
Это приводит к проблемам, т.к. во-первых — все запросы от приложений на инстансах в VPC начинают ходить «через мир», во-вторых — доступ к RDS ограничен Secuirty Group-ми, и если имя хоста резолвится на внешний IP и трафик идёт «через мир» — то залогиниться на сервер нельзя.
В примере ниже используется имя RDS stage.backend-db1-slave.example.com, которое через CNAME
направлено на RDS-домен mobilebackend-stage-db1-replica-rds.example.us-east-2.rds.amazonaws.com, а он уже, в свою очередь, должен резолвиться на приватный IP из VPC-сети.
Содержимое resolv.conf
:
Тут:
- nameserver 127.0.0.1 —
dnsmasq
- nameserver 10.0.6.2 — VPC’s DNS
- 1.1.1.1 и 8.8.8.8 — Cloudflare и Google
Включаем логи dnsmasq
— в /etc/dnsmasq.conf
добавляем строку log-queries
, и перезапускаем dnsmasq
:
Проверяем лог:
Dec 10 17:35:18 bttrm-stage-app-1 dnsmasq[538]: reading /etc/resolv.conf
Dec 10 17:35:18 bttrm-stage-app-1 dnsmasq[538]: ignoring nameserver 127.0.0.1 — local interface
Dec 10 17:35:18 bttrm-stage-app-1 dnsmasq[538]: using nameserver 10.0.6.2#53
Dec 10 17:35:18 bttrm-stage-app-1 dnsmasq[538]: using nameserver 1.1.1.1#53
Dec 10 17:35:18 bttrm-stage-app-1 dnsmasq[538]: using nameserver 8.8.8.8#53
Окей.
Теперь запрашиваем имя:
И смотрим лог:
Dec 10 17:47:45 bttrm-stage-app-1 dnsmasq[29188]: forwarded stage.backend-db1-replica.example.com to 10.0.6.2
Dec 10 17:47:45 bttrm-stage-app-1 dnsmasq[29188]: forwarded stage.backend-db1-replica.example.com to 1.1.1.1
Dec 10 17:47:45 bttrm-stage-app-1 dnsmasq[29188]: forwarded stage.backend-db1-replica.example.comto 8.8.8.8
Dec 10 17:47:45 bttrm-stage-app-1 dnsmasq[29188]: reply stage.backend-db1-replica.example.com is <CNAME>
Dec 10 17:47:45 bttrm-stage-app-1 dnsmasq[29188]: reply mobilebackend-stage-db1-replica-rds.example.us-east-2.rds.amazonaws.com is <CNAME>
Dec 10 17:47:45 bttrm-stage-app-1 dnsmasq[29188]: reply ec2-18-***-***-186.us-east-2.compute.amazonaws.com is NODATA-IPv6
Dec 10 17:47:45 bttrm-stage-app-1 dnsmasq[29188]: reply stage.backend-db1-replica.example.com is <CNAME>
Dec 10 17:47:45 bttrm-stage-app-1 dnsmasq[29188]: reply mobilebackend-stage-db1-replica-rds.example.us-east-2.rds.amazonaws.com is <CNAME>
Dec 10 17:47:45 bttrm-stage-app-1 dnsmasq[29188]: reply ec2-18-***-***-186.us-east-2.compute.amazonaws.com is 18.***.***.186
В
By default, dnsmasq will send queries to any of the upstream servers it knows about and tries to favour servers that are known to be up.
Т.к. в resolv.conf
кроме самого dnsmasq
есть три сервера — VPC, Cloudflare и Google — то dnsmasq
получает ответ от одного, и использует его в дальнейшем для форвадинга новых запросов и кеширует значение для уже отправленных запросов.
Т.к. Cloudflare отвечает зачастую быстрее, чем DNS в самой VPC — то его ответ и кешируется.
Проверить скорость ответа можно с помощью dnsping
из набора dnsdiag
.
Ответ от Cloudflare — 18 ms:
Ответ от VPC DNS — 24 ms:
Google со своими 134 ms вообще теряется 🙂
Само собой — Cloudflare содержит публичный IP нашего RDS-сервера, что совсем не то, чего хотелось бы.
Первым вариантом могло бы стать включение опции strict-order
:
-o, —strict-order
By default, dnsmasq will send queries to any of the upstream servers it knows about and tries to favour servers that are known to be up. Setting this flag forces dnsmasq to try each query with each server strictly in the order they appear in /etc/resolv.conf
Но тут возникает другая проблема: клиент отправляет запрос к dnsmasq
, dnsmasq
выполняет запрос к первому серверу из resolv.conf
, в случае, если сервер не отвечает или на нём нет записи — dnsmasq
вернёт клиенту ошибку. Но для того, что бы dnsmasq
выполнил запрос ко второму серверу из списка в resolv.conf
— клиент должен отправить повторный запрос к dnsmasq
. См. обсуждение
В нашем случае — как раз не проблема, и можно было бы использовать такой подход.
Но есть второе решение — использовать параметр server
, и задать конкретный DNS-сервер для конкретного домена/ов.
Обвновляем /etc/dnsmasq.conf
:
... server=/stage.backend-db1-slave.example.com/10.0.6.2 ...
Теперь при запросе stage.backend-db1-slave.example.com — dnsmasq
должен запросить ответ у DNS этой VPC, т.е. 10.0.6.2.
Перезапускаем:
Выполняем запрос:
Проверяем лог:
Dec 10 18:32:04 bttrm-stage-app-1 dnsmasq[29527]: query[A] stage.backend-db1-slave.example.com from 127.0.0.1
Dec 10 18:32:04 bttrm-stage-app-1 dnsmasq[29527]: forwarded stage.backend-db1-slave.example.com to 10.0.6.2
Dec 10 18:32:04 bttrm-stage-app-1 dnsmasq[29527]: reply stage.backend-db1-slave.example.com is <CNAME>
Dec 10 18:32:04 bttrm-stage-app-1 dnsmasq[29527]: reply mobilebackend-stage-db1-replica-rds.example.us-east-2.rds.amazonaws.com is <CNAME>
Dec 10 18:32:04 bttrm-stage-app-1 dnsmasq[29527]: reply ec2-18-***-***-186.us-east-2.compute.amazonaws.com is 10.0.6.42
Вроде ОК.
Готово.