์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ Prometheus์™€ Grafana๋กœ ์™„์„ฑํ•˜๋Š” ์‹ค์‹œ๊ฐ„ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ๊ณผ ์•Œ๋ฆผ ๋Œ€์‹œ๋ณด๋“œ ๊ตฌ์„ฑ ๊ฐ€์ด๋“œ

๐Ÿš€ Prometheus์™€ Grafana๋กœ ์™„์„ฑํ•˜๋Š” ์‹ค์‹œ๊ฐ„ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ๊ณผ ์•Œ๋ฆผ ๋Œ€์‹œ๋ณด๋“œ ๊ตฌ์„ฑ ๊ฐ€์ด๋“œ

์นœ๊ตฌ์ฒ˜๋Ÿผ ์‰ฝ๊ฒŒ ๋ฐฐ์šฐ๋Š” ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ๊ตฌ์ถ• ์™„๋ฒฝ ๊ฐ€์ด๋“œ ๐Ÿ“Š

์•ˆ๋…•! ๐Ÿ‘‹ ์˜ค๋Š˜์€ ๊ฐœ๋ฐœ์ž๋ผ๋ฉด ๊ผญ ์•Œ์•„์•ผ ํ•  Prometheus์™€ Grafana๋ฅผ ํ™œ์šฉํ•œ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ๊ตฌ์ถ•์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•ด๋ณผ๊ฒŒ. ์„œ๋ฒ„๊ฐ€ ๊ฐ‘์ž๊ธฐ ๋‹ค์šด๋˜๊ฑฐ๋‚˜, ํŠธ๋ž˜ํ”ฝ์ด ํญ์ฆํ•˜๋Š”๋ฐ ์•„๋ฌด๊ฒƒ๋„ ๋ชจ๋ฅด๊ณ  ์žˆ๋‹ค๊ฐ€ ์‚ฌ์šฉ์ž๋“ค์˜ ํ•ญ์˜ ์ „ํ™”๋ฅผ ๋ฐ›์€ ๊ฒฝํ—˜ ์žˆ์–ด? ๐Ÿ˜ฑ ๊ทธ๋Ÿฐ ์•…๋ชฝ ๊ฐ™์€ ์ƒํ™ฉ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์šฐ๋ฆฌ์—๊ฒŒ๋Š” ๊ฐ•๋ ฅํ•œ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์ด ํ•„์š”ํ•ด!

์š”์ฆ˜ ํด๋ผ์šฐ๋“œ ํ™˜๊ฒฝ๊ณผ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜๊ฐ€ ๋Œ€์„ธ๊ฐ€ ๋˜๋ฉด์„œ, ์‹œ์Šคํ…œ์˜ ๋ณต์žก๋„๋Š” ๊ธฐํ•˜๊ธ‰์ˆ˜์ ์œผ๋กœ ์ฆ๊ฐ€ํ–ˆ์–ด. ์˜ˆ์ „์ฒ˜๋Ÿผ ์„œ๋ฒ„ ํ•œ๋‘ ๋Œ€๋งŒ ๊ด€๋ฆฌํ•˜๋˜ ์‹œ์ ˆ์€ ์ง€๋‚˜๊ฐ”์ง€. ์ด์ œ๋Š” ์ˆ˜์‹ญ, ์ˆ˜๋ฐฑ ๊ฐœ์˜ ์ปจํ…Œ์ด๋„ˆ์™€ ์„œ๋น„์Šค๋“ค์ด ์œ ๊ธฐ์ ์œผ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๊ณ , ์ด ๋ชจ๋“  ๊ฑธ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ชจ๋‹ˆํ„ฐ๋งํ•ด์•ผ ํ•˜๋Š” ์‹œ๋Œ€์•ผ. ๐ŸŒ

Prometheus ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ Grafana ์‹œ๊ฐํ™” Server 1 Server 2 Server 3 Dashboard Alert Report ์‹ค์‹œ๊ฐ„ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜

๐ŸŽฏ Prometheus๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

Prometheus๋Š” 2012๋…„ SoundCloud์—์„œ ๊ฐœ๋ฐœ๋œ ์˜คํ”ˆ์†Œ์Šค ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์ด์•ผ. ์ง€๊ธˆ์€ CNCF(Cloud Native Computing Foundation)์˜ ์กธ์—… ํ”„๋กœ์ ํŠธ๋กœ, Kubernetes ๋‹ค์Œ์œผ๋กœ ๋‘ ๋ฒˆ์งธ๋กœ ์กธ์—…ํ•œ ํ”„๋กœ์ ํŠธ๋ผ๋Š” ์ ์—์„œ ๊ทธ ์‹ ๋ขฐ์„ฑ์„ ์•Œ ์ˆ˜ ์žˆ์ง€. ๐Ÿ†

๐Ÿ’ก Prometheus์˜ ํ•ต์‹ฌ ํŠน์ง• ์‹œ๊ณ„์—ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(Time Series Database): ์‹œ๊ฐ„์— ๋”ฐ๋ฅธ ๋ฉ”ํŠธ๋ฆญ ๋ฐ์ดํ„ฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์ €์žฅํ•˜๊ณ  ์กฐํšŒํ•  ์ˆ˜ ์žˆ์–ด. CPU ์‚ฌ์šฉ๋ฅ , ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰, ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋“ค์ด ์‹œ๊ฐ„ ์ˆœ์„œ๋Œ€๋กœ ์Œ“์ด๋Š” ๊ฑฐ์ง€.

Pull ๋ฐฉ์‹์˜ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘: ๋Œ€๋ถ€๋ถ„์˜ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์ด Push ๋ฐฉ์‹(์„œ๋ฒ„๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด๋Š” ๋ฐฉ์‹)์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๊ณผ ๋‹ฌ๋ฆฌ, Prometheus๋Š” Pull ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ด. ์ฆ‰, Prometheus๊ฐ€ ์ฃผ๊ธฐ์ ์œผ๋กœ ํƒ€๊ฒŸ ์„œ๋ฒ„๋“ค์„ ๋ฐฉ๋ฌธํ•ด์„œ ๋ฉ”ํŠธ๋ฆญ์„ ๊ฐ€์ ธ์˜ค๋Š” ๊ฑฐ์•ผ. ์ด๊ฒŒ ์™œ ์ข‹๋ƒ๊ณ ? ์ค‘์•™ ์„œ๋ฒ„๊ฐ€ ๋ชจ๋“  ๊ฑธ ํ†ต์ œํ•  ์ˆ˜ ์žˆ๊ณ , ๋„คํŠธ์›Œํฌ ๋ฌธ์ œ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ์œ ์‹ค๋  ๊ฐ€๋Šฅ์„ฑ์ด ์ค„์–ด๋“ค๊ฑฐ๋“ ! ๐ŸŽฃ

๊ฐ•๋ ฅํ•œ ์ฟผ๋ฆฌ ์–ธ์–ด(PromQL): Prometheus Query Language๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ๋ถ„์„์ด ๊ฐ€๋Šฅํ•ด. SQL์ฒ˜๋Ÿผ ์ง๊ด€์ ์ด๋ฉด์„œ๋„ ์‹œ๊ณ„์—ด ๋ฐ์ดํ„ฐ์— ํŠนํ™”๋œ ๊ธฐ๋Šฅ๋“ค์ด ๋งŽ์•„.

๋‹ค์ฐจ์› ๋ฐ์ดํ„ฐ ๋ชจ๋ธ: ๋ฉ”ํŠธ๋ฆญ ์ด๋ฆ„๊ณผ ํ•จ๊ป˜ ์—ฌ๋Ÿฌ ๋ ˆ์ด๋ธ”(label)์„ ๋ถ™์—ฌ์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์–ด. ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ฐ™์€ CPU ์‚ฌ์šฉ๋ฅ ์ด๋ผ๋„ ์„œ๋ฒ„๋ณ„, ํ™˜๊ฒฝ๋ณ„, ์ง€์—ญ๋ณ„๋กœ ๊ตฌ๋ถ„ํ•ด์„œ ์ €์žฅํ•  ์ˆ˜ ์žˆ์ง€.

๐Ÿ“ฆ Prometheus์˜ ์ฃผ์š” ์ปดํฌ๋„ŒํŠธ

Prometheus ์ƒํƒœ๊ณ„๋Š” ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์–ด. ๊ฐ๊ฐ์˜ ์—ญํ• ์„ ์ดํ•ดํ•˜๋ฉด ์ „์ฒด ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๊ฒŒ ํ›จ์”ฌ ์‰ฌ์›Œ์งˆ ๊ฑฐ์•ผ!

๐Ÿ”ง Prometheus Server ํ•ต์‹ฌ ์„œ๋ฒ„๋กœ, ๋ฉ”ํŠธ๋ฆญ์„ ์ˆ˜์ง‘ํ•˜๊ณ  ์ €์žฅํ•˜๋Š” ์—ญํ• ์„ ํ•ด. ์„ค์ • ํŒŒ์ผ(prometheus.yml)์— ์ •์˜๋œ ํƒ€๊ฒŸ๋“ค์„ ์ฃผ๊ธฐ์ ์œผ๋กœ ์Šคํฌ๋ž˜ํ•‘(scraping)ํ•˜๋ฉด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ์•„. ๊ธฐ๋ณธ์ ์œผ๋กœ 15์ดˆ๋งˆ๋‹ค ํ•œ ๋ฒˆ์”ฉ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š”๋ฐ, ์ด ๊ฐ„๊ฒฉ์€ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ์–ด.
๐Ÿ“ก Exporters Prometheus๊ฐ€ ์ง์ ‘ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์ˆ˜ ์—†๋Š” ์‹œ์Šคํ…œ๋“ค์˜ ๋ฉ”ํŠธ๋ฆญ์„ Prometheus ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ์—์ด์ „ํŠธ์•ผ. Node Exporter(์‹œ์Šคํ…œ ๋ฉ”ํŠธ๋ฆญ), MySQL Exporter(๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฉ”ํŠธ๋ฆญ), Blackbox Exporter(์—”๋“œํฌ์ธํŠธ ๋ชจ๋‹ˆํ„ฐ๋ง) ๋“ฑ ๋‹ค์–‘ํ•œ ์ข…๋ฅ˜๊ฐ€ ์žˆ์–ด. ํ•„์š”ํ•œ ๊ฑฐ ๊ณจ๋ผ ์“ฐ๋ฉด ๋ผ! ๐ŸŽ
๐Ÿšจ Alertmanager Prometheus์—์„œ ๋ฐœ์ƒํ•œ ์•Œ๋ฆผ์„ ๋ฐ›์•„์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์•ผ. ์ค‘๋ณต ์ œ๊ฑฐ, ๊ทธ๋ฃนํ™”, ๋ผ์šฐํŒ… ๊ฐ™์€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ด์„œ ์•Œ๋ฆผ์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด. ์ด๋ฉ”์ผ, Slack, PagerDuty ๋“ฑ ๋‹ค์–‘ํ•œ ์ฑ„๋„๋กœ ์•Œ๋ฆผ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์ง€.
๐Ÿ”Œ Pushgateway ๋ฐฐ์น˜ ์ž‘์—…์ฒ˜๋Ÿผ ์งง์€ ์‹œ๊ฐ„ ๋™์•ˆ๋งŒ ์‹คํ–‰๋˜๋Š” ์ž‘์—…๋“ค์˜ ๋ฉ”ํŠธ๋ฆญ์„ ์ˆ˜์ง‘ํ•˜๊ธฐ ์œ„ํ•œ ์ปดํฌ๋„ŒํŠธ์•ผ. Pull ๋ฐฉ์‹์˜ ํ•œ๊ณ„๋ฅผ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด Push ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜.

๐ŸŽจ Grafana๋กœ ๋ฐ์ดํ„ฐ ์‹œ๊ฐํ™”ํ•˜๊ธฐ

Prometheus๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ์—”์ง„์ด๋ผ๋ฉด, Grafana๋Š” ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ์•„๋ฆ„๋‹ต๊ฒŒ ๋ณด์—ฌ์ฃผ๋Š” ์บ”๋ฒ„์Šค์•ผ! ๐Ÿ–ผ๏ธ Grafana๋Š” 2014๋…„์— ์‹œ์ž‘๋œ ์˜คํ”ˆ์†Œ์Šค ์‹œ๊ฐํ™” ํ”Œ๋žซํผ์œผ๋กœ, ๋‹จ์ˆœํžˆ Prometheus๋ฟ๋งŒ ์•„๋‹ˆ๋ผ InfluxDB, Elasticsearch, MySQL ๋“ฑ ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ์ง€์›ํ•ด.

๐Ÿ’ก Grafana์˜ ๊ฐ•์  โœจ ์ง๊ด€์ ์ธ ๋Œ€์‹œ๋ณด๋“œ ๊ตฌ์„ฑ: ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญ์œผ๋กœ ์‰ฝ๊ฒŒ ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด. ์ฝ”๋”ฉ ์—†์ด๋„ ๋ฉ‹์ง„ ์ฐจํŠธ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒŒ ์ตœ๊ณ ์˜ ์žฅ์ ์ด์ง€!

๐ŸŽญ ๋‹ค์–‘ํ•œ ์‹œ๊ฐํ™” ์˜ต์…˜: ๊ทธ๋ž˜ํ”„, ๊ฒŒ์ด์ง€, ํžˆํŠธ๋งต, ํ…Œ์ด๋ธ” ๋“ฑ 30๊ฐ€์ง€๊ฐ€ ๋„˜๋Š” ํŒจ๋„ ํƒ€์ž…์„ ์ œ๊ณตํ•ด. ๋ฐ์ดํ„ฐ์˜ ํŠน์„ฑ์— ๋งž๋Š” ์ตœ์ ์˜ ์‹œ๊ฐํ™”๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ์–ด.

๐Ÿ”” ์•Œ๋ฆผ ๊ธฐ๋Šฅ: ๋Œ€์‹œ๋ณด๋“œ์—์„œ ์ง์ ‘ ์•Œ๋ฆผ ๊ทœ์น™์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์–ด. ํŠน์ • ์ž„๊ณ„๊ฐ’์„ ๋„˜์œผ๋ฉด ์ž๋™์œผ๋กœ ์•Œ๋ฆผ์„ ๋ณด๋‚ด๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์ง€.

๐Ÿ‘ฅ ํŒ€ ํ˜‘์—… ๊ธฐ๋Šฅ: ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ํŒ€์›๋“ค๊ณผ ๊ณต์œ ํ•˜๊ณ , ๊ถŒํ•œ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด. ์กฐ์ง ๋‹จ์œ„๋กœ ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ์— ์ตœ์ ํ™”๋˜์–ด ์žˆ์–ด.

๐Ÿ› ๏ธ ์‹ค์ „! Prometheus ์„ค์น˜ ๋ฐ ์„ค์ •

์ž, ์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ Prometheus๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์„ค์ •ํ•ด๋ณด์ž! ์—ฌ๊ธฐ์„œ๋Š” Linux ํ™˜๊ฒฝ์„ ๊ธฐ์ค€์œผ๋กœ ์„ค๋ช…ํ• ๊ฒŒ. Docker๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋” ์‰ฝ์ง€๋งŒ, ๊ธฐ๋ณธ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ์ง์ ‘ ์„ค์น˜ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์•Œ์•„๋‘๋Š” ๊ฒŒ ์ข‹์•„. ๐Ÿ’ช

๐Ÿ“ฅ Prometheus ์„ค์น˜ํ•˜๊ธฐ

# Prometheus ๋‹ค์šด๋กœ๋“œ
wget https://github.com/prometheus/prometheus/releases/download/v2.45.0/prometheus-2.45.0.linux-amd64.tar.gz

# ์••์ถ• ํ•ด์ œ
tar xvfz prometheus-2.45.0.linux-amd64.tar.gz

# ๋””๋ ‰ํ† ๋ฆฌ ์ด๋™
cd prometheus-2.45.0.linux-amd64

# Prometheus ์‹คํ–‰
./prometheus --config.file=prometheus.yml

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ธฐ๋ณธ ์„ค์ •์œผ๋กœ Prometheus๊ฐ€ ์‹คํ–‰๋ผ. ๋ธŒ๋ผ์šฐ์ €์—์„œ http://localhost:9090์— ์ ‘์†ํ•˜๋ฉด Prometheus ์›น UI๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์–ด! ๐ŸŽ‰

โš™๏ธ prometheus.yml ์„ค์ • ํŒŒ์ผ ์ดํ•ดํ•˜๊ธฐ

Prometheus์˜ ํ•ต์‹ฌ์€ ์„ค์ • ํŒŒ์ผ์ด์•ผ. ์ด ํŒŒ์ผ์—์„œ ์–ด๋–ค ํƒ€๊ฒŸ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ• ์ง€, ์–ผ๋งˆ๋‚˜ ์ž์ฃผ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ• ์ง€ ๋“ฑ์„ ์ •์˜ํ•ด. ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ฅผ ์‚ดํŽด๋ณด์ž:

global:
  scrape_interval: 15s      # ๊ธฐ๋ณธ ์Šคํฌ๋ž˜ํ•‘ ๊ฐ„๊ฒฉ
  evaluation_interval: 15s  # ๊ทœ์น™ ํ‰๊ฐ€ ๊ฐ„๊ฒฉ
  
  external_labels:
    cluster: 'production'
    region: 'asia-northeast-2'

# Alertmanager ์„ค์ •
alerting:
  alertmanagers:
    - static_configs:
        - targets:
          - 'localhost:9093'

# ์•Œ๋ฆผ ๊ทœ์น™ ํŒŒ์ผ ๋กœ๋“œ
rule_files:
  - "alerts.yml"
  - "recording_rules.yml"

# ์Šคํฌ๋ž˜ํ•‘ ํƒ€๊ฒŸ ์„ค์ •
scrape_configs:
  # Prometheus ์ž์ฒด ๋ชจ๋‹ˆํ„ฐ๋ง
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']
  
  # Node Exporter ๋ชจ๋‹ˆํ„ฐ๋ง
  - job_name: 'node'
    static_configs:
      - targets: 
        - 'server1:9100'
        - 'server2:9100'
        - 'server3:9100'
        labels:
          env: 'production'
  
  # ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ชจ๋‹ˆํ„ฐ๋ง
  - job_name: 'my-app'
    scrape_interval: 5s  # ์ด job๋งŒ 5์ดˆ ๊ฐ„๊ฒฉ
    static_configs:
      - targets: ['app1:8080', 'app2:8080']
        labels:
          service: 'api'
          version: 'v2.0'
๐Ÿ” ์„ค์ • ํŒŒ์ผ ์ฃผ์š” ์„น์…˜ ์„ค๋ช… global: ์ „์—ญ ์„ค์ •์œผ๋กœ, ๋ชจ๋“  job์— ๊ธฐ๋ณธ์ ์œผ๋กœ ์ ์šฉ๋˜๋Š” ๊ฐ’๋“ค์ด์•ผ. scrape_interval์€ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ ์ฃผ๊ธฐ, evaluation_interval์€ ์•Œ๋ฆผ ๊ทœ์น™์„ ํ‰๊ฐ€ํ•˜๋Š” ์ฃผ๊ธฐ๋ฅผ ์˜๋ฏธํ•ด.

alerting: Alertmanager์˜ ์ฃผ์†Œ๋ฅผ ์ง€์ •ํ•ด. ์—ฌ๋Ÿฌ ๊ฐœ์˜ Alertmanager๋ฅผ ์„ค์ •ํ•ด์„œ ๊ณ ๊ฐ€์šฉ์„ฑ์„ ํ™•๋ณดํ•  ์ˆ˜๋„ ์žˆ์–ด.

rule_files: ์•Œ๋ฆผ ๊ทœ์น™๊ณผ ๋ ˆ์ฝ”๋”ฉ ๊ทœ์น™์ด ์ •์˜๋œ ํŒŒ์ผ๋“ค์„ ์ง€์ •ํ•ด. ๊ทœ์น™์ด ๋งŽ์•„์ง€๋ฉด ํŒŒ์ผ์„ ๋ถ„๋ฆฌํ•ด์„œ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒŒ ์ข‹์•„.

scrape_configs: ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ถ€๋ถ„! ์–ด๋–ค ํƒ€๊ฒŸ๋“ค์„ ๋ชจ๋‹ˆํ„ฐ๋งํ• ์ง€ ์ •์˜ํ•ด. job_name์œผ๋กœ ๊ทธ๋ฃน์„ ๋งŒ๋“ค๊ณ , ๊ฐ ๊ทธ๋ฃน๋งˆ๋‹ค ํƒ€๊ฒŸ๋“ค์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์–ด.

๐ŸŽฏ Service Discovery ํ™œ์šฉํ•˜๊ธฐ

ํด๋ผ์šฐ๋“œ ํ™˜๊ฒฝ์—์„œ๋Š” ์„œ๋ฒ„๊ฐ€ ๋™์ ์œผ๋กœ ์ƒ์„ฑ๋˜๊ณ  ์‚ญ์ œ๋˜์ž–์•„? ๋งค๋ฒˆ ์„ค์ • ํŒŒ์ผ์„ ์ˆ˜์ •ํ•˜๋Š” ๊ฑด ๋น„ํšจ์œจ์ ์ด์ง€. ์ด๋Ÿด ๋•Œ Service Discovery๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ž๋™์œผ๋กœ ํƒ€๊ฒŸ์„ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์–ด! ๐Ÿ˜Ž

# Kubernetes Service Discovery ์˜ˆ์ œ
scrape_configs:
  - job_name: 'kubernetes-pods'
    kubernetes_sd_configs:
      - role: pod
    relabel_configs:
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
        action: keep
        regex: true
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
        action: replace
        target_label: __metrics_path__
        regex: (.+)
      - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
        action: replace
        regex: ([^:]+)(?::\d+)?;(\d+)
        replacement: $1:$2
        target_label: __address__

# AWS EC2 Service Discovery ์˜ˆ์ œ
  - job_name: 'ec2-nodes'
    ec2_sd_configs:
      - region: ap-northeast-2
        access_key: YOUR_ACCESS_KEY
        secret_key: YOUR_SECRET_KEY
        port: 9100
    relabel_configs:
      - source_labels: [__meta_ec2_tag_Environment]
        target_label: environment

Kubernetes, AWS EC2, Consul, Azure ๋“ฑ ๋‹ค์–‘ํ•œ ํ”Œ๋žซํผ์˜ Service Discovery๋ฅผ ์ง€์›ํ•ด. ์ด๊ฑธ ์‚ฌ์šฉํ•˜๋ฉด ์ธํ”„๋ผ๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด๋„ ์ž๋™์œผ๋กœ ๋ชจ๋‹ˆํ„ฐ๋ง ํƒ€๊ฒŸ์ด ์—…๋ฐ์ดํŠธ๋ผ! ๐Ÿš€

๐Ÿ“Š Node Exporter๋กœ ์‹œ์Šคํ…œ ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘ํ•˜๊ธฐ

์„œ๋ฒ„์˜ CPU, ๋ฉ”๋ชจ๋ฆฌ, ๋””์Šคํฌ, ๋„คํŠธ์›Œํฌ ๊ฐ™์€ ์‹œ์Šคํ…œ ๋ฉ”ํŠธ๋ฆญ์„ ์ˆ˜์ง‘ํ•˜๋ ค๋ฉด Node Exporter๊ฐ€ ํ•„์š”ํ•ด. ๊ฐ ์„œ๋ฒ„์— Node Exporter๋ฅผ ์„ค์น˜ํ•˜๋ฉด Prometheus๊ฐ€ ์ด ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•  ์ˆ˜ ์žˆ์–ด.

# Node Exporter ๋‹ค์šด๋กœ๋“œ ๋ฐ ์„ค์น˜
wget https://github.com/prometheus/node_exporter/releases/download/v1.6.0/node_exporter-1.6.0.linux-amd64.tar.gz
tar xvfz node_exporter-1.6.0.linux-amd64.tar.gz
cd node_exporter-1.6.0.linux-amd64

# Node Exporter ์‹คํ–‰
./node_exporter

# systemd ์„œ๋น„์Šค๋กœ ๋“ฑ๋ก (๊ถŒ์žฅ)
sudo tee /etc/systemd/system/node_exporter.service << EOF
[Unit]
Description=Node Exporter
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/node_exporter
Restart=always

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl start node_exporter
sudo systemctl enable node_exporter

Node Exporter๊ฐ€ ์‹คํ–‰๋˜๋ฉด http://localhost:9100/metrics์—์„œ ๋ฉ”ํŠธ๋ฆญ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด. ์ˆ˜๋ฐฑ ๊ฐœ์˜ ๋ฉ”ํŠธ๋ฆญ์ด ํ…์ŠคํŠธ ํ˜•์‹์œผ๋กœ ๋…ธ์ถœ๋˜๋Š”๋ฐ, ์ด๊ฒŒ ๋ฐ”๋กœ Prometheus๊ฐ€ ์ˆ˜์ง‘ํ•˜๋Š” ๋ฐ์ดํ„ฐ์•ผ! ๐Ÿ“ˆ

๐ŸŽ“ ์ฃผ์š” Node Exporter ๋ฉ”ํŠธ๋ฆญ node_cpu_seconds_total: CPU ์‚ฌ์šฉ ์‹œ๊ฐ„ (mode๋ณ„๋กœ ๊ตฌ๋ถ„)
node_memory_MemAvailable_bytes: ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฉ”๋ชจ๋ฆฌ
node_disk_io_time_seconds_total: ๋””์Šคํฌ I/O ์‹œ๊ฐ„
node_network_receive_bytes_total: ๋„คํŠธ์›Œํฌ ์ˆ˜์‹  ๋ฐ”์ดํŠธ
node_filesystem_avail_bytes: ํŒŒ์ผ์‹œ์Šคํ…œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ ๊ณต๊ฐ„
node_load1, node_load5, node_load15: ์‹œ์Šคํ…œ ๋กœ๋“œ ํ‰๊ท 

๐Ÿ” PromQL ๋งˆ์Šคํ„ฐํ•˜๊ธฐ

PromQL(Prometheus Query Language)์€ Prometheus์˜ ๊ฝƒ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์–ด! ๐Ÿ’ ์ด ์ฟผ๋ฆฌ ์–ธ์–ด๋ฅผ ์ž˜ ๋‹ค๋ฃจ๋ฉด ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ž์œ ์ž์žฌ๋กœ ๋ถ„์„ํ•  ์ˆ˜ ์žˆ์ง€. ์ฒ˜์Œ์—” ์–ด๋ ค์›Œ ๋ณด์ด์ง€๋งŒ, ๋ช‡ ๊ฐ€์ง€ ํŒจํ„ด๋งŒ ์ตํžˆ๋ฉด ๊ธˆ๋ฐฉ ์ต์ˆ™ํ•ด์งˆ ๊ฑฐ์•ผ.

๐Ÿ“ ๊ธฐ๋ณธ ์ฟผ๋ฆฌ ๋ฌธ๋ฒ•

1๏ธโƒฃ ๋‹จ์ˆœ ๋ฉ”ํŠธ๋ฆญ ์กฐํšŒ

๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ํ˜•ํƒœ๋กœ, ๋ฉ”ํŠธ๋ฆญ ์ด๋ฆ„๋งŒ ์ž…๋ ฅํ•˜๋ฉด ๋ชจ๋“  ์‹œ๊ณ„์—ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€:
node_cpu_seconds_total

2๏ธโƒฃ ๋ ˆ์ด๋ธ” ํ•„ํ„ฐ๋ง

์ค‘๊ด„ํ˜ธ ์•ˆ์— ๋ ˆ์ด๋ธ” ์กฐ๊ฑด์„ ๋„ฃ์–ด์„œ ํ•„ํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์–ด:
node_cpu_seconds_total{mode="idle"}
node_cpu_seconds_total{instance="server1:9100", mode!="idle"}

node_cpu_seconds_total{mode=~"user|system"} (์ •๊ทœํ‘œํ˜„์‹ ์‚ฌ์šฉ)

3๏ธโƒฃ ๋ฒ”์œ„ ๋ฒกํ„ฐ ์„ ํƒ

ํŠน์ • ์‹œ๊ฐ„ ๋ฒ”์œ„์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ ์‚ฌ์šฉํ•ด:
node_cpu_seconds_total[5m] (์ตœ๊ทผ 5๋ถ„๊ฐ„์˜ ๋ฐ์ดํ„ฐ)
node_cpu_seconds_total[1h] (์ตœ๊ทผ 1์‹œ๊ฐ„์˜ ๋ฐ์ดํ„ฐ)

๐Ÿงฎ ์ง‘๊ณ„ ํ•จ์ˆ˜์™€ ์—ฐ์‚ฐ์ž

PromQL์˜ ์ง„์งœ ํŒŒ์›Œ๋Š” ์ง‘๊ณ„ ํ•จ์ˆ˜์—์„œ ๋‚˜์™€! ์—ฌ๋Ÿฌ ์‹œ๊ณ„์—ด ๋ฐ์ดํ„ฐ๋ฅผ ํ•˜๋‚˜๋กœ ํ•ฉ์น˜๊ฑฐ๋‚˜, ํ†ต๊ณ„๋ฅผ ๋‚ด๊ฑฐ๋‚˜, ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ์–ด.

# CPU ์‚ฌ์šฉ๋ฅ  ๊ณ„์‚ฐ (idle ๋ชจ๋“œ๋ฅผ ์ œ์™ธํ•œ ๋น„์œจ)
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

# ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋ฅ  ๊ณ„์‚ฐ
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100

# ๋””์Šคํฌ ์‚ฌ์šฉ๋ฅ  ๊ณ„์‚ฐ
(node_filesystem_size_bytes - node_filesystem_avail_bytes) / node_filesystem_size_bytes * 100

# ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ ์†๋„ (์ดˆ๋‹น ๋ฐ”์ดํŠธ)
rate(node_network_receive_bytes_total[5m])

# HTTP ์š”์ฒญ ์„ฑ๊ณต๋ฅ 
sum(rate(http_requests_total{status=~"2.."}[5m])) / sum(rate(http_requests_total[5m])) * 100

# 95 percentile ์‘๋‹ต ์‹œ๊ฐ„
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
๐ŸŽฏ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” PromQL ํ•จ์ˆ˜๋“ค rate(): ์ดˆ๋‹น ์ฆ๊ฐ€์œจ์„ ๊ณ„์‚ฐํ•ด. Counter ํƒ€์ž… ๋ฉ”ํŠธ๋ฆญ์— ์ฃผ๋กœ ์‚ฌ์šฉํ•ด.
irate(): rate()์™€ ๋น„์Šทํ•˜์ง€๋งŒ ๋งˆ์ง€๋ง‰ ๋‘ ๋ฐ์ดํ„ฐ ํฌ์ธํŠธ๋งŒ ์‚ฌ์šฉํ•ด์„œ ๋” ๋ฏผ๊ฐํ•˜๊ฒŒ ๋ฐ˜์‘ํ•ด.
increase(): ํŠน์ • ์‹œ๊ฐ„ ๋™์•ˆ์˜ ์ด ์ฆ๊ฐ€๋Ÿ‰์„ ๊ณ„์‚ฐํ•ด.
sum(): ์—ฌ๋Ÿฌ ์‹œ๊ณ„์—ด์˜ ๊ฐ’์„ ํ•ฉ์ณ.
avg(): ํ‰๊ท ๊ฐ’์„ ๊ณ„์‚ฐํ•ด.
max(), min(): ์ตœ๋Œ€๊ฐ’, ์ตœ์†Œ๊ฐ’์„ ์ฐพ์•„.
count(): ์‹œ๊ณ„์—ด์˜ ๊ฐœ์ˆ˜๋ฅผ ์„ธ.
topk(), bottomk(): ์ƒ์œ„/ํ•˜์œ„ k๊ฐœ์˜ ์‹œ๊ณ„์—ด์„ ์„ ํƒํ•ด.
histogram_quantile(): ํžˆ์Šคํ† ๊ทธ๋žจ์—์„œ ํŠน์ • ๋ฐฑ๋ถ„์œ„์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•ด.

๐ŸŽช ์‹ค์ „ PromQL ์˜ˆ์ œ

์‹ค์ œ ์šด์˜ ํ™˜๊ฒฝ์—์„œ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์ฟผ๋ฆฌ๋“ค์„ ๋ชจ์•„๋ดค์–ด. ์ด๋Ÿฐ ์ฟผ๋ฆฌ๋“ค์„ ๋Œ€์‹œ๋ณด๋“œ๋‚˜ ์•Œ๋ฆผ ๊ทœ์น™์— ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์–ด! ๐ŸŽฏ

๐Ÿ“Œ ์„œ๋ฒ„๋ณ„ CPU ์‚ฌ์šฉ๋ฅ  Top 5
topk(5, 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100))
๐Ÿ“Œ ๋ฉ”๋ชจ๋ฆฌ ๋ถ€์กฑ ์„œ๋ฒ„ ์ฐพ๊ธฐ (์‚ฌ์šฉ ๊ฐ€๋Šฅ ๋ฉ”๋ชจ๋ฆฌ 1GB ๋ฏธ๋งŒ)
node_memory_MemAvailable_bytes / 1024 / 1024 / 1024 < 1
๐Ÿ“Œ ๋””์Šคํฌ ์‚ฌ์šฉ๋ฅ  80% ์ด์ƒ์ธ ํŒŒ์ผ์‹œ์Šคํ…œ
(node_filesystem_size_bytes - node_filesystem_avail_bytes) / node_filesystem_size_bytes * 100 > 80
๐Ÿ“Œ ์ตœ๊ทผ 5๋ถ„๊ฐ„ HTTP 5xx ์—๋Ÿฌ ๋ฐœ์ƒ ๊ฑด์ˆ˜
sum(increase(http_requests_total{status=~"5.."}[5m]))
๐Ÿ“Œ ์„œ๋น„์Šค๋ณ„ ํ‰๊ท  ์‘๋‹ต ์‹œ๊ฐ„
avg by (service) (rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_count[5m]))

๐Ÿšจ Alertmanager๋กœ ์•Œ๋ฆผ ์‹œ์Šคํ…œ ๊ตฌ์ถ•ํ•˜๊ธฐ

๋ชจ๋‹ˆํ„ฐ๋ง์˜ ๊ถ๊ทน์ ์ธ ๋ชฉํ‘œ๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ๋น ๋ฅด๊ฒŒ ๋Œ€์‘ํ•˜๋Š” ๊ฑฐ์•ผ! ๐Ÿš‘ Alertmanager๋Š” Prometheus์—์„œ ๋ฐœ์ƒํ•œ ์•Œ๋ฆผ์„ ๋ฐ›์•„์„œ ์ ์ ˆํ•œ ์ฑ„๋„๋กœ ์ „๋‹ฌํ•˜๊ณ , ์ค‘๋ณต์„ ์ œ๊ฑฐํ•˜๊ณ , ๊ทธ๋ฃนํ™”ํ•˜๋Š” ์—ญํ• ์„ ํ•ด.

๐Ÿ“ฅ Alertmanager ์„ค์น˜ ๋ฐ ์„ค์ •

# Alertmanager ๋‹ค์šด๋กœ๋“œ
wget https://github.com/prometheus/alertmanager/releases/download/v0.26.0/alertmanager-0.26.0.linux-amd64.tar.gz
tar xvfz alertmanager-0.26.0.linux-amd64.tar.gz
cd alertmanager-0.26.0.linux-amd64

# Alertmanager ์‹คํ–‰
./alertmanager --config.file=alertmanager.yml

Alertmanager์˜ ์„ค์ • ํŒŒ์ผ(alertmanager.yml)์€ ์•Œ๋ฆผ์„ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€ ์ •์˜ํ•ด. ๋ผ์šฐํŒ… ๊ทœ์น™, ์ˆ˜์‹ ์ž ์„ค์ •, ์•Œ๋ฆผ ๊ทธ๋ฃนํ™” ๋“ฑ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์–ด.

global:
  resolve_timeout: 5m
  slack_api_url: 'https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK'

# ์•Œ๋ฆผ ๋ผ์šฐํŒ… ์„ค์ •
route:
  group_by: ['alertname', 'cluster', 'service']
  group_wait: 10s        # ์ฒซ ์•Œ๋ฆผ์„ ๋ณด๋‚ด๊ธฐ ์ „ ๋Œ€๊ธฐ ์‹œ๊ฐ„
  group_interval: 10s    # ๊ฐ™์€ ๊ทธ๋ฃน์˜ ์ถ”๊ฐ€ ์•Œ๋ฆผ ๊ฐ„๊ฒฉ
  repeat_interval: 12h   # ์•Œ๋ฆผ ๋ฐ˜๋ณต ๊ฐ„๊ฒฉ
  receiver: 'default'
  
  routes:
    # ์‹ฌ๊ฐํ•œ ์•Œ๋ฆผ์€ ์ฆ‰์‹œ PagerDuty๋กœ
    - match:
        severity: critical
      receiver: 'pagerduty'
      continue: true
    
    # ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ด€๋ จ ์•Œ๋ฆผ์€ DBA ํŒ€์œผ๋กœ
    - match_re:
        service: mysql|postgresql
      receiver: 'dba-team'
    
    # ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์•Œ๋ฆผ์€ Slack์œผ๋กœ๋งŒ
    - match:
        environment: development
      receiver: 'slack-dev'

# ์ˆ˜์‹ ์ž ์„ค์ •
receivers:
  - name: 'default'
    slack_configs:
      - channel: '#alerts'
        title: '{{ .GroupLabels.alertname }}'
        text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
  
  - name: 'pagerduty'
    pagerduty_configs:
      - service_key: 'YOUR_PAGERDUTY_KEY'
  
  - name: 'dba-team'
    email_configs:
      - to: 'dba-team@company.com'
        from: 'alertmanager@company.com'
        smarthost: 'smtp.gmail.com:587'
        auth_username: 'alertmanager@company.com'
        auth_password: 'your-password'
    slack_configs:
      - channel: '#dba-alerts'
  
  - name: 'slack-dev'
    slack_configs:
      - channel: '#dev-alerts'
        send_resolved: true

# ์•Œ๋ฆผ ์–ต์ œ ๊ทœ์น™
inhibit_rules:
  # ๋…ธ๋“œ๊ฐ€ ๋‹ค์šด๋˜๋ฉด ํ•ด๋‹น ๋…ธ๋“œ์˜ ๋‹ค๋ฅธ ์•Œ๋ฆผ์€ ์–ต์ œ
  - source_match:
      severity: 'critical'
      alertname: 'NodeDown'
    target_match:
      severity: 'warning'
    equal: ['instance']

๐Ÿ“‹ ์•Œ๋ฆผ ๊ทœ์น™ ์ž‘์„ฑํ•˜๊ธฐ

Prometheus์—์„œ ์•Œ๋ฆผ ๊ทœ์น™์„ ์ •์˜ํ•˜๋ฉด, ์กฐ๊ฑด์ด ๋งŒ์กฑ๋  ๋•Œ Alertmanager๋กœ ์•Œ๋ฆผ์ด ์ „์†ก๋ผ. alerts.yml ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์„œ ๊ทœ์น™์„ ์ •์˜ํ•ด๋ณด์ž!

groups:
  - name: node_alerts
    interval: 30s
    rules:
      # ์ธ์Šคํ„ด์Šค ๋‹ค์šด ์•Œ๋ฆผ
      - alert: InstanceDown
        expr: up == 0
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Instance {{ $labels.instance }} down"
          description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes."
      
      # CPU ์‚ฌ์šฉ๋ฅ  ๋†’์Œ
      - alert: HighCPUUsage
        expr: 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "High CPU usage on {{ $labels.instance }}"
          description: "CPU usage is above 80% (current value: {{ $value }}%)"
      
      # ๋ฉ”๋ชจ๋ฆฌ ๋ถ€์กฑ
      - alert: LowMemory
        expr: (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 < 10
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Low memory on {{ $labels.instance }}"
          description: "Available memory is below 10% (current: {{ $value }}%)"
      
      # ๋””์Šคํฌ ๊ณต๊ฐ„ ๋ถ€์กฑ
      - alert: DiskSpaceLow
        expr: (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100 < 15
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Low disk space on {{ $labels.instance }}"
          description: "Disk space is below 15% (current: {{ $value }}%)"
      
      # ๋””์Šคํฌ ๊ณต๊ฐ„ ์‹ฌ๊ฐ
      - alert: DiskSpaceCritical
        expr: (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100 < 5
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Critical disk space on {{ $labels.instance }}"
          description: "Disk space is critically low at {{ $value }}%"

  - name: application_alerts
    interval: 30s
    rules:
      # HTTP ์—๋Ÿฌ์œจ ๋†’์Œ
      - alert: HighErrorRate
        expr: (sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))) * 100 > 5
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "High HTTP error rate"
          description: "Error rate is above 5% (current: {{ $value }}%)"
      
      # ์‘๋‹ต ์‹œ๊ฐ„ ๋А๋ฆผ
      - alert: SlowResponseTime
        expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 2
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Slow response time"
          description: "95th percentile response time is above 2s (current: {{ $value }}s)"
      
      # ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ์‹คํŒจ
      - alert: DatabaseConnectionFailed
        expr: mysql_up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Database connection failed"
          description: "Cannot connect to database {{ $labels.instance }}"
โš ๏ธ ์•Œ๋ฆผ ๊ทœ์น™ ์ž‘์„ฑ ์‹œ ์ฃผ์˜์‚ฌํ•ญ for ์ ˆ ํ™œ์šฉ: ์ผ์‹œ์ ์ธ ์ŠคํŒŒ์ดํฌ๋กœ ์ธํ•œ ์˜ค์•Œ๋ฆผ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด for ์ ˆ์„ ์‚ฌ์šฉํ•ด์„œ ์ผ์ • ์‹œ๊ฐ„ ๋™์•ˆ ์กฐ๊ฑด์ด ์œ ์ง€๋  ๋•Œ๋งŒ ์•Œ๋ฆผ์„ ๋ฐœ์ƒ์‹œ์ผœ.

์ ์ ˆํ•œ ์ž„๊ณ„๊ฐ’ ์„ค์ •: ๋„ˆ๋ฌด ๋‚ฎ์œผ๋ฉด ์˜ค์•Œ๋ฆผ์ด ๋งŽ์•„์ง€๊ณ , ๋„ˆ๋ฌด ๋†’์œผ๋ฉด ์‹ค์ œ ๋ฌธ์ œ๋ฅผ ๋†“์น  ์ˆ˜ ์žˆ์–ด. ์šด์˜ํ•˜๋ฉด์„œ ์ ์ง„์ ์œผ๋กœ ์กฐ์ •ํ•ด์•ผ ํ•ด.

์‹ฌ๊ฐ๋„ ๊ตฌ๋ถ„: critical, warning, info ๋“ฑ์œผ๋กœ ์‹ฌ๊ฐ๋„๋ฅผ ๊ตฌ๋ถ„ํ•ด์„œ ๋Œ€์‘ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ •ํ•  ์ˆ˜ ์žˆ์–ด.

๋ช…ํ™•ํ•œ ์„ค๋ช…: annotations์— ๋ฌธ์ œ ์ƒํ™ฉ๊ณผ ํ˜„์žฌ ๊ฐ’์„ ๋ช…ํ™•ํžˆ ๊ธฐ์ˆ ํ•ด์„œ ๋ฐ›๋Š” ์‚ฌ๋žŒ์ด ๋ฐ”๋กœ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์•ผ ํ•ด.

๐ŸŽจ Grafana ์„ค์น˜ ๋ฐ ๋Œ€์‹œ๋ณด๋“œ ๊ตฌ์„ฑ

์ด์ œ Grafana๋ฅผ ์„ค์น˜ํ•˜๊ณ  ๋ฉ‹์ง„ ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž! Grafana๋Š” Prometheus ๋ฐ์ดํ„ฐ๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ํ‘œํ˜„ํ•˜๋Š” ์ตœ๊ณ ์˜ ๋„๊ตฌ์•ผ. ๐Ÿ“Š

๐Ÿ“ฆ Grafana ์„ค์น˜ํ•˜๊ธฐ

# Ubuntu/Debian
sudo apt-get install -y software-properties-common
sudo add-apt-repository "deb https://packages.grafana.com/oss/deb stable main"
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
sudo apt-get update
sudo apt-get install grafana

# CentOS/RHEL
sudo tee /etc/yum.repos.d/grafana.repo << EOF
[grafana]
name=grafana
baseurl=https://packages.grafana.com/oss/rpm
repo_gpgcheck=1
enabled=1
gpgcheck=1
gpgkey=https://packages.grafana.com/gpg.key
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
EOF

sudo yum install grafana

# ์„œ๋น„์Šค ์‹œ์ž‘
sudo systemctl start grafana-server
sudo systemctl enable grafana-server

Grafana๊ฐ€ ์‹คํ–‰๋˜๋ฉด http://localhost:3000์— ์ ‘์†ํ•  ์ˆ˜ ์žˆ์–ด. ๊ธฐ๋ณธ ๋กœ๊ทธ์ธ ์ •๋ณด๋Š” admin/admin์ด์•ผ. ์ฒ˜์Œ ๋กœ๊ทธ์ธํ•˜๋ฉด ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ผ๊ณ  ํ•  ๊ฑฐ์•ผ! ๐Ÿ”

๐Ÿ”Œ Prometheus ๋ฐ์ดํ„ฐ ์†Œ์Šค ์—ฐ๊ฒฐํ•˜๊ธฐ

Grafana์—์„œ Prometheus ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋จผ์ € ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ด:

๐Ÿ“ ๋ฐ์ดํ„ฐ ์†Œ์Šค ์ถ”๊ฐ€ ๋‹จ๊ณ„ 1๏ธโƒฃ Grafana ์ขŒ์ธก ๋ฉ”๋‰ด์—์„œ Configuration โ†’ Data Sources ํด๋ฆญ
2๏ธโƒฃ "Add data source" ๋ฒ„ํŠผ ํด๋ฆญ
3๏ธโƒฃ Prometheus ์„ ํƒ
4๏ธโƒฃ URL์— Prometheus ์„œ๋ฒ„ ์ฃผ์†Œ ์ž…๋ ฅ (์˜ˆ: http://localhost:9090)
5๏ธโƒฃ "Save & Test" ๋ฒ„ํŠผ ํด๋ฆญํ•ด์„œ ์—ฐ๊ฒฐ ํ™•์ธ

์—ฐ๊ฒฐ์ด ์„ฑ๊ณตํ•˜๋ฉด "Data source is working" ๋ฉ”์‹œ์ง€๊ฐ€ ๋‚˜ํƒ€๋‚  ๊ฑฐ์•ผ! โœ…

๐Ÿ“Š ๋Œ€์‹œ๋ณด๋“œ ๋งŒ๋“ค๊ธฐ

์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž! Grafana์—๋Š” ์ด๋ฏธ ๋งŒ๋“ค์–ด์ง„ ์ˆ˜์ฒœ ๊ฐœ์˜ ๋Œ€์‹œ๋ณด๋“œ ํ…œํ”Œ๋ฆฟ์ด ์žˆ์–ด์„œ, ์ฒ˜์Œ๋ถ€ํ„ฐ ๋งŒ๋“ค ํ•„์š” ์—†์ด ๊ฐ€์ ธ๋‹ค ์“ธ ์ˆ˜ ์žˆ์–ด. ํ•˜์ง€๋งŒ ์ง์ ‘ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•๋„ ์•Œ์•„๋‘๋ฉด ์ข‹์ง€! ๐Ÿ˜Š

๐ŸŽฏ ์ธ๊ธฐ ์žˆ๋Š” Grafana ๋Œ€์‹œ๋ณด๋“œ ํ…œํ”Œ๋ฆฟ Node Exporter Full (ID: 1860): ์‹œ์Šคํ…œ ๋ฉ”ํŠธ๋ฆญ์„ ์ข…ํ•ฉ์ ์œผ๋กœ ๋ณด์—ฌ์ฃผ๋Š” ๋Œ€์‹œ๋ณด๋“œ. CPU, ๋ฉ”๋ชจ๋ฆฌ, ๋””์Šคํฌ, ๋„คํŠธ์›Œํฌ ๋“ฑ ๋ชจ๋“  ๊ธฐ๋ณธ ๋ฉ”ํŠธ๋ฆญ์„ ํ•œ๋ˆˆ์—!

Kubernetes Cluster Monitoring (ID: 7249): Kubernetes ํด๋Ÿฌ์Šคํ„ฐ ์ „์ฒด๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋Œ€์‹œ๋ณด๋“œ.

MySQL Overview (ID: 7362): MySQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง.

NGINX Ingress Controller (ID: 9614): NGINX ์ธ๊ทธ๋ ˆ์Šค ์ปจํŠธ๋กค๋Ÿฌ ๋ชจ๋‹ˆํ„ฐ๋ง.

๋Œ€์‹œ๋ณด๋“œ๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๋ฉด: Dashboard โ†’ Import โ†’ ๋Œ€์‹œ๋ณด๋“œ ID ์ž…๋ ฅ โ†’ Load!

๐ŸŽจ ์ปค์Šคํ…€ ํŒจ๋„ ๋งŒ๋“ค๊ธฐ

์ง์ ‘ ํŒจ๋„์„ ๋งŒ๋“ค์–ด์„œ ์›ํ•˜๋Š” ๋ฉ”ํŠธ๋ฆญ์„ ์‹œ๊ฐํ™”ํ•ด๋ณด์ž. ์˜ˆ๋ฅผ ๋“ค์–ด, CPU ์‚ฌ์šฉ๋ฅ ์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ทธ๋ž˜ํ”„๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊ฒŒ:

๐Ÿ–Œ๏ธ ํŒจ๋„ ์ƒ์„ฑ ๋‹จ๊ณ„

1๏ธโƒฃ ๋Œ€์‹œ๋ณด๋“œ์—์„œ "Add panel" ํด๋ฆญ
2๏ธโƒฃ "Add a new panel" ์„ ํƒ
3๏ธโƒฃ Query ํƒญ์—์„œ PromQL ์ฟผ๋ฆฌ ์ž…๋ ฅ:
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

4๏ธโƒฃ Legend์— {{instance}} ์ž…๋ ฅํ•ด์„œ ์ธ์Šคํ„ด์Šค๋ณ„๋กœ ๊ตฌ๋ถ„
5๏ธโƒฃ ์šฐ์ธก ํŒจ๋„์—์„œ ์‹œ๊ฐํ™” ํƒ€์ž… ์„ ํƒ (Time series, Gauge, Stat ๋“ฑ)
6๏ธโƒฃ Panel options์—์„œ ์ œ๋ชฉ, ์„ค๋ช… ๋“ฑ ์„ค์ •
7๏ธโƒฃ Thresholds์—์„œ ์ž„๊ณ„๊ฐ’ ์„ค์ • (์˜ˆ: 80% ์ด์ƒ ๋นจ๊ฐ„์ƒ‰)
8๏ธโƒฃ "Apply" ๋ฒ„ํŠผ ํด๋ฆญ!

๐ŸŽญ ๋‹ค์–‘ํ•œ ์‹œ๊ฐํ™” ํƒ€์ž… ํ™œ์šฉํ•˜๊ธฐ

Grafana๋Š” ๋ฐ์ดํ„ฐ์˜ ํŠน์„ฑ์— ๋งž๋Š” ๋‹ค์–‘ํ•œ ์‹œ๊ฐํ™” ์˜ต์…˜์„ ์ œ๊ณตํ•ด. ์–ด๋–ค ์ƒํ™ฉ์— ์–ด๋–ค ํƒ€์ž…์„ ์“ฐ๋ฉด ์ข‹์„์ง€ ์•Œ์•„๋ณด์ž! ๐ŸŽจ

๐Ÿ“ˆ Time Series (์‹œ๊ณ„์—ด ๊ทธ๋ž˜ํ”„) ์‹œ๊ฐ„์— ๋”ฐ๋ฅธ ๋ณ€ํ™”๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ๊ทธ๋ž˜ํ”„. CPU ์‚ฌ์šฉ๋ฅ , ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰, ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ์ฒ˜๋Ÿผ ์—ฐ์†์ ์ธ ๋ฐ์ดํ„ฐ์— ์ ํ•ฉํ•ด.
๐ŸŽฏ Gauge (๊ฒŒ์ด์ง€) ํ˜„์žฌ ๊ฐ’์„ ์‹œ๊ฐ์ ์œผ๋กœ ํ‘œํ˜„ํ•˜๋Š” ๊ฒŒ์ด์ง€. ๋””์Šคํฌ ์‚ฌ์šฉ๋ฅ , ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋ฅ ์ฒ˜๋Ÿผ 0~100% ๋ฒ”์œ„์˜ ๊ฐ’์„ ๋ณด์—ฌ์ค„ ๋•Œ ์ข‹์•„.
๐Ÿ“Š Bar Chart (๋ง‰๋Œ€ ๊ทธ๋ž˜ํ”„) ์—ฌ๋Ÿฌ ํ•ญ๋ชฉ์„ ๋น„๊ตํ•  ๋•Œ ์œ ์šฉํ•ด. ์„œ๋ฒ„๋ณ„ CPU ์‚ฌ์šฉ๋ฅ , ์„œ๋น„์Šค๋ณ„ ์š”์ฒญ ์ˆ˜ ๊ฐ™์€ ๊ฑธ ๋น„๊ตํ•  ๋•Œ ์“ฐ๋ฉด ์ข‹์•„.
๐Ÿ”ฅ Heatmap (ํžˆํŠธ๋งต) ๋ถ„ํฌ๋ฅผ ์ƒ‰์ƒ์œผ๋กœ ํ‘œํ˜„ํ•˜๋Š” ํžˆํŠธ๋งต. ์‘๋‹ต ์‹œ๊ฐ„ ๋ถ„ํฌ, ์š”์ฒญ ํŒจํ„ด ๊ฐ™์€ ๊ฑธ ์‹œ๊ฐํ™”ํ•  ๋•Œ ํšจ๊ณผ์ ์ด์•ผ.
๐Ÿ“‹ Table (ํ…Œ์ด๋ธ”) ์—ฌ๋Ÿฌ ๋ฉ”ํŠธ๋ฆญ์„ ํ•œ ๋ฒˆ์— ๋ณด์—ฌ์ค„ ๋•Œ ์œ ์šฉํ•ด. ์„œ๋ฒ„ ๋ชฉ๋ก๊ณผ ๊ฐ ์„œ๋ฒ„์˜ ์ƒํƒœ๋ฅผ ํ‘œ ํ˜•ํƒœ๋กœ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์–ด.
๐Ÿ”ข Stat (ํ†ต๊ณ„) ๋‹จ์ผ ๊ฐ’์„ ํฌ๊ฒŒ ํ‘œ์‹œํ•˜๋Š” ํŒจ๋„. ํ˜„์žฌ ํ™œ์„ฑ ์‚ฌ์šฉ์ž ์ˆ˜, ์ด ์š”์ฒญ ์ˆ˜ ๊ฐ™์€ ์ค‘์š”ํ•œ ์ง€ํ‘œ๋ฅผ ๊ฐ•์กฐํ•  ๋•Œ ์ข‹์•„.

๐ŸŽช ์‹ค์ „ ๋Œ€์‹œ๋ณด๋“œ ๊ตฌ์„ฑ ์˜ˆ์ œ

์ด๋ก ์€ ์ถฉ๋ถ„ํžˆ ๋ฐฐ์› ์œผ๋‹ˆ, ์ด์ œ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ๊ตฌ์„ฑํ•ด๋ณด์ž! ์—ฌ๊ธฐ์„œ๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ชจ๋‹ˆํ„ฐ๋ง ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊ฒŒ. ๐Ÿš€

๐ŸŒ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ชจ๋‹ˆํ„ฐ๋ง ๋Œ€์‹œ๋ณด๋“œ

๐Ÿ“Œ ๋Œ€์‹œ๋ณด๋“œ ๊ตฌ์„ฑ ์š”์†Œ ์ƒ๋‹จ Row: ์ „์ฒด ๊ฐœ์š”
โ€ข ์ด ์š”์ฒญ ์ˆ˜ (Stat ํŒจ๋„)
โ€ข ํ‰๊ท  ์‘๋‹ต ์‹œ๊ฐ„ (Stat ํŒจ๋„)
โ€ข ์—๋Ÿฌ์œจ (Gauge ํŒจ๋„)
โ€ข ํ™œ์„ฑ ์—ฐ๊ฒฐ ์ˆ˜ (Stat ํŒจ๋„)

์ค‘๊ฐ„ Row: ํŠธ๋ž˜ํ”ฝ ๋ถ„์„
โ€ข ์ดˆ๋‹น ์š”์ฒญ ์ˆ˜ (Time Series)
โ€ข HTTP ์ƒํƒœ ์ฝ”๋“œ๋ณ„ ๋ถ„ํฌ (Bar Chart)
โ€ข ์—”๋“œํฌ์ธํŠธ๋ณ„ ์š”์ฒญ ์ˆ˜ (Table)

ํ•˜๋‹จ Row: ์„ฑ๋Šฅ ๋ฉ”ํŠธ๋ฆญ
โ€ข ์‘๋‹ต ์‹œ๊ฐ„ ๋ถ„ํฌ (Heatmap)
โ€ข 95th/99th percentile ์‘๋‹ต ์‹œ๊ฐ„ (Time Series)
โ€ข ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ ์‹œ๊ฐ„ (Time Series)

๊ฐ ํŒจ๋„์— ์‚ฌ์šฉํ•  PromQL ์ฟผ๋ฆฌ๋ฅผ ์ •๋ฆฌํ•ด๋ดค์–ด:

# ์ด ์š”์ฒญ ์ˆ˜
sum(increase(http_requests_total[24h]))

# ํ‰๊ท  ์‘๋‹ต ์‹œ๊ฐ„
avg(rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_count[5m]))

# ์—๋Ÿฌ์œจ
(sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))) * 100

# ์ดˆ๋‹น ์š”์ฒญ ์ˆ˜
sum(rate(http_requests_total[5m]))

# HTTP ์ƒํƒœ ์ฝ”๋“œ๋ณ„ ์š”์ฒญ ์ˆ˜
sum by (status) (rate(http_requests_total[5m]))

# ์—”๋“œํฌ์ธํŠธ๋ณ„ ์š”์ฒญ ์ˆ˜
topk(10, sum by (endpoint) (rate(http_requests_total[5m])))

# 95th percentile ์‘๋‹ต ์‹œ๊ฐ„
histogram_quantile(0.95, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))

# 99th percentile ์‘๋‹ต ์‹œ๊ฐ„
histogram_quantile(0.99, sum by (le) (rate(http_request_duration_seconds_bucket[5m])))

๐Ÿ–ฅ๏ธ ์ธํ”„๋ผ ๋ชจ๋‹ˆํ„ฐ๋ง ๋Œ€์‹œ๋ณด๋“œ

์„œ๋ฒ„ ์ธํ”„๋ผ๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋Š” ๋Œ€์‹œ๋ณด๋“œ๋„ ๋งŒ๋“ค์–ด๋ณด์ž. ์ด๊ฑด Node Exporter ๋ฉ”ํŠธ๋ฆญ์„ ํ™œ์šฉํ•ด์„œ ๊ตฌ์„ฑํ•  ๊ฑฐ์•ผ!

# CPU ์‚ฌ์šฉ๋ฅ  (์„œ๋ฒ„๋ณ„)
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

# ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋ฅ 
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100

# ๋””์Šคํฌ ์‚ฌ์šฉ๋ฅ 
(node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) / node_filesystem_size_bytes{mountpoint="/"} * 100

# ๋„คํŠธ์›Œํฌ ์ˆ˜์‹  ์†๋„ (Mbps)
rate(node_network_receive_bytes_total[5m]) * 8 / 1000000

# ๋„คํŠธ์›Œํฌ ์†ก์‹  ์†๋„ (Mbps)
rate(node_network_transmit_bytes_total[5m]) * 8 / 1000000

# ๋””์Šคํฌ I/O ์‚ฌ์šฉ๋ฅ 
rate(node_disk_io_time_seconds_total[5m]) * 100

# ์‹œ์Šคํ…œ ๋กœ๋“œ ํ‰๊ท 
node_load1
node_load5
node_load15

# ํ”„๋กœ์„ธ์Šค ์ˆ˜
node_procs_running

# ํŒŒ์ผ ๋””์Šคํฌ๋ฆฝํ„ฐ ์‚ฌ์šฉ๋ฅ 
(node_filefd_allocated / node_filefd_maximum) * 100

๐Ÿ”” Grafana ์•Œ๋ฆผ ์„ค์ •ํ•˜๊ธฐ

Grafana์—์„œ๋„ ์ž์ฒด์ ์œผ๋กœ ์•Œ๋ฆผ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์–ด! Prometheus Alertmanager์™€๋Š” ๋ณ„๊ฐœ๋กœ ๋™์ž‘ํ•˜๋Š”๋ฐ, ๋Œ€์‹œ๋ณด๋“œ ํŒจ๋„์—์„œ ์ง์ ‘ ์•Œ๋ฆผ ๊ทœ์น™์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์–ด. ๐Ÿ“ข

๐Ÿ“ง ์•Œ๋ฆผ ์ฑ„๋„ ์„ค์ •ํ•˜๊ธฐ

๋จผ์ € ์•Œ๋ฆผ์„ ๋ฐ›์„ ์ฑ„๋„์„ ์„ค์ •ํ•ด์•ผ ํ•ด. Grafana๋Š” ๋‹ค์–‘ํ•œ ์•Œ๋ฆผ ์ฑ„๋„์„ ์ง€์›ํ•ด:

๐ŸŽฏ ์ง€์›ํ•˜๋Š” ์•Œ๋ฆผ ์ฑ„๋„ โ€ข Email
โ€ข Slack
โ€ข PagerDuty
โ€ข Microsoft Teams
โ€ข Discord
โ€ข Telegram
โ€ข Webhook (์ปค์Šคํ…€ ํ†ตํ•ฉ)
โ€ข OpsGenie
โ€ข VictorOps
๊ทธ ์™ธ 30๊ฐœ ์ด์ƒ์˜ ์ฑ„๋„ ์ง€์›!

Slack ์•Œ๋ฆผ ์ฑ„๋„์„ ์„ค์ •ํ•˜๋Š” ์˜ˆ์ œ๋ฅผ ๋ณด์—ฌ์ค„๊ฒŒ:

๐Ÿ“ Slack ์•Œ๋ฆผ ์ฑ„๋„ ์„ค์ • 1๏ธโƒฃ Alerting โ†’ Notification channels โ†’ New channel
2๏ธโƒฃ Type์—์„œ "Slack" ์„ ํƒ
3๏ธโƒฃ Slack Webhook URL ์ž…๋ ฅ
4๏ธโƒฃ ์•Œ๋ฆผ์„ ๋ฐ›์„ ์ฑ„๋„ ์ง€์ • (์˜ˆ: #alerts)
5๏ธโƒฃ "Test" ๋ฒ„ํŠผ์œผ๋กœ ํ…Œ์ŠคํŠธ ์•Œ๋ฆผ ์ „์†ก
6๏ธโƒฃ "Save" ๋ฒ„ํŠผ ํด๋ฆญ!

โšก ํŒจ๋„์— ์•Œ๋ฆผ ๊ทœ์น™ ์ถ”๊ฐ€ํ•˜๊ธฐ

์ด์ œ ํŠน์ • ํŒจ๋„์— ์•Œ๋ฆผ ๊ทœ์น™์„ ์ถ”๊ฐ€ํ•ด๋ณด์ž. ์˜ˆ๋ฅผ ๋“ค์–ด, CPU ์‚ฌ์šฉ๋ฅ ์ด 80%๋ฅผ ๋„˜์œผ๋ฉด ์•Œ๋ฆผ์„ ๋ฐ›๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์–ด:

๐Ÿ”” ์•Œ๋ฆผ ๊ทœ์น™ ์ƒ์„ฑ ๋‹จ๊ณ„ 1๏ธโƒฃ ํŒจ๋„ ํŽธ์ง‘ ๋ชจ๋“œ๋กœ ๋“ค์–ด๊ฐ€๊ธฐ
2๏ธโƒฃ Alert ํƒญ ํด๋ฆญ
3๏ธโƒฃ "Create Alert" ๋ฒ„ํŠผ ํด๋ฆญ
4๏ธโƒฃ Conditions ์„ค์ •:
โ€ข WHEN: avg()
โ€ข OF: query(A, 5m, now)
โ€ข IS ABOVE: 80
5๏ธโƒฃ Evaluate every: 1m (ํ‰๊ฐ€ ์ฃผ๊ธฐ)
6๏ธโƒฃ For: 5m (์กฐ๊ฑด ์ง€์† ์‹œ๊ฐ„)
7๏ธโƒฃ Notifications์—์„œ ์•Œ๋ฆผ ์ฑ„๋„ ์„ ํƒ
8๏ธโƒฃ Message์— ์•Œ๋ฆผ ๋‚ด์šฉ ์ž‘์„ฑ
9๏ธโƒฃ "Apply" ๋ฒ„ํŠผ ํด๋ฆญ!

๐Ÿš€ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ ํ™œ์šฉํ•˜๊ธฐ

๊ธฐ๋ณธ์ ์ธ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ–ˆ๋‹ค๋ฉด, ์ด์ œ ์ข€ ๋” ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์„ ํ™œ์šฉํ•ด์„œ ์‹œ์Šคํ…œ์„ ์—…๊ทธ๋ ˆ์ด๋“œํ•ด๋ณด์ž! ๐Ÿ’ช

๐Ÿ”„ Recording Rules๋กœ ์„ฑ๋Šฅ ์ตœ์ ํ™”

๋ณต์žกํ•œ PromQL ์ฟผ๋ฆฌ๋ฅผ ๋งค๋ฒˆ ์‹คํ–‰ํ•˜๋ฉด ์„ฑ๋Šฅ์— ๋ถ€๋‹ด์ด ๋  ์ˆ˜ ์žˆ์–ด. Recording Rules๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฏธ๋ฆฌ ๊ณ„์‚ฐ๋œ ๊ฒฐ๊ณผ๋ฅผ ์ €์žฅํ•ด์„œ ์ฟผ๋ฆฌ ์„ฑ๋Šฅ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์–ด!

groups:
  - name: recording_rules
    interval: 30s
    rules:
      # CPU ์‚ฌ์šฉ๋ฅ ์„ ๋ฏธ๋ฆฌ ๊ณ„์‚ฐ
      - record: instance:node_cpu_utilization:rate5m
        expr: 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
      
      # ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋ฅ ์„ ๋ฏธ๋ฆฌ ๊ณ„์‚ฐ
      - record: instance:node_memory_utilization:ratio
        expr: 1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)
      
      # HTTP ์š”์ฒญ ์„ฑ๊ณต๋ฅ ์„ ๋ฏธ๋ฆฌ ๊ณ„์‚ฐ
      - record: job:http_requests:success_rate5m
        expr: sum by (job) (rate(http_requests_total{status=~"2.."}[5m])) / sum by (job) (rate(http_requests_total[5m]))
      
      # ์„œ๋น„์Šค๋ณ„ ํ‰๊ท  ์‘๋‹ต ์‹œ๊ฐ„
      - record: service:http_request_duration:avg5m
        expr: sum by (service) (rate(http_request_duration_seconds_sum[5m])) / sum by (service) (rate(http_request_duration_seconds_count[5m]))

Recording Rules๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋Œ€์‹œ๋ณด๋“œ์—์„œ instance:node_cpu_utilization:rate5m์ฒ˜๋Ÿผ ๊ฐ„๋‹จํ•œ ๋ฉ”ํŠธ๋ฆญ ์ด๋ฆ„์œผ๋กœ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์–ด. ์ฟผ๋ฆฌ๊ฐ€ ๋นจ๋ผ์ง€๊ณ , ๋Œ€์‹œ๋ณด๋“œ ๋กœ๋”ฉ ์†๋„๋„ ๊ฐœ์„ ๋ผ! โšก

๐Ÿ“Š Variables๋กœ ๋™์  ๋Œ€์‹œ๋ณด๋“œ ๋งŒ๋“ค๊ธฐ

Grafana์˜ Variables ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•˜๋‚˜์˜ ๋Œ€์‹œ๋ณด๋“œ๋กœ ์—ฌ๋Ÿฌ ํ™˜๊ฒฝ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์–ด. ์˜ˆ๋ฅผ ๋“ค์–ด, ์„œ๋ฒ„๋ฅผ ์„ ํƒํ•˜๋ฉด ํ•ด๋‹น ์„œ๋ฒ„์˜ ๋ฉ”ํŠธ๋ฆญ๋งŒ ๋ณด์—ฌ์ฃผ๋Š” ์‹์ด์ง€!

๐ŸŽฏ Variable ์ƒ์„ฑํ•˜๊ธฐ 1๏ธโƒฃ Dashboard settings โ†’ Variables โ†’ New variable
2๏ธโƒฃ Name: instance
3๏ธโƒฃ Type: Query
4๏ธโƒฃ Query: label_values(node_cpu_seconds_total, instance)
5๏ธโƒฃ Multi-value ์˜ต์…˜ ํ™œ์„ฑํ™” (์—ฌ๋Ÿฌ ์„œ๋ฒ„ ์„ ํƒ ๊ฐ€๋Šฅ)
6๏ธโƒฃ Include All option ํ™œ์„ฑํ™” (์ „์ฒด ์„ ํƒ ๊ฐ€๋Šฅ)

์ด์ œ ํŒจ๋„ ์ฟผ๋ฆฌ์—์„œ $instance๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์„ ํƒํ•œ ์„œ๋ฒ„์˜ ๋ฐ์ดํ„ฐ๋งŒ ๋ณด์—ฌ์ค˜!
์˜ˆ: node_cpu_seconds_total{instance="$instance"}

๐Ÿ”— Annotations๋กœ ์ด๋ฒคํŠธ ํ‘œ์‹œํ•˜๊ธฐ

๋ฐฐํฌ, ์„ค์ • ๋ณ€๊ฒฝ, ์žฅ์•  ๊ฐ™์€ ์ด๋ฒคํŠธ๋ฅผ ๊ทธ๋ž˜ํ”„์— ํ‘œ์‹œํ•˜๋ฉด ๋ฉ”ํŠธ๋ฆญ ๋ณ€ํ™”์˜ ์›์ธ์„ ์‰ฝ๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์–ด. Annotations ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•ด๋ณด์ž! ๐Ÿ“

๐Ÿ’ก Annotations ํ™œ์šฉ ์˜ˆ์‹œ โ€ข ๋ฐฐํฌ ์‹œ์  ํ‘œ์‹œ: ์„ฑ๋Šฅ ๋ณ€ํ™”๊ฐ€ ๋ฐฐํฌ์™€ ๊ด€๋ จ ์žˆ๋Š”์ง€ ํ™•์ธ
โ€ข ์•Œ๋ฆผ ๋ฐœ์ƒ ์‹œ์  ํ‘œ์‹œ: ์–ด๋–ค ๋ฉ”ํŠธ๋ฆญ์ด ์•Œ๋ฆผ์„ ํŠธ๋ฆฌ๊ฑฐํ–ˆ๋Š”์ง€ ํ™•์ธ
โ€ข ์Šค์ผ€์ผ๋ง ์ด๋ฒคํŠธ ํ‘œ์‹œ: ์˜คํ† ์Šค์ผ€์ผ๋ง์ด ๋ฐœ์ƒํ•œ ์‹œ์  ํ™•์ธ
โ€ข ์™ธ๋ถ€ ์ด๋ฒคํŠธ ํ‘œ์‹œ: ๋งˆ์ผ€ํŒ… ์บ ํŽ˜์ธ, ์ด๋ฒคํŠธ ์‹œ์ž‘ ์‹œ์  ๋“ฑ

๐Ÿณ Docker์™€ Kubernetes ํ™˜๊ฒฝ์—์„œ์˜ ๋ชจ๋‹ˆํ„ฐ๋ง

์š”์ฆ˜์€ ๋Œ€๋ถ€๋ถ„ ์ปจํ…Œ์ด๋„ˆ ํ™˜๊ฒฝ์—์„œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์šด์˜ํ•˜์ž–์•„? Docker์™€ Kubernetes ํ™˜๊ฒฝ์—์„œ Prometheus์™€ Grafana๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์•Œ์•„๋ณด์ž! ๐Ÿšข

๐Ÿ‹ Docker Compose๋กœ ๋น ๋ฅด๊ฒŒ ๊ตฌ์ถ•ํ•˜๊ธฐ

Docker Compose๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Prometheus, Grafana, Alertmanager๋ฅผ ํ•œ ๋ฒˆ์— ๋„์šธ ์ˆ˜ ์žˆ์–ด. ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์ด๋‚˜ ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์— ๋”ฑ์ด์ง€!

version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - ./alerts.yml:/etc/prometheus/alerts.yml
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/usr/share/prometheus/console_libraries'
      - '--web.console.templates=/usr/share/prometheus/consoles'
    ports:
      - "9090:9090"
    networks:
      - monitoring
    restart: unless-stopped

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    volumes:
      - grafana-data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
      - GF_USERS_ALLOW_SIGN_UP=false
    ports:
      - "3000:3000"
    networks:
      - monitoring
    restart: unless-stopped
    depends_on:
      - prometheus

  alertmanager:
    image: prom/alertmanager:latest
    container_name: alertmanager
    volumes:
      - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
      - alertmanager-data:/alertmanager
    command:
      - '--config.file=/etc/alertmanager/alertmanager.yml'
      - '--storage.path=/alertmanager'
    ports:
      - "9093:9093"
    networks:
      - monitoring
    restart: unless-stopped

  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    ports:
      - "9100:9100"
    networks:
      - monitoring
    restart: unless-stopped

  cadvisor:
    image: gcr.io/cadvisor/cadvisor:latest
    container_name: cadvisor
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    ports:
      - "8080:8080"
    networks:
      - monitoring
    restart: unless-stopped

networks:
  monitoring:
    driver: bridge

volumes:
  prometheus-data:
  grafana-data:
  alertmanager-data:

์ด Docker Compose ํŒŒ์ผ ํ•˜๋‚˜๋กœ ์ „์ฒด ๋ชจ๋‹ˆํ„ฐ๋ง ์Šคํƒ์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์–ด! docker-compose up -d ๋ช…๋ น์–ด ํ•˜๋‚˜๋ฉด ๋์ด์•ผ. ๐Ÿ˜Ž

โ˜ธ๏ธ Kubernetes์—์„œ Prometheus Operator ์‚ฌ์šฉํ•˜๊ธฐ

Kubernetes ํ™˜๊ฒฝ์—์„œ๋Š” Prometheus Operator๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ํ‘œ์ค€์ด์•ผ. Helm ์ฐจํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์‰ฝ๊ฒŒ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ์–ด:

# Helm ์ €์žฅ์†Œ ์ถ”๊ฐ€
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

# kube-prometheus-stack ์„ค์น˜
helm install prometheus prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --create-namespace \
  --set prometheus.prometheusSpec.retention=30d \
  --set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.resources.requests.storage=50Gi \
  --set grafana.adminPassword=admin123

# ์„ค์น˜ ํ™•์ธ
kubectl get pods -n monitoring

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Prometheus, Grafana, Alertmanager๊ฐ€ ๋ชจ๋‘ ์„ค์น˜๋˜๊ณ , Kubernetes ํด๋Ÿฌ์Šคํ„ฐ ์ „์ฒด๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋ณธ ๋Œ€์‹œ๋ณด๋“œ๋„ ํ•จ๊ป˜ ์ œ๊ณต๋ผ! ๐ŸŽ

๐ŸŽ“ ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค

๋งˆ์ง€๋ง‰์œผ๋กœ, ์‹ค์ œ ์šด์˜ ํ™˜๊ฒฝ์—์„œ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์„ ํšจ๊ณผ์ ์œผ๋กœ ์šด์˜ํ•˜๊ธฐ ์œ„ํ•œ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค๋ฅผ ๊ณต์œ ํ• ๊ฒŒ! ์ด๊ฑด ๋‚ด๊ฐ€ ์—ฌ๋Ÿฌ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฒฝํ—˜ํ•˜๋ฉด์„œ ๋ฐฐ์šด ๋…ธํ•˜์šฐ๋“ค์ด์•ผ. ๐Ÿ’ก

1๏ธโƒฃ ์ ์ ˆํ•œ ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘ ๊ฐ„๊ฒฉ ์„ค์ • ๋„ˆ๋ฌด ์งง์œผ๋ฉด ์Šคํ† ๋ฆฌ์ง€์™€ CPU ๋ถ€๋‹ด์ด ์ปค์ง€๊ณ , ๋„ˆ๋ฌด ๊ธธ๋ฉด ์ค‘์š”ํ•œ ๋ณ€ํ™”๋ฅผ ๋†“์น  ์ˆ˜ ์žˆ์–ด. ์ผ๋ฐ˜์ ์œผ๋กœ:
โ€ข ์‹œ์Šคํ…œ ๋ฉ”ํŠธ๋ฆญ: 15~30์ดˆ
โ€ข ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฉ”ํŠธ๋ฆญ: 10~15์ดˆ
โ€ข ๋ฐฐ์น˜ ์ž‘์—…: 1~5๋ถ„
์ค‘์š”๋„์™€ ๋ณ€ํ™” ์†๋„์— ๋”ฐ๋ผ ์กฐ์ •ํ•ด์•ผ ํ•ด!
2๏ธโƒฃ ๋ ˆ์ด๋ธ” ์„ค๊ณ„๋ฅผ ์‹ ์ค‘ํ•˜๊ฒŒ ๋ ˆ์ด๋ธ”์€ ๊ฐ•๋ ฅํ•˜์ง€๋งŒ, ์นด๋””๋„๋ฆฌํ‹ฐ(๊ณ ์œ ํ•œ ์กฐํ•ฉ์˜ ์ˆ˜)๊ฐ€ ๋„ˆ๋ฌด ๋†’์œผ๋ฉด ์„ฑ๋Šฅ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ด. ๋‹ค์Œ ์›์น™์„ ๋”ฐ๋ผ:
โ€ข ๊ณ ์ •๋œ ๊ฐ’๋งŒ ๋ ˆ์ด๋ธ”๋กœ ์‚ฌ์šฉ (์‚ฌ์šฉ์ž ID, ์„ธ์…˜ ID ๊ฐ™์€ ๊ฑด X)
โ€ข ๋ ˆ์ด๋ธ” ๊ฐœ์ˆ˜๋Š” 10๊ฐœ ์ดํ•˜๋กœ ์ œํ•œ
โ€ข ๋ ˆ์ด๋ธ” ๊ฐ’์˜ ์ข…๋ฅ˜๋Š” 100๊ฐœ ์ดํ•˜๊ฐ€ ์ด์ƒ์ 
โ€ข ํ™˜๊ฒฝ(env), ์„œ๋น„์Šค(service), ์ธ์Šคํ„ด์Šค(instance) ๊ฐ™์€ ๊ธฐ๋ณธ ๋ ˆ์ด๋ธ”์€ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์‚ฌ์šฉ
3๏ธโƒฃ ์•Œ๋ฆผ ํ”ผ๋กœ๋„ ๊ด€๋ฆฌ ์•Œ๋ฆผ์ด ๋„ˆ๋ฌด ๋งŽ์œผ๋ฉด ์ค‘์š”ํ•œ ์•Œ๋ฆผ์„ ๋†“์น˜๊ฒŒ ๋ผ. ์•Œ๋ฆผ ํ”ผ๋กœ๋„๋ฅผ ์ค„์ด๋Š” ๋ฐฉ๋ฒ•:
โ€ข ์‹ฌ๊ฐ๋„๋ฅผ ๋ช…ํ™•ํžˆ ๊ตฌ๋ถ„ (critical, warning, info)
โ€ข for ์ ˆ์„ ์‚ฌ์šฉํ•ด์„œ ์ผ์‹œ์ ์ธ ์ŠคํŒŒ์ดํฌ ๋ฌด์‹œ
โ€ข ์•Œ๋ฆผ ๊ทธ๋ฃนํ™”์™€ ์–ต์ œ ๊ทœ์น™ ํ™œ์šฉ
โ€ข ์ •๊ธฐ์ ์œผ๋กœ ์•Œ๋ฆผ ๊ทœ์น™ ๊ฒ€ํ†  ๋ฐ ์กฐ์ •
โ€ข ํ•ด๊ฒฐ๋œ ์•Œ๋ฆผ๋„ ํ†ต์ง€ํ•ด์„œ ์ƒํ™ฉ ์ข…๋ฃŒ๋ฅผ ๋ช…ํ™•ํžˆ
4๏ธโƒฃ ๋Œ€์‹œ๋ณด๋“œ๋Š” ๋ชฉ์ ๋ณ„๋กœ ๋ถ„๋ฆฌ ํ•˜๋‚˜์˜ ๋Œ€์‹œ๋ณด๋“œ์— ๋ชจ๋“  ๊ฑธ ๋‹ด์œผ๋ ค๊ณ  ํ•˜์ง€ ๋งˆ! ๋ชฉ์ ์— ๋”ฐ๋ผ ๋ถ„๋ฆฌํ•˜๋ฉด ํ›จ์”ฌ ํšจ์œจ์ ์ด์•ผ:
โ€ข Executive Dashboard: ๊ฒฝ์˜์ง„์„ ์œ„ํ•œ ๊ณ ์ˆ˜์ค€ ์ง€ํ‘œ
โ€ข Operations Dashboard: ์šด์˜ํŒ€์„ ์œ„ํ•œ ์ƒ์„ธ ๋ฉ”ํŠธ๋ฆญ
โ€ข Service Dashboard: ์„œ๋น„์Šค๋ณ„ ์ „์šฉ ๋Œ€์‹œ๋ณด๋“œ
โ€ข Troubleshooting Dashboard: ๋ฌธ์ œ ํ•ด๊ฒฐ์„ ์œ„ํ•œ ์ƒ์„ธ ๋ถ„์„
โ€ข SLA Dashboard: SLA ์ง€ํ‘œ ์ถ”์ 
5๏ธโƒฃ ๋ฐ์ดํ„ฐ ๋ณด์กด ์ •์ฑ… ์ˆ˜๋ฆฝ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ์˜์›ํžˆ ๋ณด๊ด€ํ•  ์ˆœ ์—†์–ด. ๋‹จ๊ณ„๋ณ„ ๋ณด์กด ์ •์ฑ…์„ ์ˆ˜๋ฆฝํ•ด:
โ€ข ๊ณ ํ•ด์ƒ๋„ ๋ฐ์ดํ„ฐ: 7~30์ผ
โ€ข ์ค‘๊ฐ„ ํ•ด์ƒ๋„ ๋ฐ์ดํ„ฐ: 3~6๊ฐœ์›” (Recording Rules ํ™œ์šฉ)
โ€ข ์ €ํ•ด์ƒ๋„ ๋ฐ์ดํ„ฐ: 1~2๋…„
โ€ข ์žฅ๊ธฐ ๋ณด๊ด€์ด ํ•„์š”ํ•˜๋ฉด Thanos๋‚˜ Cortex ๊ฐ™์€ ์žฅ๊ธฐ ์ €์žฅ ์†”๋ฃจ์…˜ ๊ณ ๋ ค
6๏ธโƒฃ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ๋„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ธฐ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ์ž์ฒด๊ฐ€ ๋‹ค์šด๋˜๋ฉด ์•„๋ฌด๊ฒƒ๋„ ๋ณผ ์ˆ˜ ์—†์–ด! ๋‹ค์Œ์„ ํ™•์ธํ•ด:
โ€ข Prometheus ์ž์ฒด์˜ ๋ฉ”ํŠธ๋ฆญ ๋ชจ๋‹ˆํ„ฐ๋ง
โ€ข ์Šคํฌ๋ž˜ํ•‘ ์‹คํŒจ์œจ ์ถ”์ 
โ€ข ์ฟผ๋ฆฌ ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง
โ€ข ์Šคํ† ๋ฆฌ์ง€ ์‚ฌ์šฉ๋Ÿ‰ ์ถ”์ 
โ€ข Alertmanager ์•Œ๋ฆผ ์ „์†ก ์„ฑ๊ณต๋ฅ 

๐ŸŒŸ ์žฌ๋Šฅ๋„ท์—์„œ ๋ชจ๋‹ˆํ„ฐ๋ง ์ „๋ฌธ๊ฐ€ ์ฐพ๊ธฐ

์—ฌ๊ธฐ๊นŒ์ง€ Prometheus์™€ Grafana๋ฅผ ํ™œ์šฉํ•œ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ๊ตฌ์ถ•์— ๋Œ€ํ•ด ์•Œ์•„๋ดค์–ด. ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์— ์ ์šฉํ•˜๋ ค๋ฉด ๋” ๋งŽ์€ ๊ณ ๋ฏผ๊ณผ ๊ฒฝํ—˜์ด ํ•„์š”ํ•˜์ง€. ๐Ÿค”

๋งŒ์•ฝ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ๊ตฌ์ถ•์ด๋‚˜ ์ตœ์ ํ™”์— ๋„์›€์ด ํ•„์š”ํ•˜๋‹ค๋ฉด, ์žฌ๋Šฅ๋„ท์—์„œ ๊ด€๋ จ ์ „๋ฌธ๊ฐ€๋ฅผ ์ฐพ์•„๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ด์•ผ! ์žฌ๋Šฅ๋„ท์€ ๋‹ค์–‘ํ•œ IT ์ „๋ฌธ๊ฐ€๋“ค์ด ๋ชจ์—ฌ ์žˆ๋Š” ํ”Œ๋žซํผ์ด๋ผ์„œ, Prometheus/Grafana ๊ตฌ์ถ• ๊ฒฝํ—˜์ด ํ’๋ถ€ํ•œ ์ „๋ฌธ๊ฐ€๋“ค์—๊ฒŒ ์ปจ์„คํŒ…์„ ๋ฐ›๊ฑฐ๋‚˜ ์ง์ ‘ ๊ตฌ์ถ•์„ ์˜๋ขฐํ•  ์ˆ˜ ์žˆ์–ด. ํŠนํžˆ ๋ณต์žกํ•œ Kubernetes ํ™˜๊ฒฝ์ด๋‚˜ ๋Œ€๊ทœ๋ชจ ์ธํ”„๋ผ์˜ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•  ๋•Œ๋Š” ๊ฒฝํ—˜ ์žˆ๋Š” ์ „๋ฌธ๊ฐ€์˜ ๋„์›€์ด ํฐ ์ฐจ์ด๋ฅผ ๋งŒ๋“ค์–ด๋‚ผ ์ˆ˜ ์žˆ์ง€! ๐Ÿ’ช

๐Ÿ“Š ๐Ÿ”” ๐Ÿ“ˆ ๐ŸŽฏ โœจ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ ์•Œ๋ฆผ ๊ด€๋ฆฌ ์‹œ๊ฐํ™” ๋ถ„์„ ์ตœ์ ํ™” ์™„๋ฒฝํ•œ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์˜ 5๊ฐ€์ง€ ํ•ต์‹ฌ ์š”์†Œ

๐ŸŽฌ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

์™€, ์ •๋ง ๊ธด ์—ฌ์ •์ด์—ˆ์ง€? ๐Ÿ˜… Prometheus์™€ Grafana๋ฅผ ํ™œ์šฉํ•œ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ๊ตฌ์ถ•์— ๋Œ€ํ•ด ๊ธฐ์ดˆ๋ถ€ํ„ฐ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๊นŒ์ง€ ๋ชจ๋‘ ๋‹ค๋ค„๋ดค์–ด. ์ด์ œ ๋„ˆ๋„ ๋ฉ‹์ง„ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ์„ ๊ฑฐ์•ผ!

๊ธฐ์–ตํ•ด์•ผ ํ•  ํ•ต์‹ฌ ํฌ์ธํŠธ๋ฅผ ์ •๋ฆฌํ•˜๋ฉด:

๐ŸŽฏ ํ•ต์‹ฌ ์š”์•ฝ
  • โœ… Prometheus๋Š” ์‹œ๊ณ„์—ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ธฐ๋ฐ˜์˜ ๊ฐ•๋ ฅํ•œ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ
  • โœ… PromQL์„ ๋งˆ์Šคํ„ฐํ•˜๋ฉด ์›ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ž์œ ์ž์žฌ๋กœ ๋ถ„์„ ๊ฐ€๋Šฅ
  • โœ… Grafana๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์•„๋ฆ„๋‹ต๊ฒŒ ์‹œ๊ฐํ™”ํ•˜๊ณ  ์ง๊ด€์ ์ธ ๋Œ€์‹œ๋ณด๋“œ ๊ตฌ์„ฑ
  • โœ… Alertmanager๋กœ ํšจ๊ณผ์ ์ธ ์•Œ๋ฆผ ์‹œ์Šคํ…œ ๊ตฌ์ถ•
  • โœ… Recording Rules๋กœ ์„ฑ๋Šฅ ์ตœ์ ํ™”
  • โœ… Service Discovery๋กœ ๋™์  ํ™˜๊ฒฝ์— ๋Œ€์‘
  • โœ… ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค๋ฅผ ๋”ฐ๋ผ ์•ˆ์ •์ ์ธ ์šด์˜ ํ™˜๊ฒฝ ๊ตฌ์ถ•

๋ชจ๋‹ˆํ„ฐ๋ง์€ ํ•œ ๋ฒˆ ๊ตฌ์ถ•ํ•˜๊ณ  ๋๋‚˜๋Š” ๊ฒŒ ์•„๋‹ˆ์•ผ. ์‹œ์Šคํ…œ์ด ์„ฑ์žฅํ•˜๊ณ  ๋ณ€ํ™”ํ•˜๋ฉด์„œ ๋ชจ๋‹ˆํ„ฐ๋ง๋„ ํ•จ๊ป˜ ์ง„ํ™”ํ•ด์•ผ ํ•ด. ์ฒ˜์Œ์—” ๊ธฐ๋ณธ์ ์ธ ์‹œ์Šคํ…œ ๋ฉ”ํŠธ๋ฆญ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ, ์ ์ฐจ ๋น„์ฆˆ๋‹ˆ์Šค ๋ฉ”ํŠธ๋ฆญ, ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ๋ฉ”ํŠธ๋ฆญ๊นŒ์ง€ ํ™•์žฅํ•ด๋‚˜๊ฐ€๋ฉด ๋ผ. ๐ŸŒฑ

๊ทธ๋ฆฌ๊ณ  ๋ฌด์—‡๋ณด๋‹ค ์ค‘์š”ํ•œ ๊ฑด, ๋ชจ๋‹ˆํ„ฐ๋ง ๋ฐ์ดํ„ฐ๋ฅผ ์‹ค์ œ๋กœ ํ™œ์šฉํ•˜๋Š” ๊ฑฐ์•ผ! ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ๋งŒ๋“ค์–ด๋†“๊ณ  ์•ˆ ๋ณด๋ฉด ๋ฌด์Šจ ์†Œ์šฉ์ด๊ฒ ์–ด? ์ •๊ธฐ์ ์œผ๋กœ ๋ฉ”ํŠธ๋ฆญ์„ ๊ฒ€ํ† ํ•˜๊ณ , ํŠธ๋ Œ๋“œ๋ฅผ ๋ถ„์„ํ•˜๊ณ , ๊ฐœ์„ ์ ์„ ์ฐพ์•„๋‚ด๋Š” ์Šต๊ด€์„ ๋“ค์ด์ž. ๊ทธ๊ฒŒ ์ง„์งœ DevOps ๋ฌธํ™”์˜ ์‹œ์ž‘์ด์•ผ! ๐Ÿš€

ํ˜น์‹œ ๊ตฌ์ถ•ํ•˜๋‹ค๊ฐ€ ๋ง‰ํžˆ๋Š” ๋ถ€๋ถ„์ด ์žˆ๊ฑฐ๋‚˜, ๋” ๊นŠ์ด ์žˆ๋Š” ๋‚ด์šฉ์ด ๊ถ๊ธˆํ•˜๋‹ค๋ฉด ์žฌ๋Šฅ๋„ท์˜ ์ง€์‹์ธ์˜ ์ˆฒ์—์„œ ๋‹ค๋ฅธ ์ „๋ฌธ๊ฐ€๋“ค์˜ ๊ธ€๋„ ์ฐพ์•„๋ณด๊ณ , ํ•„์š”ํ•˜๋ฉด ์ „๋ฌธ๊ฐ€์—๊ฒŒ ์ง์ ‘ ๋„์›€์„ ์š”์ฒญํ•ด๋ด. ํ•จ๊ป˜ ๋ฐฐ์šฐ๊ณ  ์„ฑ์žฅํ•˜๋Š” ๊ฒŒ ๊ฐœ๋ฐœ์ž ์ปค๋ฎค๋‹ˆํ‹ฐ์˜ ์•„๋ฆ„๋‹ค์›€์ด์ž–์•„? ๐Ÿ˜Š

์ž, ์ด์ œ ๋‹น์‹ ์˜ ์ฐจ๋ก€์•ผ! ์˜ค๋Š˜ ๋ฐฐ์šด ๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ ๋ฉ‹์ง„ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•ด๋ณด์ž. ์ฒ˜์Œ์—” ์ž‘๊ฒŒ ์‹œ์ž‘ํ•ด๋„ ๊ดœ์ฐฎ์•„. ํ•˜๋‚˜์”ฉ ์ถ”๊ฐ€ํ•˜๊ณ  ๊ฐœ์„ ํ•˜๋‹ค ๋ณด๋ฉด ์–ด๋А์ƒˆ ํ”„๋กœ๋•์…˜ ๋ ˆ๋ฒจ์˜ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์„ ์šด์˜ํ•˜๊ณ  ์žˆ๋Š” ์ž์‹ ์„ ๋ฐœ๊ฒฌํ•˜๊ฒŒ ๋  ๊ฑฐ์•ผ! ๐Ÿ’ช

Happy Monitoring! ๐Ÿ“Šโœจ

๐ŸŽ“ ๋” ๋ฐฐ์šฐ๊ณ  ์‹ถ๋‹ค๋ฉด?

Prometheus ๊ณต์‹ ๋ฌธ์„œ: prometheus.io/docs
Grafana ๊ณต์‹ ๋ฌธ์„œ: grafana.com/docs
PromQL ์น˜ํŠธ์‹œํŠธ: promlabs.com/promql-cheat-sheet
Awesome Prometheus: github.com/roaldnefs/awesome-prometheus

๊ณ„์† ํ•™์Šตํ•˜๊ณ , ์‹คํ—˜ํ•˜๊ณ , ๊ณต์œ ํ•˜์ž! ๐Ÿš€
๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.