ドメインの管理をVALUE DOMAINからRoute 53に安全に移行した話

はじめに

イタンジのSREチームの田渕です!

イタンジでは、基本的にはRoute 53でドメインを管理していますが、古くから使っているものに関しては、VALUE DOMAINでも管理をしていました。
しかしVALUE DOMAINではIaCツールによる管理ができないため、先日、ドメインの管理をVALUE DOMAINからRoute 53に移行しました。

その際に、IaCツールや小さなRubyスクリプトを活用し、できるだけ安全に移行を試み、障害もなく進めることができたので、手順を共有します。

要件

VALUE DOMAINで、ドメインもDNSレコードも管理している状態から、DNSレコードは全てRoute 53の管理にする。
一部のドメインはVALUE DOMAINでの管理を引き続き行うが、基本的にはドメインの移管も行う。

移行するドメインは4個で、DNSレコードは総計で200個ほどありました。

利用ツール

roadworkerというIaCツールを使用することにしました。
DSLを自動生成しやすそうだったことと、自動生成後にimport等の操作が不要で手軽だったことが理由で、terraformではなくroadworkerを採用しました。

github.com

DNSレコードの移行

VALUE DOMAINのDNSレコードの記述から、roadworkerのDSLを出力するRubyのスクリプトを書きました。
使い捨てのスクリプトなのでかなり荒いですが、参考程度に張り付けておきます。(正しく変換できない例もあるかと思いますので、利用は自己責任でお願いします)

# VALUE DOMAINのデータをroadworkerのDSLに変換するスクリプト
# 読み込むVALUE DOMAINのデータをテキストとして保存して(ファイル名はdomain名と一致させる)、そのpathを引数に渡す

class Record
  attr_reader :type, :domain, :value
  def initialize(str)
    @type, raw_domain, @value = str.split(' ', 3)
    @type.upcase!
    raw_domain.chop! if raw_domain.end_with?('.')
    @domain = if raw_domain.end_with?(File.basename(ARGV[0])) 
                raw_domain
              elsif raw_domain == '@'
                File.basename(ARGV[0])
              else
                "#{raw_domain}.#{File.basename(ARGV[0])}"
              end
    @value = "\\\"#{@value}\\\"" if @type == 'TXT'
  end

  def to_s
    <<-STR
  rrset "#{domain}", "#{type}" do
    ttl 300
    resource_records(
      "#{value}"
    )
  end
    STR
  end
end

records_txt = File.read(ARGV[0])
domain = File.basename(ARGV[0])

records = records_txt.split("\n").map { Record.new(_1) }.reject do |record|
  # MXレコードとワイルドカードレコードは、単純な変換が難しいため手作業で移動する
  record.type == 'MX' || record.domain.include?('*')
end

File.write(
  "routes/#{domain}.route",
  <<~RESULT
    # -*- mode: ruby -*-
    # vi: set ft=ruby :
    hosted_zone "#{domain}." do
      #{records.map(&:to_s).join("\n")}
    end  
  RESULT
)

コード中にもありますが、MXレコードとワイルドカードレコードの変換は、コードで頑張らずに手動で行いました。
単純な変換が難しく、該当レコード数も少なかったため、手動で行うのが効率的だったためです。

上記のスクリプトでファイルを出力し、手動で少しだけ書き加えたものをroadworkerで適用し、Route 53にレコードを作成しました。

レコードの移行結果の確認

こちらもスクリプトで行いました。実際に検証を行うメソッドだけを抜き出して張り付けておきます。

def validate(domain, type, old_ns, new_ns)
  command1 = "dig #{domain} #{type} +short +noedns @#{old_ns}"
  command2 = "dig #{domain} #{type} +short +noedns @#{new_ns}"
  puts command1
  puts command2
  result1 = `#{command1}`.split("\n")
  result2 = `#{command2}`.split("\n")

  raise if result1.nil? || result2.nil?

  p result1
  p result2

  if result1 != result2
    print "\e[31m"
    puts 'NG'
    print "\e[0m"
  else
    print "\e[32m"
    puts 'OK'
    print "\e[0m"
  end
end

検証したいレコードとネームサーバーが一覧になったテキストファイルは別で作成し、それらを読み込んでこのメソッドに渡すような実装をしました。
このスクリプトを用いて、全てのレコードが正しく移行できているか確認しました。

ネームサーバーの切り替え

VALUE DOMAINのUI上から、NSレコードを変更しました。
切り替えには1分-30分程度かかり、かかる時間のばらつきは大きかったです。

待っている間は暇なので、念の為、前項で作ったスクリプトを回して、レコードがおかしくなっていないかを確認していました。

DNS CheckerというサイトでNSレコードが切り替わったことを確認し、VALUE DOMAINからはNSレコード以外のDNSレコードを削除しました。

ドメインの移管

AWSのドキュメントに書いてあるとおりに進めました。 ドキュメントの通りにやって、特に詰まるところもありませんでした。

移管を依頼してから1日~2週間後に移管が完了していました。

まとめ

スクリプトやIaCツールを最大限活用することによって、手動の手間をなくし、安全かつ効率よく移管を行うことができました。

また、Route 53への移管を行ったことで、今後はIaCツールもより一層活用していける体制が整いました。

今後も、できる限りコード化した上で作業を行い、安全なインフラ作業を心がけていきたいです。