こんにちは、久保です。
AWSでEC2やコンテナを利用する際、OSとしてLinuxを利用される方も多いと思います。
LinuxではDNSによる名前解決結果がキャッシュされないことはご存知でしょうか。また、複数のDNSサーバの参照が必要なケースでは、耐障害性を確保するために注意すべき動作があります。
本記事では、EC2でAmazon Linux 2023を利用する際の、ローカルDNSキャッシュが必要なケースとAmazon Linux 2023における設定についてご紹介いたします。
ローカルDNSキャッシュとは
その名のとおり、Linuxサーバ上(ローカル)で、DNSによる名前解決結果をキャッシュする仕組みです。
Amazon Linux 2023においてはデフォルトでローカルDNSキャッシュは構成されていない状態となっています。(2025年4月執筆現在。厳密にはsystemd-resolved
が入っていますがDNSキャッシュとしては無効化されています。)
例えば、
$ curl https://s3.amazonaws.com
のようにしてs3.amazonaws.com
の名前解決が発生する場合について考えてみます。
ローカルDNSキャッシュがない場合
ローカルDNSキャッシュがない、デフォルトの状態ではリクエストが発生する度に、DNSサーバへ名前解決リクエストを行います。 1万回アクセスすれば1万回の名前解決が必要となります。
※図は、VPCのDHCP Option Setにてデフォルトの設定(Route 53 Resolverを参照)を利用いただいている場合のイメージです。*1

ローカルDNSキャッシュがある場合
ローカルDNSキャッシュがある場合は、初回の名前解決の際にs3.amazonaws.com.
の名前解決結果がキャッシュされ、一定期間の間は同じ名前がリクエストされた場合に外部のDNSサーバへの問合せは行わず、キャッシュから返す動作となります。

では、どのような場合にローカルDNSキャッシュを構成するのがよいのでしょうか?
ローカルDNSキャッシュが必要となるケース
参照先DNSサーバが複数あるケース
例えば企業内ネットワークの独自ドメイン用の権威サーバをオンプレミス側で運用されており、AWSとDirect Connect等で接続しハイブリッドなご利用をされている場合です。
独自ドメインの解決のために独自のDNSキャッシュサーバを用意し、各サーバにそれらDNSキャッシュサーバを参照させるケースが考えられます。
複数のDNSサーバを参照させる場合、Amazon Linux 2023では /etc/resolv.conf
に以下のように複数のDNSサーバを参照する方法が取られるかもしれません。
※/etc/resolv.confは直接編集できません。/etc/systemd/resolved.confでの指定等が必要なためご注意ください。*2
$ cat /etc/resolv.conf nameserver 192.168.1.100 nameserver 192.168.1.200
例を図にすると以下のような構成となります。
単一障害点(SPOF)とならないよう、DNSキャッシュサーバを2台用意し、各クライアントが2台参照するように設定しています。
しかし、この設定には問題があります。
例えば、DNSキャッシュサーバ#1(192.168.1.100)がダウンした場合、上記のような/etc/resolv.confの設定では以下のような挙動となります。
$ curl https://s3.amazonaws.com
- 192.168.1.100 に 名前解決リクエスト
- 5秒待ちタイムアウト
- 192.168.1.200 に 名前解決リクエスト
- 名前解決結果を取得
最終的にDNSキャッシュサーバ#2を利用して名前解決することができましたが、5秒ものタイムアウト待ちが発生しています。
最初に申し上げたとおり、Linuxでは名前解決結果をキャッシュしないため、この挙動が毎回繰り返されます。 つまり、上記の例ですとS3へのリクエストが毎回必ず5秒のオーバーヘッドがかかることとなり、システムとしては許容できないレベルの遅延が発生することとなります。
このようなケースで、ローカルDNSキャッシュを構成して/etc/resolv.conf
ではnameserver 127.0.0.1
のようにローカルDNSキャッシュのみ参照する構成にしておくことで、ローカルDNSキャッシュ側で、障害が発生している参照先DNSサーバの迅速な切り離しや切り替えが実現可能です。

※切り替え、切り離しにかかる速度や仕様は利用するソフトウェアにより変わります(dnsmasq, unbound, bind)
このように、Linuxサーバから複数のDNSサーバを参照する必要があるような構成において、ローカルDNSキャッシュが必要となる場合があります。
Route 53 アウトバウンドエンドポイントを利用することで独自ドメインのDNSクエリをオンプレミスなど独自のDNSサーバで行うことも可能です。*3 EC2やコンテナが参照するDNSのIPアドレスは1つにするが運用効率や耐障害性として最も推奨されます。ここでは構成上、DNSキャッシュサーバを複数参照する必要がある場合を想定した例をご紹介しています。
短時間に大量の名前解決が必要なケース
2点目は、短時間に大量の名前解決が必要なケースです。
Linuxから参照するDNSサーバがRoute 53 Resolver1つで済む場合であっても、AWSの名前解決のクォータを超過する場合には対応が必要となります。
Route 53 Resolverは、利用可能なリクエストが秒間1,024パケットまでという制限があります。
Amazon DNS について理解する - Amazon Virtual Private Cloud
秒間であるため、かなりの高パフォーマンスが必要なサーバでなければ本クォータに達することは少ないと考えられますが、制限以上のパフォーマンスが必要な場合には、対応が必要となります。
本制限は上限を変更することができないため、ローカルDNSキャッシュを構成することで、繰り返し発生する名前解決について外部へのリクエストを減らすなどの対応を行うこととなります。
ローカルDNSキャッシュの設定方法
以下のような仕組みを利用して構成することが可能です。
- systemd-resolved
- dnsmasq
- unbound
- bind
本記事では、AWSのre:Postでも紹介されている、dnsmasq
を利用した方法をご紹介します。
dnsmasqは非常に軽量で、設定もシンプルなOSSのDNSソフトウェアです。
環境
- 2025年4月21日時点の最新版のAmazon Linux 2023を利用します
- EC2が存在するVPCのCIDRは
172.31.0/16
とします
構成前の所要時間
dnsmasqがない状態で、/etc/resolv.conf
が以下のようになっているものとします。
$ cat /etc/resolv.conf nameserver 192.168.1.100 # 存在しないサーバです。タイムアウトします。 nameserver 172.31.0.2
この状態でcurlでアクセスすると、まず192.168.1.100
を利用して名前解決を試行しますが、当該サーバは存在しません。タイムアウトまでに5秒を要するため、リクエストが処理完了するまで5秒強の時間がかかります。
$ time curl https://s3.amazonaws.com real 0m5.477s user 0m0.019s sys 0m0.000s
dnsmasqを設定
前出のre:Postの記事を参考にdnsmasqをインストール、設定します。
dnsmasq パッケージをインストールします。
sudo dnf makecache --refresh sudo dnf install -y dnsmasq
デフォルト設定のバックアップを行います。
sudo cp /etc/dnsmasq.conf{,.bak}
メイン設定を作成します。
cat <<'EOF' | sudo tee /etc/dnsmasq.conf # https://thekelleys.org.uk/dnsmasq/docs/dnsmasq-man.html # https://thekelleys.org.uk/gitweb/?p=dnsmasq.git ### Server Configuration # The alternative would be just 127.0.0.1 without ::1 listen-address=::1,127.0.0.1 # Listen on port 53 port=53 # Listen only on the specified interface(s). # For a local only DNS resolver use interface=lo + bind-interfaces # See for more details: https://serverfault.com/a/830737 interface=lo # dnsmasq binds to the wildcard address, even if it is listening # on only some of the interfaces. It then discards requests that # it shouldn't reply to. This has the advantage of working even # when interfaces come and go and change address. bind-interfaces #bind-dynamic # DO NOT listen on the specified interface(s). #except-interface=eth0 #except-interface=eth1 # Turn off DHCP and TFTP Server features. #no-dhcp-interface=eth0 # The user to which dnsmasq will change to after startup. user=dnsmasq # The group which dnsmasq will run as on startup. group=dnsmasq # File path to the PID file pid-file=/var/run/dnsmasq.pid # Clears the cache whenever /etc/resolv.conf is re-read or upstream servers are set via DBus, # This is useful when new nameservers may have different data than those held in local cache. #clear-on-reload ### Name resolution options # Specify the upstream resolver within another file resolv-file=/etc/resolv.dnsmasq # Specify the upstream AWS VPC Resolver within this config file # https://docs.aws.amazon.com/vpc/latest/userguide/vpc-dns.html#AmazonDNS # Setting this does not suppress reading of /etc/resolv.conf, use --no-resolv to do that. #server=169.254.169.253 #server=fd00:ec2::253 # Specify upstream servers directly #server=/ec2.internal/169.254.169.253 #server=/compute.internal/169.254.169.253 # IPv6 addresses may include an %interface scope-id #server=/ec2.internal/fd00:ec2::253%eth0 #server=/compute.internal/fd00:ec2::253%eth0 # To query all upstream servers simultaneously #all-servers # Query servers in order #strict-order # Uncomment if you specify the upstream server in here so you don't read # /etc/resolv.conf. Get upstream servers only from cli or dnsmasq conf. #no-resolv # Uncomment if specify the upstream server in here so you no longer poll # the /etc/resolv.conf file for changes. #no-poll # Additional hosts files to include #addn-hosts=/etc/dnsmasq-blocklist # Send queries for internal domain to another internal resolver #address=/int.example.com/10.10.10.10 # Examples of blocking TLDs or subdomains #address=/.local/0.0.0.0 #address=/.example.com/0.0.0.0 # Return answers to DNS queries from /etc/hosts and --interface-name and # --dynamic-host which depend on the interface over which the query was received. #localise-queries # Later versions of windows make periodic DNS requests which don't get sensible answers # from the public DNS and can cause problems by triggering dial-on-demand links. # This flag turns on an option to filter such requests. #filterwin2k # Never forward addresses in the non-routed address spaces bogus-priv # Never forward plain names domain-needed # Reject private addresses from upstream nameservers stop-dns-rebind # Disable the above entirely by commenting out the option OR allow RFC1918 responses # from specific domains by commenting out and/or adding additional internal domains. #rebind-domain-ok=/int.example.com/ # https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-naming.html rebind-domain-ok=/ec2.internal/compute.internal/local/ # Exempt 127.0.0.0/8 and ::1 from rebinding checks rebind-localhost-ok # Set the maximum number of concurrent DNS queries. # The default value is 150. Adjust to your needs. #dns-forward-max=150 # Set the size of dnsmasq's cache, default is 150 names cache-size=1000 # Without this option being set, the cache statistics are also available in # the DNS as answers to queries of class CHAOS and type TXT in domain bind. no-ident # The following directive controls whether negative caching # should be enabled or not. Negative caching allows dnsmasq # to remember “no such domain” answers from the parent # nameservers, so it does not query for the same non-existent # hostnames again and again. #no-negcache # Negative replies from upstream servers normally contain # time-to-live information in SOA records which dnsmasq uses # for caching. If the replies from upstream servers omit this # information, dnsmasq does not cache the reply. This option # gives a default value for time-to-live (in seconds) which # dnsmasq uses to cache negative replies even in the absence # of an SOA record. neg-ttl=60 # Uncomment to enable validation of DNS replies and cache DNSSEC data. # Validate DNS replies and cache DNSSEC data. #dnssec # As a default, dnsmasq checks that unsigned DNS replies are legitimate: this entails # possible extra queries even for the majority of DNS zones which are not, at the moment, # signed. #dnssec-check-unsigned # Copy the DNSSEC Authenticated Data bit from upstream servers to downstream clients. #proxy-dnssec # https://data.iana.org/root-anchors/root-anchors.xml #conf-file=/usr/share/dnsmasq/trust-anchors.conf # The root DNSSEC trust anchor # # Note that this is a DS record (ie a hash of the root Zone Signing Key) # If was downloaded from https://data.iana.org/root-anchors/root-anchors.xml #trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5 ## Logging directives #log-async #log-dhcp # Uncomment to log all queries #log-queries # Uncomment to log to stdout #log-facility=- # Uncomment to log to /var/log/dnsmasq.log log-facility=/var/log/dnsmasq.log EOF
ポイントとして、re:Postのエントリではstrict-order
が有効にされていますが、上記例ではコメントアウトしています。
〜略 #strict-order 〜略
本設定をコメントアウトしておかないと、/etc/resolv.dnsmasq
に記載された参照先DNSサーバについて必ず上から順に試行してしまうため、dnsmasqを追加する意味がなくなってしまうためです。
参照先DNSサーバの設定を作成します。(192.168.1.100
は存在しないサーバ)
cat <<'EOF' | sudo tee /etc/resolv.dnsmasq nameserver 192.168.1.100 nameserver 172.31.0.2 EOF
設定ファイルのシンタックスチェックを行います。
$ sudo dnsmasq --test dnsmasq: syntax check OK.
OSがdnsmasq(127.0.0.1
でリスン)を参照するように設定します。
$ sudo vim /etc/systemd/resolved.conf
↓以下のようにDNS
を指定します。
〜略〜 [Resolve] DNS=127.0.0.1 〜略〜
systemd-resolvedを再起動し反映します。
$ sudo systemctl restart systemd-resolved $ cat /etc/resolv.conf
設定が反映されていることを確認します。
$ cat /etc/resolv.conf nameserver 127.0.0.1
dnsmasqを起動し、自動起動も設定しておきます。
$ sudo systemctl enable --now dnsmasq.service $ sudo systemctl start dnsmasq.service
構成後の所要時間
dnsmasqを利用する構成で、同じリクエストを実行してみます。
$ time curl https://s3.amazonaws.com real 0m0.472s user 0m0.018s sys 0m0.000s
dnsmasqの構成前には5秒を要していたDNSのタイムアウト部分がなくなり、高速に処理できるようになりました。
注意点
構成要素の増加
ローカルDNSキャッシュを利用することで複数のDNSサーバを参照する際の耐障害性の向上およびクォータに達する可能性の緩和が可能ですが、dnsmasqなどの構成要素が増えるため、設計や運用の対象が増加いたします。
Route 53 アウトバウンドエンドポイントを活用することにより、EC2やコンテナが参照するDNSはRoute 53 Resolver1つにしつつ、その先で参照する独自ドメインのDNSサーバは複数設定することも可能です。 構成・コスト上採用が可能であれば、こちらの構成もご検討ください。
Fargateで利用される場合の注意点
ECS on Fargateなどの構成においてもローカルDNSキャッシュが必要な場合、サイドカーとしてローカルDNSキャッシュを構成することが考えられます。 dnsmasqは実行に特権が必要なため、Fargateでは利用できません。 Fargateで利用されたい場合は、unboundの利用をご検討ください。
さいごに
- 参照先DNSサーバが複数あるケース
- 短時間に大量の名前解決が必要なケース
上記のケースにおいて、ローカルDNSキャッシュを利用することで耐障害性向上やクォータ到達の緩和を行う例をご紹介いたしました。
AWSではRoute 53 ResolverやRoute 53 アウトバウンドエンドポイントといったDNSの仕組みが充実しているためローカルDNSキャッシュを必要とするケースは多くないと思いますが、どなたかのお役に立てば幸いです。
*1:https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/vpc-dns.html#AmazonDNS
*2:https://repost.aws/ja/knowledge-center/ec2-static-dns-ubuntu-debian
*3:https://docs.aws.amazon.com/ja_jp/Route53/latest/DeveloperGuide/resolver.html
久保 賢二(執筆記事の一覧)
猫とAWSが好きです。