Route 53の運用をやっと見える化出来た話

Posted on

Infrastructure as CodeやDevOpsが謳われ始めてだいぶ時間が経った。

当記事はInfrastructure as Codeについて語る事はせず、DNSの設定をコード化し見える化した事、本番反映作業を自動化した事による属人化の排除に焦点を当てた記事である。
以前から試行錯誤していたが、やっと自分たちのプロダクトにフィットする形で実現出来たので公開する。

なぜ知らないDNSレコードが本番に存在するのか

少し怖い話だが、みなさんも一度は経験があるかもしれない。

とある担当者が「その時」は最適な解決策と判断した「DNSレコードの追加」「DNSレコードの修正」が周知されず、引き継いだエンジニアやチームがDNSレコードを見て言葉を失う…

考えたくない事だが現場では想像を超えた事が起きる。それが現場だと思う。

本来DNSの設定はサービス設計やシステムデザインにおいて、初期に決まるものだと思う。
そこから運用が進み、スケールしたり一工夫を加えていく。

肝心な事は何かと考えると「その時に最適である」という事ではないだろうか。

あるべき姿をTO-BEと定義するなら、AS-ISは何だろうか。
AS-ISは理想論になってはいけないと考えている。

常に「最適」である事が大切なのではないだろうか。

我々のチームにとってのAS-ISは何だろうか

チームの力量やビジネスサイドからの要求、サービスの成長段階においてそれは変わってくると思うし、変わるべきだと思う。

常に「その時」最適である事が大切で、将来のための最適や、過去の最適は価値が高いとは言えないのではないだろうか。
未来を見据えた機能を開発しても、それがdelivery出来ないのであれば価値を見出す事は難しい。
逆に言えば、どんなに価値が低いものでもdelivery出来ている以上は一定の価値があるのではないだろうか。

我々のチームにとってAS-ISは、見える化出来ている事と属人化しない事であると判断した。
今日現在において、だ。

そこにソフトウェア開発のノウハウやエッセンスを少し足してみた。可能な範囲で。

無理はいけない。
無理をすると必ず返ってくる。
チームの負債になってしまう。

Roadworker

Roadworkerを使うことで、Route53のDNSレコードをDSLとして管理する事が出来る。
詳しい使い方はREADME.mdを見てもらうのが吉だ。

AWSの1アカウントで1サービスを運用している事を想定すると、Route53で複数のドメインを関している事が多いと思う。我々もそうだ。

その為、Exportする際はroadwork -e --split --with-soa-nsを指定した。

--splitでHosted zone毎にファイル出力を行う。
また--with-soa-nsはSOAレコードとNSレコードも出力するもので、デフォルトではSOAレコードとNSレコードは出力されない為、SOAレコードとNSレコードが必要な場合は意識が必要だ。

また、今回環境構築している中でRoute53におけるhealth checkのregion指定は出力されなかった。
その為、Export後Hosted zoneファイルを修正し手動でhealth checkのregion指定を行った。

GitHub

GitHubにPrivateリポジトリでソース管理を行った。
各種権限はチームに合わせた設定が必要だと思う。

比較的標準的な設定を行ったが、今回はPull Requestをmergeする前のreviewを必須 Require pull request reviews before merging にし、merge前にstatus checkのpassも必須 Require status checks to pass before merging とした。

masterへのpushでCircleCIのtestをrunさせ、Pull Requestのmergeで本番にapplyする。
それが我々のチームの戦略とした為だ。

AWS

Route53へアクセスするAWSユーザーが必要で、DNSレコードの追加だけでなくレコードの削除も行うためRoute53へのフルアクセス権限を付与したユーザを用意した。

CircleCI

AWSのkey情報はAWSの権限を設定する専用画面がある為、environment variables ではなく permissions/AWS permissions へと設定を行った。

CircleCIのVersionは1.0を使っている。
その為、roadworkerを使うために一工夫が必要となった。

circle.ymlにおいて、sudo apt-get install libpcap-dev libpq-devとして必要な環境を用意するのだ。
それから、Gemfilegem 'roadworker'としてroadworkerを使う。

circle.ymlは記述方法が柔軟だが、シンプルな記述となる点も気に入っている。
以下にサンプルを載せておく。

circle.yml

dependencies:
  pre:
    - sudo apt-get install libpcap-dev libpq-dev
    - bundle install:
        timeout: 600

test:
  post:
    - bundle exec roadwork --dry-run --apply

deployment:
  foobar:
    branch: deployment/foobar
    commands:
      - bundle exec roadwork -a --target-zone foobar

  bazqux:
    branch: deployment/bazqux
    commands:
      - bundle exec roadwork -a --target-zone bazqux

Gemfile

source "https://rubygems.org"

gem 'roadworker'

これで、deployment/foobarブランチはfoobar Hosted zoneへ適用され、deployment/bazquxブランチはbazqux Hosted zoneに適用される。
必要ならもっと増やしても良いし、シンプルにmasterブランチの内容を単一のHosted zoneに適用しても良い。
どういった戦略を選択するのか考える事が重要だ。それが最適化なのだから。

見えてきた、次にやるべきこと

実際の運用は良くある話になる。

修正をmasterに加えpushする。
CircleCIによるテストが実施され、passすればPull Requestを作成出来る。
mergeされたブランチによって、内容がapplyされるHosted zoneが切り替わる。
成功の結果をSlackへ流す。

これで、Route53の変更履歴も残すことが出来るし、複数人によるreviewが行える。
反映自体もmergeするだけなので手間が掛からない。
これで、見える化と属人化の排除が行えた。

本当にそうだろうか。

この運用を始めて分かった事は、当たり前過ぎてこの構想を考えている最中には思いつかなかった事だ。

それはRoute53のお作法を理解する必要があるという事だ。

通常のDNSサーバに+αで便利な機能が使えるRoute53だが、果たしてその機能や使い方を全て理解出来ているだろうか?

テストをpassしなかった際に出力される例外をすぐに理解出来るだろうか?AWSのGUI上に表示されるヘルプがない状態で、それくらいroadworkerを使いこなせるだろうか?

きっとこの例外をクリアする為に、AWSの知見があるエンジニアに頼る事になるだろう。
我々は誰かに頼るのではなく、チームで解決しなくてはいけない。


当たり前になってしまった事は、常に忘れてしまう。
人間がエンジニアリングをしている以上、つきまとう問題かもしれない。

それでも次の課題がある事は素晴らしい。
また次の進歩に向けて学ぶことが出来る。
そう考えよう。

こうして我々は機械化の波に飲まれていくのである。
我々のチームに必要なのは「脱機械化」なのかもしれない。