Private Host Zoneを使ってDB接続情報の`.env`運用から脱却する
TL;DR
-
.env
を利用した設定値の管理は結構つらいので可能な限り控えるべき - 各環境がVPCで隔離されている場合はDBのエンドポイントをPrivate Host ZoneのCNAMEレコードに登録することでアプリケーションがアクセスするDBのhost名を固定値にできる
- DBのhost名だけでなく、VPCエンドポイントを付与できるリソースはPrivate Host Zoneを経由することで
.env
から設定値を排除できる
モチベーション
DB接続情報のような、環境毎に異なる設定値を管理する方法として.env
が広く普及している。
しかし、筆者はこう考えている。
.env
を使うくらいなら環境毎に異なる設定値が存在しないよう最大限努力すべきである、と。
アプリケーションの設定値の管理というと、Twelve-Factor Appが思い浮かぶが、該当の項では下記のように述べられている。
アプリケーションは設定を名前付きのグループ(しばしば“環境”と呼ばれる)にまとめることがある。グループは、Rails における
development
、test
、production
環境のように、デプロイの名前を取って名付けられる。この方法はうまくスケールしない。アプリケーションのデプロイが増えるにつれて、新しい環境名(staging
やqa
)が必要になる。さらにプロジェクトが拡大すると、開発者はjoes-staging
のような自分用の環境を追加する。結果として設定が組み合わせ的に爆発し、アプリケーションのデプロイの管理が非常に不安定になる。
III. 設定 | The Twelve-Factor App (日本語訳)
言及されているグループという概念について、資料中では明言されていないものの、筆者は.env
もこれに該当すると解釈している。加えて、CakePHPなどのフレームワークで利用するapp_local.php
も同様である。
本稿では.env
管理される設定値の代表例としてDB接続情報を取り上げ、これを.env
運用から脱却させる方法を紹介する。
前提条件
- アプリケーションをデプロイする環境がVPCレベルで隔離されていること
.env
の管理は結構つらい
環境数に応じて管理するファイルが増えがち
1つのサービスを運用する場合でも、本番環境、リモート開発環境、ローカル開発環境、QA環境、E2Eテスト環境など利用する環境は複数あるのが一般的である。
場合によっては少ない人数で複数のサービスの運用をしなければならないケースもあり、サービス数 × 環境数分の.env
を管理するのは非常にコストがかかる。
.env
を編集する機会は意外と多い
今日のWebアプリケーション開発において、.env
が塩漬けになることは珍しい。
新しい機能のためにS3を追加するときや、新しいサブシステムのためのlambdaやAPI Gaytewayを追加するときには.env
を編集することになる。
設定値の増減に合わせて修正する箇所が多くなりがち
たとえば1項目.env
に追加するだけでも、最低3箇所は変更しなければならない。
- 各環境毎の
.env
- リポジトリにコミットする.env.sample
- 環境変数を読み込むアプリケーションのコード
これは、たいへん手間である。
ミスオペを誘発しやすい
上記の通り、一度の修正でこれだけ多くの変更オペレーションを伴うということは、それだけ人手によるミスが紛れ込みやすいということである。
- タイポ
- ファイルの保存先を間違える
- 修正漏れ
運悪く本番環境の.env
でミスが混入してしまうと、それだけで障害となる。
Private Host Zoneを使おう
DBのエンドポイントをPrivate Host ZoneのCNAMEレコードに登録することでアプリケーションがアクセスするDBのhost名を固定値にできる。
Private Host Zoneとは
プライベートホストゾーンは、Amazon VPCサービスで作成する1つ以上のVPC内のドメインとそのサブドメインへのDNSクエリに対し、Amazon Route 53がどのように応答するかに関する情報を保持するコンテナです。
プライベートホストゾーンの使用 - Amazon Route 53
平たく言えば、VPC内でのみ名前解決してくれる君である。
サンプルコード
サンプルとしてTerraformとdocker composeの例を示す。
# DBへの接続用Private hosted zone
resource "aws_route53_zone" "aurora_mysql" {
name = "db.example.com"
vpc {
vpc_id = aws_vpc.your_vpc.id
vpc_region = "ap-northeast-1"
}
force_destroy = false
comment = "Managed by Terraform"
}
# Private Host ZoneのCNAMEレコードwiterエンドポイント用
resource "aws_route53_record" "aurora_mysql_writer" {
name = "writer.db.example.com"
zone_id = aws_route53_zone.aurora_mysql.id
type = "CNAME"
records = [
aws_rds_cluster.your_cluster.endpoint
]
ttl = 60
}
# Private Host ZoneのCNAMEレコードreaderエンドポイント用
resource "aws_route53_record" "aurora_mysql_reader" {
name = "reader.db.example.com"
zone_id = aws_route53_zone.aurora_mysql.id
type = "CNAME"
records = [
aws_rds_cluster_endpoint.your.endpoint,
]
ttl = 60
}
docker composeを利用して開発環境を構築している場合は下記のようにaliasをつける。
mysql:
image: mysql
aliases:
- writer.db.example.com
- reader.db.example.com
まとめ
-
.env
運用はつらいのでなくしていこう- Twelve-Factor Appにもちゃんとそう書いてある
- 環境毎にVPCが隔離されていればPrivate Host Zoneを使ってDBのhost名を固定値で運用できる
- VPCエンドポイントを作成できるリソースであれば同様のアプローチを使うことができる
Discussion