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.8k
アプリケーションコンフィグの設定パターン 銀座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
540
20220125_令和版!RailsアプリでPDF生成するテクニック集 in 銀座Rails#41
morimorihoge
8
6.3k
それ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
420
Other Decks in Programming
See All in Programming
良いユニットテストを書こう
mototakatsu
11
3.6k
『改訂新版 良いコード/悪いコードで学ぶ設計入門』活用方法−爆速でスキルアップする!効果的な学習アプローチ / effective-learning-of-good-code
minodriven
28
4k
快速入門可觀測性
blueswen
0
500
CQRS+ES の力を使って効果を感じる / Feel the effects of using the power of CQRS+ES
seike460
PRO
0
240
アクターシステムに頼らずEvent Sourcingする方法について
j5ik2o
6
700
Jaspr Dart Web Framework 박제창 @Devfest 2024
itsmedreamwalker
0
150
PicoRubyと暮らす、シェアハウスハック
ryosk7
0
200
AIレシート読み取り機能をRuby on Rails on AWSで実現するLLMにまつわるアレコレ / AI-based receipt reading function powered by LLM on Ruby on Rails on AWS
moznion
3
130
技術的負債と向き合うカイゼン活動を1年続けて分かった "持続可能" なプロダクト開発
yuichiro_serita
0
300
PHPで学ぶプログラミングの教訓 / Lessons in Programming Learned through PHP
nrslib
4
1.1k
ドメインイベント増えすぎ問題
h0r15h0
2
560
return文におけるstd::moveについて
onihusube
1
1.4k
Featured
See All Featured
Making the Leap to Tech Lead
cromwellryan
133
9k
Done Done
chrislema
182
16k
Build your cross-platform service in a week with App Engine
jlugia
229
18k
BBQ
matthewcrist
85
9.4k
How to train your dragon (web standard)
notwaldorf
89
5.8k
The Art of Programming - Codeland 2020
erikaheidi
53
13k
Automating Front-end Workflow
addyosmani
1366
200k
GraphQLの誤解/rethinking-graphql
sonatard
68
10k
Why You Should Never Use an ORM
jnunemaker
PRO
54
9.1k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
38
1.9k
Bash Introduction
62gerente
610
210k
The Invisible Side of Design
smashingmag
299
50k
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