Firebase-tools: ํ•จ์ˆ˜์— ๋Œ€ํ•œ JSON ํŒŒ์ผ ์ˆ˜๋ฝ:config:set

์— ๋งŒ๋“  2017๋…„ 07์›” 20์ผ  ยท  37์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: firebase/firebase-tools

ํ˜„์žฌ firebase functions:config:get ์‚ฌ์šฉํ•˜์—ฌ ์ „์ฒด ๊ธฐ๋Šฅ ๊ตฌ์„ฑ์„ JSON ํŒŒ์ผ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์ง€๋งŒ firebase functions:config:set ๋ช…๋ น์„ ์‚ฌ์šฉํ•  ๋•Œ ๊ฐ ๋ณ€์ˆ˜๋ฅผ ์ˆ˜๋™์œผ๋กœ ์ธ๋ผ์ธํ•ด์•ผ ํ•˜๋ฏ€๋กœ ์ž‘์—…ํ•  ๋•Œ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ํ™˜๊ฒฝ.

์ด์ƒ์ ์œผ๋กœ๋Š” ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

firebase functions:config:get > config.json
firebase functions:config:set -f config.json

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

๊ณต์œ ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! @laurenzlong
ํŒŒ์ผ์—์„œ ๊ฐ€์ ธ์˜ค๊ณ  ์‹ถ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ช…๋ น์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

firebase functions:config:set service_account="$(cat service-account.json)"

Firebase Admin SDK์˜ ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ API๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋น„์Šค ๊ณ„์ • json ํŒŒ์ผ์„ Firebase Cloud Functions๋กœ ๊ฐ€์ ธ์™”์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  37 ๋Œ“๊ธ€

@jpreynat์— ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœ๋•์…˜์— ๋ฐฐํฌํ•˜๊ธฐ ์ „์— ๊ตฌ์„ฑ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์„ ์žŠ์–ด๋ฒ„๋ฆฌ๋Š” ๋‚ ์ด config:set ์„ config.json์œผ๋กœ ์‚ฌ์šฉ์ž ์ง€์ • ๋ฐฐํฌ ์Šคํฌ๋ฆฝํŠธ์— ์—ฐ๊ฒฐํ•˜๋ฉด ์ถ”๊ฐ€๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋Š” ์ข‹์€ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.
์ง€๊ธˆ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์•„๋งˆ๋„ ๊ตฌ์„ฑ์— ํŒŒ์ดํ”„๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

ํ”„๋กœ์ ํŠธ ๊ฐ„์— ๊ตฌ์„ฑ์„ ๋ณต์ œํ•˜๋ ค๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. firebase functions:config:clone ์ด(๊ฐ€) ๋„์›€์ด ๋ ๊นŒ์š”?

์•ฝ๊ฐ„์˜ ๋งฅ๋ฝ์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๊ตฌ์„ฑ์€ ๋‚˜์œ ๊ด€ํ–‰(์ฆ‰, ์ฝ”๋“œ์™€ ํ•จ๊ป˜ ์ €์žฅ๋œ ๋น„๋ฐ€๋กœ ๊ฐ€๋“ ์ฐฌ ํŒŒ์ผ์„ ์œ ์ง€ํ•˜๊ณ  ์ž ์žฌ์ ์œผ๋กœ ์†Œ์Šค ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ์ฒดํฌ์ธํ•  ์ˆ˜๋„ ์žˆ์Œ)์„ ์กฐ์žฅํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜๋„์ ์œผ๋กœ ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๊ตฌ์„ฑ์—์„œ ๋ฒ—์–ด๋‚ฌ์Šต๋‹ˆ๋‹ค.

"ํ•„์ˆ˜" ๊ตฌ์„ฑ ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•˜๋Š” ๋ฐฉ๋ฒ•(์—ญํ•™ ๋ฏธ์ •)์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜์‹œ๋‚˜์š”? ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์—์„œ ํ•„์ˆ˜ ๊ตฌ์„ฑ ์—†์ด ๋ฐฐํฌํ•˜๋ ค๊ณ  ํ•˜๋ฉด ๋ณ€๊ฒฝ๋˜๊ธฐ ์ „์— ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ฒŒ ํ•˜๋ฉด ์ฃผ์š” ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋ฉ๋‹ˆ๊นŒ? ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด ์™œ ํŒŒ์ผ์„ ๊ฐ–๋Š” ๊ฒƒ์ด ๋‹น์‹ ์—๊ฒŒ ํŠนํžˆ ์œ ์šฉํ•ฉ๋‹ˆ๊นŒ?

@mbleigh ๊ทธ๊ฒŒ ๋ฐ”๋กœ ๋‚ด๊ฐ€ ์›ํ•˜๋Š”์ง€ ๋ชฐ๋ž๋˜ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ข‹์€ ์ƒ๊ฐ!
์•„๋งˆ๋„ 'Mechanics TBD'๊ฐ€ ์˜๋ฏธํ•˜๋Š” ๋ฐ”๋Š” ๊ฐ™์ง€๋งŒ: ์›๊ฒฉ์ด ์•„๋‹Œ ํ”„๋กœ์ ํŠธ ๋‚ด์˜ ์ผ๋ถ€ ํŒŒ์ผ์—์„œ ํ‚ค/๊ตฌ์„ฑ ๊ตฌ์กฐ๋ฅผ ์ •์˜ํ•˜์—ฌ ๋‹ค๋ฅธ ๋ชจ๋“  ๊ฒƒ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ git/PR ๊ฒ€ํ†  ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ฑฐ์น˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
@jpreynat ๋„์šฉ ๋ฌธ์ œ์— ๋Œ€ํ•ด ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค.

@laurenzlong ์กฐ์–ธ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ตฌ์„ฑ์„ ๋ณต์ œํ•˜๋ ค๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.
์šฐ๋ฆฌ์˜ ์ฃผ์š” ๊ด€์‹ฌ์‚ฌ๋Š” ๋ฐฐํฌ ๋‹จ๊ณ„์— ๋”ฐ๋ผ ๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ ๊ตฌ์„ฑ์„ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™˜๊ฒฝ(dev, staging ๋ฐ prod)๋ณ„๋กœ ๊ตฌ์„ฑ ํŒŒ์ผ์ด ์žˆ๊ณ  Firebase ๊ตฌ์„ฑ์„ ๊ฐ๊ฐ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค(PR์˜ ๊ฒฝ์šฐ ๋งˆ์Šคํ„ฐ ๋ฐ ํƒœ๊ทธ ํ‘ธ์‹œ).

@mbleigh ์ •๋ณด ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿฌ๋‚˜ ๊ตฌ์„ฑ ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ ์ด๋Ÿฌํ•œ ๋ชจ๋“  ํ™˜๊ฒฝ์„ ์ €์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ํ™•์‹คํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
ํ˜„์žฌ๋Š” ๋‹จ์ˆœํ•˜๊ฒŒ ์ฝ๊ธฐ ์œ„ํ•ด JSON ํ˜•์‹์œผ๋กœ ์ง€์ •๋˜์–ด ์žˆ์ง€๋งŒ functions:config:set ๋ช…๋ น์— ์ง์ ‘ ์ „๋‹ฌํ•˜๊ธฐ ์œ„ํ•ด ํ‚ค/๊ฐ’ ์Œ์œผ๋กœ ํ˜•์‹์„ ์ง€์ •ํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
์ด๊ฒƒ์ด JSON ํŒŒ์ผ์„ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ์•ˆ์ „ํ•˜์ง€ ์•Š๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.
ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ ์™ธ์— ๋‹ค๋ฅธ ๋‹จ๊ณ„์— ๋Œ€ํ•ด ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ๊ถŒ์žฅ ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

@ahaverty ๊ฑฑ์ •ํ•˜์ง€ ๋งˆ์„ธ์š”. ์—ฌ๊ธฐ์„œ ํ† ๋ก ํ•  ์ˆ˜ ์žˆ์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค.

@jpreynat functions:config:set ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์™€ ํ•จ๊ป˜ ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. firebase use ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กœ์ ํŠธ ๊ฐ„์— ์ „ํ™˜ํ•˜๋Š” ๊ฒฝ์šฐ ๊ตฌ์„ฑ์ด ์˜๊ตฌ์ ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ”„๋กœ์ ํŠธ๋‹น set ํ•œ ๋ฒˆ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๊ทธ๋Ÿฌ๋ฉด ํ•ญ์ƒ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ "๋‹ค๋ฅธ ํ™˜๊ฒฝ์— ๋Œ€ํ•œ ๋‹ค๋ฅธ ๊ตฌ์„ฑ"๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์•ผํ•˜๋ฏ€๋กœ ์‹ค์ œ ๋ฌธ์ œ๋ฅผ ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๊นŒ?

@jpreynat ์ง€๊ธˆ์€ ์ด ๋ฌธ์ œ๋ฅผ ๋‹ซ์„ ์˜ˆ์ •์ด์ง€๋งŒ Michael๊ณผ ๋‚ด๊ฐ€ ๊ท€ํ•˜์˜ ์š”์ฒญ์„ ์ž˜๋ชป ์ดํ•ดํ•œ ๊ฒฝ์šฐ ๋‹ค์‹œ ์—ฌ์‹ญ์‹œ์˜ค.

@laurenzlong @mbleigh ์ด ์Šค๋ ˆ๋“œ์— ๋Œ€ํ•ด ๋น ๋ฅด๊ฒŒ ๋‹ต๋ณ€ํ•˜์ง€
ํ˜„์žฌ ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์ฐพ์•˜์ง€๋งŒ ๋‹ค์Œ์€ ๋‚ด ์š”์ฒญ์„ ๋ช…ํ™•ํžˆ ํ•˜๊ธฐ ์œ„ํ•œ ๋ช‡ ๊ฐ€์ง€ ์ปจํ…์ŠคํŠธ์ž…๋‹ˆ๋‹ค.

Travis๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ฑ์„ ๋ฐฐํฌํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค(์ด๋Š” ๋ชจ๋“  CI ๋˜๋Š” ๋กœ์ปฌ์—์„œ ์œ ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค). ๋ธŒ๋žœ์น˜์™€ ํƒœ๊ทธ์— ๋”ฐ๋ผ ๋‹ค์–‘ํ•œ ์Šคํ…Œ์ด์ง€์— ์•ฑ์„ ๋ฐฐํฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ™˜๊ฒฝ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ JSON ํŒŒ์ผ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด ์ด ์กฐ๊ฑด์— ๋”ฐ๋ผ firebase config:set -f staging.json ๋˜๋Š” firebase config:set -f prod.json ๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์šฐ๋ฆฌ์˜ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ firebase ๋ฅผ ๋…ธ๋“œ ๋ชจ๋“ˆ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด์ง€๋งŒ ์—ฌ์ „ํžˆ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์‰ฌ์šด JSON ๊ตฌ์„ฑ์„ ์ธ๋ผ์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š” @jpreynat ๊ท€ํ•˜์˜ ๋‹ต๋ณ€์— ์—ฌ์ „ํžˆ ์•ฝ๊ฐ„ ํ˜ผ๋ž€ ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค. ๊ตฌ์„ฑ์„ ํ•œ ๋ฒˆ ์„ค์ •ํ•˜๋ฉด firebase functions:config :unset์„ ์‹คํ–‰ํ•˜์—ฌ ๊ตฌ์„ฑ ๊ฐ’์„ ๋ช…์‹œ์ ์œผ๋กœ ์„ค์ • ํ•ด์ œํ•˜์ง€ ์•Š๋Š” ํ•œ ๋ฐฐํฌ ์ „๋ฐ˜์— ๊ฑธ์ณ ํ•ญ์ƒ ๊ทธ๋Œ€๋กœ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ CI ํ”„๋กœ์„ธ์Šค์˜ ์ผ๋ถ€๋กœ ์ด๊ฒƒ์„ ๊ฐ€์งˆ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€ ์ด๊ฒƒ์„ ๋‹ค์‹œ ์—ด ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? %) @jpreynat @mbleigh ์ •๋ง ๋น ์ง„ ๊ฒƒ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. Atm ๋‚˜๋Š” ๊ฑฐ์˜ 15๊ฐœ์˜ ๊ตฌ์„ฑ ๋ณ€์ˆ˜๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ functions:config:set ๊ฐ€ ์–ด๋–ค ์‹์œผ๋กœ๋“  JSON์„ ๋ฐ›์•„๋“ค์ผ ์ˆ˜ ์žˆ๋‹ค๋ฉด ๋งค์šฐ ํŽธ๋ฆฌํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

"ํ•„์ˆ˜" ๊ตฌ์„ฑ ๋ณ€์ˆ˜ ์„ ์–ธ์— ๋Œ€ํ•œ @mbleigh ์ œ์•ˆ์— ๋Œ€ํ•œ ์šฐ๋ฆฌ์˜ ํฐ ํˆฌํ‘œ -- ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์—์„œ ํ•„์ˆ˜ ๊ตฌ์„ฑ ์—†์ด ๋ฐฐํฌํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์•„๋ฌด๊ฒƒ๋„ ๋ณ€๊ฒฝ๋˜๊ธฐ ์ „์— ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
์šฐ๋ฆฌ์—๊ฒŒ๋„ ๊ณจ์นซ๊ฑฐ๋ฆฌ๊ฐ€ ๋˜์ง€๋งŒ, ๊ทธ๊ฒƒ์€ ์šฐ๋ฆฌ์˜ ๋ชจ๋“  ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ๋ฒ„์ „ ๊ด€๋ฆฌ/๊ฒ€ํ†  ํ”„๋กœ์„ธ์Šค์— ์ž˜ ๋งž์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค ๐Ÿ‘

https://medium.com/@AllanHasegawa/setting -config-for-firebase-cloud-functions-with-json-136f455e7c69

@yaronyosef firebase functions:config :set ๋ช…๋ น์— JSON์„ ์ง์ ‘ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”Œ๋žซํผ์— ์ ํ•ฉํ•œ ๋ฐฉ์‹์œผ๋กœ ํ˜•์‹์„ ์ง€์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. Linux์˜ ๊ฒฝ์šฐ ๋‹ค์Œ์ด ์ž‘๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

firebase functions:config:set foo='{"bar":"something","faz":"other"}'

๊ณต์œ ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! @laurenzlong
ํŒŒ์ผ์—์„œ ๊ฐ€์ ธ์˜ค๊ณ  ์‹ถ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ช…๋ น์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

firebase functions:config:set service_account="$(cat service-account.json)"

Firebase Admin SDK์˜ ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ API๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋น„์Šค ๊ณ„์ • json ํŒŒ์ผ์„ Firebase Cloud Functions๋กœ ๊ฐ€์ ธ์™”์Šต๋‹ˆ๋‹ค.

๋ฉ‹์ง„ ์‚ฌ์šฉ ์‚ฌ๋ก€! ๊ณต์œ ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

๋˜ํ•œ Git์„ ํ†ตํ•ด ๋น„๋ฐ€์ด ์•„๋‹Œ ๊ตฌ์„ฑ์„ ์ถ”์ ํ•˜๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ปค๋ฐ‹๋œ JSON ๋Ÿฐํƒ€์ž„ ๊ตฌ์„ฑ ํŒŒ์ผ(์—ฌ๋Ÿฌ ํ™˜๊ฒฝ์šฉ)์€ ๊ถŒํ•œ์ด ์žˆ๊ณ  CI ํ™˜๊ฒฝ์€ ํŠน์ • ํ™˜๊ฒฝ์— ํ•ด๋‹นํ•˜๋Š” ํŒŒ์ผ์—์„œ functions:config:set ๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ํ™˜๊ฒฝ์€ ๋ณ„๋„์˜ Firebase ํ”„๋กœ์ ํŠธ์— ํ•ด๋‹นํ•ฉ๋‹ˆ๋‹ค.

git์— ๊ตฌ์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ๊ฒฝ์šฐ ๊ธฐ๋Šฅ ๋Ÿฐํƒ€์ž„์œผ๋กœ ๊ตฌ์„ฑ์„ ์ฝ๋Š” ๊ฒƒ์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. configs/<project_id>.json ์— ๋„ฃ์€ ๋‹ค์Œ:

let config = {};
try {
  config = require(`./configs/${process.env.GCLOUD_PROJECT}.json`);
} catch (e) {
  console.log('No config found for project', process.env.GCLOUD_PROJECT);
}

Firebase์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋Ÿฐํƒ€์ž„ ๊ตฌ์„ฑ์€ (ํŠนํžˆ ๋น„๋ฐ€์˜ ๊ฒฝ์šฐ) ๊ตฌ์„ฑ์ด ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ๋งŽ์€ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ค๋Š” ํŒจํ„ด์œผ๋กœ ๋ฐํ˜€์กŒ๊ธฐ ๋•Œ๋ฌธ์— ๊ตฌ์„ฑ์ด git์— ์ฒดํฌ์ธ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋„๋ก ํŠน๋ณ„ํžˆ ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค์ด์ง€๋งŒ ๋” ์ด์ƒ ์ด ๋ชฉ์ ์œผ๋กœ Config API๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฏผ๊ฐํ•œ ๊ฐ’์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด Config API(Firebase ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด ์ ์ ˆํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์ธ ๊ฒƒ์œผ๋กœ ๋ณด์ž„)๋ฅผ ๊ณ„์† ์ง„ํ–‰ํ•˜๊ณ  ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ์†Œ์Šค ์ œ์–ด ๊ฐ’๊ณผ ์ถ”์ ๋˜์ง€ ์•Š์€ ๊ฐ’์„ ๋ชจ๋‘ ๋กœ๋“œํ•˜๋Š” ๊ฒƒ์ด ์œ ๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: config() ์ œ๊ณต firebase-functions ).

๋‹น๋ถ„๊ฐ„์€ .runtimeconfig ์— functions:config:set ์ „์ฒด๋ฅผ ๊ณต๊ธ‰ํ•˜๊ธฐ ์œ„ํ•ด ๋‹ค์Œ ํ•œ ์ค„์งœ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

firebase functions:config:set $(jq -r 'to_entries[] | [.key, (.value | tojson)] | join("=")' < .runtimeconfig/${FIREBASE_ENV}.json)

์—ฌ๊ธฐ์„œ FIREBASE_ENV ๋Š” ๋ฐฐํฌ์— ์‚ฌ์šฉ๋œ ํ™˜๊ฒฝ์˜ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค(์˜ˆ: dev ). ์ด๊ฒƒ์„ ๋” ์ค„์ผ ์ˆ˜ ์žˆ์œผ๋ฉด ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด

firebase functions:config:set -f .runtimeconfig/${FIREBASE_ENV}.json

๊ทธ๋Ÿฌ๋‚˜ ๊ถ๊ทน์ ์œผ๋กœ Config API๊ฐ€ ๋ชจ๋“  ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋Œ€ํ•œ ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฌ์šด ๊ฐ์‚ฌ ์ถ”์ ์„ ํ™œ์„ฑํ™”ํ•œ ๊ฒฝ์šฐ์—๋„ ํ•„์š”ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(์ด๋ฏธ ๊ทธ๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ์ˆ˜์ •ํ•ด ์ฃผ์„ธ์š”. ์ด์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค).

๊ทธ๋ž˜์„œ ์ด๊ฒƒ์€ ์–ด๋–ป๊ฒŒ ์˜ค๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? ๐Ÿ˜„

@mbleigh ์ œ์•ˆ ์ด ์—ฌ์ „ํžˆ ๊ตฌํ˜„๋˜๋Š” ๊ฒƒ์„ ๋ณด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค ! ๊ฐœ๋ฐœ์ž๊ฐ€ ์•„๋‹Œ ๋Œ€์ƒ์—์„œ ๊ตฌ์„ฑ์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์„ ์žŠ์–ด๋ฒ„๋ฆฌ๋Š” ๋ฌธ์ œ๊ฐ€ ์ง€์†์ ์œผ๋กœ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์Šค๋ ˆ๋“œ ๋ฒ”ํ”„ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์•„์ง ๋ณด๊ณ ํ•  ๋‚ด์šฉ์ด ์—†์ง€๋งŒ ๊ณ„ํš ํšŒ์˜์—์„œ ์ด๋ฅผ ๋‹ค์‹œ ์–ธ๊ธ‰ํ•˜์—ฌ ์ด์— ๋Œ€ํ•œ ์ง„์ „์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

JSON ์Šคํ‚ค๋งˆ ํŒŒ์ผ๋กœ ๊ตฌ์„ฑ์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ•˜์—ฌ ์˜ˆ์ƒํ•œ ๋ชจ๋“  ๊ฐ’์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ์ด ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋Š” ๋‚ด CI ํŒŒ์ดํ”„๋ผ์ธ์˜ ์ผ๋ถ€์ด๋ฉฐ ์‹คํŒจํ•  ๊ฒฝ์šฐ ๋ฐฐํฌ๋ฅผ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค. ์ €์ฒ˜๋Ÿผ TypeScript๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝ์šฐ ์œ ํ˜•์—์„œ JSON ์Šคํ‚ค๋งˆ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

config ํ•จ์ˆ˜๊ฐ€ ๋ฌธ์ž์—ด๋งŒ ํ—ˆ์šฉํ•œ๋‹ค๋Š” ์ œํ•œ๊ณผ ํ•จ๊ป˜ ํ›Œ๋ฅญํ•˜๊ฒŒ ์ž‘๋™ํ•˜๋ฏ€๋กœ ์Šคํ‚ค๋งˆ๋Š” config ๊ฐ’์ด ์ˆซ์ž์ธ์ง€ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๋ถ€์šธ์˜ ๊ฒฝ์šฐ "true" ๋ฐ "false" ์žˆ๋Š” ์—ด๊ฑฐํ˜•์„ ์œ ์ผํ•œ ์œ ํšจํ•œ ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค.

๋‚ด CircleCI ๊ตฌ์„ฑ ๊ณผ ์ด ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ ์„ ์ฐธ์กฐํ•˜์„ธ์š”.

@hgwood ๊ณต์œ 

์ด "๋ฌธ์ œ"์— ๋Œ€ํ•œ ๋‚ด ์†”๋ฃจ์…˜๊ณผ ํ† ๋ก ์— ๋Œ€ํ•œ ๋‚ด ์ƒ๊ฐ์„ ๋‚จ๊ธฐ๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

  1. ๋‚˜๋Š” ๋น„๋ฐ€/๋ฏผ๊ฐํ•œ ๊ฐ’์ด ์ €์žฅ์†Œ์— ์ €์žฅ๋˜์–ด์„œ๋Š” ์•ˆ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ์†”๋ฃจ์…˜์€ ๋น„๋ฐ€์ด ์•„๋‹Œ ๊ฐ’์—๋งŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ๋น„๋ฐ€ ๊ฐ’์€ ์ˆ˜๋™์œผ๋กœ ์„ค์ •๋˜์ง€๋งŒ ๊ตฌ์„ฑ ๊ฐ’์„ ํ•„์š”์— ๋”ฐ๋ผ ํ‘œ์‹œํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ด๋Ÿฌํ•œ ๋น„๋ฐ€ ๊ฐ’์— ๋Œ€ํ•ด ํ›Œ๋ฅญํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  2. ๋‚˜๋Š” ์ด๊ฒƒ์ด ์ผ๋ถ€ ์‚ฌ๋žŒ๋“ค์ด ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋” ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋ฐฐ์น˜ ํ™˜๊ฒฝ ํ”„๋กœ์ ํŠธ์— ๋Œ€ํ•ด ๊ฐœ๋ณ„ ๊ตฌ์„ฑ ๊ฐ’์„ ์ˆ˜๋™์œผ๋กœ ์„ค์ •ํ•ด์•ผ ํ•˜๋ฉฐ ๋™์‹œ์— ์‰ฝ๊ฒŒ ๋ณด๊ณ /๋น„๊ตํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ด PITA์ž…๋‹ˆ๋‹ค. ํŒŒ์ผ์— ๊ตฌ์„ฑ์„ ์ •์˜ํ•˜๋ฉด ํ”„๋กœ์„ธ์Šค๊ฐ€ ํ›จ์”ฌ ๋œ ๋ฒˆ๊ฑฐ๋กญ์Šต๋‹ˆ๋‹ค.
  3. ์›น ์ฝ˜์†”์— ๊ธฐ๋Šฅ ๊ตฌ์„ฑ ํŽธ์ง‘๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์ด ์ ์ด ๋งŽ์ด ๊ฐœ์„ ๋  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ ์—ฌ๋Ÿฌ ํ”„๋กœ์ ํŠธ์— ๋Œ€ํ•œ ๊ตฌ์„ฑ์„ ๋™์‹œ์— ๋ณผ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์œผ๋ฉด ๋‹ค๋ฅธ ๋ฐฐํฌ ํ™˜๊ฒฝ์— ๋Œ€ํ•œ ๊ตฌ์„ฑ์„ ์‰ฝ๊ฒŒ ๋น„๊ตํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์œผ๋ฉด ์ •๋ง ์ข‹์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  4. ์ €๋Š” Firebase๊ฐ€ ๋‹จ์ผ ํ”„๋กœ์ ํŠธ ๋‚ด์—์„œ ํ™˜๊ฒฝ์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๋ฏ€๋กœ ๋ฐฐํฌ ํ™˜๊ฒฝ์œผ๋กœ ์‚ฌ์šฉํ•  ์—ฌ๋Ÿฌ ํ”„๋กœ์ ํŠธ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค๊ณ  ์˜์›ํžˆ ๋งํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ์กด์žฌํ•œ๋‹ค๋ฉด ๋‹จ์ผ ํ”„๋กœ์ ํŠธ ๋‚ด์—์„œ ์—ฌ๋Ÿฌ ํ™˜๊ฒฝ์— ๋Œ€ํ•œ ๊ตฌ์„ฑ์„ ๋™์‹œ์— ๋ณด๋Š” ๊ฒƒ์ด ๋งค์šฐ ์‰ฌ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  5. ๋‚ด ์†”๋ฃจ์…˜์—๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ์ฝ”๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฏฟ์ง€๋Š” ์•Š์ง€๋งŒ ์ผ๋ฐ˜์ ์ธ ๊ฐœ๋…์€ ๋งˆ์Œ์— ๋“ญ๋‹ˆ๋‹ค.

๋‚ด ์†”๋ฃจ์…˜

์ €๋Š” cascading yaml ๊ตฌ์„ฑ ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, ์ด๋Š” ๋ฐฐํฌ ํ™˜๊ฒฝ์— ๊ด€๊ณ„์—†์ด ๋ชจ๋“  ๊ตฌ์„ฑ์— ์ ์šฉ๋˜๋Š” ๊ธฐ๋ณธ๊ฐ’๊ณผ ๊ฐ’์— ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

./config/default.yml

app:
  name: My App
featureFlags:
  someFeature:
    enabled: false

./config/dev.yml (๋‹ค๋ฅธ ๋ฐฐํฌ ํ™˜๊ฒฝ์— ๋Œ€ํ•œ ์œ ์‚ฌํ•œ ๊ตฌ์„ฑ ํŒŒ์ผ)

imports:
  - {resource: default.yml}
app:
  environmentName: Development
services:
  someOtherService:
    baseUrl: https://dev.someotherservice.com/api
featureFlags:
  someFeature:
    enabled: true

๊ทธ๋Ÿฐ ๋‹ค์Œ ํ™•์ธ๋œ ๊ตฌ์„ฑ์„ ๋กœ๋“œํ•˜๊ณ  ๊ณต๋ฐฑ์œผ๋กœ ๊ตฌ๋ถ„๋œ key=val ์Œ ๋ชฉ๋ก์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ž‘์€ ๋…ธ๋“œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

yaml_to_keyval.ts

import * as configYaml from "config-yaml"
import * as flat from "flat"


const yamlFile = process.argv[2]
const config = configYaml(yamlFile)
const flatConfig = flat(config)

const key_val_list = Object.keys(flatConfig).map(function(key){
    return `${key}=${flatConfig[key]}`
})

console.log(key_val_list.join(' '))

CI ๋ฐฐํฌ ์ค‘์— ์ด bash ์…ธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ key=val ์Œ์„ ์–ป๊ณ  functions:config :set ์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

# env is set to the desired deployment environment (eg "dev"), which is passed as an argument to the CI script command
config_in="$(readlink -f ./config/$env.yml)"
key_vals="$(ts-node ./scripts/node/yaml_to_keyval.ts $config_in)"
firebase functions:config:set $key_vals

@kanemotos cat ์†”๋ฃจ์…˜์ด ๋งˆ์Œ์— ๋“œ๋Š”๋ฐ ์ธ์ฆ์„œ ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๋ ค๊ณ  ํ•  ๋•Œ Precondition check failed ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๊นŒ?

์ด๋Ÿฌํ•œ ์ด์œ ๋กœ ๊ฒฐ๊ตญ Deployment Manager๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

DM์šฉ "config Yaml"์„ ํ†ตํ•ด ๋ชจ๋“  ๊ตฌ์„ฑ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ DM์€ ์ ์ ˆํ•œ ๋Ÿฐํƒ€์ž„ ๊ตฌ์„ฑ ๋ฐ ๋ณ€์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๊ณ  firebase deploy ๋Š” firebase config:set ๋ฅผ ์ „ํ˜€ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ ๋„ ๋ฐฐํฌ ์‹œ ํ•ด๋‹น ๊ฐ’์„ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋‹ค๋ฅธ ๋ฆฌ์†Œ์Šค(์˜ˆ: ๋ฒ„ํ‚ท ๋ฐ ํ•ด๋‹น ์•ก์„ธ์Šค ์ œ์–ด)๋ฅผ ์„ค์ •ํ•˜๊ณ  ํ…œํ”Œ๋ฆฟ์— ์™ธ๋ถ€์ ์œผ๋กœ ์ œ๊ณตํ•˜์ง€ ์•Š๊ณ ๋„ RC์—์„œ ๊ฐ’์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์ด๋ฅผ ํ†ตํ•ด camelCase ๊ตฌ์„ฑ ๋ฐ ๋ณ€์ˆ˜ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์™ธ๋ถ€์ ์œผ๋กœ ๊ฐ’์„ ์„ค์ •ํ•˜๋Š” ์œ ์ผํ•œ ๊ฒฝ์šฐ๋Š” DM์ด ๊ฐ’์„ ์•ˆ์ „ํ•˜๊ฒŒ ์•”ํ˜ธํ™”ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋Ÿฐํƒ€์ž„ ๊ตฌ์„ฑ์„ ํ†ตํ•ด (์•”ํ˜ธํ™”๋œ) ์„œ๋น„์Šค ๊ณ„์ • ํ‚ค๋ฅผ ์ „๋‹ฌํ•ด์•ผ ํ•  ๋•Œ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ „์ž๋Š” KMS์—์„œ stdout์„ ํ—ˆ์šฉํ•˜๋ฏ€๋กœ firebase config:set ์•„๋‹ˆ๋ผ gcloud beta runtime-config configs variables set (DM ๋ฐฐํฌ ํ›„ ๋ฐ firebase deploy ์ด์ „)๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๋‹จ์ง€ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ์ฝ์œผ๋ฉด ์ผ๋ถ€ ์‚ฌ๋žŒ๋“ค์€ ์•ฝ๊ฐ„์˜ ํ˜ผ๋ž€์œผ๋กœ ์ด๋„๋Š” ์ค‘์š”ํ•œ ์š”์ ์„ ๋†“์นœ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ฌธ์„œ์—์„œ๋„ ์ง€์›Œ์ง„๋‹ค๋ฉด ์ •๋ง ์œ ์šฉํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ functions.config() ๋Š” _deployments_ ์‚ฌ์ด์— ์œ ์ง€๋˜์ง€๋งŒ ๋‹ค๋ฅธ Firebase ํ”„๋กœ์ ํŠธ ๊ฐ„์— ๋ณ„๋„๋กœ ์„ค์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค!

์ฆ‰, dev, staging ๋ฐ prod ํ™˜๊ฒฝ์˜ ๊ฒฝ์šฐ ์—ฌ๋Ÿฌ ๋™์ผํ•œ Firebase ํ”„๋กœ์ ํŠธ๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(๋‹ค์ค‘ ์‚ฌ์ดํŠธ ํ˜ธ์ŠคํŒ…์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ๋™์ผํ•œ ํ”„๋กœ์ ํŠธ์— ๋ฐฐํฌํ•˜๋Š” ๋Œ€์‹ ... ๐Ÿ‘Ž ). ๊ฐ๊ฐ์€ ๊ณ ์œ ํ•œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์ง€์†์ ์œผ๋กœ ๋ณด์œ ํ•ฉ๋‹ˆ๋‹ค. .

๋ณ„์นญ์„ ์„ค์ •ํ•˜๊ฑฐ๋‚˜ firebase use ํ•˜์—ฌ ํ”„๋กœ์ ํŠธ ๊ฐ„์— ์ „ํ™˜ํ•˜๋ฉด ๋™์ผํ•œ ์ €์žฅ์†Œ ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๊ฐœ๋ณ„ Firebase ํ”„๋กœ์ ํŠธ์— ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณ„๋„์˜ Firebase ํ”„๋กœ์ ํŠธ๋กœ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ, ์Šคํ…Œ์ด์ง• ๋ฐ ํ”„๋กœ๋•์…˜์„ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ ๋‹ค์Œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ๊ฐ์— ๋Œ€ํ•ด ๋ณ„๋„์˜ ํ™˜๊ฒฝ ๊ตฌ์„ฑ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
firebase -P dev config:set - ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์— ๋Œ€ํ•œ ๋ณ€์ˆ˜ ์„ค์ •
firebase -P prod config:set - ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์— ๋Œ€ํ•œ ๋ณ€์ˆ˜ ์„ค์ •...

๊ทธ๋Ÿฐ ๋‹ค์Œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋™์ผํ•œ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ๋‘ โ€‹โ€‹๋ฒˆ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
firebase deploy -P dev
firebase deploy -P prod
๋‘˜ ๋‹ค ๊ฐ๊ฐ์˜ Firebase ํ”„๋กœ์ ํŠธ์— ๋ฐฐํฌํ•˜๊ณ  ๋ฐฐํฌ ๊ฐ„์— ์œ ์ง€๋˜๋Š” ๋ณ„๋„์˜ ํ™˜๊ฒฝ ๊ตฌ์„ฑ์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.

๋„ค, ์ €ํฌ๋„ ๊ทธ๋ ‡๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. dev/test/prod์— ๋Œ€ํ•œ ๋ณ„๋„์˜ ํ”„๋กœ์ ํŠธ.

๊ฐœ๋ฐœ ์ค‘์ธ ํ”Œ๋žซํผ(Windows, MacOS, Linux)๊ณผ ๊ด€๋ จํ•˜์—ฌ ์ž‘๋™ํ•˜๋Š” ๋ฐ”๋‹๋ผ JS ์†”๋ฃจ์…˜์„ ๊ณต์œ ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

dev/test/prod์— ๋Œ€ํ•ด ๋ณ„๋„์˜ ํ”„๋กœ์ ํŠธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

/.firebaserc

{
  "projects": {
    "dev": "my-project-name-dev",
    "test": "my-project-name-test",
    "prod": "my-project-name-prod"
  }
}

๊ตฌ์„ฑ ํŒŒ์ผ

/functions/config ํด๋”์˜ JSON ํŒŒ์ผ:

/functions/config/config.dev.json 
/functions/config/config.test.json 
/functions/config/config.prod.json 
/functions/config/config.SAMPLE.json <-- only file tracked in git

Example content:
{
    "google": {
        "key": "my-api-key",
        "storage_bucket": "firebase-storage-bucket"
    },
    "another_vendor": {
        "my_prop": "my value"
    },
    ...
}

/functions/set-config.js

const fs = require('fs');
const env = process.argv[2];

const configPath = `./config/config.${env}.json`;

if (!(configPath && fs.existsSync(configPath))) {
    return;
}

const collectConfigLines = (o, propPath, configLines) => {
    propPath = propPath || '';
    configLines = configLines || [];
    for (const key of Object.keys(o)) {
        const newPropPath = propPath + key;
        if (typeof o[key] === 'object') {
            collectConfigLines(o[key], newPropPath + '.', configLines);
        } else if (o[key] != null && o[key] !== '') {
            configLines.push(`${newPropPath}=${JSON.stringify(o[key])}`);
        }
    }
}

const config = require(configPath);
const configLines = [];
collectConfigLines(config, '', configLines);

const cp = require('child_process');
cp.execSync(`firebase -P ${env} functions:config:set ${configLines.join(' ')}`);

/ํ•จ์ˆ˜/ํŒจํ‚ค์ง€.json

...
"scripts": {
    "config:set:dev": "node set-config dev",
    "config:set:test": "node set-config test",
    "config:set:prod": "node set-config prod",
    ...
},
...

๋ˆ„๊ตฐ๊ฐ€ ์—ฌ์ „ํžˆ ์ฐพ๊ณ  ์žˆ๋‹ค๋ฉด ์ด ๋งค์ฒด ๊ธฐ์‚ฌ https://medium.com/indielayer/deploying-environment-variables-with-firebase-cloud-functions-680779413484์— ์‚ฌ์šฉ๋œ ๋ฐฉ๋ฒ•์ด

๊ฐœ์ธ์ ์œผ๋กœ ๋ˆ„๋ฝ๋œ ๊ฒƒ์€ ๋ฐฐํฌ ๋ฅผ ์ˆ˜ํ–‰

๋˜ํ•œ ์ผ๋ถ€ ๊ธฐ๋Šฅ์ด ๊ฐœ๋ฐœ ์ค‘์ธ ์ƒํƒœ์—์„œ ๋‚˜์ค‘์— ๊ธฐ์กด ๋ณ€์ˆ˜๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์ง€๊ธˆ ๋งˆ์ง€๋ง‰์œผ๋กœ ๋ฆด๋ฆฌ์Šค๋œ ํƒœ๊ทธ๋ฅผ ์ฒดํฌ์•„์›ƒํ•˜๊ณ  ๋นŒ๋“œํ•˜๊ณ  ๋ฐฐํฌํ•˜๊ณ  ๊ธฐ๋Šฅ ๋ถ„๊ธฐ๋กœ ๋‹ค์‹œ ์ฒดํฌ์•„์›ƒํ•˜๊ณ  ๊ณ„์†ํ•˜์‹ญ์‹œ์˜ค. ์ด๊ฒƒ์€ ์‹ค์ œ๋กœ ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ ์šฐ๋ฆฌ๋Š” ํด๋ผ์šฐ๋“œ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์›๊ฒฉ ๊ตฌ์„ฑ์„ ์›ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@bezysoftware ํ™˜๊ฒฝ ๊ตฌ์„ฑ ๋Œ€์‹  ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. Firebase ๋ ˆ์ด์–ด๋ฅผ ๊ฑด๋„ˆ๋›ฐ๊ณ  Google ํด๋ผ์šฐ๋“œ ํ”Œ๋žซํผ์—์„œ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. https://cloud.google.com/functions/docs/env- var

๊ณต์œ ํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! @laurenzlong
ํŒŒ์ผ์—์„œ ๊ฐ€์ ธ์˜ค๊ณ  ์‹ถ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ช…๋ น์„ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

firebase functions:config:set service_account="$(cat service-account.json)"

Firebase Admin SDK์˜ ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ API๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋น„์Šค ๊ณ„์ • json ํŒŒ์ผ์„ Firebase Cloud Functions๋กœ ๊ฐ€์ ธ์™”์Šต๋‹ˆ๋‹ค.

์ž‘๋™ํ•˜์ง€ ์•Š์•˜๋‹ค

@Md-Abdul-Halim-Rafi

firebase functions:config :set service_account="$(cat service-account.json)"

๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ–ˆ๊ณ  firebase functions:config:get ์™€ ํ•จ๊ป˜ config var๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ํ”„๋กœ์ ํŠธ ํด๋”์— ์—†์—ˆ๊ณ  config ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•  Firebase ํ”„๋กœ์ ํŠธ๋ฅผ ์„ ํƒํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฒ˜์Œ์—๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. Firebase ํ”„๋กœ์ ํŠธ๋ฅผ ์„ ํƒํ•˜๋ ค๋ฉด firebase use --add ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด CLI์—์„œ Firebase ์ฝ˜์†”์˜ ํ”„๋กœ์ ํŠธ ๋ชฉ๋ก( firebase login CLI์— ๋กœ๊ทธ์ธํ–ˆ๋‹ค๊ณ  ๊ฐ€์ •)

@dnhyde

firebase functions:config :set service_account="$(cat service-account.json)"

json ํŒŒ์ผ์—์„œ ๋ฌธ์ž์—ด(์˜ˆ: ๋ถ€์šธ ๋˜๋Š” ์ˆซ์ž)์„ ์ œ์™ธํ•œ ๋‹ค๋ฅธ ๊ฐ’ ์œ ํ˜•์„ ์‚ฌ์šฉํ•˜๋Š” ๋™์•ˆ์—๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

{
   "test": {
        "hmm": true
    }
}

์‹คํŒจ:

Error: HTTP Error: 400, Invalid value at 'variable.text' (TYPE_STRING), true

๋‚ด๊ฐ€ ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

firebase functions:config:get > config.json

๊ทธ๋ฆฌ๊ณ  ๋‚˜์ค‘์—:

firebase functions:config:set < config.json

์ด ๋‘ ๋ช…๋ น์„ ๋ณด์™„์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์ž…๋‹ˆ๋‹ค.

ํŒŒ์ผ์— ๊ตฌ์„ฑ์ด ์žˆ์œผ๋ฉด ๋ฒ„์ „์„ ์ œ์–ดํ•˜๊ณ  ์‹œ๊ฐ„์ด ์ง€๋‚จ์— ๋”ฐ๋ผ ์–ด๋–ป๊ฒŒ ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ง€๊ธˆ ๋‹น์žฅ ์ด๊ฒƒ์„ ๋‹ฌ์„ฑํ•ด์•ผ ํ•˜๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•( env=$(cat config.json) )๋„ { env: ... } ๋ž˜ํ•‘ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— config.json ์ด ์‹ค์ œ ๊ฐ’์ด ๋˜๋„๋ก ํ•˜๋Š” ๋Šฅ๋ ฅ์„ ๊นจ๋œจ๋ฆฌ๋Š” ๊ฒฐ๊ณผ๋ฅผ ์ดˆ๋ž˜ํ•œ๋‹ค๋Š” ๊ฒƒ์€ ๋ถˆํ–‰ํ•œ ์ผ์ž…๋‹ˆ๋‹ค.

์ฐธ๊ณ  ์‚ฌํ•ญ: ์—ฌ๊ธฐ์—์„œ ๊ธฐ๋Šฅ ํ’€ ์š”์ฒญ์„ ์‹œ์ž‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. https://github.com/firebase/firebase-tools/blob/b17611a4ff0d36e157ed06a24f6c81d4e146d9e2/src/functionsConfig.js#L142

๊ฐœ๋ฐœ ์ค‘์ธ ํ”Œ๋žซํผ(Windows, MacOS, Linux)๊ณผ ๊ด€๋ จํ•˜์—ฌ ์ž‘๋™ํ•˜๋Š” ๋ฐ”๋‹๋ผ JS ์†”๋ฃจ์…˜์„ ๊ณต์œ ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

dev/test/prod์— ๋Œ€ํ•ด ๋ณ„๋„์˜ ํ”„๋กœ์ ํŠธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

/.firebaserc

{
  "projects": {
    "dev": "my-project-name-dev",
    "test": "my-project-name-test",
    "prod": "my-project-name-prod"
  }
}

๊ตฌ์„ฑ ํŒŒ์ผ

/functions/config ํด๋”์˜ JSON ํŒŒ์ผ:

/functions/config/config.dev.json 
/functions/config/config.test.json 
/functions/config/config.prod.json 
/functions/config/config.SAMPLE.json <-- only file tracked in git

Example content:
{
    "google": {
        "key": "my-api-key",
        "storage_bucket": "firebase-storage-bucket"
    },
    "another_vendor": {
        "my_prop": "my value"
    },
    ...
}

/functions/set-config.js

const fs = require('fs');
const env = process.argv[2];

const configPath = `./config/config.${env}.json`;

if (!(configPath && fs.existsSync(configPath))) {
    return;
}

const collectConfigLines = (o, propPath, configLines) => {
    propPath = propPath || '';
    configLines = configLines || [];
    for (const key of Object.keys(o)) {
        const newPropPath = propPath + key;
        if (typeof o[key] === 'object') {
            collectConfigLines(o[key], newPropPath + '.', configLines);
        } else if (o[key] != null && o[key] !== '') {
            configLines.push(`${newPropPath}=${JSON.stringify(o[key])}`);
        }
    }
}

const config = require(configPath);
const configLines = [];
collectConfigLines(config, '', configLines);

const cp = require('child_process');
cp.execSync(`firebase -P ${env} functions:config:set ${configLines.join(' ')}`);

/ํ•จ์ˆ˜/ํŒจํ‚ค์ง€.json

...
"scripts": {
    "config:set:dev": "node set-config dev",
    "config:set:test": "node set-config test",
    "config:set:prod": "node set-config prod",
    ...
},
...

๊ฐœ๋ฐœ ์ค‘์ธ ํ”Œ๋žซํผ(Windows, MacOS, Linux)๊ณผ ๊ด€๋ จํ•˜์—ฌ ์ž‘๋™ํ•˜๋Š” ๋ฐ”๋‹๋ผ JS ์†”๋ฃจ์…˜์„ ๊ณต์œ ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

dev/test/prod์— ๋Œ€ํ•ด ๋ณ„๋„์˜ ํ”„๋กœ์ ํŠธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

/.firebaserc

{
  "projects": {
    "dev": "my-project-name-dev",
    "test": "my-project-name-test",
    "prod": "my-project-name-prod"
  }
}

๊ตฌ์„ฑ ํŒŒ์ผ

/functions/config ํด๋”์˜ JSON ํŒŒ์ผ:

/functions/config/config.dev.json 
/functions/config/config.test.json 
/functions/config/config.prod.json 
/functions/config/config.SAMPLE.json <-- only file tracked in git

Example content:
{
    "google": {
        "key": "my-api-key",
        "storage_bucket": "firebase-storage-bucket"
    },
    "another_vendor": {
        "my_prop": "my value"
    },
    ...
}

/functions/set-config.js

const fs = require('fs');
const env = process.argv[2];

const configPath = `./config/config.${env}.json`;

if (!(configPath && fs.existsSync(configPath))) {
    return;
}

const collectConfigLines = (o, propPath, configLines) => {
    propPath = propPath || '';
    configLines = configLines || [];
    for (const key of Object.keys(o)) {
        const newPropPath = propPath + key;
        if (typeof o[key] === 'object') {
            collectConfigLines(o[key], newPropPath + '.', configLines);
        } else if (o[key] != null && o[key] !== '') {
            configLines.push(`${newPropPath}=${JSON.stringify(o[key])}`);
        }
    }
}

const config = require(configPath);
const configLines = [];
collectConfigLines(config, '', configLines);

const cp = require('child_process');
cp.execSync(`firebase -P ${env} functions:config:set ${configLines.join(' ')}`);

/ํ•จ์ˆ˜/ํŒจํ‚ค์ง€.json

...
"scripts": {
    "config:set:dev": "node set-config dev",
    "config:set:test": "node set-config test",
    "config:set:prod": "node set-config prod",
    ...
},
...

์ฃ„์†กํ•˜์ง€๋งŒ " config:set :dev" ์Šคํฌ๋ฆฝํŠธ๋Š” ์–ธ์ œ ์‹คํ–‰ํ•ฉ๋‹ˆ๊นŒ? ์ดํ•ด๊ฐ€ ์•ˆ๋˜๋„ค์š”... ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰