ํ์ฌ firebase functions:config:get
์ฌ์ฉํ์ฌ ์ ์ฒด ๊ธฐ๋ฅ ๊ตฌ์ฑ์ JSON ํ์ผ๋ก ๊ฐ์ ธ์ฌ ์ ์์ง๋ง firebase functions:config:set
๋ช
๋ น์ ์ฌ์ฉํ ๋ ๊ฐ ๋ณ์๋ฅผ ์๋์ผ๋ก ์ธ๋ผ์ธํด์ผ ํ๋ฏ๋ก ์์
ํ ๋ ์ค์ ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ค๋ฅธ ํ๊ฒฝ.
์ด์์ ์ผ๋ก๋ ๋ค์์ ์ํํ ์ ์์ด์ผ ํฉ๋๋ค.
firebase functions:config:get > config.json
firebase functions:config:set -f config.json
@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 ๊ณต์
์ด "๋ฌธ์ "์ ๋ํ ๋ด ์๋ฃจ์ ๊ณผ ํ ๋ก ์ ๋ํ ๋ด ์๊ฐ์ ๋จ๊ธฐ๊ณ ์ถ์์ต๋๋ค.
์ ๋ 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์ ๋ํด ๋ณ๋์ ํ๋ก์ ํธ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
{
"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"
},
...
}
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(' ')}`);
...
"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" ์คํฌ๋ฆฝํธ๋ ์ธ์ ์คํํฉ๋๊น? ์ดํด๊ฐ ์๋๋ค์... ๊ฐ์ฌํฉ๋๋ค!
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
๊ณต์ ํด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค! @laurenzlong
ํ์ผ์์ ๊ฐ์ ธ์ค๊ณ ์ถ์๊ธฐ ๋๋ฌธ์ ๋ค์๊ณผ ๊ฐ์ ๋ช ๋ น์ ์ฌ์ฉํ์ต๋๋ค.
Firebase Admin SDK์ ์ฌ์ฉ์ ๊ด๋ฆฌ API๋ฅผ ์ฌ์ฉํ๊ณ ์ถ์๊ธฐ ๋๋ฌธ์ ์๋น์ค ๊ณ์ json ํ์ผ์ Firebase Cloud Functions๋ก ๊ฐ์ ธ์์ต๋๋ค.