Ver3.0 ๐ Prometheus์ Grafana๋ก ์์ฑํ๋ ์ค์๊ฐ ๋ชจ๋ํฐ๋ง ์์คํ ๊ณผ ์๋ฆผ ๋์๋ณด๋ ๊ตฌ์ฑ ๊ฐ์ด๋

๐ Prometheus์ Grafana๋ก ์์ฑํ๋ ์ค์๊ฐ ๋ชจ๋ํฐ๋ง ์์คํ ๊ณผ ์๋ฆผ ๋์๋ณด๋ ๊ตฌ์ฑ ๊ฐ์ด๋
์๋ ! ๐ ์ค๋์ ๊ฐ๋ฐ์๋ผ๋ฉด ๊ผญ ์์์ผ ํ Prometheus์ Grafana๋ฅผ ํ์ฉํ ๋ชจ๋ํฐ๋ง ์์คํ ๊ตฌ์ถ์ ๋ํด ์ด์ผ๊ธฐํด๋ณผ๊ฒ. ์๋ฒ๊ฐ ๊ฐ์๊ธฐ ๋ค์ด๋๊ฑฐ๋, ํธ๋ํฝ์ด ํญ์ฆํ๋๋ฐ ์๋ฌด๊ฒ๋ ๋ชจ๋ฅด๊ณ ์๋ค๊ฐ ์ฌ์ฉ์๋ค์ ํญ์ ์ ํ๋ฅผ ๋ฐ์ ๊ฒฝํ ์์ด? ๐ฑ ๊ทธ๋ฐ ์ ๋ชฝ ๊ฐ์ ์ํฉ์ ๋ฐฉ์งํ๊ธฐ ์ํด ์ฐ๋ฆฌ์๊ฒ๋ ๊ฐ๋ ฅํ ๋ชจ๋ํฐ๋ง ์์คํ ์ด ํ์ํด!
์์ฆ ํด๋ผ์ฐ๋ ํ๊ฒฝ๊ณผ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ๊ฐ ๋์ธ๊ฐ ๋๋ฉด์, ์์คํ ์ ๋ณต์ก๋๋ ๊ธฐํ๊ธ์์ ์ผ๋ก ์ฆ๊ฐํ์ด. ์์ ์ฒ๋ผ ์๋ฒ ํ๋ ๋๋ง ๊ด๋ฆฌํ๋ ์์ ์ ์ง๋๊ฐ์ง. ์ด์ ๋ ์์ญ, ์๋ฐฑ ๊ฐ์ ์ปจํ ์ด๋์ ์๋น์ค๋ค์ด ์ ๊ธฐ์ ์ผ๋ก ์ฐ๊ฒฐ๋์ด ์๊ณ , ์ด ๋ชจ๋ ๊ฑธ ์ค์๊ฐ์ผ๋ก ๋ชจ๋ํฐ๋งํด์ผ ํ๋ ์๋์ผ. ๐
๐ฏ Prometheus๋ ๋ฌด์์ธ๊ฐ?
Prometheus๋ 2012๋ SoundCloud์์ ๊ฐ๋ฐ๋ ์คํ์์ค ๋ชจ๋ํฐ๋ง ์์คํ ์ด์ผ. ์ง๊ธ์ CNCF(Cloud Native Computing Foundation)์ ์กธ์ ํ๋ก์ ํธ๋ก, Kubernetes ๋ค์์ผ๋ก ๋ ๋ฒ์งธ๋ก ์กธ์ ํ ํ๋ก์ ํธ๋ผ๋ ์ ์์ ๊ทธ ์ ๋ขฐ์ฑ์ ์ ์ ์์ง. ๐
Pull ๋ฐฉ์์ ๋ฐ์ดํฐ ์์ง: ๋๋ถ๋ถ์ ๋ชจ๋ํฐ๋ง ์์คํ ์ด Push ๋ฐฉ์(์๋ฒ๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋ ๋ฐฉ์)์ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ๋ฌ๋ฆฌ, Prometheus๋ Pull ๋ฐฉ์์ ์ฌ์ฉํด. ์ฆ, Prometheus๊ฐ ์ฃผ๊ธฐ์ ์ผ๋ก ํ๊ฒ ์๋ฒ๋ค์ ๋ฐฉ๋ฌธํด์ ๋ฉํธ๋ฆญ์ ๊ฐ์ ธ์ค๋ ๊ฑฐ์ผ. ์ด๊ฒ ์ ์ข๋๊ณ ? ์ค์ ์๋ฒ๊ฐ ๋ชจ๋ ๊ฑธ ํต์ ํ ์ ์๊ณ , ๋คํธ์ํฌ ๋ฌธ์ ๋ก ๋ฐ์ดํฐ๊ฐ ์ ์ค๋ ๊ฐ๋ฅ์ฑ์ด ์ค์ด๋ค๊ฑฐ๋ ! ๐ฃ
๊ฐ๋ ฅํ ์ฟผ๋ฆฌ ์ธ์ด(PromQL): Prometheus Query Language๋ฅผ ์ฌ์ฉํด์ ๋ณต์กํ ๋ฐ์ดํฐ ๋ถ์์ด ๊ฐ๋ฅํด. SQL์ฒ๋ผ ์ง๊ด์ ์ด๋ฉด์๋ ์๊ณ์ด ๋ฐ์ดํฐ์ ํนํ๋ ๊ธฐ๋ฅ๋ค์ด ๋ง์.
๋ค์ฐจ์ ๋ฐ์ดํฐ ๋ชจ๋ธ: ๋ฉํธ๋ฆญ ์ด๋ฆ๊ณผ ํจ๊ป ์ฌ๋ฌ ๋ ์ด๋ธ(label)์ ๋ถ์ฌ์ ๋ฐ์ดํฐ๋ฅผ ๊ตฌ๋ถํ ์ ์์ด. ์๋ฅผ ๋ค์ด, ๊ฐ์ CPU ์ฌ์ฉ๋ฅ ์ด๋ผ๋ ์๋ฒ๋ณ, ํ๊ฒฝ๋ณ, ์ง์ญ๋ณ๋ก ๊ตฌ๋ถํด์ ์ ์ฅํ ์ ์์ง.
๐ฆ Prometheus์ ์ฃผ์ ์ปดํฌ๋ํธ
Prometheus ์ํ๊ณ๋ ์ฌ๋ฌ ์ปดํฌ๋ํธ๋ก ๊ตฌ์ฑ๋์ด ์์ด. ๊ฐ๊ฐ์ ์ญํ ์ ์ดํดํ๋ฉด ์ ์ฒด ์์คํ ์ ๊ตฌ์ถํ๋ ๊ฒ ํจ์ฌ ์ฌ์์ง ๊ฑฐ์ผ!
๐จ Grafana๋ก ๋ฐ์ดํฐ ์๊ฐํํ๊ธฐ
Prometheus๊ฐ ๋ฐ์ดํฐ๋ฅผ ์์งํ๋ ์์ง์ด๋ผ๋ฉด, Grafana๋ ๊ทธ ๋ฐ์ดํฐ๋ฅผ ์๋ฆ๋ต๊ฒ ๋ณด์ฌ์ฃผ๋ ์บ๋ฒ์ค์ผ! ๐ผ๏ธ Grafana๋ 2014๋ ์ ์์๋ ์คํ์์ค ์๊ฐํ ํ๋ซํผ์ผ๋ก, ๋จ์ํ Prometheus๋ฟ๋ง ์๋๋ผ InfluxDB, Elasticsearch, MySQL ๋ฑ ๋ค์ํ ๋ฐ์ดํฐ ์์ค๋ฅผ ์ง์ํด.
๐ญ ๋ค์ํ ์๊ฐํ ์ต์ : ๊ทธ๋ํ, ๊ฒ์ด์ง, ํํธ๋งต, ํ ์ด๋ธ ๋ฑ 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'
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_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์ ๊ฝ์ด๋ผ๊ณ ํ ์ ์์ด! ๐ ์ด ์ฟผ๋ฆฌ ์ธ์ด๋ฅผ ์ ๋ค๋ฃจ๋ฉด ์ํ๋ ๋ฐ์ดํฐ๋ฅผ ์์ ์์ฌ๋ก ๋ถ์ํ ์ ์์ง. ์ฒ์์ ์ด๋ ค์ ๋ณด์ด์ง๋ง, ๋ช ๊ฐ์ง ํจํด๋ง ์ตํ๋ฉด ๊ธ๋ฐฉ ์ต์ํด์ง ๊ฑฐ์ผ.
๐ ๊ธฐ๋ณธ ์ฟผ๋ฆฌ ๋ฌธ๋ฒ
๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ํํ๋ก, ๋ฉํธ๋ฆญ ์ด๋ฆ๋ง ์ ๋ ฅํ๋ฉด ๋ชจ๋ ์๊ณ์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์:
node_cpu_seconds_total2๏ธโฃ ๋ ์ด๋ธ ํํฐ๋ง
์ค๊ดํธ ์์ ๋ ์ด๋ธ ์กฐ๊ฑด์ ๋ฃ์ด์ ํํฐ๋งํ ์ ์์ด:
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]))
irate(): rate()์ ๋น์ทํ์ง๋ง ๋ง์ง๋ง ๋ ๋ฐ์ดํฐ ํฌ์ธํธ๋ง ์ฌ์ฉํด์ ๋ ๋ฏผ๊ฐํ๊ฒ ๋ฐ์ํด.
increase(): ํน์ ์๊ฐ ๋์์ ์ด ์ฆ๊ฐ๋์ ๊ณ์ฐํด.
sum(): ์ฌ๋ฌ ์๊ณ์ด์ ๊ฐ์ ํฉ์ณ.
avg(): ํ๊ท ๊ฐ์ ๊ณ์ฐํด.
max(), min(): ์ต๋๊ฐ, ์ต์๊ฐ์ ์ฐพ์.
count(): ์๊ณ์ด์ ๊ฐ์๋ฅผ ์ธ.
topk(), bottomk(): ์์/ํ์ k๊ฐ์ ์๊ณ์ด์ ์ ํํด.
histogram_quantile(): ํ์คํ ๊ทธ๋จ์์ ํน์ ๋ฐฑ๋ถ์์๋ฅผ ๊ณ์ฐํด.
๐ช ์ค์ PromQL ์์
์ค์ ์ด์ ํ๊ฒฝ์์ ์์ฃผ ์ฌ์ฉํ๋ ์ฟผ๋ฆฌ๋ค์ ๋ชจ์๋ดค์ด. ์ด๋ฐ ์ฟผ๋ฆฌ๋ค์ ๋์๋ณด๋๋ ์๋ฆผ ๊ท์น์ ํ์ฉํ ์ ์์ด! ๐ฏ
topk(5, 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100))
node_memory_MemAvailable_bytes / 1024 / 1024 / 1024 < 1
(node_filesystem_size_bytes - node_filesystem_avail_bytes) / node_filesystem_size_bytes * 100 > 80
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 }}"
์ ์ ํ ์๊ณ๊ฐ ์ค์ : ๋๋ฌด ๋ฎ์ผ๋ฉด ์ค์๋ฆผ์ด ๋ง์์ง๊ณ , ๋๋ฌด ๋์ผ๋ฉด ์ค์ ๋ฌธ์ ๋ฅผ ๋์น ์ ์์ด. ์ด์ํ๋ฉด์ ์ ์ง์ ์ผ๋ก ์กฐ์ ํด์ผ ํด.
์ฌ๊ฐ๋ ๊ตฌ๋ถ: 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 ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ๋จผ์ ๋ฐ์ดํฐ ์์ค๋ฅผ ์ถ๊ฐํด์ผ ํด:
2๏ธโฃ "Add data source" ๋ฒํผ ํด๋ฆญ
3๏ธโฃ Prometheus ์ ํ
4๏ธโฃ URL์ Prometheus ์๋ฒ ์ฃผ์ ์ ๋ ฅ (์: http://localhost:9090)
5๏ธโฃ "Save & Test" ๋ฒํผ ํด๋ฆญํด์ ์ฐ๊ฒฐ ํ์ธ
์ฐ๊ฒฐ์ด ์ฑ๊ณตํ๋ฉด "Data source is working" ๋ฉ์์ง๊ฐ ๋ํ๋ ๊ฑฐ์ผ! โ
๐ ๋์๋ณด๋ ๋ง๋ค๊ธฐ
์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก ๋์๋ณด๋๋ฅผ ๋ง๋ค์ด๋ณด์! Grafana์๋ ์ด๋ฏธ ๋ง๋ค์ด์ง ์์ฒ ๊ฐ์ ๋์๋ณด๋ ํ ํ๋ฆฟ์ด ์์ด์, ์ฒ์๋ถํฐ ๋ง๋ค ํ์ ์์ด ๊ฐ์ ธ๋ค ์ธ ์ ์์ด. ํ์ง๋ง ์ง์ ๋ง๋๋ ๋ฐฉ๋ฒ๋ ์์๋๋ฉด ์ข์ง! ๐
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๋ ๋ฐ์ดํฐ์ ํน์ฑ์ ๋ง๋ ๋ค์ํ ์๊ฐํ ์ต์ ์ ์ ๊ณตํด. ์ด๋ค ์ํฉ์ ์ด๋ค ํ์ ์ ์ฐ๋ฉด ์ข์์ง ์์๋ณด์! ๐จ
๐ช ์ค์ ๋์๋ณด๋ ๊ตฌ์ฑ ์์
์ด๋ก ์ ์ถฉ๋ถํ ๋ฐฐ์ ์ผ๋, ์ด์ ์ค์ ๋ก ์ฌ์ฉํ ์ ์๋ ๋์๋ณด๋๋ฅผ ๊ตฌ์ฑํด๋ณด์! ์ฌ๊ธฐ์๋ ์น ์ ํ๋ฆฌ์ผ์ด์ ๋ชจ๋ํฐ๋ง ๋์๋ณด๋๋ฅผ ๋ง๋ค์ด๋ณผ๊ฒ. ๐
๐ ์น ์ ํ๋ฆฌ์ผ์ด์ ๋ชจ๋ํฐ๋ง ๋์๋ณด๋
โข ์ด ์์ฒญ ์ (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๋ ๋ค์ํ ์๋ฆผ ์ฑ๋์ ์ง์ํด:
โข Slack
โข PagerDuty
โข Microsoft Teams
โข Discord
โข Telegram
โข Webhook (์ปค์คํ ํตํฉ)
โข OpsGenie
โข VictorOps
๊ทธ ์ธ 30๊ฐ ์ด์์ ์ฑ๋ ์ง์!
Slack ์๋ฆผ ์ฑ๋์ ์ค์ ํ๋ ์์ ๋ฅผ ๋ณด์ฌ์ค๊ฒ:
2๏ธโฃ Type์์ "Slack" ์ ํ
3๏ธโฃ Slack Webhook URL ์ ๋ ฅ
4๏ธโฃ ์๋ฆผ์ ๋ฐ์ ์ฑ๋ ์ง์ (์: #alerts)
5๏ธโฃ "Test" ๋ฒํผ์ผ๋ก ํ ์คํธ ์๋ฆผ ์ ์ก
6๏ธโฃ "Save" ๋ฒํผ ํด๋ฆญ!
โก ํจ๋์ ์๋ฆผ ๊ท์น ์ถ๊ฐํ๊ธฐ
์ด์ ํน์ ํจ๋์ ์๋ฆผ ๊ท์น์ ์ถ๊ฐํด๋ณด์. ์๋ฅผ ๋ค์ด, CPU ์ฌ์ฉ๋ฅ ์ด 80%๋ฅผ ๋์ผ๋ฉด ์๋ฆผ์ ๋ฐ๋๋ก ์ค์ ํ ์ ์์ด:
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 ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด ํ๋์ ๋์๋ณด๋๋ก ์ฌ๋ฌ ํ๊ฒฝ์ ๋ชจ๋ํฐ๋งํ ์ ์์ด. ์๋ฅผ ๋ค์ด, ์๋ฒ๋ฅผ ์ ํํ๋ฉด ํด๋น ์๋ฒ์ ๋ฉํธ๋ฆญ๋ง ๋ณด์ฌ์ฃผ๋ ์์ด์ง!
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 ๊ธฐ๋ฅ์ ํ์ฉํด๋ณด์! ๐
โข ์๋ฆผ ๋ฐ์ ์์ ํ์: ์ด๋ค ๋ฉํธ๋ฆญ์ด ์๋ฆผ์ ํธ๋ฆฌ๊ฑฐํ๋์ง ํ์ธ
โข ์ค์ผ์ผ๋ง ์ด๋ฒคํธ ํ์: ์คํ ์ค์ผ์ผ๋ง์ด ๋ฐ์ํ ์์ ํ์ธ
โข ์ธ๋ถ ์ด๋ฒคํธ ํ์: ๋ง์ผํ ์บ ํ์ธ, ์ด๋ฒคํธ ์์ ์์ ๋ฑ
๐ณ 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 ํด๋ฌ์คํฐ ์ ์ฒด๋ฅผ ๋ชจ๋ํฐ๋งํ ์ ์๋ ๊ธฐ๋ณธ ๋์๋ณด๋๋ ํจ๊ป ์ ๊ณต๋ผ! ๐
๐ ๋ชจ๋ํฐ๋ง ๋ฒ ์คํธ ํ๋ํฐ์ค
๋ง์ง๋ง์ผ๋ก, ์ค์ ์ด์ ํ๊ฒฝ์์ ๋ชจ๋ํฐ๋ง ์์คํ ์ ํจ๊ณผ์ ์ผ๋ก ์ด์ํ๊ธฐ ์ํ ๋ฒ ์คํธ ํ๋ํฐ์ค๋ฅผ ๊ณต์ ํ ๊ฒ! ์ด๊ฑด ๋ด๊ฐ ์ฌ๋ฌ ํ๋ก์ ํธ๋ฅผ ๊ฒฝํํ๋ฉด์ ๋ฐฐ์ด ๋ ธํ์ฐ๋ค์ด์ผ. ๐ก
โข ์์คํ ๋ฉํธ๋ฆญ: 15~30์ด
โข ์ ํ๋ฆฌ์ผ์ด์ ๋ฉํธ๋ฆญ: 10~15์ด
โข ๋ฐฐ์น ์์ : 1~5๋ถ
์ค์๋์ ๋ณํ ์๋์ ๋ฐ๋ผ ์กฐ์ ํด์ผ ํด!
โข ๊ณ ์ ๋ ๊ฐ๋ง ๋ ์ด๋ธ๋ก ์ฌ์ฉ (์ฌ์ฉ์ ID, ์ธ์ ID ๊ฐ์ ๊ฑด X)
โข ๋ ์ด๋ธ ๊ฐ์๋ 10๊ฐ ์ดํ๋ก ์ ํ
โข ๋ ์ด๋ธ ๊ฐ์ ์ข ๋ฅ๋ 100๊ฐ ์ดํ๊ฐ ์ด์์
โข ํ๊ฒฝ(env), ์๋น์ค(service), ์ธ์คํด์ค(instance) ๊ฐ์ ๊ธฐ๋ณธ ๋ ์ด๋ธ์ ์ผ๊ด์ฑ ์๊ฒ ์ฌ์ฉ
โข ์ฌ๊ฐ๋๋ฅผ ๋ช ํํ ๊ตฌ๋ถ (critical, warning, info)
โข for ์ ์ ์ฌ์ฉํด์ ์ผ์์ ์ธ ์คํ์ดํฌ ๋ฌด์
โข ์๋ฆผ ๊ทธ๋ฃนํ์ ์ต์ ๊ท์น ํ์ฉ
โข ์ ๊ธฐ์ ์ผ๋ก ์๋ฆผ ๊ท์น ๊ฒํ ๋ฐ ์กฐ์
โข ํด๊ฒฐ๋ ์๋ฆผ๋ ํต์งํด์ ์ํฉ ์ข ๋ฃ๋ฅผ ๋ช ํํ
โข Executive Dashboard: ๊ฒฝ์์ง์ ์ํ ๊ณ ์์ค ์งํ
โข Operations Dashboard: ์ด์ํ์ ์ํ ์์ธ ๋ฉํธ๋ฆญ
โข Service Dashboard: ์๋น์ค๋ณ ์ ์ฉ ๋์๋ณด๋
โข Troubleshooting Dashboard: ๋ฌธ์ ํด๊ฒฐ์ ์ํ ์์ธ ๋ถ์
โข SLA Dashboard: SLA ์งํ ์ถ์
โข ๊ณ ํด์๋ ๋ฐ์ดํฐ: 7~30์ผ
โข ์ค๊ฐ ํด์๋ ๋ฐ์ดํฐ: 3~6๊ฐ์ (Recording Rules ํ์ฉ)
โข ์ ํด์๋ ๋ฐ์ดํฐ: 1~2๋
โข ์ฅ๊ธฐ ๋ณด๊ด์ด ํ์ํ๋ฉด Thanos๋ Cortex ๊ฐ์ ์ฅ๊ธฐ ์ ์ฅ ์๋ฃจ์ ๊ณ ๋ ค
โข Prometheus ์์ฒด์ ๋ฉํธ๋ฆญ ๋ชจ๋ํฐ๋ง
โข ์คํฌ๋ํ ์คํจ์จ ์ถ์
โข ์ฟผ๋ฆฌ ์ฑ๋ฅ ๋ชจ๋ํฐ๋ง
โข ์คํ ๋ฆฌ์ง ์ฌ์ฉ๋ ์ถ์
โข Alertmanager ์๋ฆผ ์ ์ก ์ฑ๊ณต๋ฅ
๐ ์ฌ๋ฅ๋ท์์ ๋ชจ๋ํฐ๋ง ์ ๋ฌธ๊ฐ ์ฐพ๊ธฐ
์ฌ๊ธฐ๊น์ง Prometheus์ Grafana๋ฅผ ํ์ฉํ ๋ชจ๋ํฐ๋ง ์์คํ ๊ตฌ์ถ์ ๋ํด ์์๋ดค์ด. ํ์ง๋ง ์ค์ ๋ก ํ๋ก๋์ ํ๊ฒฝ์ ์ ์ฉํ๋ ค๋ฉด ๋ ๋ง์ ๊ณ ๋ฏผ๊ณผ ๊ฒฝํ์ด ํ์ํ์ง. ๐ค
๋ง์ฝ ๋ชจ๋ํฐ๋ง ์์คํ ๊ตฌ์ถ์ด๋ ์ต์ ํ์ ๋์์ด ํ์ํ๋ค๋ฉด, ์ฌ๋ฅ๋ท์์ ๊ด๋ จ ์ ๋ฌธ๊ฐ๋ฅผ ์ฐพ์๋ณด๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์ผ! ์ฌ๋ฅ๋ท์ ๋ค์ํ IT ์ ๋ฌธ๊ฐ๋ค์ด ๋ชจ์ฌ ์๋ ํ๋ซํผ์ด๋ผ์, Prometheus/Grafana ๊ตฌ์ถ ๊ฒฝํ์ด ํ๋ถํ ์ ๋ฌธ๊ฐ๋ค์๊ฒ ์ปจ์คํ ์ ๋ฐ๊ฑฐ๋ ์ง์ ๊ตฌ์ถ์ ์๋ขฐํ ์ ์์ด. ํนํ ๋ณต์กํ Kubernetes ํ๊ฒฝ์ด๋ ๋๊ท๋ชจ ์ธํ๋ผ์ ๋ชจ๋ํฐ๋ง ์์คํ ์ ๊ตฌ์ถํ ๋๋ ๊ฒฝํ ์๋ ์ ๋ฌธ๊ฐ์ ๋์์ด ํฐ ์ฐจ์ด๋ฅผ ๋ง๋ค์ด๋ผ ์ ์์ง! ๐ช
๐ฌ ๋ง๋ฌด๋ฆฌํ๋ฉฐ
์, ์ ๋ง ๊ธด ์ฌ์ ์ด์์ง? ๐ 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
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.