Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
アプリケーションコンフィグの設定パターン 銀座Rails #27
Search
Masato Mori
November 27, 2020
Programming
4
5.9k
アプリケーションコンフィグの設定パターン 銀座Rails #27
2020/11/27に銀座Rails#27で発表したスライドです。
https://ginza-rails.connpass.com/event/193008/
Masato Mori
November 27, 2020
Tweet
Share
More Decks by Masato Mori
See All by Masato Mori
20220218_Rails開発プロジェクトチームの始め方と入り方 in 銀座Rails#42
morimorihoge
3
550
20220125_令和版!RailsアプリでPDF生成するテクニック集 in 銀座Rails#41
morimorihoge
8
6.4k
それVIEWでできるよ!(Kaigi on Rails _2021_ new LT)
morimorihoge
2
140
20210827_出張!Railsウォッチ in 銀座Rails#36
morimorihoge
0
1.7k
20210730_出張!Railsウォッチ in 銀座Rails#35
morimorihoge
0
1.6k
20210618_出張!Railsウォッチ in 銀座Rails#34
morimorihoge
0
2k
20210521_出張!Railsウォッチ in 銀座Rails#33
morimorihoge
1
6.4k
20210423_出張!Railsウォッチ in 銀座Rails#32
morimorihoge
0
27
20210226_出張!Railsウォッチ in 銀座Rails#30
morimorihoge
0
430
Other Decks in Programming
See All in Programming
SwiftUI Viewの責務分離
elmetal
PRO
1
240
Amazon Q Developer Proで効率化するAPI開発入門
seike460
PRO
0
110
Open source software: how to live long and go far
gaelvaroquaux
0
640
仕様変更に耐えるための"今の"DRY原則を考える / Rethinking the "Don't repeat yourself" for resilience to specification changes
mkmk884
4
710
CI改善もDatadogとともに
taumu
0
120
Spring gRPC について / About Spring gRPC
mackey0225
0
220
時計仕掛けのCompose
mkeeda
1
300
さいきょうのレイヤードアーキテクチャについて考えてみた
yahiru
3
760
CDK開発におけるコーディング規約の運用
yamanashi_ren01
2
140
法律の脱レガシーに学ぶフロントエンド刷新
oguemon
5
740
第3回 Snowflake 中部ユーザ会- dbt × Snowflake ハンズオン
hoto17296
4
370
Amazon S3 TablesとAmazon S3 Metadataを触ってみた / 20250201-jawsug-tochigi-s3tables-s3metadata
kasacchiful
0
170
Featured
See All Featured
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
7
630
Making the Leap to Tech Lead
cromwellryan
133
9.1k
Six Lessons from altMBA
skipperchong
27
3.6k
Building an army of robots
kneath
303
45k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
12
960
Dealing with People You Can't Stand - Big Design 2015
cassininazir
366
25k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
21
2.5k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
6
550
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
330
21k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
33
2.1k
Into the Great Unknown - MozCon
thekraken
35
1.6k
Adopting Sorbet at Scale
ufuk
74
9.2k
Transcript
アプリケーションコンフィグの設計 パターン 森 雅智 / @morimorihoge 2020/11/27 1 銀座Rails
#27 ※スライドは発表後に #ginzarails で公開します
About Me • 森 雅智: @morimorihoge • BPS株式会社でRailsの受託開発チームをやってたり、週1大学非常勤で Web開発を教えてたりします •
Ruby/Rails歴は11年くらい。Web開発は17年くらい • 銀座Ralis #10でActiveRecordでVIEWを使おうという話をしました • 最近の銀座Railsでは出張Railsウォッチという枠を頂いて発表しています About BPS & TechRacho • Web受託開発や電子書籍製品開発をやっている会社です • TechRachoという自社技術Blogを運営しています ◦ 3年半ほど前から平日毎日更新してます ◦ https://techracho.bpsinc.jp/ • お仕事相談、転職相談、TechRachoへのご意見など気軽にどうぞ ◦ https://www.bpsinc.jp/ 2
アプリケーションの「設定」どうしてますか? サービスが成長するにつれて増えていく色々な「設定」 例)外部サービスの接続情報、S3 Bucket ARNなどのインフラ情報 消費税率、祝日、リスト項目の選択肢 システム内の動作モード切替フラグなど 必須の設定項目が増えすぎると環境構築時の初期設定が匠の技化してしまっ
たり、どこにどんな設定項目があって動いているのかよく分からなくなりがち (Config Hell) 3
この発表の目指すところ アプリケーションの「設定」を設計するにあたって、どのような設定の種類や実装方法が あるのかをまとめ、それぞれのメリット・デメリットを洗い出していきたい 4
取っかかりのための12-Factor App 2017年当時、HerokuにいたAdam Wigginsが現代的なWebアプリケーションやSoftware as a Serviceを作るのにあたりまとめた方法論集 どちらかというとインフラ~DevOpsエンジニアの視点で書かれているが、恐らく現代の Railsエンジニアはその辺りを兼務していることが多いと思うので必読 コンテナ化されたモダンなインフラ環境でまさに参考にできることが多い
今日はここからIII: Configurationをピックアップ 5 https://12factor.net/ja/
12-Factor Appにおける「設定」の定義 • アプリケーションの 設定 は、デプロイ(ステージング、本番、開発環境など)の間で 異なり得る唯一のものである • 認証情報を漏洩させることなく、コードベースを今すぐにでもオープンソースにする ことができるなら、アプリケーションの設定が正しく外部に分離できている
12-Factor Appでは設定を環境変数に格納することを勧めている(利点は後述) 一方で、アプリケーション内部の設定については12-Factor Appは定義の対象外として いる -> 今回の発表ではこちらも対象としていく 6
本発表における「設定」の想定範囲 外部から調整可能な何らかのデータを渡すことにより、アプリケーションの動作を変更し 得るもの、とする。 • 環境変数や引数など、プロセス実行時に引き渡されるもの • プログラムの外からファイルやURLとして渡されて読み込むもの • DBの特定テーブルに入っていて都度読み出す設定情報など どれも広義の設定として考える
7
設定の注入方法 8
色々な設定注入方法一覧 9 • ソースコード内定数 • コマンドライン実行時引数 • 環境変数 • 定数型設定ファイル(YAML、JSONなど)
• ソースコード形式設定ファイル(config/initializersなど) • DBやKVSの設定情報用テーブル • その他の方式
ソースコード内定数 ソースコード内に定数として設定を記述する方式。いわゆるmagic numberに相当する • 設定値を変更するにはソースコードの変更が必要なため、扱いづらい • 外部から設定値を変更するのも困難なため、テストもし辛い 10
コマンドライン実行時引数 RakeタスクやRails runner経由で実行する場合は、実行時コマンドに設定を渡すこともで きる • rakeやrailsコマンドが実行できるシェルが取れる場合に柔軟に利用可能 • Rails runner経由であればRubyコードも書けるので、Time.nowなどの取得も可能 11
rails runner "HogeService.call(from: Time.now)"
環境変数 12-Factor Appでもオススメされる設定方法。RubyではENVから取る • PaaSやCIツールが設定をサポートしているケースが多く、つなぎ込みという点では 最も柔軟かつ汎用性が高い • Rails以外のソフトウェアと設定値を共有したい場合にも便利 • 文字列しか渡せないため、複雑なデータ構造を渡すのは不向き
12
定義型設定ファイル(YAML、JSONなど) `rubyconfig/config` gem(旧rails_config)などがメジャーどころ • ArrayやHashなどの文字列以外の構造データを格納することができる • 階層構造に対応するのでnamespace的な整理が可能 13 ※以下は`rubyconfig/config` gemを使ったサンプル
ソースコード形式設定ファイル config/initializers/*に置かれるようなRubyコードとして実行時に初期化・設定のために 読み込まれる方式 • pureなRubyコードが書けるため、値の設定だけでなく初期化の重いオブジェクトの 生成なども可能 • lambdaやProcも設定することができるため、定数による設定ファイルでは書けない ロジック(Time.now.yesterdayなど)も記述できる ◦
既存のライブラリの設定値にlambdaやProcを設定してちゃんと動くかは作りに依る 起動前の事前設定が必要なRails系Gemなどはこの形式を取っているものが多い 14
DBやKVSの設定情報用テーブル アプリケーション設定情報用のkey-valueデータを格納したテーブルを用意し、必要に応 じて参照・更新する • 古くからある方式で、feature toggleなどに良く利用される • プロセスの再起動なしに値の更新が可能 • DBアクセスが発生するため、DBサーバーが遠かったり設定値が多すぎると速度面
が問題になるかもしれない 15
その他 フロントエンド系ではサーバーサイドを介さずに外部サービスで設定を行うこともある が、ここでは非サーバーサイド系ということで対象外としておく • 例:Google TagManagerで条件に合わせて表示する内容をJavaScriptで切り替えて A-Bテストを行うなど 他にもAWSなどのインフラサイドの設定のみでcanary deployするようなことも最近はでき たりするが、こちらも完全にクラウド側の設定になってしまうので今回は対象外としてお
きます 16
各手法の特徴や使いどころを見ていく 17
ざっくり整理してみる 18 読み込みタイミング 設定値の編集方法 再読込方法 リクエスト処理時 オーバーヘッド ソース内定数 プロセス起動時 ソース修正
プロセス再起動 低 コマンドライン引数 プロセス起動時 実行コマンド変更 プロセス再起動 低 環境変数 プロセス起動時 環境設定更新 プロセス再起動 低 YAML/JSON プロセス起動時 ファイル修正 プロセス再起動 低 ソースコード設定ファ イル プロセス起動時 ソース修正 プロセス再起動 低 DB/KVSテーブル 値参照時 DB値更新 DB値参照 小 次ページから切り口ごとに見ていきます
読み込みタイミングによる違い 多くの手法はプロセス実行時読み込みとなるが、それはすなわち設定値の変更に deployが必要になるということ(まさに12-Factor Appの「設定」の定義) 19 読み込みタイミング 設定値の編集方法 再読込方法 リクエスト処理時オー バーヘッド
ソース内定数 プロセス起動時 ソース修正 プロセス再起動 低 コマンドライン引数 プロセス起動時 実行コマンド変更 プロセス再起動 低 環境変数 プロセス起動時 環境設定更新 プロセス再起動 低 YAML/JSON プロセス起動時 ファイル修正 プロセス再起動 低 ソースコード設定ファイ ル プロセス起動時 ソース修正 プロセス再起動 低 DB/KVSテーブル 値参照時 DB値更新 DB値参照 小 多くの手法はプロセス実行時読み込みとなるが、それはすなわち設定値の変更に deployが必要になるということ(まさに12-Factor Appの「設定」の定義) -> deployせずに設定変更したければ、DB/KVSを使うのが良さそう
設定変更方法による違い 設定変更にソース修正が必要な方法を使う場合、運用上のニーズである設定変更が機 能開発のソース変更と混じる -> branchのmerge運用がカオスになりやすい要因の一つ 20 読み込みタイミング 設定値の編集方法 再読込方法 リクエスト処理時オー
バーヘッド ソース内定数 プロセス起動時 ソース修正 プロセス再起動 低 コマンドライン引数 プロセス起動時 実行コマンド変更 プロセス再起動 低 環境変数 プロセス起動時 環境設定更新 プロセス再起動 低 YAML/JSON プロセス起動時 ファイル修正 プロセス再起動 低 ソースコード設定ファイ ル プロセス起動時 ソース修正 プロセス再起動 低 DB/KVSテーブル 値参照時 DB値更新 DB値参照 小 ※YAML/JSON方式は当該configをcommitするかにも依る -> deployせずに設定変更したければ、DB/KVSを使うのが良さそう
API KEYなどの秘密情報管理の観点 21 参照・更新権限 ソース内定数 リポジトリへのアクセス権限次第 コマンドライン引数 設定されている場所や実行方法によるが、 リポジトリのCI設定ファイルなどに書かれている場合はそのファイルの書き方依存となる ※Secure
Variable的な機能があればよりセキュアに設定できる 環境変数 設定されている場所や実行方法によるが、 リポジトリのCI設定ファイルなどに書かれている場合はそのファイルの書き方依存となる ※Secure Variable的な機能があればよりセキュアに設定できる YAML/JSON リポジトリに置く場合はcredentials機能などを使わないととても危険 リポジトリ管理外に置くのであれば、当該設定ファイルのアクセス権限依存 ※AWS S3などであればpolicy設定などで細かく設定できる ソースコード設定ファイル 基本的にここに生で書くことはなさそう? もしやる場合はYAML/JSONの場合と同様 DB/KVSテーブル DB/KVSへのアクセス権限次第 どのケースでも、shellが取れてrails consoleが使えると見られない情報はないので、踏み台サー バーなどでshell環境を用意する場合は権限に要注意
その他のトピック 22
configからconfigを作るという選択肢 ファイル形式の設定しか受け入れてくれないが、設定を環境変数で渡したいというケー ス(DockerでApacheやMySQLのコンテナを使おうとするとありがち) Dockerだとentrypoint.shの中でenvsubst(gettextパッケージ内)などのテンプレートエン ジンを使ってテンプレート化されたconfigに環境変数を実行時展開して読み込ませるとい う手が使える # buildに含めるのでも良いが、その場合設定変更時に毎回buildが必要 -> 参考:
envsubstを使ってDockerで設定ファイルに環境変数を埋め込めこむ汎用的な パターン https://qiita.com/minamijoyo/items/63ae57b99d4a4c5d7987 23 # entrypoint.sh . /container.env EXTRACT_VARS=’$VAR_A $VAR_B...’ envsubst “$EXTRACT_VARS” < httpd.conf.tpl > /etc/apache2/conf/httpd.conf apache2-foreground やや冗長だが、こういうやり方もあるということで・・・
複数の設定方式に同時対応する OSSなどで色々な環境で動作させることを想定する場合、複数の設定方式に対応すると より柔軟な使い方ができる よく見るのは以下のように環境変数・設定ファイルに同時対応しているもの ※上に行くほど優先度が高く、設定がなければ順に下の値を見に行く • 環境変数の設定値 • 設定ファイルの設定値 ◦
この中にさらに優先順位があることもある(例:`config` gem) • アプリケーションのデフォルト設定値 24
デフォルト値問題 可能ならデフォルト値を設定し、デフォルトでいい感じに動くようにしておきたい ※これはRailsのCoC(Convention over Configuration)原則にも通じる デフォルト値がある場合でも、設定ファイルを使うのであればリポジトリに全パラメータの デフォルト値が記述されたデフォルト設定ファイルがあるととても親切 ※rubocop-todo.yml みたいなイメージ。「その設定パラメータがある」ことが明示的に分 かることで得られる情報がかなり増えるのと、既存設定とのdiffを見ることで何がカスタマ
イズすべきパラメータなのかを調べたりできる 25
環境変数に全部乗せるのは難しい問題 環境変数は文字列しか設定できないので、配列やハッシュなどの構造を持ったデータは 扱いづらい(不可能ではないが・・・) すべてのconfigを環境変数に出すというのは現実的ではないので、開発環境や動作環 境によって切り替えることが多いものは環境変数、そうでないものは設定ファイルに入れ るなどの対応は必要 一般的にはWebサーバーレベルの挙動や外部連携周りは環境変数、アプリケーション 内の振る舞いに関連する部分は設定ファイルに記述することが多いように思える ・・・が、アプリケーション内の振る舞いでも環境変数で渡したいデータは出てくるケース があるので、この辺りはニーズに応じて調整するしかなさそう?
26
まとめ Railsにおけるアプリケーションコンフィグの設計パターンを整理し、解説してみました いろいろな実装方法があることを知ることで、新しい設定値を追加しようとしたときにどの 手法が最適化を考える一助になれば幸いです 設定情報はアプリケーションが育てば育つほど増えていく傾向があるので、将来の自分 や同僚が発狂しないようにしたいものですね 27
次回以降もブラッシュアップしていきます 感想・リクエストなどあればTwitter #ginzarails @morimorihoge までお声かけください 28