2021-05-21に更新

Vagrant で Temporary failure resolving となる問題の解決 - イントラネット DNS 編

Vagrant で Ubuntu の VM を立ち上げたとき、 apt 等を行おうとすると、以下のようなエラーに遭遇した。

client: Err:1 http://security.ubuntu.com/ubuntu focal-updates/main amd64 libjpeg-turbo8 amd64 2.0.3-0ubuntu1.20.04.1
client:   Temporary failure resolving 'proxy.local.example'

上記のエラーの内容はプロキシに接続できないというものだが、 問題のポイントはプロキシかどうかはあまり関係が無く、 名前解決に失敗しているという部分だ。
こういうのはだいたい systemd-resolved のスタブリゾルバ周りの問題だと相場が決まっている。

…ということで、順番に確認しながら問題を解決していこう。

なお、 使った box は generic/ubuntu2004 で、 VirtualBox で VM をホストしている。

スタブリゾルバの確認

まず、 resolv.conf を確認してみる。

$ cat /etc/resolv.conf
# This file is managed by man:systemd-resolved(8). Do not edit.
#
# This is a dynamic resolv.conf file for connecting local clients to the
# internal DNS stub resolver of systemd-resolved. This file lists all
# configured search domains.
#
# Run "resolvectl status" to see details about the uplink DNS servers
# currently in use.
nameserver 127.0.0.53

テキストファイルのコメントに書いてあるとおり、コイツを書き換えるのは悪手。

ネームサーバーが 127.0.0.53 を指しているが、 これが systemd-resolved のスタブリゾルバだ。

ここで言うリゾルバとは、ドメイン名を元にIPアドレスを解決する仕組みのことを指していて、 DNS なども同様の機能を持っている。
その中でも、スタブリゾルバは、(「スタブ」と言うだけあって、)それ自身はドメイン名とIPの対応リストを持たずに、 DNS 等の他のリゾルバを呼び出して解決する仕組みをもっている、ローカルのサービスだ。
ローカルアプリケーションが直接 DNS を参照せず、一旦スタブリゾルバを参照することで、 systemd で管理された適切な DNS を自動的に参照されるようになったり、 DNS では解決できない hostname.local といったホスト名ベースの名前解決 (mDNS) を行えるようになっている。

さて、 そのスタブリゾルバがどう動いているか resolvectl status で確認してみよう。

$ resolvectl status
[...]
Global
  Current DNS Server: 4.2.2.1
         DNS Servers: 4.2.2.1
                      4.2.2.2
[...]
Link 2 (eth0)
      Current Scopes: DNS
    DNSSEC supported: yes
  Current DNS Server: 4.2.2.1
         DNS Servers: 4.2.2.1
                      4.2.2.2
                      208.67.220.220
                      10.0.2.3

4.2.2.1 や 208.67.220.220 などが DNS に設定されているのがわかる。
これらは、いわゆるパブリックDNSだ。

実は、先ほど名前解決できなかったプロキシは、 LAN 内のサーバーだった。 このため、 パブリックDNSに問い合わせられてしまっては、名前解決ができないのも当然だ。

パブリックDNS はどこで設定されているのか

名前解決に失敗する理由はわかった。 しかし、この DNS はどこで設定されているのか?

ざっと確認してみたところ、 resolved.conf の設定と、 仮想マシン内の NAT を繋いだ NIC の netplan 設定に、それっぽい設定が書かれていた。

$ cat /etc/systemd/resolved.conf 
[Resolve]
DNS=4.2.2.1 4.2.2.2 208.67.220.220
$ cat /etc/netplan/01-netcfg.yaml 
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: true
      dhcp6: false
      optional: true
      nameservers:
        addresses: [4.2.2.1, 4.2.2.2, 208.67.220.220]

これらは通常の Ubuntu のインストールプロセスでは設定されないので、 generic/ubuntu2004 の box の作成者の味付けなのだろう。

これらの DNS のアドレスの設定を、プライベートネットワーク内の DNS のアドレスに書き換えてしまえば、きっと意図した動作に近づくはずだ。

スタブリゾルバを使わずに LAN内 の DNS を指定する

スタブリゾルバは、細かい優先度合いの制御などを外から行えない。 これはネットワークの状況に応じて最適調整してくれる設計だからなのだが、 Vagrant で立ちあげる VM のように、 NAT の DNS や ローカルの DNS が混在していると、うまく調整できずに、こういった問題の解決がやりにくい。

スタブリゾルバを動かしているままでも問題なく動いているのならそれでもかまわないのだが、 上記の DNS の書き換えを行ってもどうも意図通りに名前解決されない場合は、 systemd-resolved のスタブリゾルバを使わずに、 /etc/resolv.conf の nameserver を切り替えるようにしたい。

具体的には、 /etc/resolv.conf../run/resolvconf/resolv.conf へのシンボリックリンクになっているところ、 ../run/systemd/resolve/resolv.conf へのシンボリックリンクに書き換える。
こうすることで、 resolved.conf や netplan で設定した DNS が直接 /etc/resolv.conf の nameserver に書かれるようになる。
詳しくは、 systemd-resolved.service のマニュアル あたりを見て欲しい。

…と、このような書き換えを、 Vagrantfile の定義に書き落とすと、以下のようになる。
なお、以下は 192.168.11.1 がローカルネットワークの DNS のアドレスである場合の例なので、適宜書き換えていただければと。

config.vm.provision :shell, inline: <<-'SHELL'
    ln -sf ../run/systemd/resolve/resolv.conf /etc/resolv.conf
    sed -i -E '/nameservers:/{n; s/(addresses:).*/\1 [192.168.11.1]/}' /etc/netplan/01-netcfg.yaml
    netplan apply
    sed -i -E 's/(^\s*DNS\s*=\s*).*$/\1192.168.11.1/' /etc/systemd/resolved.conf
    systemctl restart systemd-resolved.service
SHELL

そうすると、 resolv.conf の中身が以下のように netplan の設定などから求められた DNS に置き換えられ、スタブリゾルバを経由せずに名前解決されるようになる。

$ cat /etc/resolv.conf
# This file is managed by man:systemd-resolved(8). Do not edit.
#
# This is a dynamic resolv.conf file for connecting local clients directly to
# all known uplink DNS servers. This file lists all configured search domains.
#
nameserver 192.168.11.1
nameserver 10.0.2.3

このようになれば、ローカルの DNS でキチンと名前解決されるようになるだろう。

Originally published at aquasoftware.net
ツイッターでシェア
みんなに共有、忘れないようにメモ

advanceboy

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント